Search in sources :

Example 11 with Type

use of soot.Type in project robovm by robovm.

the class ObjCMemberPlugin method findStrongRefGetter.

private SootMethod findStrongRefGetter(SootClass sootClass, final SootMethod method, boolean extensions) {
    AnnotationTag annotation = getAnnotation(method, PROPERTY);
    if (annotation == null) {
        annotation = getAnnotation(method, IBOUTLET);
    }
    if (annotation == null) {
        annotation = getAnnotation(method, IBOUTLETCOLLECTION);
    }
    String setterPropName = readStringElem(annotation, "name", "").trim();
    if (setterPropName.length() == 0) {
        String methodName = method.getName();
        if (!methodName.startsWith("set") || methodName.length() == 3) {
            throw new CompilerException("Failed to determine the property " + "name from the @Property method " + method + ". Either specify the name explicitly in the @Property " + "annotation or rename the method according to the Java " + "beans property setter method naming convention.");
        }
        setterPropName = methodName.substring(3);
        setterPropName = setterPropName.substring(0, 1).toLowerCase() + setterPropName.substring(1);
    }
    int paramCount = extensions ? 1 : 0;
    Type propType = method.getParameterType(extensions ? 1 : 0);
    for (SootMethod m : sootClass.getMethods()) {
        if (m != method && method.isStatic() == m.isStatic() && m.getParameterCount() == paramCount && m.getReturnType().equals(propType)) {
            AnnotationTag propertyAnno = getAnnotation(m, PROPERTY);
            if (propertyAnno != null) {
                String getterPropName = readStringElem(propertyAnno, "name", "").trim();
                if (getterPropName.length() == 0) {
                    String methodName = m.getName();
                    if (!methodName.startsWith("get") || methodName.length() == 3) {
                        // style getter
                        continue;
                    }
                    getterPropName = methodName.substring(3);
                    getterPropName = getterPropName.substring(0, 1).toLowerCase() + getterPropName.substring(1);
                }
                if (setterPropName.equals(getterPropName)) {
                    return m;
                }
            }
        }
    }
    throw new CompilerException("Failed to determine the getter method " + "corresponding to the strong ref @Property setter method " + method + ". The getter must either specify the name explicitly in the @Property " + "annotation or be named according to the Java " + "beans property getter method naming convention.");
}
Also used : AnnotationTag(soot.tagkit.AnnotationTag) 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) CompilerException(org.robovm.compiler.CompilerException) SootMethod(soot.SootMethod)

Example 12 with Type

use of soot.Type in project robovm by robovm.

the class ObjCMemberPlugin method transformMethod.

private void transformMethod(Config config, Clazz clazz, SootClass sootClass, SootMethod method, Set<String> selectors, Set<String> overridables, boolean extensions) {
    AnnotationTag annotation = getAnnotation(method, METHOD);
    if (annotation != null) {
        if (extensions && !(method.isStatic() && method.isNative())) {
            throw new CompilerException("Objective-C @Method method " + method + " in extension class must be static and native.");
        }
        transformObjCMethod(annotation, sootClass, method, selectors, overridables, extensions);
        return;
    }
    annotation = getAnnotation(method, IBACTION);
    if (annotation != null) {
        if (method.isStatic() || method.isNative()) {
            throw new CompilerException("Objective-C @IBAction method " + method + " must not be static or native.");
        }
        int paramCount = method.getParameterCount();
        Type param1 = paramCount > 0 ? method.getParameterType(0) : null;
        Type param2 = paramCount > 1 ? method.getParameterType(1) : null;
        if (method.getReturnType() != VoidType.v() || paramCount > 2 || (param1 != null && (!isNSObject(param1) && !isNSObject(param1))) || (param2 != null && (!isUIEvent(param2) || isNSObject(param1)))) {
            throw new CompilerException("Objective-C @IBAction method " + method + " does not have a supported signature. @IBAction methods" + " must return void and either take no arguments, 1 argument of type NSObject" + ", or 2 arguments of types NSObject and UIEvent.");
        }
        transformObjCMethod(annotation, sootClass, method, selectors, overridables, extensions);
        return;
    }
    annotation = getAnnotation(method, PROPERTY);
    if (annotation != null) {
        if (extensions && !(method.isStatic() && method.isNative())) {
            throw new CompilerException("Objective-C @Property method " + method + " in extension class must be static and native.");
        }
        transformObjCProperty(annotation, "@Property", sootClass, method, selectors, overridables, extensions);
        return;
    }
    annotation = getAnnotation(method, IBOUTLET);
    if (annotation != null) {
        if (method.isStatic()) {
            throw new CompilerException("Objective-C @IBOutlet method " + method + " must not be static.");
        }
        transformObjCProperty(annotation, "@IBOutlet", sootClass, method, selectors, overridables, extensions);
        return;
    }
    annotation = getAnnotation(method, IBOUTLETCOLLECTION);
    if (annotation != null) {
        if (method.isStatic()) {
            throw new CompilerException("Objective-C @IBOutletCollection method " + method + " must not be static.");
        }
        if (method.getReturnType() != VoidType.v() && !isNSArray(method.getReturnType()) || method.getReturnType() == VoidType.v() && method.getParameterCount() == 1 && !isNSArray(method.getParameterType(0))) {
            throw new CompilerException("Objective-C @IBOutletCollection method " + method + " does not have a supported signature. " + "@IBOutletCollection getter methods must return NSArray. " + "@IBOutletCollection setter methods must have 1 parameter of type NSArray.");
        }
        transformObjCProperty(annotation, "@IBOutletCollection", sootClass, method, selectors, overridables, extensions);
        return;
    }
    if (!method.isStatic() && !method.isNative() && !method.isAbstract() && !method.isPrivate() && isCustomClass(sootClass) && !hasAnnotation(method, NOT_IMPLEMENTED)) {
        /*
             * Create a @Callback for this method if it overrides a
             * @Method/@Property method in a superclass/interface.
             */
        List<SootMethod> superMethods = findOverriddenMethods(sootClass, method);
        for (SootMethod superMethod : superMethods) {
            if (createCustomClassCallbackIfNeeded(sootClass, method, superMethod)) {
                break;
            }
        }
    }
}
Also used : AnnotationTag(soot.tagkit.AnnotationTag) 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) CompilerException(org.robovm.compiler.CompilerException) SootMethod(soot.SootMethod)

Example 13 with Type

use of soot.Type 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)

Example 14 with Type

use of soot.Type in project robovm by robovm.

the class TypeEncoder method getStructMembers.

private List<Member> getStructMembers(SootClass clazz, boolean is64bit) {
    List<Member> members = new ArrayList<>();
    if (clazz.hasSuperclass()) {
        SootClass superclass = clazz.getSuperclass();
        if (!superclass.getName().equals("org.robovm.rt.bro.Struct")) {
            members.addAll(getStructMembers(clazz, is64bit));
        }
    }
    for (SootMethod method : clazz.getMethods()) {
        int offset = getStructMemberOffset(method);
        if (offset != -1) {
            if (!method.isNative() && !method.isStatic()) {
                // thrown by the ClassCompiler later on.
                continue;
            }
            Type type;
            int idx;
            if (method.getParameterCount() == 0) {
                type = method.getReturnType();
                idx = -1;
            } else if (method.getParameterCount() == 1) {
                type = method.getParameterType(0);
                idx = 0;
            } else {
                // throw by the ClassCompiler later on.
                continue;
            }
            Member member = new Member();
            member.offset = offset;
            member.type = encodeOne(method, type, idx, is64bit);
            members.add(member);
        }
    }
    return members;
}
Also used : RefType(soot.RefType) Type(soot.Type) PrimType(soot.PrimType) VoidType(soot.VoidType) ArrayList(java.util.ArrayList) SootMethod(soot.SootMethod) SootClass(soot.SootClass)

Aggregations

RefType (soot.RefType)14 Type (soot.Type)14 PrimType (soot.PrimType)13 VoidType (soot.VoidType)13 DoubleType (soot.DoubleType)12 FloatType (soot.FloatType)12 LongType (soot.LongType)12 SootMethod (soot.SootMethod)8 SootMethodType (org.robovm.compiler.util.generic.SootMethodType)7 BooleanType (soot.BooleanType)7 RefLikeType (soot.RefLikeType)7 ArrayList (java.util.ArrayList)6 SootMethodType (soot.SootMethodType)6 CompilerException (org.robovm.compiler.CompilerException)5 LinkedList (java.util.LinkedList)3 MethodVisitor (org.objectweb.asm.MethodVisitor)3 Body (soot.Body)3 Local (soot.Local)3 SootClass (soot.SootClass)3 SootMethodRef (soot.SootMethodRef)3