use of soot.jimple.JimpleBody in project robovm by robovm.
the class ClassCompiler method compile.
private void compile(Clazz clazz, OutputStream out) throws IOException {
javaMethodCompiler.reset(clazz);
bridgeMethodCompiler.reset(clazz);
callbackMethodCompiler.reset(clazz);
nativeMethodCompiler.reset(clazz);
structMemberMethodCompiler.reset(clazz);
globalValueMethodCompiler.reset(clazz);
ClazzInfo ci = clazz.resetClazzInfo();
mb = new ModuleBuilder();
for (CompilerPlugin compilerPlugin : config.getCompilerPlugins()) {
compilerPlugin.beforeClass(config, clazz, mb);
}
sootClass = clazz.getSootClass();
trampolines = new HashMap<>();
catches = new HashSet<String>();
classFields = getClassFields(config.getOs(), config.getArch(), sootClass);
instanceFields = getInstanceFields(config.getOs(), config.getArch(), sootClass);
classType = getClassType(config.getOs(), config.getArch(), sootClass);
instanceType = getInstanceType(config.getOs(), config.getArch(), sootClass);
attributesEncoder.encode(mb, sootClass);
// will never be initialized.
if (!sootClass.declaresMethodByName("<clinit>") && hasConstantValueTags(classFields)) {
SootMethod clinit = new SootMethod("<clinit>", Collections.EMPTY_LIST, VoidType.v(), Modifier.STATIC);
JimpleBody body = Jimple.v().newBody(clinit);
clinit.setActiveBody(body);
body.getUnits().add(new JReturnVoidStmt());
this.sootClass.addMethod(clinit);
}
if (isStruct(sootClass)) {
SootMethod _sizeOf = new SootMethod("_sizeOf", Collections.EMPTY_LIST, IntType.v(), Modifier.PROTECTED | Modifier.NATIVE);
sootClass.addMethod(_sizeOf);
SootMethod sizeOf = new SootMethod("sizeOf", Collections.EMPTY_LIST, IntType.v(), Modifier.PUBLIC | Modifier.STATIC | Modifier.NATIVE);
sootClass.addMethod(sizeOf);
}
mb.addInclude(getClass().getClassLoader().getResource(String.format("header-%s-%s.ll", config.getOs().getFamily(), config.getArch())));
mb.addInclude(getClass().getClassLoader().getResource("header.ll"));
mb.addFunction(createLdcClass());
mb.addFunction(createLdcClassWrapper());
Function allocator = createAllocator();
mb.addFunction(allocator);
mb.addFunction(createClassInitWrapperFunction(allocator.ref()));
for (SootField f : sootClass.getFields()) {
Function getter = createFieldGetter(f, classFields, classType, instanceFields, instanceType);
Function setter = createFieldSetter(f, classFields, classType, instanceFields, instanceType);
mb.addFunction(getter);
mb.addFunction(setter);
if (f.isStatic() && !f.isPrivate()) {
mb.addFunction(createClassInitWrapperFunction(getter.ref()));
if (!f.isFinal()) {
mb.addFunction(createClassInitWrapperFunction(setter.ref()));
}
}
}
// After this point no changes to methods/fields may be done by CompilerPlugins.
ci.initClassInfo();
for (SootMethod method : sootClass.getMethods()) {
for (CompilerPlugin compilerPlugin : config.getCompilerPlugins()) {
compilerPlugin.beforeMethod(config, clazz, method, mb);
}
String name = method.getName();
Function function = null;
if (hasBridgeAnnotation(method)) {
function = bridgeMethod(method);
} else if (hasGlobalValueAnnotation(method)) {
function = globalValueMethod(method);
} else if (isStruct(sootClass) && ("_sizeOf".equals(name) || "sizeOf".equals(name) || hasStructMemberAnnotation(method))) {
function = structMember(method);
} else if (method.isNative()) {
function = nativeMethod(method);
} else if (!method.isAbstract()) {
function = method(method);
}
if (hasCallbackAnnotation(method)) {
callbackMethod(method);
}
if (!name.equals("<clinit>") && !name.equals("<init>") && !method.isPrivate() && !method.isStatic() && !Modifier.isFinal(method.getModifiers()) && !Modifier.isFinal(sootClass.getModifiers())) {
createLookupFunction(method);
}
if (method.isStatic() && !name.equals("<clinit>")) {
String fnName = method.isSynchronized() ? Symbols.synchronizedWrapperSymbol(method) : Symbols.methodSymbol(method);
FunctionRef fn = new FunctionRef(fnName, getFunctionType(method));
mb.addFunction(createClassInitWrapperFunction(fn));
}
for (CompilerPlugin compilerPlugin : config.getCompilerPlugins()) {
if (function != null) {
compilerPlugin.afterMethod(config, clazz, method, mb, function);
}
}
}
for (Trampoline trampoline : trampolines.keySet()) {
Set<String> deps = new HashSet<String>();
Set<Triple<String, String, String>> mDeps = new HashSet<>();
trampolineResolver.compile(mb, clazz, trampoline, deps, mDeps);
for (SootMethod m : trampolines.get(trampoline)) {
MethodInfo mi = ci.getMethod(m.getName(), getDescriptor(m));
mi.addClassDependencies(deps, false);
mi.addInvokeMethodDependencies(mDeps, false);
}
}
/*
* Add method dependencies from overriding methods to the overridden
* super method(s). These will be reversed by the DependencyGraph to
* create edges from the super/interface method to the overriding
* method.
*/
Map<SootMethod, Set<SootMethod>> overriddenMethods = getOverriddenMethods(this.sootClass);
for (SootMethod from : overriddenMethods.keySet()) {
MethodInfo mi = ci.getMethod(from.getName(), getDescriptor(from));
for (SootMethod to : overriddenMethods.get(from)) {
mi.addSuperMethodDependency(getInternalName(to.getDeclaringClass()), to.getName(), getDescriptor(to), false);
}
}
/*
* Edge case. A method in a superclass might satisfy an interface method
* in the interfaces implemented by this class. See e.g. the abstract
* class HashMap$HashIterator which doesn't implement Iterator but has
* the hasNext() and other methods. We add a dependency from the current
* class to the super method to ensure it's included if the current
* class is linked in.
*/
if (sootClass.hasSuperclass()) {
for (SootClass interfaze : getImmediateInterfaces(sootClass)) {
for (SootMethod m : interfaze.getMethods()) {
if (!m.isStatic()) {
try {
this.sootClass.getMethod(m.getName(), m.getParameterTypes());
} catch (RuntimeException e) {
/*
* Not found. Find the implementation in
* superclasses.
*/
SootMethod superMethod = null;
for (SootClass sc = sootClass.getSuperclass(); sc.hasSuperclass(); sc = sc.getSuperclass()) {
try {
SootMethod candidate = sc.getMethod(m.getName(), m.getParameterTypes());
if (!candidate.isStatic()) {
superMethod = candidate;
break;
}
} catch (RuntimeException e2) {
// Not found.
}
}
if (superMethod != null) {
ci.addSuperMethodDependency(getInternalName(superMethod.getDeclaringClass()), superMethod.getName(), getDescriptor(superMethod), false);
}
}
}
}
}
}
Global classInfoStruct = null;
try {
if (!sootClass.isInterface()) {
config.getVTableCache().get(sootClass);
}
classInfoStruct = new Global(Symbols.infoStructSymbol(clazz.getInternalName()), Linkage.weak, createClassInfoStruct());
} catch (IllegalArgumentException e) {
// VTable throws this if any of the superclasses of the class is actually an interface.
// Shouldn't happen frequently but the DRLVM test suite has some tests for this.
// The Linker will take care of making sure the class cannot be loaded at runtime.
classInfoStruct = new Global(Symbols.infoStructSymbol(clazz.getInternalName()), I8_PTR, true);
}
mb.addGlobal(classInfoStruct);
/*
* Emit an internal i8* alias for the info struct which MethodCompiler
* can use when referencing this info struct in exception landing pads
* in methods in the same class. See #1007.
*/
mb.addAlias(new Alias(classInfoStruct.getName() + "_i8ptr", Linkage._private, new ConstantBitcast(classInfoStruct.ref(), I8_PTR)));
Function infoFn = FunctionBuilder.infoStruct(sootClass);
infoFn.add(new Ret(new ConstantBitcast(classInfoStruct.ref(), I8_PTR_PTR)));
mb.addFunction(infoFn);
for (CompilerPlugin compilerPlugin : config.getCompilerPlugins()) {
compilerPlugin.afterClass(config, clazz, mb);
}
OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8");
mb.build().write(writer);
writer.flush();
ci.setCatchNames(catches);
// Make sure no class or interface has zero dependencies
ci.addClassDependency("java/lang/Object", false);
if (sootClass.hasSuperclass() && !sootClass.isInterface()) {
ci.addClassDependency(getInternalName(sootClass.getSuperclass()), false);
}
for (SootClass iface : sootClass.getInterfaces()) {
ci.addClassDependency(getInternalName(iface), false);
}
for (SootField f : sootClass.getFields()) {
addClassDependencyIfNeeded(clazz, f.getType(), false);
}
for (SootMethod m : sootClass.getMethods()) {
MethodInfo mi = ci.getMethod(m.getName(), getDescriptor(m));
addClassDependencyIfNeeded(clazz, mi, m.getReturnType(), false);
@SuppressWarnings("unchecked") List<soot.Type> paramTypes = (List<soot.Type>) m.getParameterTypes();
for (soot.Type type : paramTypes) {
addClassDependencyIfNeeded(clazz, mi, type, false);
}
}
ci.addClassDependencies(attributesEncoder.getDependencies(), false);
ci.addClassDependencies(catches, false);
for (Trampoline t : trampolines.keySet()) {
if (t instanceof Checkcast) {
ci.addCheckcast(t.getTarget());
} else if (t instanceof Instanceof) {
ci.addInstanceof(t.getTarget());
} else if (t instanceof Invokevirtual || t instanceof Invokeinterface) {
ci.addInvoke(t.getTarget() + "." + ((Invoke) t).getMethodName() + ((Invoke) t).getMethodDesc());
}
}
clazz.saveClazzInfo();
}
use of soot.jimple.JimpleBody in project soot by Sable.
the class AsmMethodSource method getBody.
@Override
public Body getBody(SootMethod m, String phaseName) {
if (!m.isConcrete())
return null;
JimpleBody jb = Jimple.v().newBody(m);
/* initialize */
int nrInsn = instructions.size();
nextLocal = maxLocals;
locals = new HashMap<Integer, Local>(maxLocals + (maxLocals / 2));
labels = ArrayListMultimap.create(4, 1);
units = new HashMap<AbstractInsnNode, Unit>(nrInsn);
frames = new HashMap<AbstractInsnNode, StackFrame>(nrInsn);
trapHandlers = ArrayListMultimap.create(tryCatchBlocks.size(), 1);
body = jb;
/* retrieve all trap handlers */
for (TryCatchBlockNode tc : tryCatchBlocks) trapHandlers.put(tc.handler, Jimple.v().newStmtBox(null));
/* convert instructions */
try {
convert();
} catch (Throwable t) {
throw new RuntimeException("Failed to convert " + m, t);
}
/* build body (add units, locals, traps, etc.) */
emitLocals();
emitTraps();
emitUnits();
/* clean up */
locals = null;
labels = null;
units = null;
stack = null;
frames = null;
body = null;
// Make sure to inline patterns of the form to enable proper variable
// splitting and type assignment:
// a = new A();
// goto l0;
// l0:
// b = (B) a;
// return b;
castAndReturnInliner.transform(jb);
try {
PackManager.v().getPack("jb").apply(jb);
} catch (Throwable t) {
throw new RuntimeException("Failed to apply jb to " + m, t);
}
return jb;
}
use of soot.jimple.JimpleBody in project soot by Sable.
the class AsmMethodSource method emitLocals.
private void emitLocals() {
JimpleBody jb = body;
SootMethod m = jb.getMethod();
Collection<Local> jbl = jb.getLocals();
Collection<Unit> jbu = jb.getUnits();
int iloc = 0;
if (!m.isStatic()) {
Local l = getLocal(iloc++);
jbu.add(Jimple.v().newIdentityStmt(l, Jimple.v().newThisRef(m.getDeclaringClass().getType())));
}
int nrp = 0;
for (Object ot : m.getParameterTypes()) {
Type t = (Type) ot;
Local l = getLocal(iloc);
jbu.add(Jimple.v().newIdentityStmt(l, Jimple.v().newParameterRef(t, nrp++)));
if (AsmUtil.isDWord(t))
iloc += 2;
else
iloc++;
}
for (Local l : locals.values()) {
jbl.add(l);
}
}
use of soot.jimple.JimpleBody in project soot by Sable.
the class TypeAssigner method internalTransform.
/**
* Assign types to local variables. *
*/
@Override
protected void internalTransform(Body b, String phaseName, Map<String, String> options) {
if (b == null) {
throw new NullPointerException();
}
Date start = new Date();
if (Options.v().verbose())
logger.debug("[TypeAssigner] typing system started on " + start);
JBTROptions opt = new JBTROptions(options);
/*
* Setting this guard to true enables comparison of the original and new
* type assigners. This will be slow since type assignment will always
* happen twice. The actual types used for Jimple are determined by the
* use-old-type-assigner option.
*
* Each comparison is written as a separate semicolon-delimited line to
* the standard output, and the first field is always 'cmp' for use in
* grep. The format is:
*
* cmp;Method Name;Stmt Count;Old Inference Time (ms); New Inference
* Time (ms);Typing Comparison
*
* The Typing Comparison field compares the old and new typings: -2 -
* Old typing contains fewer variables (BAD!) -1 - Old typing is tighter
* (BAD!) 0 - Typings are equal 1 - New typing is tighter 2 - New typing
* contains fewer variables 3 - Typings are incomparable (inspect
* manually)
*
* In a final release this guard, and anything in the first branch,
* would probably be removed.
*/
if (opt.compare_type_assigners()) {
compareTypeAssigners(b, opt.use_older_type_assigner());
} else {
if (opt.use_older_type_assigner())
TypeResolver.resolve((JimpleBody) b, Scene.v());
else
(new soot.jimple.toolkits.typing.fast.TypeResolver((JimpleBody) b)).inferTypes();
}
Date finish = new Date();
if (Options.v().verbose()) {
long runtime = finish.getTime() - start.getTime();
long mins = runtime / 60000;
long secs = (runtime % 60000) / 1000;
logger.debug("[TypeAssigner] typing system ended. It took " + mins + " mins and " + secs + " secs.");
}
if (!opt.ignore_nullpointer_dereferences())
replaceNullType(b);
if (typingFailed((JimpleBody) b))
throw new RuntimeException("type inference failed!");
}
use of soot.jimple.JimpleBody in project soot by Sable.
the class LockAllocationBodyTransformer method getLockFor.
public static Value getLockFor(EquivalentValue lockEqVal) {
Value lock = lockEqVal.getValue();
if (lock instanceof InstanceFieldRef)
return lock;
if (// it would be better to lock the array
lock instanceof ArrayRef)
// ref for each value of the index!
return ((ArrayRef) lock).getBase();
if (lock instanceof Local)
return lock;
if (lock instanceof StaticFieldRef || lock instanceof NewStaticLock) {
if (lockEqValToLock.containsKey(lockEqVal))
return lockEqValToLock.get(lockEqVal);
SootClass lockClass = null;
if (lock instanceof StaticFieldRef) {
StaticFieldRef sfrLock = (StaticFieldRef) lock;
lockClass = sfrLock.getField().getDeclaringClass();
} else if (lock instanceof NewStaticLock) {
DeadlockAvoidanceEdge dae = (DeadlockAvoidanceEdge) lock;
lockClass = dae.getLockClass();
}
SootMethod clinitMethod = null;
JimpleBody clinitBody = null;
Stmt firstStmt = null;
boolean addingNewClinit = !lockClass.declaresMethod("void <clinit>()");
if (addingNewClinit) {
clinitMethod = Scene.v().makeSootMethod("<clinit>", new ArrayList(), VoidType.v(), Modifier.PUBLIC | Modifier.STATIC);
clinitBody = Jimple.v().newBody(clinitMethod);
clinitMethod.setActiveBody(clinitBody);
lockClass.addMethod(clinitMethod);
} else {
clinitMethod = lockClass.getMethod("void <clinit>()");
clinitBody = (JimpleBody) clinitMethod.getActiveBody();
firstStmt = clinitBody.getFirstNonIdentityStmt();
}
PatchingChain<Unit> clinitUnits = clinitBody.getUnits();
Local lockLocal = Jimple.v().newLocal("objectLockLocal" + lockNumber, RefType.v("java.lang.Object"));
// lockNumber is increased below
// TODO: add name conflict
clinitBody.getLocals().add(lockLocal);
// avoidance code
// assign new object to lock obj
Stmt newStmt = Jimple.v().newAssignStmt(lockLocal, Jimple.v().newNewExpr(RefType.v("java.lang.Object")));
if (addingNewClinit)
clinitUnits.add(newStmt);
else
clinitUnits.insertBeforeNoRedirect(newStmt, firstStmt);
// initialize new object
SootClass objectClass = Scene.v().loadClassAndSupport("java.lang.Object");
RefType type = RefType.v(objectClass);
SootMethod initMethod = objectClass.getMethod("void <init>()");
Stmt initStmt = Jimple.v().newInvokeStmt(Jimple.v().newSpecialInvokeExpr(lockLocal, initMethod.makeRef(), Collections.EMPTY_LIST));
if (addingNewClinit)
clinitUnits.add(initStmt);
else
clinitUnits.insertBeforeNoRedirect(initStmt, firstStmt);
// copy new object to global static lock object (for use by other
// fns)
SootField actualLockObject = Scene.v().makeSootField("objectLockGlobal" + lockNumber, RefType.v("java.lang.Object"), Modifier.STATIC | Modifier.PUBLIC);
lockNumber++;
lockClass.addField(actualLockObject);
StaticFieldRef actualLockSfr = Jimple.v().newStaticFieldRef(actualLockObject.makeRef());
Stmt assignStmt = Jimple.v().newAssignStmt(actualLockSfr, lockLocal);
if (addingNewClinit)
clinitUnits.add(assignStmt);
else
clinitUnits.insertBeforeNoRedirect(assignStmt, firstStmt);
if (addingNewClinit)
clinitUnits.add(Jimple.v().newReturnVoidStmt());
lockEqValToLock.put(lockEqVal, actualLockSfr);
return actualLockSfr;
}
throw new RuntimeException("Unknown type of lock (" + lock + "): expected FieldRef, ArrayRef, or Local");
}
Aggregations