use of soot.SootMethodRef in project robovm by robovm.
the class MethodCompiler method invokeExpr.
private Value invokeExpr(Stmt stmt, InvokeExpr expr) {
SootMethodRef methodRef = expr.getMethodRef();
ArrayList<Value> args = new ArrayList<Value>();
args.add(env);
if (!(expr instanceof StaticInvokeExpr)) {
Value base = immediate(stmt, (Immediate) ((InstanceInvokeExpr) expr).getBase());
checkNull(stmt, base);
args.add(base);
}
int i = 0;
for (soot.Value sootArg : (List<soot.Value>) expr.getArgs()) {
Value arg = immediate(stmt, (Immediate) sootArg);
args.add(narrowFromI32Value(stmt, getType(methodRef.parameterType(i)), arg));
i++;
}
Value result = null;
FunctionRef functionRef = config.isDebug() ? null : Intrinsics.getIntrinsic(sootMethod, stmt, expr);
if (functionRef == null) {
Trampoline trampoline = null;
String targetClassName = getInternalName(methodRef.declaringClass());
String methodName = methodRef.name();
String methodDesc = getDescriptor(methodRef);
if (expr instanceof SpecialInvokeExpr) {
soot.Type runtimeType = ((SpecialInvokeExpr) expr).getBase().getType();
String runtimeClassName = runtimeType == NullType.v() ? targetClassName : getInternalName(runtimeType);
trampoline = new Invokespecial(this.className, targetClassName, methodName, methodDesc, runtimeClassName);
} else if (expr instanceof StaticInvokeExpr) {
trampoline = new Invokestatic(this.className, targetClassName, methodName, methodDesc);
} else if (expr instanceof VirtualInvokeExpr) {
soot.Type runtimeType = ((VirtualInvokeExpr) expr).getBase().getType();
String runtimeClassName = runtimeType == NullType.v() ? targetClassName : getInternalName(runtimeType);
trampoline = new Invokevirtual(this.className, targetClassName, methodName, methodDesc, runtimeClassName);
} else if (expr instanceof InterfaceInvokeExpr) {
trampoline = new Invokeinterface(this.className, targetClassName, methodName, methodDesc);
}
trampolines.add(trampoline);
if (canCallDirectly(expr)) {
SootMethod method = this.sootMethod.getDeclaringClass().getMethod(methodRef.name(), methodRef.parameterTypes(), methodRef.returnType());
if (method.isSynchronized()) {
functionRef = FunctionBuilder.synchronizedWrapper(method).ref();
} else {
functionRef = createMethodFunction(method).ref();
}
} else {
functionRef = trampoline.getFunctionRef();
}
}
result = call(stmt, functionRef, args.toArray(new Value[0]));
if (result != null) {
return widenToI32Value(stmt, result, methodRef.returnType().equals(CharType.v()));
} else {
return null;
}
}
use of soot.SootMethodRef in project robovm by robovm.
the class MethodCompiler method canCallDirectly.
private boolean canCallDirectly(InvokeExpr expr) {
if (expr instanceof InterfaceInvokeExpr) {
// Never possible
return false;
}
SootClass sootClass = this.sootMethod.getDeclaringClass();
SootMethodRef methodRef = expr.getMethodRef();
if (!methodRef.declaringClass().equals(sootClass)) {
return false;
}
try {
SootMethod method = sootClass.getMethod(methodRef.name(), methodRef.parameterTypes(), methodRef.returnType());
if (method.isAbstract()) {
return false;
}
/*
* The method exists and isn't abstract. Non virtual (invokespecial)
* as well as static calls and calls to final methods can be done directly.
*/
if (method.isStatic()) {
// want an exception to be thrown so we need a trampoline.
return expr instanceof StaticInvokeExpr;
}
if (expr instanceof SpecialInvokeExpr) {
return true;
}
if (expr instanceof VirtualInvokeExpr) {
// the method must be private
return Modifier.isFinal(sootClass.getModifiers()) || Modifier.isFinal(method.getModifiers()) || method.isPrivate();
}
return false;
} catch (RuntimeException e) {
// isn't declared in the class.
return false;
}
}
use of soot.SootMethodRef in project robovm by robovm.
the class LambdaPlugin method transformMethod.
private void transformMethod(Config config, Clazz clazz, SootClass sootClass, SootMethod method, ModuleBuilder moduleBuilder) throws IOException {
if (!method.isConcrete()) {
return;
}
int tmpCounter = 0;
Body body = method.retrieveActiveBody();
PatchingChain<Unit> units = body.getUnits();
for (Unit unit = units.getFirst(); unit != null; unit = body.getUnits().getSuccOf(unit)) {
if (unit instanceof DefinitionStmt) {
if (((DefinitionStmt) unit).getRightOp() instanceof DynamicInvokeExpr) {
DynamicInvokeExpr expr = (DynamicInvokeExpr) ((DefinitionStmt) unit).getRightOp();
if (isLambdaBootstrapMethod(expr.getBootstrapMethodRef())) {
LambdaClassGenerator generator = null;
synchronized (generators) {
generator = generators.get(sootClass);
if (generator == null) {
generator = new LambdaClassGenerator();
generators.put(sootClass, generator);
}
}
List<Value> bsmArgs = expr.getBootstrapArgs();
SootClass caller = sootClass;
String invokedName = expr.getMethodRef().name();
SootMethodRef invokedType = expr.getMethodRef();
SootMethodType samMethodType = (SootMethodType) bsmArgs.get(0);
SootMethodHandle implMethod = (SootMethodHandle) bsmArgs.get(1);
SootMethodType instantiatedMethodType = (SootMethodType) bsmArgs.get(2);
try {
LambdaClass callSite = null;
List<Type> markerInterfaces = new ArrayList<>();
List<SootMethodType> bridgeMethods = new ArrayList<>();
if (expr.getBootstrapMethodRef().name().equals("altMetafactory")) {
int flags = ((IntConstant) bsmArgs.get(3)).value;
int bsmArgsIdx = 4;
if ((flags & FLAG_MARKERS) > 0) {
int count = ((IntConstant) bsmArgs.get(bsmArgsIdx++)).value;
for (int i = 0; i < count; i++) {
Object value = bsmArgs.get(bsmArgsIdx++);
if (value instanceof Type) {
markerInterfaces.add((Type) value);
} else if (value instanceof ClassConstant) {
String className = ((ClassConstant) value).getValue().replace('/', '.');
markerInterfaces.add(SootResolver.v().resolveClass(className, SootClass.HIERARCHY).getType());
}
}
}
if ((flags & FLAG_BRIDGES) > 0) {
int count = ((IntConstant) bsmArgs.get(bsmArgsIdx++)).value;
for (int i = 0; i < count; i++) {
bridgeMethods.add((SootMethodType) bsmArgs.get(bsmArgsIdx++));
}
}
}
// see issue #1087
if (bridgeMethods.size() == 0) {
SootClass targetType = SootResolver.v().resolveClass(invokedType.returnType().toString().replace('/', '.'), SootClass.SIGNATURES);
String samDescriptor = Types.getDescriptor(samMethodType.getParameterTypes(), samMethodType.getReturnType());
for (SootMethod targetTypeMethod : targetType.getMethods()) {
boolean isBridgeMethod = targetTypeMethod.getName().equals(invokedName);
isBridgeMethod &= targetTypeMethod.getName().equals(invokedName);
isBridgeMethod &= targetTypeMethod.getParameterCount() == samMethodType.getParameterTypes().size();
isBridgeMethod &= ((targetTypeMethod.getModifiers() & BRIDGE) != 0);
isBridgeMethod &= ((targetTypeMethod.getModifiers() & SYNTHETIC) != 0);
if (isBridgeMethod) {
String targetTypeMethodDesc = Types.getDescriptor(targetTypeMethod);
if (!targetTypeMethodDesc.equals(samDescriptor)) {
bridgeMethods.add(new BridgeMethodType(targetTypeMethod.getReturnType(), targetTypeMethod.getParameterTypes()));
}
}
}
}
// generate the lambda class
callSite = generator.generate(caller, invokedName, invokedType, samMethodType, implMethod, instantiatedMethodType, markerInterfaces, bridgeMethods);
File f = clazz.getPath().getGeneratedClassFile(callSite.getLambdaClassName());
FileUtils.writeByteArrayToFile(f, callSite.getClassData());
// The lambda class is created after the caller is
// compiled.
// This prevents the triggering of a recompile of
// the caller.
f.setLastModified(clazz.lastModified());
SootClass lambdaClass = SootResolver.v().makeClassRef(callSite.getLambdaClassName().replace('/', '.'));
Local l = (Local) ((DefinitionStmt) unit).getLeftOp();
Type samType = callSite.getTargetMethodReturnType();
LinkedList<Unit> newUnits = new LinkedList<>();
if (callSite.getTargetMethodName().equals("<init>")) {
// Constant lambda. Create an instance once and
// reuse for
// every call.
String fieldName = lambdaClass.getName().substring(lambdaClass.getName().lastIndexOf('.') + 1);
SootField field = new SootField(fieldName, lambdaClass.getType(), Modifier.STATIC | Modifier.PRIVATE | Modifier.TRANSIENT | 0x1000);
method.getDeclaringClass().addField(field);
// l = LambdaClass.lambdaField
newUnits.add(Jimple.v().newAssignStmt(l, Jimple.v().newStaticFieldRef(field.makeRef())));
// if l != null goto succOfInvokedynamic
newUnits.add(Jimple.v().newIfStmt(Jimple.v().newNeExpr(l, NullConstant.v()), units.getSuccOf(unit)));
// $tmpX = new LambdaClass()
Local tmp = Jimple.v().newLocal("$tmp" + (tmpCounter++), lambdaClass.getType());
body.getLocals().add(tmp);
newUnits.add(Jimple.v().newAssignStmt(tmp, Jimple.v().newNewExpr(lambdaClass.getType())));
newUnits.add(Jimple.v().newInvokeStmt(Jimple.v().newSpecialInvokeExpr(tmp, Scene.v().makeConstructorRef(lambdaClass, Collections.<Type>emptyList()))));
// LambdaClass.lambdaField = $tmpX
newUnits.add(Jimple.v().newAssignStmt(Jimple.v().newStaticFieldRef(field.makeRef()), tmp));
// l = $tmpX
newUnits.add(Jimple.v().newAssignStmt(l, tmp));
} else {
// Static factory method returns the lambda to
// use.
newUnits.add(Jimple.v().newAssignStmt(l, Jimple.v().newStaticInvokeExpr(Scene.v().makeMethodRef(lambdaClass, callSite.getTargetMethodName(), callSite.getTargetMethodParameters(), samType, true), expr.getArgs())));
}
units.insertAfter(newUnits, unit);
units.remove(unit);
unit = newUnits.getLast();
} catch (Throwable e) {
// LambdaConversionException at runtime.
throw new CompilerException(e);
}
}
}
}
}
}
use of soot.SootMethodRef in project robovm by robovm.
the class ObjCMemberPlugin method createCallback.
private void createCallback(SootClass sootClass, SootMethod method, SootMethod annotatedMethod, String selectorName, Type receiverType) {
Jimple j = Jimple.v();
SootMethod callbackMethod = getCallbackMethod(selectorName, method, annotatedMethod, receiverType);
sootClass.addMethod(callbackMethod);
addCallbackAnnotation(callbackMethod);
addBindSelectorAnnotation(callbackMethod, selectorName);
if (!hasAnnotation(annotatedMethod, TYPE_ENCODING) && (isCustomClass(sootClass) || ObjCProtocolProxyPlugin.isObjCProxy(sootClass))) {
String encoding = generateTypeEncoding(callbackMethod);
try {
addTypeEncodingAnnotation(callbackMethod, encoding);
} catch (IllegalArgumentException e) {
throw new CompilerException("Failed to determine method type encoding for method " + method + ": " + e.getMessage());
}
}
Body body = j.newBody(callbackMethod);
callbackMethod.setActiveBody(body);
PatchingChain<Unit> units = body.getUnits();
Local thiz = null;
if (!method.isStatic()) {
thiz = j.newLocal("$this", receiverType);
body.getLocals().add(thiz);
units.add(j.newIdentityStmt(thiz, j.newParameterRef(receiverType, 0)));
}
LinkedList<Value> args = new LinkedList<>();
for (int i = 0; i < method.getParameterCount(); i++) {
Type t = method.getParameterType(i);
Local p = j.newLocal("$p" + i, t);
body.getLocals().add(p);
units.add(j.newIdentityStmt(p, j.newParameterRef(t, i + 2)));
args.add(p);
}
Local ret = null;
if (method.getReturnType() != VoidType.v()) {
ret = j.newLocal("$ret", method.getReturnType());
body.getLocals().add(ret);
}
SootMethodRef targetMethod = method.makeRef();
if (((RefType) receiverType).getSootClass().isInterface()) {
@SuppressWarnings("unchecked") List<Type> parameterTypes = method.getParameterTypes();
targetMethod = Scene.v().makeMethodRef(((RefType) receiverType).getSootClass(), method.getName(), parameterTypes, method.getReturnType(), false);
}
InvokeExpr expr = method.isStatic() ? j.newStaticInvokeExpr(targetMethod, args) : (((RefType) receiverType).getSootClass().isInterface() ? j.newInterfaceInvokeExpr(thiz, targetMethod, args) : j.newVirtualInvokeExpr(thiz, targetMethod, args));
units.add(ret == null ? j.newInvokeStmt(expr) : j.newAssignStmt(ret, expr));
if (ret != null) {
units.add(j.newReturnStmt(ret));
} else {
units.add(j.newReturnVoidStmt());
}
}
use of soot.SootMethodRef in project robovm by robovm.
the class ObjCMemberPlugin method addBindCall.
private void addBindCall(SootClass sootClass) {
Jimple j = Jimple.v();
SootMethod clinit = getOrCreateStaticInitializer(sootClass);
Body body = clinit.retrieveActiveBody();
String internalName = sootClass.getName().replace('.', '/');
ClassConstant c = ClassConstant.v(internalName);
Chain<Unit> units = body.getUnits();
// Don't call bind if there's already a call in the static initializer
for (Unit unit : units) {
if (unit instanceof InvokeStmt) {
InvokeStmt stmt = (InvokeStmt) unit;
if (stmt.getInvokeExpr() instanceof StaticInvokeExpr) {
StaticInvokeExpr expr = (StaticInvokeExpr) stmt.getInvokeExpr();
SootMethodRef ref = expr.getMethodRef();
if (ref.isStatic() && ref.declaringClass().equals(org_robovm_objc_ObjCRuntime) && ref.name().equals("bind")) {
if (ref.parameterTypes().isEmpty() || expr.getArg(0).equals(c)) {
return;
}
}
}
}
}
// Call ObjCRuntime.bind(<class>)
units.insertBefore(j.newInvokeStmt(j.newStaticInvokeExpr(org_robovm_objc_ObjCRuntime_bind, ClassConstant.v(internalName))), units.getLast());
}
Aggregations