Search in sources :

Example 1 with StaticInvokeExpr

use of soot.jimple.StaticInvokeExpr 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;
    }
}
Also used : Trampoline(org.robovm.compiler.trampoline.Trampoline) SootMethodRef(soot.SootMethodRef) SpecialInvokeExpr(soot.jimple.SpecialInvokeExpr) ArrayList(java.util.ArrayList) InstanceInvokeExpr(soot.jimple.InstanceInvokeExpr) InterfaceInvokeExpr(soot.jimple.InterfaceInvokeExpr) Invokeinterface(org.robovm.compiler.trampoline.Invokeinterface) Invokespecial(org.robovm.compiler.trampoline.Invokespecial) StaticInvokeExpr(soot.jimple.StaticInvokeExpr) Invokestatic(org.robovm.compiler.trampoline.Invokestatic) Value(org.robovm.compiler.llvm.Value) SootMethod(soot.SootMethod) ArrayList(java.util.ArrayList) List(java.util.List) VirtualInvokeExpr(soot.jimple.VirtualInvokeExpr) Invokevirtual(org.robovm.compiler.trampoline.Invokevirtual) FunctionRef(org.robovm.compiler.llvm.FunctionRef)

Example 2 with StaticInvokeExpr

use of soot.jimple.StaticInvokeExpr 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;
    }
}
Also used : StaticInvokeExpr(soot.jimple.StaticInvokeExpr) SootMethodRef(soot.SootMethodRef) SpecialInvokeExpr(soot.jimple.SpecialInvokeExpr) InterfaceInvokeExpr(soot.jimple.InterfaceInvokeExpr) SootMethod(soot.SootMethod) SootClass(soot.SootClass) VirtualInvokeExpr(soot.jimple.VirtualInvokeExpr)

Example 3 with StaticInvokeExpr

use of soot.jimple.StaticInvokeExpr 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());
}
Also used : StaticInvokeExpr(soot.jimple.StaticInvokeExpr) InvokeStmt(soot.jimple.InvokeStmt) SootMethodRef(soot.SootMethodRef) SootMethod(soot.SootMethod) Jimple(soot.jimple.Jimple) Unit(soot.Unit) Body(soot.Body) ClassConstant(soot.jimple.ClassConstant)

Example 4 with StaticInvokeExpr

use of soot.jimple.StaticInvokeExpr in project robovm by robovm.

the class ObjCMemberPlugin method createBridge.

private void createBridge(SootClass sootClass, SootMethod method, String selectorName, boolean strongRefSetter, boolean extensions) {
    Jimple j = Jimple.v();
    boolean usingGenericInstanceMethod = false;
    SootMethod msgSendMethod = getMsgSendMethod(selectorName, method, extensions);
    /*
         * Add the method even if we might remove it later to make marshaler
         * lookup on the method work as expected.
         */
    sootClass.addMethod(msgSendMethod);
    addBridgeAnnotation(msgSendMethod);
    SootMethodRef msgSendMethodRef = getGenericMsgSendReplacementMethod(msgSendMethod);
    if (!msgSendMethodRef.declaringClass().getType().equals(msgSendMethod.getDeclaringClass().getType())) {
        /*
             * There's a generic objc_msgSend method we can use. Remove
             * msgSendMethod from the class.
             */
        sootClass.removeMethod(msgSendMethod);
        /*
             * Can we use a generic <name>_instance method from $M? If we can we
             * won't have to make a call to objc_msgSendSuper.
             */
        if (!method.isStatic()) {
            // Yes!
            msgSendMethodRef = Scene.v().makeMethodRef(msgSendMethodRef.declaringClass(), msgSendMethodRef.name() + "_instance", msgSendMethodRef.parameterTypes(), msgSendMethodRef.returnType(), true);
            usingGenericInstanceMethod = true;
        }
    }
    SootMethodRef msgSendSuperMethodRef = null;
    if (!usingGenericInstanceMethod && !extensions && !method.isStatic()) {
        SootMethod msgSendSuperMethod = getMsgSendSuperMethod(selectorName, method);
        /*
             * Add the method even if we might remove it later to make marshaler
             * lookup on the method work as expected.
             */
        sootClass.addMethod(msgSendSuperMethod);
        addBridgeAnnotation(msgSendSuperMethod);
        msgSendSuperMethodRef = getGenericMsgSendSuperReplacementMethod(msgSendSuperMethod);
        if (!msgSendSuperMethodRef.declaringClass().getType().equals(msgSendSuperMethod.getDeclaringClass().getType())) {
            /*
                 * There's a generic objc_msgSendSuper method we can use. Remove
                 * msgSendSuperMethod from the class.
                 */
            sootClass.removeMethod(msgSendSuperMethod);
        }
    }
    method.setModifiers(method.getModifiers() & ~NATIVE);
    Body body = j.newBody(method);
    method.setActiveBody(body);
    PatchingChain<Unit> units = body.getUnits();
    Local thiz = null;
    if (extensions) {
        thiz = j.newLocal("$this", method.getParameterType(0));
        body.getLocals().add(thiz);
        units.add(j.newIdentityStmt(thiz, j.newParameterRef(method.getParameterType(0), 0)));
    } else if (!method.isStatic()) {
        thiz = j.newLocal("$this", sootClass.getType());
        body.getLocals().add(thiz);
        units.add(j.newIdentityStmt(thiz, j.newThisRef(sootClass.getType())));
    }
    LinkedList<Value> args = new LinkedList<>();
    for (int i = extensions ? 1 : 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)));
        args.add(p);
    }
    Local objCClass = null;
    if (!extensions && method.isStatic()) {
        objCClass = j.newLocal("$objCClass", org_robovm_objc_ObjCClass.getType());
        body.getLocals().add(objCClass);
        units.add(j.newAssignStmt(objCClass, j.newStaticFieldRef(Scene.v().makeFieldRef(sootClass, "$objCClass", org_robovm_objc_ObjCClass.getType(), true))));
    }
    if (strongRefSetter) {
        Type propType = method.getParameterType(extensions ? 1 : 0);
        if (propType instanceof RefLikeType) {
            SootMethodRef getter = findStrongRefGetter(sootClass, method, extensions).makeRef();
            Local before = j.newLocal("$before", propType);
            body.getLocals().add(before);
            units.add(j.newAssignStmt(before, extensions ? j.newStaticInvokeExpr(getter, thiz) : (objCClass != null ? j.newStaticInvokeExpr(getter) : j.newVirtualInvokeExpr(thiz, getter))));
            Value after = args.get(0);
            if (extensions) {
                units.add(j.newInvokeStmt(j.newStaticInvokeExpr(org_robovm_objc_ObjCExtensions_updateStrongRef, Arrays.asList(thiz, before, after))));
            } else {
                units.add(j.newInvokeStmt(j.newVirtualInvokeExpr(objCClass != null ? objCClass : thiz, org_robovm_objc_ObjCObject_updateStrongRef, before, after)));
            }
        }
    }
    Local sel = j.newLocal("$sel", org_robovm_objc_Selector.getType());
    body.getLocals().add(sel);
    // $sel = <selector>
    units.add(j.newAssignStmt(sel, j.newStaticFieldRef(Scene.v().makeFieldRef(sootClass, getSelectorFieldName(selectorName), org_robovm_objc_Selector.getType(), true))));
    args.addFirst(sel);
    Local customClass = null;
    if (!usingGenericInstanceMethod && !extensions && !Modifier.isFinal(sootClass.getModifiers()) && !method.isStatic()) {
        customClass = j.newLocal("$customClass", BooleanType.v());
        body.getLocals().add(customClass);
        units.add(j.newAssignStmt(customClass, j.newInstanceFieldRef(thiz, org_robovm_objc_ObjCObject_customClass)));
    }
    Local ret = null;
    if (method.getReturnType() != VoidType.v()) {
        ret = j.newLocal("$ret", msgSendMethodRef.returnType());
        body.getLocals().add(ret);
    }
    Local castRet = null;
    if (!msgSendMethodRef.returnType().equals(method.getReturnType())) {
        /*
             * We're calling a generic method in $M which returns an NSObject.
             * We need to cast that to the return type declared by the method
             * being generated.
             */
        castRet = j.newLocal("$castRet", method.getReturnType());
        body.getLocals().add(castRet);
    }
    StaticInvokeExpr invokeMsgSendExpr = j.newStaticInvokeExpr(msgSendMethodRef, l(thiz != null ? thiz : objCClass, args));
    Stmt invokeMsgSendStmt = ret == null ? j.newInvokeStmt(invokeMsgSendExpr) : j.newAssignStmt(ret, invokeMsgSendExpr);
    if (customClass != null) {
        // if $customClass == 0 goto <invokeMsgSendStmt>
        units.add(j.newIfStmt(j.newEqExpr(customClass, IntConstant.v(0)), invokeMsgSendStmt));
        // $super = this.getSuper()
        Local zuper = j.newLocal("$super", org_robovm_objc_ObjCSuper.getType());
        body.getLocals().add(zuper);
        units.add(j.newAssignStmt(zuper, j.newVirtualInvokeExpr(body.getThisLocal(), org_robovm_objc_ObjCObject_getSuper)));
        StaticInvokeExpr invokeMsgSendSuperExpr = j.newStaticInvokeExpr(msgSendSuperMethodRef, l(zuper, args));
        units.add(ret == null ? j.newInvokeStmt(invokeMsgSendSuperExpr) : j.newAssignStmt(ret, invokeMsgSendSuperExpr));
        if (ret != null) {
            if (castRet != null) {
                units.add(j.newAssignStmt(castRet, j.newCastExpr(ret, castRet.getType())));
                units.add(j.newReturnStmt(castRet));
            } else {
                units.add(j.newReturnStmt(ret));
            }
        } else {
            units.add(j.newReturnVoidStmt());
        }
    }
    units.add(invokeMsgSendStmt);
    if (ret != null) {
        if (castRet != null) {
            units.add(j.newAssignStmt(castRet, j.newCastExpr(ret, castRet.getType())));
            units.add(j.newReturnStmt(castRet));
        } else {
            units.add(j.newReturnStmt(ret));
        }
    } else {
        units.add(j.newReturnVoidStmt());
    }
}
Also used : SootMethodRef(soot.SootMethodRef) Local(soot.Local) Unit(soot.Unit) LinkedList(java.util.LinkedList) InvokeStmt(soot.jimple.InvokeStmt) Stmt(soot.jimple.Stmt) RefLikeType(soot.RefLikeType) StaticInvokeExpr(soot.jimple.StaticInvokeExpr) RefType(soot.RefType) BooleanType(soot.BooleanType) SootMethodType(org.robovm.compiler.util.generic.SootMethodType) Type(soot.Type) DoubleType(soot.DoubleType) FloatType(soot.FloatType) LongType(soot.LongType) RefLikeType(soot.RefLikeType) PrimType(soot.PrimType) VoidType(soot.VoidType) Value(soot.Value) SootMethod(soot.SootMethod) Jimple(soot.jimple.Jimple) Body(soot.Body)

Aggregations

SootMethod (soot.SootMethod)4 SootMethodRef (soot.SootMethodRef)4 StaticInvokeExpr (soot.jimple.StaticInvokeExpr)4 Body (soot.Body)2 Unit (soot.Unit)2 InterfaceInvokeExpr (soot.jimple.InterfaceInvokeExpr)2 InvokeStmt (soot.jimple.InvokeStmt)2 Jimple (soot.jimple.Jimple)2 SpecialInvokeExpr (soot.jimple.SpecialInvokeExpr)2 VirtualInvokeExpr (soot.jimple.VirtualInvokeExpr)2 ArrayList (java.util.ArrayList)1 LinkedList (java.util.LinkedList)1 List (java.util.List)1 FunctionRef (org.robovm.compiler.llvm.FunctionRef)1 Value (org.robovm.compiler.llvm.Value)1 Invokeinterface (org.robovm.compiler.trampoline.Invokeinterface)1 Invokespecial (org.robovm.compiler.trampoline.Invokespecial)1 Invokestatic (org.robovm.compiler.trampoline.Invokestatic)1 Invokevirtual (org.robovm.compiler.trampoline.Invokevirtual)1 Trampoline (org.robovm.compiler.trampoline.Trampoline)1