Search in sources :

Example 1 with Stmt

use of soot.jimple.Stmt 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

LinkedList (java.util.LinkedList)1 SootMethodType (org.robovm.compiler.util.generic.SootMethodType)1 Body (soot.Body)1 BooleanType (soot.BooleanType)1 DoubleType (soot.DoubleType)1 FloatType (soot.FloatType)1 Local (soot.Local)1 LongType (soot.LongType)1 PrimType (soot.PrimType)1 RefLikeType (soot.RefLikeType)1 RefType (soot.RefType)1 SootMethod (soot.SootMethod)1 SootMethodRef (soot.SootMethodRef)1 Type (soot.Type)1 Unit (soot.Unit)1 Value (soot.Value)1 VoidType (soot.VoidType)1 InvokeStmt (soot.jimple.InvokeStmt)1 Jimple (soot.jimple.Jimple)1 StaticInvokeExpr (soot.jimple.StaticInvokeExpr)1