soot.jimple.toolkits.thread.synchronization.LockAllocationBodyTransformer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of soot Show documentation
Show all versions of soot Show documentation
A Java Optimization Framework
package soot.jimple.toolkits.thread.synchronization;
/*-
* #%L
* Soot - a J*va Optimization Framework
* %%
* Copyright (C) 1997 - 2018 Raja Vallée-Rai and others
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 2.1 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import soot.Body;
import soot.BodyTransformer;
import soot.EquivalentValue;
import soot.Local;
import soot.Modifier;
import soot.PatchingChain;
import soot.RefType;
import soot.Scene;
import soot.SootClass;
import soot.SootField;
import soot.SootMethod;
import soot.Trap;
import soot.Unit;
import soot.Value;
import soot.VoidType;
import soot.jimple.ArrayRef;
import soot.jimple.FieldRef;
import soot.jimple.InstanceFieldRef;
import soot.jimple.InstanceInvokeExpr;
import soot.jimple.Jimple;
import soot.jimple.JimpleBody;
import soot.jimple.Ref;
import soot.jimple.StaticFieldRef;
import soot.jimple.Stmt;
import soot.jimple.toolkits.infoflow.FakeJimpleLocal;
import soot.toolkits.scalar.FlowSet;
import soot.toolkits.scalar.Pair;
import soot.util.Chain;
public class LockAllocationBodyTransformer extends BodyTransformer {
private static final Logger logger = LoggerFactory.getLogger(LockAllocationBodyTransformer.class);
private static final LockAllocationBodyTransformer instance = new LockAllocationBodyTransformer();
private LockAllocationBodyTransformer() {
}
public static LockAllocationBodyTransformer v() {
return instance;
}
private static boolean addedGlobalLockDefs = false;
private static int throwableNum = 0; // doesn't matter if not reinitialized
// to 0
protected void internalTransform(Body b, String phase, Map opts) {
throw new RuntimeException("Not Supported");
}
protected void internalTransform(Body b, FlowSet fs, List groups, boolean[] insertedGlobalLock) {
//
JimpleBody j = (JimpleBody) b;
SootMethod thisMethod = b.getMethod();
PatchingChain units = b.getUnits();
Iterator 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;
}
// Add all global lock objects to the main class if not yet added.
// 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]) {
// Add globalLockObj field if possible...
// Avoid name collision... if it's already there, then just
// 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);
}
}
}
// If the current method is the clinit method of the main class, for
// each global lock object,
// add a local lock object and assign it a new object. Copy the new
// local lock object into the global lock object for use by other fns.
if (!addedGlobalLockDefs)// thisMethod.getSubSignature().equals("void
// ()") &&
// thisMethod.getDeclaringClass() ==
// Scene.v().getMainClass())
{
// Either get or add the method to the main class
SootClass mainClass = Scene.v().getMainClass();
SootMethod clinitMethod = null;
JimpleBody clinitBody = null;
Stmt firstStmt = null;
boolean addingNewClinit = !mainClass.declaresMethod("void ()");
if (addingNewClinit) {
clinitMethod
= Scene.v().makeSootMethod("", new ArrayList(), VoidType.v(), Modifier.PUBLIC | Modifier.STATIC);
clinitBody = Jimple.v().newBody(clinitMethod);
clinitMethod.setActiveBody(clinitBody);
mainClass.addMethod(clinitMethod);
} else {
clinitMethod = mainClass.getMethod("void ()");
clinitBody = (JimpleBody) clinitMethod.getActiveBody();
firstStmt = clinitBody.getFirstNonIdentityStmt();
}
PatchingChain 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;
clinitBody.getLocals().add(lockObj[i]); // TODO: add name
// 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 ()");
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) {
continue; // this tn should be deleted... for now just skip it!
}
if (tn.wholeMethod) {
thisMethod.setModifiers(thisMethod.getModifiers() & ~(Modifier.SYNCHRONIZED)); // remove
// synchronized
// modifier
// for
// this
// method
}
Local clo = null; // depends on type of locking
SynchronizedRegion csr = null; // current synchronized region
int lockNum = 0;
boolean moreLocks = true;
while (moreLocks) {
// If this method does not yet have a reference to the lock
// object
// needed for this transaction, then create one.
if (tn.group.useDynamicLock) {
Value lock = getLockFor((EquivalentValue) tn.lockObject); // adds
// local
// vars
// and
// global
// objects
// if
// 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) {
Value lock = getLockFor((EquivalentValue) tn.lockset.get(lockNum)); // adds
// local
// vars
// and
// global
// objects
// if
// 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();
nsr.earlyEnds.add(new Pair(earlyExitmonitor, null)); //
}
nsr.last = csr.last; // last stmt before exception
// 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;
}
// Add synchronization code
// For transactions from synchronized methods, use
// synchronizeSingleEntrySingleExitBlock()
// to add all necessary code (including ugly exception handling)
// For transactions from synchronized blocks, simply replace the
// 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> newEarlyEnds = new ArrayList>();
for (Pair 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();
units.insertBefore(tmp, exitmonitor); // seems
// to
// avoid
// code
// generation
// bugs?
}
units.insertBefore(newExitmonitor, exitmonitor);
// redirectTraps(b, exitmonitor, newExitmonitor); //
// EXPERIMENTAL
units.remove(exitmonitor);
newEarlyEnds.add(new Pair(earlyEnd, newExitmonitor));
} else {
if (newPrep != null) {
Stmt tmp = (Stmt) newPrep.clone();
units.insertBefore(tmp, earlyEnd);
}
units.insertBefore(newExitmonitor, earlyEnd);
newEarlyEnds.add(new Pair(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(csr.end.getO1(), newExitmonitor);
} else {
if (newPrep != null) {
Stmt tmp = (Stmt) newPrep.clone();
units.insertBefore(tmp, csr.after);
}
units.insertBefore(newExitmonitor, csr.after); // steal
// jumps
// to
// end,
// send
// them
// to
// monitorexit
Stmt newGotoStmt = Jimple.v().newGotoStmt(csr.after);
units.insertBeforeNoRedirect(newGotoStmt, csr.after);
csr.end = new Pair(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(csr.exceptionalEnd.getO1(), newExitmonitor);
} else {
// insert after the last end
Stmt lastEnd = null; // last end stmt (not same as last
// 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 (csr.last == null) {
csr.last = lastEnd; // last stmt and last end are
}
// 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(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;
((InstanceInvokeExpr) sWait.getInvokeExpr()).setBase(clo); // WHAT
// IF
// THIS
// IS
// THE
// WRONG
// LOCK
// IN
// A
// PAIR
// OF
// NESTED
// LOCKS???
if (newPrep != null) {
units.insertBefore((Stmt) newPrep.clone(), sWait);
}
}
}
}
}
static int baseLocalNum = 0;
public InstanceFieldRef reconstruct(Body b, PatchingChain 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) {
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;
}
static int lockNumber = 0;
static Map lockEqValToLock = new HashMap();
static public Value getLockFor(EquivalentValue lockEqVal) {
Value lock = lockEqVal.getValue();
if (lock instanceof InstanceFieldRef) {
return lock;
}
if (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 ()");
if (addingNewClinit) {
clinitMethod
= Scene.v().makeSootMethod("", new ArrayList(), VoidType.v(), Modifier.PUBLIC | Modifier.STATIC);
clinitBody = Jimple.v().newBody(clinitMethod);
clinitMethod.setActiveBody(clinitBody);
lockClass.addMethod(clinitMethod);
} else {
clinitMethod = lockClass.getMethod("void ()");
clinitBody = (JimpleBody) clinitMethod.getActiveBody();
firstStmt = clinitBody.getFirstNonIdentityStmt();
}
PatchingChain clinitUnits = clinitBody.getUnits();
Local lockLocal = Jimple.v().newLocal("objectLockLocal" + lockNumber, RefType.v("java.lang.Object"));
// lockNumber is increased below
clinitBody.getLocals().add(lockLocal); // TODO: add name conflict
// 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 ()");
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");
}
public void redirectTraps(Body b, Unit oldUnit, Unit newUnit) {
Chain traps = b.getTraps();
for (Trap trap : traps) {
if (trap.getHandlerUnit() == oldUnit) {
trap.setHandlerUnit(newUnit);
}
if (trap.getBeginUnit() == oldUnit) {
trap.setBeginUnit(newUnit);
}
if (trap.getEndUnit() == oldUnit) {
trap.setEndUnit(newUnit);
}
}
}
}