Search in sources :

Example 46 with SootField

use of soot.SootField in project robovm by robovm.

the class AttributesEncoder method encode.

public void encode(ModuleBuilder mb, SootClass sootClass) {
    this.mb = mb;
    dependencies = new HashSet<String>();
    classAttributes = null;
    fieldAttributes = new HashMap<SootField, Global>();
    methodAttributes = new HashMap<SootMethod, Global>();
    encodeAttributes(sootClass);
    Constant classAttributes = encodeAttributes(sootClass);
    if (classAttributes != null) {
        Global g = new Global(Symbols.classAttributesSymbol(sootClass), Linkage._private, classAttributes, true);
        mb.addGlobal(g);
        this.classAttributes = g;
    }
    for (SootField field : sootClass.getFields()) {
        Constant fieldAttributes = encodeAttributes(field);
        if (fieldAttributes != null) {
            Global g = new Global(Symbols.fieldAttributesSymbol(field), Linkage._private, fieldAttributes, true);
            mb.addGlobal(g);
            this.fieldAttributes.put(field, g);
        }
    }
    for (SootMethod method : sootClass.getMethods()) {
        Constant methodAttributes = encodeAttributes(method);
        if (methodAttributes != null) {
            Global g = new Global(Symbols.methodAttributesSymbol(method), Linkage._private, methodAttributes, true);
            mb.addGlobal(g);
            this.methodAttributes.put(method, g);
        }
    }
}
Also used : IntegerConstant(org.robovm.compiler.llvm.IntegerConstant) StructureConstant(org.robovm.compiler.llvm.StructureConstant) Constant(org.robovm.compiler.llvm.Constant) PackedStructureConstant(org.robovm.compiler.llvm.PackedStructureConstant) FloatingPointConstant(org.robovm.compiler.llvm.FloatingPointConstant) ArrayConstant(org.robovm.compiler.llvm.ArrayConstant) SootMethod(soot.SootMethod) SootField(soot.SootField) Global(org.robovm.compiler.llvm.Global)

Example 47 with SootField

use of soot.SootField in project robovm by robovm.

the class ClassCompiler method createClassInfoStruct.

private StructureConstant createClassInfoStruct() {
    int flags = 0;
    if (Modifier.isPublic(sootClass.getModifiers())) {
        flags |= CI_PUBLIC;
    }
    if (Modifier.isFinal(sootClass.getModifiers())) {
        flags |= CI_FINAL;
    }
    if (Modifier.isInterface(sootClass.getModifiers())) {
        flags |= CI_INTERFACE;
    }
    if (Modifier.isAbstract(sootClass.getModifiers())) {
        flags |= CI_ABSTRACT;
    }
    if ((sootClass.getModifiers() & 0x1000) > 0) {
        flags |= CI_SYNTHETIC;
    }
    if (Modifier.isAnnotation(sootClass.getModifiers())) {
        flags |= CI_ANNOTATION;
    }
    if (Modifier.isEnum(sootClass.getModifiers())) {
        flags |= CI_ENUM;
    }
    if (attributesEncoder.classHasAttributes()) {
        flags |= CI_ATTRIBUTES;
    }
    if (hasFinalizer(sootClass)) {
        flags |= CI_FINALIZABLE;
    }
    // Create the ClassInfoHeader structure.
    StructureConstantBuilder header = new StructureConstantBuilder();
    // Points to the runtime Class struct
    header.add(new NullConstant(I8_PTR));
    header.add(new IntegerConstant(flags));
    header.add(getString(getInternalName(sootClass)));
    if (sootClass.declaresMethod("<clinit>", Collections.emptyList(), VoidType.v())) {
        SootMethod method = sootClass.getMethod("<clinit>", Collections.emptyList(), VoidType.v());
        header.add(new FunctionRef(Symbols.methodSymbol(method), getFunctionType(method)));
    } else {
        header.add(new NullConstant(I8_PTR));
    }
    mb.addGlobal(new Global(Symbols.typeInfoSymbol(getInternalName(sootClass)), Linkage.external, I8_PTR, true));
    // TypeInfo* generated by Linker
    header.add(new GlobalRef(Symbols.typeInfoSymbol(getInternalName(sootClass)), I8_PTR));
    if (!sootClass.isInterface()) {
        header.add(createVTableStruct());
    } else {
        header.add(createITableStruct());
    }
    header.add(createITablesStruct());
    header.add(sizeof(classType));
    header.add(sizeof(instanceType));
    if (!instanceFields.isEmpty()) {
        header.add(offsetof(instanceType, 1, 1));
    } else {
        header.add(sizeof(instanceType));
    }
    header.add(new IntegerConstant((short) countReferences(classFields)));
    header.add(new IntegerConstant((short) countReferences(instanceFields)));
    PackedStructureConstantBuilder body = new PackedStructureConstantBuilder();
    body.add(new IntegerConstant((short) sootClass.getInterfaceCount()));
    body.add(new IntegerConstant((short) sootClass.getFieldCount()));
    body.add(new IntegerConstant((short) sootClass.getMethodCount()));
    if (!sootClass.isInterface()) {
        body.add(getStringOrNull(sootClass.hasSuperclass() ? getInternalName(sootClass.getSuperclass()) : null));
    }
    if (attributesEncoder.classHasAttributes()) {
        body.add(new ConstantBitcast(attributesEncoder.getClassAttributes().ref(), I8_PTR));
    }
    for (SootClass s : sootClass.getInterfaces()) {
        body.add(getString(getInternalName(s)));
    }
    for (SootField f : sootClass.getFields()) {
        flags = 0;
        soot.Type t = f.getType();
        if (t instanceof PrimType) {
            if (t.equals(BooleanType.v())) {
                flags |= DESC_Z;
            } else if (t.equals(ByteType.v())) {
                flags |= DESC_B;
            } else if (t.equals(ShortType.v())) {
                flags |= DESC_S;
            } else if (t.equals(CharType.v())) {
                flags |= DESC_C;
            } else if (t.equals(IntType.v())) {
                flags |= DESC_I;
            } else if (t.equals(LongType.v())) {
                flags |= DESC_J;
            } else if (t.equals(FloatType.v())) {
                flags |= DESC_F;
            } else if (t.equals(DoubleType.v())) {
                flags |= DESC_D;
            }
            flags <<= 12;
        }
        if (Modifier.isPublic(f.getModifiers())) {
            flags |= FI_PUBLIC;
        } else if (Modifier.isPrivate(f.getModifiers())) {
            flags |= FI_PRIVATE;
        } else if (Modifier.isProtected(f.getModifiers())) {
            flags |= FI_PROTECTED;
        }
        if (Modifier.isStatic(f.getModifiers())) {
            flags |= FI_STATIC;
        }
        if (Modifier.isFinal(f.getModifiers())) {
            flags |= FI_FINAL;
        }
        if (Modifier.isVolatile(f.getModifiers())) {
            flags |= FI_VOLATILE;
        }
        if (Modifier.isTransient(f.getModifiers())) {
            flags |= FI_TRANSIENT;
        }
        if ((f.getModifiers() & 0x1000) > 0) {
            flags |= FI_SYNTHETIC;
        }
        if (Modifier.isEnum(f.getModifiers())) {
            flags |= FI_ENUM;
        }
        if (attributesEncoder.fieldHasAttributes(f)) {
            flags |= FI_ATTRIBUTES;
        }
        body.add(new IntegerConstant((short) flags));
        body.add(getString(f.getName()));
        if (!(t instanceof PrimType)) {
            body.add(getString(getDescriptor(f)));
        }
        if (f.isStatic()) {
            int index = classFields.indexOf(f);
            body.add(offsetof(classType, 1, index, 1));
        } else {
            int index = instanceFields.indexOf(f);
            body.add(offsetof(instanceType, 1, 1 + index, 1));
        }
        if (attributesEncoder.fieldHasAttributes(f)) {
            body.add(new ConstantBitcast(attributesEncoder.getFieldAttributes(f).ref(), I8_PTR));
        }
    }
    VTable vtable = !sootClass.isInterface() ? config.getVTableCache().get(sootClass) : null;
    ITable itable = sootClass.isInterface() ? config.getITableCache().get(sootClass) : null;
    ;
    for (SootMethod m : sootClass.getMethods()) {
        soot.Type t = m.getReturnType();
        flags = 0;
        if (Modifier.isPublic(m.getModifiers())) {
            flags |= MI_PUBLIC;
        } else if (Modifier.isPrivate(m.getModifiers())) {
            flags |= MI_PRIVATE;
        } else if (Modifier.isProtected(m.getModifiers())) {
            flags |= MI_PROTECTED;
        }
        if (Modifier.isStatic(m.getModifiers())) {
            flags |= MI_STATIC;
        }
        if (Modifier.isFinal(m.getModifiers())) {
            flags |= MI_FINAL;
        }
        if (Modifier.isSynchronized(m.getModifiers())) {
            flags |= MI_SYNCHRONIZED;
        }
        if ((m.getModifiers() & 0x0040) > 0) {
            flags |= MI_BRIDGE;
        }
        if ((m.getModifiers() & 0x0080) > 0) {
            flags |= MI_VARARGS;
        }
        if (Modifier.isNative(m.getModifiers())) {
            if (!isStruct(sootClass) && !hasStructMemberAnnotation(m)) {
                flags |= MI_NATIVE;
            }
        }
        if (Modifier.isAbstract(m.getModifiers())) {
            flags |= MI_ABSTRACT;
        }
        if (Modifier.isStrictFP(m.getModifiers())) {
            flags |= MI_STRICT;
        }
        if ((m.getModifiers() & 0x1000) > 0) {
            flags |= MI_SYNTHETIC;
        }
        if (attributesEncoder.methodHasAttributes(m)) {
            flags |= MI_ATTRIBUTES;
        }
        if (hasBridgeAnnotation(m) || hasGlobalValueAnnotation(m)) {
            flags |= MI_BRO_BRIDGE;
        }
        if (hasCallbackAnnotation(m)) {
            flags |= MI_BRO_CALLBACK;
        }
        if ((t instanceof PrimType || t == VoidType.v()) && m.getParameterCount() == 0) {
            flags |= MI_COMPACT_DESC;
        }
        body.add(new IntegerConstant((short) flags));
        Constant viTableIndex = new IntegerConstant((short) -1);
        if (vtable != null) {
            VTable.Entry entry = vtable.getEntry(m);
            if (entry != null) {
                viTableIndex = new IntegerConstant((short) entry.getIndex());
            }
        } else {
            ITable.Entry entry = itable.getEntry(m);
            if (entry != null) {
                viTableIndex = new IntegerConstant((short) entry.getIndex());
            }
        }
        body.add(viTableIndex);
        body.add(getString(m.getName()));
        if ((flags & MI_COMPACT_DESC) > 0) {
            int desc = 0;
            if (t.equals(BooleanType.v())) {
                desc = DESC_Z;
            } else if (t.equals(ByteType.v())) {
                desc = DESC_B;
            } else if (t.equals(ShortType.v())) {
                desc = DESC_S;
            } else if (t.equals(CharType.v())) {
                desc = DESC_C;
            } else if (t.equals(IntType.v())) {
                desc = DESC_I;
            } else if (t.equals(LongType.v())) {
                desc = DESC_J;
            } else if (t.equals(FloatType.v())) {
                desc = DESC_F;
            } else if (t.equals(DoubleType.v())) {
                desc = DESC_D;
            } else if (t.equals(VoidType.v())) {
                desc = DESC_V;
            }
            body.add(new IntegerConstant((byte) desc));
        } else {
            body.add(getString(getDescriptor(m)));
        }
        if (attributesEncoder.methodHasAttributes(m)) {
            body.add(new ConstantBitcast(attributesEncoder.getMethodAttributes(m).ref(), I8_PTR));
        }
        if (!m.isAbstract()) {
            body.add(new ConstantBitcast(new FunctionRef(Symbols.methodSymbol(m), getFunctionType(m)), I8_PTR));
            // Size of function. This value will be modified later by patching the .s file.
            body.add(new IntegerConstant(DUMMY_METHOD_SIZE));
            if (m.isSynchronized()) {
                body.add(new ConstantBitcast(new FunctionRef(Symbols.synchronizedWrapperSymbol(m), getFunctionType(m)), I8_PTR));
            }
            if ((flags & MI_NATIVE) == 0) {
                // Cannot use m.isNative() in the condition above since methods which are native in the
                // Java class file may have been changed to non-native by the RoboVM compiler 
                // (e.g. @StructMember methods). The native code which parses the info structs will see 
                // the method as non-native.
                // Add a weak linetable pointer which points to a -1 value which will be interpreted as 0 linenumbers in the table
                Global linetableGlobal = new Global(Symbols.linetableSymbol(m), Linkage.weak, new IntegerConstant(-1));
                mb.addGlobal(linetableGlobal);
                body.add(linetableGlobal.ref());
            }
        }
        if (hasBridgeAnnotation(m)) {
            if (!readBooleanElem(getAnnotation(m, BRIDGE), "dynamic", false)) {
                body.add(new GlobalRef(Symbols.bridgePtrSymbol(m), I8_PTR));
            } else {
                body.add(new NullConstant(I8_PTR));
            }
        } else if (hasGlobalValueAnnotation(m)) {
            body.add(new GlobalRef(Symbols.globalValuePtrSymbol(m), I8_PTR));
        }
        if (hasCallbackAnnotation(m)) {
            body.add(new AliasRef(Symbols.callbackPtrSymbol(m), I8_PTR));
        }
    }
    // after sizeof(ClassInfoHeader) bytes.
    return new StructureConstantBuilder().add(header.build()).add(body.build()).build();
}
Also used : GlobalRef(org.robovm.compiler.llvm.GlobalRef) PackedStructureConstantBuilder(org.robovm.compiler.llvm.PackedStructureConstantBuilder) AliasRef(org.robovm.compiler.llvm.AliasRef) StructureConstant(org.robovm.compiler.llvm.StructureConstant) Constant(org.robovm.compiler.llvm.Constant) NullConstant(org.robovm.compiler.llvm.NullConstant) IntegerConstant(org.robovm.compiler.llvm.IntegerConstant) ConstantBitcast(org.robovm.compiler.llvm.ConstantBitcast) NullConstant(org.robovm.compiler.llvm.NullConstant) SootClass(soot.SootClass) StructureConstantBuilder(org.robovm.compiler.llvm.StructureConstantBuilder) PackedStructureConstantBuilder(org.robovm.compiler.llvm.PackedStructureConstantBuilder) IntegerConstant(org.robovm.compiler.llvm.IntegerConstant) Global(org.robovm.compiler.llvm.Global) SootMethod(soot.SootMethod) PrimType(soot.PrimType) SootField(soot.SootField) FunctionRef(org.robovm.compiler.llvm.FunctionRef)

Example 48 with SootField

use of soot.SootField in project soot by Sable.

the class SynchronizerManager method addStmtsToFetchClassBefore.

/**
 * Adds code to fetch the static Class object to the given JimpleBody before
 * the target Stmt.
 *
 * Uses our custom classToClassField field to cache the results.
 *
 * The code will look like this:
 *
 * <pre>
 *	        $r3 = <quack: java.lang.Class class$quack>;
 *	        .if $r3 != .null .goto label2;
 *
 *	        $r3 = .staticinvoke <quack: java.lang.Class class$(java.lang.String)>("quack");
 *	        <quack: java.lang.Class class$quack> = $r3;
 *
 *	     label2:
 * </pre>
 */
public Local addStmtsToFetchClassBefore(JimpleBody jb, Stmt target) {
    SootClass sc = jb.getMethod().getDeclaringClass();
    SootField classCacher = classToClassField.get(sc);
    if (classCacher == null) {
        // Add a unique field named [__]class$name
        String n = "class$" + sc.getName().replace('.', '$');
        while (sc.declaresFieldByName(n)) n = "_" + n;
        classCacher = Scene.v().makeSootField(n, RefType.v("java.lang.Class"), Modifier.STATIC);
        sc.addField(classCacher);
        classToClassField.put(sc, classCacher);
    }
    String lName = "$uniqueClass";
    // Find unique name. Not strictly necessary unless we parse Jimple code.
    while (true) {
        Iterator it = jb.getLocals().iterator();
        boolean oops = false;
        while (it.hasNext()) {
            Local jbLocal = (Local) it.next();
            if (jbLocal.getName().equals(lName))
                oops = true;
        }
        if (!oops)
            break;
        lName = "_" + lName;
    }
    Local l = Jimple.v().newLocal(lName, RefType.v("java.lang.Class"));
    jb.getLocals().add(l);
    Chain units = jb.getUnits();
    units.insertBefore(Jimple.v().newAssignStmt(l, Jimple.v().newStaticFieldRef(classCacher.makeRef())), target);
    IfStmt ifStmt;
    units.insertBefore(ifStmt = Jimple.v().newIfStmt(Jimple.v().newNeExpr(l, NullConstant.v()), target), target);
    units.insertBefore(Jimple.v().newAssignStmt(l, Jimple.v().newStaticInvokeExpr(getClassFetcherFor(sc).makeRef(), Arrays.asList(new Value[] { StringConstant.v(sc.getName()) }))), target);
    units.insertBefore(Jimple.v().newAssignStmt(Jimple.v().newStaticFieldRef(classCacher.makeRef()), l), target);
    ifStmt.setTarget(target);
    return l;
}
Also used : Chain(soot.util.Chain) IfStmt(soot.jimple.IfStmt) Iterator(java.util.Iterator) Value(soot.Value) Local(soot.Local) SootField(soot.SootField) SootClass(soot.SootClass)

Example 49 with SootField

use of soot.SootField in project soot by Sable.

the class AnnotationGenerator method annotate.

/**
 * Applies a Java 1.5-style annotation to a given Host. The Host must be of type {@link SootClass}, {@link SootMethod}
 * or {@link SootField}.
 *
 * @param h a method, field, or class
 * @param klass the class of the annotation to apply to <code>h</code>
 * @param elems a (possibly empty) sequence of AnnotationElem objects corresponding to the elements that should be contained in this annotation
 */
public void annotate(Host h, Class<? extends Annotation> klass, List<AnnotationElem> elems) {
    // error-checking -- is this annotation appropriate for the target Host?
    Target t = klass.getAnnotation(Target.class);
    Collection<ElementType> elementTypes = Arrays.asList(t.value());
    final String ERR = "Annotation class " + klass + " not applicable to host of type " + h.getClass() + ".";
    if (h instanceof SootClass) {
        if (!elementTypes.contains(ElementType.TYPE)) {
            throw new RuntimeException(ERR);
        }
    } else if (h instanceof SootMethod) {
        if (!elementTypes.contains(ElementType.METHOD)) {
            throw new RuntimeException(ERR);
        }
    } else if (h instanceof SootField) {
        if (!elementTypes.contains(ElementType.FIELD)) {
            throw new RuntimeException(ERR);
        }
    } else {
        throw new RuntimeException("Tried to attach annotation to host of type " + h.getClass() + ".");
    }
    // get the retention type of the class
    Retention r = klass.getAnnotation(Retention.class);
    // CLASS (runtime invisible) retention is the default
    int retPolicy = AnnotationConstants.RUNTIME_INVISIBLE;
    if (r != null) {
        // RetentionPolicy directly? (Eric Bodden 20/05/2008)
        switch(r.value()) {
            case CLASS:
                retPolicy = AnnotationConstants.RUNTIME_INVISIBLE;
                break;
            case RUNTIME:
                retPolicy = AnnotationConstants.RUNTIME_VISIBLE;
                break;
            default:
                throw new RuntimeException("Unexpected retention policy: " + retPolicy);
        }
    }
    annotate(h, klass.getCanonicalName(), retPolicy, elems);
}
Also used : Target(java.lang.annotation.Target) ElementType(java.lang.annotation.ElementType) SootMethod(soot.SootMethod) SootField(soot.SootField) SootClass(soot.SootClass) Retention(java.lang.annotation.Retention)

Example 50 with SootField

use of soot.SootField in project soot by Sable.

the class LockAllocationBodyTransformer method internalTransform.

protected void internalTransform(Body b, FlowSet fs, List<CriticalSectionGroup> groups, boolean[] insertedGlobalLock) {
    // 
    JimpleBody j = (JimpleBody) b;
    SootMethod thisMethod = b.getMethod();
    PatchingChain<Unit> units = b.getUnits();
    Iterator<Unit> unitIt = units.iterator();
    Unit firstUnit = j.getFirstNonIdentityStmt();
    Unit lastUnit = units.getLast();
    // Objects of synchronization, plus book keeping
    Local[] lockObj = new Local[groups.size()];
    boolean[] addedLocalLockObj = new boolean[groups.size()];
    SootField[] globalLockObj = new SootField[groups.size()];
    for (int i = 1; i < groups.size(); i++) {
        lockObj[i] = Jimple.v().newLocal("lockObj" + i, RefType.v("java.lang.Object"));
        addedLocalLockObj[i] = false;
        globalLockObj[i] = null;
    }
    // Get references to them if they do already exist.
    for (int i = 1; i < groups.size(); i++) {
        CriticalSectionGroup tnGroup = groups.get(i);
        if (!tnGroup.useDynamicLock && !tnGroup.useLocksets) {
            if (!insertedGlobalLock[i]) {
                // use it!
                try {
                    globalLockObj[i] = Scene.v().getMainClass().getFieldByName("globalLockObj" + i);
                // field already exists
                } catch (RuntimeException re) {
                    // field does not yet exist (or, as a pre-existing
                    // error, there is more than one field by this name)
                    globalLockObj[i] = Scene.v().makeSootField("globalLockObj" + i, RefType.v("java.lang.Object"), Modifier.STATIC | Modifier.PUBLIC);
                    Scene.v().getMainClass().addField(globalLockObj[i]);
                }
                insertedGlobalLock[i] = true;
            } else {
                globalLockObj[i] = Scene.v().getMainClass().getFieldByName("globalLockObj" + i);
            }
        }
    }
    // local lock object into the global lock object for use by other fns.
    if (// thisMethod.getSubSignature().equals("void
    !addedGlobalLockDefs) // <clinit>()") &&
    // thisMethod.getDeclaringClass() ==
    // Scene.v().getMainClass())
    {
        // Either get or add the <clinit> method to the main class
        SootClass mainClass = Scene.v().getMainClass();
        SootMethod clinitMethod = null;
        JimpleBody clinitBody = null;
        Stmt firstStmt = null;
        boolean addingNewClinit = !mainClass.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);
            mainClass.addMethod(clinitMethod);
        } else {
            clinitMethod = mainClass.getMethod("void <clinit>()");
            clinitBody = (JimpleBody) clinitMethod.getActiveBody();
            firstStmt = clinitBody.getFirstNonIdentityStmt();
        }
        PatchingChain<Unit> clinitUnits = clinitBody.getUnits();
        for (int i = 1; i < groups.size(); i++) {
            CriticalSectionGroup tnGroup = groups.get(i);
            // if( useGlobalLock[i - 1] )
            if (!tnGroup.useDynamicLock && !tnGroup.useLocksets) {
                // add local lock obj
                // addedLocalLockObj[i] = true;
                // TODO: add name
                clinitBody.getLocals().add(lockObj[i]);
                // conflict
                // avoidance code
                // assign new object to lock obj
                Stmt newStmt = Jimple.v().newAssignStmt(lockObj[i], 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(lockObj[i], 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)
                Stmt assignStmt = Jimple.v().newAssignStmt(Jimple.v().newStaticFieldRef(globalLockObj[i].makeRef()), lockObj[i]);
                if (addingNewClinit)
                    clinitUnits.add(assignStmt);
                else
                    clinitUnits.insertBeforeNoRedirect(assignStmt, firstStmt);
            }
        }
        if (addingNewClinit)
            clinitUnits.add(Jimple.v().newReturnVoidStmt());
        addedGlobalLockDefs = true;
    }
    int tempNum = 1;
    // Iterate through all of the transactions in the current method
    Iterator fsIt = fs.iterator();
    Stmt newPrep = null;
    while (fsIt.hasNext()) {
        CriticalSection tn = ((SynchronizedRegionFlowPair) fsIt.next()).tn;
        if (tn.setNumber == -1)
            // this tn should be deleted... for now just skip it!
            continue;
        if (tn.wholeMethod) {
            // remove
            thisMethod.setModifiers(thisMethod.getModifiers() & ~(Modifier.SYNCHRONIZED));
        // synchronized
        // modifier
        // for
        // this
        // method
        }
        // depends on type of locking
        Local clo = null;
        // current synchronized region
        SynchronizedRegion csr = null;
        int lockNum = 0;
        boolean moreLocks = true;
        while (moreLocks) {
            // needed for this transaction, then create one.
            if (tn.group.useDynamicLock) {
                // adds
                Value lock = getLockFor((EquivalentValue) tn.lockObject);
                // needed
                if (lock instanceof Ref) {
                    if (lock instanceof InstanceFieldRef) {
                        InstanceFieldRef ifr = (InstanceFieldRef) lock;
                        if (ifr.getBase() instanceof FakeJimpleLocal)
                            lock = reconstruct(b, units, ifr, (tn.entermonitor != null ? tn.entermonitor : tn.beginning), (tn.entermonitor != null));
                    }
                    if (!b.getLocals().contains(lockObj[tn.setNumber]))
                        b.getLocals().add(lockObj[tn.setNumber]);
                    newPrep = Jimple.v().newAssignStmt(lockObj[tn.setNumber], lock);
                    if (tn.wholeMethod)
                        units.insertBeforeNoRedirect(newPrep, firstUnit);
                    else
                        units.insertBefore(newPrep, tn.entermonitor);
                    clo = lockObj[tn.setNumber];
                } else if (lock instanceof Local)
                    clo = (Local) lock;
                else
                    throw new RuntimeException("Unknown type of lock (" + lock + "): expected Ref or Local");
                csr = tn;
                moreLocks = false;
            } else if (tn.group.useLocksets) {
                // adds
                Value lock = getLockFor((EquivalentValue) tn.lockset.get(lockNum));
                // needed
                if (lock instanceof FieldRef) {
                    if (lock instanceof InstanceFieldRef) {
                        InstanceFieldRef ifr = (InstanceFieldRef) lock;
                        if (ifr.getBase() instanceof FakeJimpleLocal)
                            lock = reconstruct(b, units, ifr, (tn.entermonitor != null ? tn.entermonitor : tn.beginning), (tn.entermonitor != null));
                    }
                    // add a local variable for this lock
                    Local lockLocal = Jimple.v().newLocal("locksetObj" + tempNum, RefType.v("java.lang.Object"));
                    tempNum++;
                    b.getLocals().add(lockLocal);
                    // make it refer to the right lock object
                    newPrep = Jimple.v().newAssignStmt(lockLocal, lock);
                    if (tn.entermonitor != null)
                        units.insertBefore(newPrep, tn.entermonitor);
                    else
                        units.insertBeforeNoRedirect(newPrep, tn.beginning);
                    // use it as the lock
                    clo = lockLocal;
                } else if (lock instanceof Local)
                    clo = (Local) lock;
                else
                    throw new RuntimeException("Unknown type of lock (" + lock + "): expected FieldRef or Local");
                if (lockNum + 1 >= tn.lockset.size())
                    moreLocks = false;
                else
                    moreLocks = true;
                if (lockNum > 0) {
                    SynchronizedRegion nsr = new SynchronizedRegion();
                    nsr.beginning = csr.beginning;
                    for (Pair earlyEnd : csr.earlyEnds) {
                        Stmt earlyExitmonitor = (Stmt) earlyEnd.getO2();
                        // <early
                        nsr.earlyEnds.add(new Pair(earlyExitmonitor, null));
                    // exitmonitor,
                    // null>
                    }
                    // last stmt before exception
                    nsr.last = csr.last;
                    // handling
                    if (csr.end != null) {
                        Stmt endExitmonitor = csr.end.getO2();
                        nsr.after = endExitmonitor;
                    }
                    csr = nsr;
                } else
                    csr = tn;
            } else // global lock
            {
                if (!addedLocalLockObj[tn.setNumber])
                    b.getLocals().add(lockObj[tn.setNumber]);
                addedLocalLockObj[tn.setNumber] = true;
                newPrep = Jimple.v().newAssignStmt(lockObj[tn.setNumber], Jimple.v().newStaticFieldRef(globalLockObj[tn.setNumber].makeRef()));
                if (tn.wholeMethod)
                    units.insertBeforeNoRedirect(newPrep, firstUnit);
                else
                    units.insertBefore(newPrep, tn.entermonitor);
                clo = lockObj[tn.setNumber];
                csr = tn;
                moreLocks = false;
            }
            // monitorenter/monitorexit statements with new ones
            if (true) {
                // Remove old prep stmt
                if (csr.prepStmt != null) {
                // units.remove(clr.prepStmt); // seems to trigger bugs
                // in code generation?
                }
                // Reuse old entermonitor or insert new one, and insert prep
                Stmt newEntermonitor = Jimple.v().newEnterMonitorStmt(clo);
                if (csr.entermonitor != null) {
                    units.insertBefore(newEntermonitor, csr.entermonitor);
                    // redirectTraps(b, clr.entermonitor, newEntermonitor);
                    // // EXPERIMENTAL
                    units.remove(csr.entermonitor);
                    csr.entermonitor = newEntermonitor;
                // units.insertBefore(newEntermonitor, newPrep); //
                // already inserted
                // clr.prepStmt = newPrep;
                } else {
                    units.insertBeforeNoRedirect(newEntermonitor, csr.beginning);
                    csr.entermonitor = newEntermonitor;
                // units.insertBefore(newEntermonitor, newPrep); //
                // already inserted
                // clr.prepStmt = newPrep;
                }
                // For each early end, reuse or insert exitmonitor stmt
                List<Pair<Stmt, Stmt>> newEarlyEnds = new ArrayList<Pair<Stmt, Stmt>>();
                for (Pair<Stmt, Stmt> end : csr.earlyEnds) {
                    Stmt earlyEnd = end.getO1();
                    Stmt exitmonitor = end.getO2();
                    Stmt newExitmonitor = Jimple.v().newExitMonitorStmt(clo);
                    if (exitmonitor != null) {
                        if (newPrep != null) {
                            Stmt tmp = (Stmt) newPrep.clone();
                            // seems
                            units.insertBefore(tmp, exitmonitor);
                        // to
                        // avoid
                        // code
                        // generation
                        // bugs?
                        }
                        units.insertBefore(newExitmonitor, exitmonitor);
                        // redirectTraps(b, exitmonitor, newExitmonitor); //
                        // EXPERIMENTAL
                        units.remove(exitmonitor);
                        newEarlyEnds.add(new Pair<Stmt, Stmt>(earlyEnd, newExitmonitor));
                    } else {
                        if (newPrep != null) {
                            Stmt tmp = (Stmt) newPrep.clone();
                            units.insertBefore(tmp, earlyEnd);
                        }
                        units.insertBefore(newExitmonitor, earlyEnd);
                        newEarlyEnds.add(new Pair<Stmt, Stmt>(earlyEnd, newExitmonitor));
                    }
                }
                csr.earlyEnds = newEarlyEnds;
                // If fallthrough end, reuse or insert goto and exit
                if (csr.after != null) {
                    Stmt newExitmonitor = Jimple.v().newExitMonitorStmt(clo);
                    if (csr.end != null) {
                        Stmt exitmonitor = csr.end.getO2();
                        if (newPrep != null) {
                            Stmt tmp = (Stmt) newPrep.clone();
                            units.insertBefore(tmp, exitmonitor);
                        }
                        units.insertBefore(newExitmonitor, exitmonitor);
                        // redirectTraps(b, exitmonitor, newExitmonitor); //
                        // EXPERIMENTAL
                        units.remove(exitmonitor);
                        csr.end = new Pair<Stmt, Stmt>(csr.end.getO1(), newExitmonitor);
                    } else {
                        if (newPrep != null) {
                            Stmt tmp = (Stmt) newPrep.clone();
                            units.insertBefore(tmp, csr.after);
                        }
                        // steal
                        units.insertBefore(newExitmonitor, csr.after);
                        // jumps
                        // to
                        // end,
                        // send
                        // them
                        // to
                        // monitorexit
                        Stmt newGotoStmt = Jimple.v().newGotoStmt(csr.after);
                        units.insertBeforeNoRedirect(newGotoStmt, csr.after);
                        csr.end = new Pair<Stmt, Stmt>(newGotoStmt, newExitmonitor);
                        csr.last = newGotoStmt;
                    }
                }
                // If exceptional end, reuse it, else insert it and traps
                Stmt newExitmonitor = Jimple.v().newExitMonitorStmt(clo);
                if (csr.exceptionalEnd != null) {
                    Stmt exitmonitor = csr.exceptionalEnd.getO2();
                    if (newPrep != null) {
                        Stmt tmp = (Stmt) newPrep.clone();
                        units.insertBefore(tmp, exitmonitor);
                    }
                    units.insertBefore(newExitmonitor, exitmonitor);
                    units.remove(exitmonitor);
                    csr.exceptionalEnd = new Pair<Stmt, Stmt>(csr.exceptionalEnd.getO1(), newExitmonitor);
                } else {
                    // insert after the last end
                    // last end stmt (not same as last
                    Stmt lastEnd = null;
                    // stmt)
                    if (csr.end != null) {
                        lastEnd = csr.end.getO1();
                    } else {
                        for (Pair earlyEnd : csr.earlyEnds) {
                            Stmt end = (Stmt) earlyEnd.getO1();
                            if (lastEnd == null || (units.contains(lastEnd) && units.contains(end) && units.follows(end, lastEnd)))
                                lastEnd = end;
                        }
                    }
                    if (// || !units.contains(clr.last))
                    csr.last == null)
                        // last stmt and last end are
                        csr.last = lastEnd;
                    // the same
                    if (lastEnd == null)
                        throw new RuntimeException("Lock Region has no ends!  Where should we put the exception handling???");
                    // Add throwable
                    Local throwableLocal = Jimple.v().newLocal("throwableLocal" + (throwableNum++), RefType.v("java.lang.Throwable"));
                    b.getLocals().add(throwableLocal);
                    // Add stmts
                    Stmt newCatch = Jimple.v().newIdentityStmt(throwableLocal, Jimple.v().newCaughtExceptionRef());
                    if (csr.last == null)
                        throw new RuntimeException("WHY IS clr.last NULL???");
                    if (newCatch == null)
                        throw new RuntimeException("WHY IS newCatch NULL???");
                    units.insertAfter(newCatch, csr.last);
                    units.insertAfter(newExitmonitor, newCatch);
                    Stmt newThrow = Jimple.v().newThrowStmt(throwableLocal);
                    units.insertAfter(newThrow, newExitmonitor);
                    // Add traps
                    SootClass throwableClass = Scene.v().loadClassAndSupport("java.lang.Throwable");
                    b.getTraps().addFirst(Jimple.v().newTrap(throwableClass, newExitmonitor, newThrow, newCatch));
                    b.getTraps().addFirst(Jimple.v().newTrap(throwableClass, csr.beginning, lastEnd, newCatch));
                    csr.exceptionalEnd = new Pair<Stmt, Stmt>(newThrow, newExitmonitor);
                }
            }
            lockNum++;
        }
        // deal with waits and notifys
        {
            for (Unit uNotify : tn.notifys) {
                Stmt sNotify = (Stmt) uNotify;
                Stmt newNotify = Jimple.v().newInvokeStmt(Jimple.v().newVirtualInvokeExpr(clo, sNotify.getInvokeExpr().getMethodRef().declaringClass().getMethod("void notifyAll()").makeRef(), Collections.EMPTY_LIST));
                if (newPrep != null) {
                    Stmt tmp = (Stmt) newPrep.clone();
                    units.insertBefore(tmp, sNotify);
                    units.insertBefore(newNotify, tmp);
                } else
                    units.insertBefore(newNotify, sNotify);
                redirectTraps(b, sNotify, newNotify);
                units.remove(sNotify);
            }
            // Replace base object of calls to wait with appropriate lockobj
            for (Unit uWait : tn.waits) {
                Stmt sWait = (Stmt) uWait;
                // WHAT
                ((InstanceInvokeExpr) sWait.getInvokeExpr()).setBase(clo);
                // LOCKS???
                if (newPrep != null)
                    units.insertBefore((Stmt) newPrep.clone(), sWait);
            }
        }
    }
}
Also used : EquivalentValue(soot.EquivalentValue) ArrayList(java.util.ArrayList) Unit(soot.Unit) Stmt(soot.jimple.Stmt) RefType(soot.RefType) Iterator(java.util.Iterator) InstanceFieldRef(soot.jimple.InstanceFieldRef) JimpleBody(soot.jimple.JimpleBody) Pair(soot.toolkits.scalar.Pair) FieldRef(soot.jimple.FieldRef) InstanceFieldRef(soot.jimple.InstanceFieldRef) StaticFieldRef(soot.jimple.StaticFieldRef) FakeJimpleLocal(soot.jimple.toolkits.infoflow.FakeJimpleLocal) Local(soot.Local) SootClass(soot.SootClass) ArrayRef(soot.jimple.ArrayRef) Ref(soot.jimple.Ref) FieldRef(soot.jimple.FieldRef) InstanceFieldRef(soot.jimple.InstanceFieldRef) StaticFieldRef(soot.jimple.StaticFieldRef) EquivalentValue(soot.EquivalentValue) Value(soot.Value) SootMethod(soot.SootMethod) SootField(soot.SootField) FakeJimpleLocal(soot.jimple.toolkits.infoflow.FakeJimpleLocal)

Aggregations

SootField (soot.SootField)73 SootMethod (soot.SootMethod)29 SootClass (soot.SootClass)26 RefType (soot.RefType)22 ArrayList (java.util.ArrayList)19 Value (soot.Value)17 Iterator (java.util.Iterator)15 Local (soot.Local)14 Type (soot.Type)14 Unit (soot.Unit)13 FieldRef (soot.jimple.FieldRef)12 BooleanType (soot.BooleanType)10 PrimType (soot.PrimType)10 VoidType (soot.VoidType)10 Stmt (soot.jimple.Stmt)10 ByteType (soot.ByteType)8 CharType (soot.CharType)8 DoubleType (soot.DoubleType)8 FloatType (soot.FloatType)8 IntType (soot.IntType)8