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);
}
}
}
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();
}
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;
}
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);
}
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);
}
}
}
}
Aggregations