Search in sources :

Example 1 with FakeJimpleLocal

use of soot.jimple.toolkits.infoflow.FakeJimpleLocal 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)

Example 2 with FakeJimpleLocal

use of soot.jimple.toolkits.infoflow.FakeJimpleLocal in project soot by Sable.

the class LockAllocationBodyTransformer method reconstruct.

public InstanceFieldRef reconstruct(Body b, PatchingChain<Unit> units, InstanceFieldRef lock, Stmt insertBefore, boolean redirect) {
    logger.debug("Reconstructing " + lock);
    if (!(lock.getBase() instanceof FakeJimpleLocal)) {
        logger.debug("  base is not a FakeJimpleLocal");
        return lock;
    }
    FakeJimpleLocal fakeBase = (FakeJimpleLocal) lock.getBase();
    if (!(fakeBase.getInfo() instanceof LockableReferenceAnalysis))
        throw new RuntimeException("InstanceFieldRef cannot be reconstructed due to missing LocksetAnalysis info: " + lock);
    LockableReferenceAnalysis la = (LockableReferenceAnalysis) fakeBase.getInfo();
    EquivalentValue baseEqVal = la.baseFor(lock);
    if (baseEqVal == null)
        throw new RuntimeException("InstanceFieldRef cannot be reconstructed due to lost base from Lockset");
    Value base = baseEqVal.getValue();
    Local baseLocal;
    if (base instanceof InstanceFieldRef) {
        Value newBase = reconstruct(b, units, (InstanceFieldRef) base, insertBefore, redirect);
        baseLocal = Jimple.v().newLocal("baseLocal" + (baseLocalNum++), newBase.getType());
        b.getLocals().add(baseLocal);
        // make it equal to the right value
        Stmt baseAssign = Jimple.v().newAssignStmt(baseLocal, newBase);
        if (redirect == true)
            units.insertBefore(baseAssign, insertBefore);
        else
            units.insertBeforeNoRedirect(baseAssign, insertBefore);
    } else if (base instanceof Local)
        baseLocal = (Local) base;
    else
        throw new RuntimeException("InstanceFieldRef cannot be reconstructed because it's base is of an unsupported type" + base.getType() + ": " + base);
    InstanceFieldRef newLock = Jimple.v().newInstanceFieldRef(baseLocal, lock.getField().makeRef());
    logger.debug("  as " + newLock);
    return newLock;
}
Also used : EquivalentValue(soot.EquivalentValue) EquivalentValue(soot.EquivalentValue) Value(soot.Value) InstanceFieldRef(soot.jimple.InstanceFieldRef) FakeJimpleLocal(soot.jimple.toolkits.infoflow.FakeJimpleLocal) Local(soot.Local) FakeJimpleLocal(soot.jimple.toolkits.infoflow.FakeJimpleLocal) Stmt(soot.jimple.Stmt)

Aggregations

EquivalentValue (soot.EquivalentValue)2 Local (soot.Local)2 Value (soot.Value)2 InstanceFieldRef (soot.jimple.InstanceFieldRef)2 Stmt (soot.jimple.Stmt)2 FakeJimpleLocal (soot.jimple.toolkits.infoflow.FakeJimpleLocal)2 ArrayList (java.util.ArrayList)1 Iterator (java.util.Iterator)1 RefType (soot.RefType)1 SootClass (soot.SootClass)1 SootField (soot.SootField)1 SootMethod (soot.SootMethod)1 Unit (soot.Unit)1 ArrayRef (soot.jimple.ArrayRef)1 FieldRef (soot.jimple.FieldRef)1 JimpleBody (soot.jimple.JimpleBody)1 Ref (soot.jimple.Ref)1 StaticFieldRef (soot.jimple.StaticFieldRef)1 Pair (soot.toolkits.scalar.Pair)1