Search in sources :

Example 1 with JimpleBody

use of soot.jimple.JimpleBody in project robovm by robovm.

the class ClassCompiler method compile.

private void compile(Clazz clazz, OutputStream out) throws IOException {
    javaMethodCompiler.reset(clazz);
    bridgeMethodCompiler.reset(clazz);
    callbackMethodCompiler.reset(clazz);
    nativeMethodCompiler.reset(clazz);
    structMemberMethodCompiler.reset(clazz);
    globalValueMethodCompiler.reset(clazz);
    ClazzInfo ci = clazz.resetClazzInfo();
    mb = new ModuleBuilder();
    for (CompilerPlugin compilerPlugin : config.getCompilerPlugins()) {
        compilerPlugin.beforeClass(config, clazz, mb);
    }
    sootClass = clazz.getSootClass();
    trampolines = new HashMap<>();
    catches = new HashSet<String>();
    classFields = getClassFields(config.getOs(), config.getArch(), sootClass);
    instanceFields = getInstanceFields(config.getOs(), config.getArch(), sootClass);
    classType = getClassType(config.getOs(), config.getArch(), sootClass);
    instanceType = getInstanceType(config.getOs(), config.getArch(), sootClass);
    attributesEncoder.encode(mb, sootClass);
    // will never be initialized.
    if (!sootClass.declaresMethodByName("<clinit>") && hasConstantValueTags(classFields)) {
        SootMethod clinit = new SootMethod("<clinit>", Collections.EMPTY_LIST, VoidType.v(), Modifier.STATIC);
        JimpleBody body = Jimple.v().newBody(clinit);
        clinit.setActiveBody(body);
        body.getUnits().add(new JReturnVoidStmt());
        this.sootClass.addMethod(clinit);
    }
    if (isStruct(sootClass)) {
        SootMethod _sizeOf = new SootMethod("_sizeOf", Collections.EMPTY_LIST, IntType.v(), Modifier.PROTECTED | Modifier.NATIVE);
        sootClass.addMethod(_sizeOf);
        SootMethod sizeOf = new SootMethod("sizeOf", Collections.EMPTY_LIST, IntType.v(), Modifier.PUBLIC | Modifier.STATIC | Modifier.NATIVE);
        sootClass.addMethod(sizeOf);
    }
    mb.addInclude(getClass().getClassLoader().getResource(String.format("header-%s-%s.ll", config.getOs().getFamily(), config.getArch())));
    mb.addInclude(getClass().getClassLoader().getResource("header.ll"));
    mb.addFunction(createLdcClass());
    mb.addFunction(createLdcClassWrapper());
    Function allocator = createAllocator();
    mb.addFunction(allocator);
    mb.addFunction(createClassInitWrapperFunction(allocator.ref()));
    for (SootField f : sootClass.getFields()) {
        Function getter = createFieldGetter(f, classFields, classType, instanceFields, instanceType);
        Function setter = createFieldSetter(f, classFields, classType, instanceFields, instanceType);
        mb.addFunction(getter);
        mb.addFunction(setter);
        if (f.isStatic() && !f.isPrivate()) {
            mb.addFunction(createClassInitWrapperFunction(getter.ref()));
            if (!f.isFinal()) {
                mb.addFunction(createClassInitWrapperFunction(setter.ref()));
            }
        }
    }
    // After this point no changes to methods/fields may be done by CompilerPlugins.
    ci.initClassInfo();
    for (SootMethod method : sootClass.getMethods()) {
        for (CompilerPlugin compilerPlugin : config.getCompilerPlugins()) {
            compilerPlugin.beforeMethod(config, clazz, method, mb);
        }
        String name = method.getName();
        Function function = null;
        if (hasBridgeAnnotation(method)) {
            function = bridgeMethod(method);
        } else if (hasGlobalValueAnnotation(method)) {
            function = globalValueMethod(method);
        } else if (isStruct(sootClass) && ("_sizeOf".equals(name) || "sizeOf".equals(name) || hasStructMemberAnnotation(method))) {
            function = structMember(method);
        } else if (method.isNative()) {
            function = nativeMethod(method);
        } else if (!method.isAbstract()) {
            function = method(method);
        }
        if (hasCallbackAnnotation(method)) {
            callbackMethod(method);
        }
        if (!name.equals("<clinit>") && !name.equals("<init>") && !method.isPrivate() && !method.isStatic() && !Modifier.isFinal(method.getModifiers()) && !Modifier.isFinal(sootClass.getModifiers())) {
            createLookupFunction(method);
        }
        if (method.isStatic() && !name.equals("<clinit>")) {
            String fnName = method.isSynchronized() ? Symbols.synchronizedWrapperSymbol(method) : Symbols.methodSymbol(method);
            FunctionRef fn = new FunctionRef(fnName, getFunctionType(method));
            mb.addFunction(createClassInitWrapperFunction(fn));
        }
        for (CompilerPlugin compilerPlugin : config.getCompilerPlugins()) {
            if (function != null) {
                compilerPlugin.afterMethod(config, clazz, method, mb, function);
            }
        }
    }
    for (Trampoline trampoline : trampolines.keySet()) {
        Set<String> deps = new HashSet<String>();
        Set<Triple<String, String, String>> mDeps = new HashSet<>();
        trampolineResolver.compile(mb, clazz, trampoline, deps, mDeps);
        for (SootMethod m : trampolines.get(trampoline)) {
            MethodInfo mi = ci.getMethod(m.getName(), getDescriptor(m));
            mi.addClassDependencies(deps, false);
            mi.addInvokeMethodDependencies(mDeps, false);
        }
    }
    /*
         * Add method dependencies from overriding methods to the overridden
         * super method(s). These will be reversed by the DependencyGraph to
         * create edges from the super/interface method to the overriding
         * method.
         */
    Map<SootMethod, Set<SootMethod>> overriddenMethods = getOverriddenMethods(this.sootClass);
    for (SootMethod from : overriddenMethods.keySet()) {
        MethodInfo mi = ci.getMethod(from.getName(), getDescriptor(from));
        for (SootMethod to : overriddenMethods.get(from)) {
            mi.addSuperMethodDependency(getInternalName(to.getDeclaringClass()), to.getName(), getDescriptor(to), false);
        }
    }
    /*
         * Edge case. A method in a superclass might satisfy an interface method
         * in the interfaces implemented by this class. See e.g. the abstract
         * class HashMap$HashIterator which doesn't implement Iterator but has
         * the hasNext() and other methods. We add a dependency from the current
         * class to the super method to ensure it's included if the current
         * class is linked in.
         */
    if (sootClass.hasSuperclass()) {
        for (SootClass interfaze : getImmediateInterfaces(sootClass)) {
            for (SootMethod m : interfaze.getMethods()) {
                if (!m.isStatic()) {
                    try {
                        this.sootClass.getMethod(m.getName(), m.getParameterTypes());
                    } catch (RuntimeException e) {
                        /*
                             * Not found. Find the implementation in
                             * superclasses.
                             */
                        SootMethod superMethod = null;
                        for (SootClass sc = sootClass.getSuperclass(); sc.hasSuperclass(); sc = sc.getSuperclass()) {
                            try {
                                SootMethod candidate = sc.getMethod(m.getName(), m.getParameterTypes());
                                if (!candidate.isStatic()) {
                                    superMethod = candidate;
                                    break;
                                }
                            } catch (RuntimeException e2) {
                            // Not found.
                            }
                        }
                        if (superMethod != null) {
                            ci.addSuperMethodDependency(getInternalName(superMethod.getDeclaringClass()), superMethod.getName(), getDescriptor(superMethod), false);
                        }
                    }
                }
            }
        }
    }
    Global classInfoStruct = null;
    try {
        if (!sootClass.isInterface()) {
            config.getVTableCache().get(sootClass);
        }
        classInfoStruct = new Global(Symbols.infoStructSymbol(clazz.getInternalName()), Linkage.weak, createClassInfoStruct());
    } catch (IllegalArgumentException e) {
        // VTable throws this if any of the superclasses of the class is actually an interface.
        // Shouldn't happen frequently but the DRLVM test suite has some tests for this.
        // The Linker will take care of making sure the class cannot be loaded at runtime.
        classInfoStruct = new Global(Symbols.infoStructSymbol(clazz.getInternalName()), I8_PTR, true);
    }
    mb.addGlobal(classInfoStruct);
    /*
         * Emit an internal i8* alias for the info struct which MethodCompiler
         * can use when referencing this info struct in exception landing pads
         * in methods in the same class. See #1007.
         */
    mb.addAlias(new Alias(classInfoStruct.getName() + "_i8ptr", Linkage._private, new ConstantBitcast(classInfoStruct.ref(), I8_PTR)));
    Function infoFn = FunctionBuilder.infoStruct(sootClass);
    infoFn.add(new Ret(new ConstantBitcast(classInfoStruct.ref(), I8_PTR_PTR)));
    mb.addFunction(infoFn);
    for (CompilerPlugin compilerPlugin : config.getCompilerPlugins()) {
        compilerPlugin.afterClass(config, clazz, mb);
    }
    OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8");
    mb.build().write(writer);
    writer.flush();
    ci.setCatchNames(catches);
    // Make sure no class or interface has zero dependencies
    ci.addClassDependency("java/lang/Object", false);
    if (sootClass.hasSuperclass() && !sootClass.isInterface()) {
        ci.addClassDependency(getInternalName(sootClass.getSuperclass()), false);
    }
    for (SootClass iface : sootClass.getInterfaces()) {
        ci.addClassDependency(getInternalName(iface), false);
    }
    for (SootField f : sootClass.getFields()) {
        addClassDependencyIfNeeded(clazz, f.getType(), false);
    }
    for (SootMethod m : sootClass.getMethods()) {
        MethodInfo mi = ci.getMethod(m.getName(), getDescriptor(m));
        addClassDependencyIfNeeded(clazz, mi, m.getReturnType(), false);
        @SuppressWarnings("unchecked") List<soot.Type> paramTypes = (List<soot.Type>) m.getParameterTypes();
        for (soot.Type type : paramTypes) {
            addClassDependencyIfNeeded(clazz, mi, type, false);
        }
    }
    ci.addClassDependencies(attributesEncoder.getDependencies(), false);
    ci.addClassDependencies(catches, false);
    for (Trampoline t : trampolines.keySet()) {
        if (t instanceof Checkcast) {
            ci.addCheckcast(t.getTarget());
        } else if (t instanceof Instanceof) {
            ci.addInstanceof(t.getTarget());
        } else if (t instanceof Invokevirtual || t instanceof Invokeinterface) {
            ci.addInvoke(t.getTarget() + "." + ((Invoke) t).getMethodName() + ((Invoke) t).getMethodDesc());
        }
    }
    clazz.saveClazzInfo();
}
Also used : Ret(org.robovm.compiler.llvm.Ret) Set(java.util.Set) HashSet(java.util.HashSet) CompilerPlugin(org.robovm.compiler.plugin.CompilerPlugin) ConstantBitcast(org.robovm.compiler.llvm.ConstantBitcast) Global(org.robovm.compiler.llvm.Global) Invoke(org.robovm.compiler.trampoline.Invoke) Function(org.robovm.compiler.llvm.Function) Instanceof(org.robovm.compiler.trampoline.Instanceof) ArrayList(java.util.ArrayList) List(java.util.List) JimpleBody(soot.jimple.JimpleBody) Checkcast(org.robovm.compiler.trampoline.Checkcast) Invokevirtual(org.robovm.compiler.trampoline.Invokevirtual) FunctionRef(org.robovm.compiler.llvm.FunctionRef) HashSet(java.util.HashSet) JReturnVoidStmt(soot.jimple.internal.JReturnVoidStmt) Trampoline(org.robovm.compiler.trampoline.Trampoline) ClazzInfo(org.robovm.compiler.clazz.ClazzInfo) SootClass(soot.SootClass) Invokeinterface(org.robovm.compiler.trampoline.Invokeinterface) Triple(org.apache.commons.lang3.tuple.Triple) CodeGenFileType(org.robovm.llvm.binding.CodeGenFileType) BooleanType(soot.BooleanType) StructureType(org.robovm.compiler.llvm.StructureType) PointerType(org.robovm.compiler.llvm.PointerType) ShortType(soot.ShortType) ByteType(soot.ByteType) DoubleType(soot.DoubleType) FloatType(soot.FloatType) IntType(soot.IntType) CharType(soot.CharType) LongType(soot.LongType) RefLikeType(soot.RefLikeType) Type(org.robovm.compiler.llvm.Type) PrimType(soot.PrimType) VoidType(soot.VoidType) Alias(org.robovm.compiler.llvm.Alias) SootMethod(soot.SootMethod) SootField(soot.SootField) MethodInfo(org.robovm.compiler.clazz.MethodInfo) OutputStreamWriter(java.io.OutputStreamWriter)

Example 2 with JimpleBody

use of soot.jimple.JimpleBody in project soot by Sable.

the class AsmMethodSource method getBody.

@Override
public Body getBody(SootMethod m, String phaseName) {
    if (!m.isConcrete())
        return null;
    JimpleBody jb = Jimple.v().newBody(m);
    /* initialize */
    int nrInsn = instructions.size();
    nextLocal = maxLocals;
    locals = new HashMap<Integer, Local>(maxLocals + (maxLocals / 2));
    labels = ArrayListMultimap.create(4, 1);
    units = new HashMap<AbstractInsnNode, Unit>(nrInsn);
    frames = new HashMap<AbstractInsnNode, StackFrame>(nrInsn);
    trapHandlers = ArrayListMultimap.create(tryCatchBlocks.size(), 1);
    body = jb;
    /* retrieve all trap handlers */
    for (TryCatchBlockNode tc : tryCatchBlocks) trapHandlers.put(tc.handler, Jimple.v().newStmtBox(null));
    /* convert instructions */
    try {
        convert();
    } catch (Throwable t) {
        throw new RuntimeException("Failed to convert " + m, t);
    }
    /* build body (add units, locals, traps, etc.) */
    emitLocals();
    emitTraps();
    emitUnits();
    /* clean up */
    locals = null;
    labels = null;
    units = null;
    stack = null;
    frames = null;
    body = null;
    // Make sure to inline patterns of the form to enable proper variable
    // splitting and type assignment:
    // a = new A();
    // goto l0;
    // l0:
    // b = (B) a;
    // return b;
    castAndReturnInliner.transform(jb);
    try {
        PackManager.v().getPack("jb").apply(jb);
    } catch (Throwable t) {
        throw new RuntimeException("Failed to apply jb to " + m, t);
    }
    return jb;
}
Also used : TryCatchBlockNode(org.objectweb.asm.tree.TryCatchBlockNode) Local(soot.Local) AbstractInsnNode(org.objectweb.asm.tree.AbstractInsnNode) Unit(soot.Unit) JimpleBody(soot.jimple.JimpleBody)

Example 3 with JimpleBody

use of soot.jimple.JimpleBody in project soot by Sable.

the class AsmMethodSource method emitLocals.

private void emitLocals() {
    JimpleBody jb = body;
    SootMethod m = jb.getMethod();
    Collection<Local> jbl = jb.getLocals();
    Collection<Unit> jbu = jb.getUnits();
    int iloc = 0;
    if (!m.isStatic()) {
        Local l = getLocal(iloc++);
        jbu.add(Jimple.v().newIdentityStmt(l, Jimple.v().newThisRef(m.getDeclaringClass().getType())));
    }
    int nrp = 0;
    for (Object ot : m.getParameterTypes()) {
        Type t = (Type) ot;
        Local l = getLocal(iloc);
        jbu.add(Jimple.v().newIdentityStmt(l, Jimple.v().newParameterRef(t, nrp++)));
        if (AsmUtil.isDWord(t))
            iloc += 2;
        else
            iloc++;
    }
    for (Local l : locals.values()) {
        jbl.add(l);
    }
}
Also used : BooleanType(soot.BooleanType) Type(soot.Type) UnknownType(soot.UnknownType) ArrayType(soot.ArrayType) RefType(soot.RefType) ShortType(soot.ShortType) ByteType(soot.ByteType) DoubleType(soot.DoubleType) FloatType(soot.FloatType) IntType(soot.IntType) CharType(soot.CharType) LongType(soot.LongType) VoidType(soot.VoidType) SootMethod(soot.SootMethod) Local(soot.Local) Unit(soot.Unit) JimpleBody(soot.jimple.JimpleBody)

Example 4 with JimpleBody

use of soot.jimple.JimpleBody in project soot by Sable.

the class TypeAssigner method internalTransform.

/**
 * Assign types to local variables. *
 */
@Override
protected void internalTransform(Body b, String phaseName, Map<String, String> options) {
    if (b == null) {
        throw new NullPointerException();
    }
    Date start = new Date();
    if (Options.v().verbose())
        logger.debug("[TypeAssigner] typing system started on " + start);
    JBTROptions opt = new JBTROptions(options);
    /*
		 * Setting this guard to true enables comparison of the original and new
		 * type assigners. This will be slow since type assignment will always
		 * happen twice. The actual types used for Jimple are determined by the
		 * use-old-type-assigner option.
		 * 
		 * Each comparison is written as a separate semicolon-delimited line to
		 * the standard output, and the first field is always 'cmp' for use in
		 * grep. The format is:
		 * 
		 * cmp;Method Name;Stmt Count;Old Inference Time (ms); New Inference
		 * Time (ms);Typing Comparison
		 * 
		 * The Typing Comparison field compares the old and new typings: -2 -
		 * Old typing contains fewer variables (BAD!) -1 - Old typing is tighter
		 * (BAD!) 0 - Typings are equal 1 - New typing is tighter 2 - New typing
		 * contains fewer variables 3 - Typings are incomparable (inspect
		 * manually)
		 * 
		 * In a final release this guard, and anything in the first branch,
		 * would probably be removed.
		 */
    if (opt.compare_type_assigners()) {
        compareTypeAssigners(b, opt.use_older_type_assigner());
    } else {
        if (opt.use_older_type_assigner())
            TypeResolver.resolve((JimpleBody) b, Scene.v());
        else
            (new soot.jimple.toolkits.typing.fast.TypeResolver((JimpleBody) b)).inferTypes();
    }
    Date finish = new Date();
    if (Options.v().verbose()) {
        long runtime = finish.getTime() - start.getTime();
        long mins = runtime / 60000;
        long secs = (runtime % 60000) / 1000;
        logger.debug("[TypeAssigner] typing system ended. It took " + mins + " mins and " + secs + " secs.");
    }
    if (!opt.ignore_nullpointer_dereferences())
        replaceNullType(b);
    if (typingFailed((JimpleBody) b))
        throw new RuntimeException("type inference failed!");
}
Also used : JBTROptions(soot.options.JBTROptions) JimpleBody(soot.jimple.JimpleBody) Date(java.util.Date)

Example 5 with JimpleBody

use of soot.jimple.JimpleBody in project soot by Sable.

the class LockAllocationBodyTransformer method getLockFor.

public static Value getLockFor(EquivalentValue lockEqVal) {
    Value lock = lockEqVal.getValue();
    if (lock instanceof InstanceFieldRef)
        return lock;
    if (// it would be better to lock the array
    lock instanceof ArrayRef)
        // ref for each value of the index!
        return ((ArrayRef) lock).getBase();
    if (lock instanceof Local)
        return lock;
    if (lock instanceof StaticFieldRef || lock instanceof NewStaticLock) {
        if (lockEqValToLock.containsKey(lockEqVal))
            return lockEqValToLock.get(lockEqVal);
        SootClass lockClass = null;
        if (lock instanceof StaticFieldRef) {
            StaticFieldRef sfrLock = (StaticFieldRef) lock;
            lockClass = sfrLock.getField().getDeclaringClass();
        } else if (lock instanceof NewStaticLock) {
            DeadlockAvoidanceEdge dae = (DeadlockAvoidanceEdge) lock;
            lockClass = dae.getLockClass();
        }
        SootMethod clinitMethod = null;
        JimpleBody clinitBody = null;
        Stmt firstStmt = null;
        boolean addingNewClinit = !lockClass.declaresMethod("void <clinit>()");
        if (addingNewClinit) {
            clinitMethod = Scene.v().makeSootMethod("<clinit>", new ArrayList(), VoidType.v(), Modifier.PUBLIC | Modifier.STATIC);
            clinitBody = Jimple.v().newBody(clinitMethod);
            clinitMethod.setActiveBody(clinitBody);
            lockClass.addMethod(clinitMethod);
        } else {
            clinitMethod = lockClass.getMethod("void <clinit>()");
            clinitBody = (JimpleBody) clinitMethod.getActiveBody();
            firstStmt = clinitBody.getFirstNonIdentityStmt();
        }
        PatchingChain<Unit> clinitUnits = clinitBody.getUnits();
        Local lockLocal = Jimple.v().newLocal("objectLockLocal" + lockNumber, RefType.v("java.lang.Object"));
        // lockNumber is increased below
        // TODO: add name conflict
        clinitBody.getLocals().add(lockLocal);
        // avoidance code
        // assign new object to lock obj
        Stmt newStmt = Jimple.v().newAssignStmt(lockLocal, Jimple.v().newNewExpr(RefType.v("java.lang.Object")));
        if (addingNewClinit)
            clinitUnits.add(newStmt);
        else
            clinitUnits.insertBeforeNoRedirect(newStmt, firstStmt);
        // initialize new object
        SootClass objectClass = Scene.v().loadClassAndSupport("java.lang.Object");
        RefType type = RefType.v(objectClass);
        SootMethod initMethod = objectClass.getMethod("void <init>()");
        Stmt initStmt = Jimple.v().newInvokeStmt(Jimple.v().newSpecialInvokeExpr(lockLocal, initMethod.makeRef(), Collections.EMPTY_LIST));
        if (addingNewClinit)
            clinitUnits.add(initStmt);
        else
            clinitUnits.insertBeforeNoRedirect(initStmt, firstStmt);
        // copy new object to global static lock object (for use by other
        // fns)
        SootField actualLockObject = Scene.v().makeSootField("objectLockGlobal" + lockNumber, RefType.v("java.lang.Object"), Modifier.STATIC | Modifier.PUBLIC);
        lockNumber++;
        lockClass.addField(actualLockObject);
        StaticFieldRef actualLockSfr = Jimple.v().newStaticFieldRef(actualLockObject.makeRef());
        Stmt assignStmt = Jimple.v().newAssignStmt(actualLockSfr, lockLocal);
        if (addingNewClinit)
            clinitUnits.add(assignStmt);
        else
            clinitUnits.insertBeforeNoRedirect(assignStmt, firstStmt);
        if (addingNewClinit)
            clinitUnits.add(Jimple.v().newReturnVoidStmt());
        lockEqValToLock.put(lockEqVal, actualLockSfr);
        return actualLockSfr;
    }
    throw new RuntimeException("Unknown type of lock (" + lock + "): expected FieldRef, ArrayRef, or Local");
}
Also used : ArrayList(java.util.ArrayList) FakeJimpleLocal(soot.jimple.toolkits.infoflow.FakeJimpleLocal) Local(soot.Local) SootClass(soot.SootClass) Unit(soot.Unit) StaticFieldRef(soot.jimple.StaticFieldRef) Stmt(soot.jimple.Stmt) ArrayRef(soot.jimple.ArrayRef) RefType(soot.RefType) EquivalentValue(soot.EquivalentValue) Value(soot.Value) InstanceFieldRef(soot.jimple.InstanceFieldRef) SootMethod(soot.SootMethod) SootField(soot.SootField) JimpleBody(soot.jimple.JimpleBody)

Aggregations

JimpleBody (soot.jimple.JimpleBody)23 Local (soot.Local)14 SootMethod (soot.SootMethod)13 Unit (soot.Unit)10 ArrayList (java.util.ArrayList)9 SootClass (soot.SootClass)9 Iterator (java.util.Iterator)7 Value (soot.Value)7 Stmt (soot.jimple.Stmt)7 RefType (soot.RefType)6 List (java.util.List)5 VoidType (soot.VoidType)5 HashMap (java.util.HashMap)4 LinkedList (java.util.LinkedList)4 Body (soot.Body)4 BooleanType (soot.BooleanType)4 ByteType (soot.ByteType)4 CharType (soot.CharType)4 DoubleType (soot.DoubleType)4 FloatType (soot.FloatType)4