Search in sources :

Example 1 with Type

use of soot.Type in project robovm by robovm.

the class LambdaClassGenerator method pushArguments.

private void pushArguments(SootClass caller, String lambdaClassName, MethodVisitor mv, GeneratorAdapter caster, List<Type> parameters, List<Type> invokedParameters, SootMethodHandle implMethod, SootMethodType instantiatedMethodType, boolean isInstanceMethod) {
    // create the object itself
    if (implMethod.getReferenceKind() == SootMethodHandle.REF_newInvokeSpecial) {
        mv.visitTypeInsn(NEW, implMethod.getMethodRef().declaringClass().getName().replace('.', '/'));
        mv.visitInsn(DUP);
    }
    // push the captured arguments
    for (int i = 0; i < invokedParameters.size(); i++) {
        Object obj = invokedParameters.get(i);
        Type captureType = (Type) obj;
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, lambdaClassName, "arg$" + (i + 1), Types.getDescriptor(captureType));
    }
    // push the functional interface parameters
    // first check if the parameters include the received, e.g.
    // "hello"::contains
    // would be called on "hello" and not on the class containing the
    // invoke dynamic call. We need to handle that parameter separately as
    // it's not part of the method signature of the implementation
    boolean paramsContainReceiver = isInstanceMethod & !caller.getName().equals(implMethod.getMethodRef().declaringClass().getName()) && parameters.size() > implMethod.getMethodRef().parameterTypes().size();
    int paramsIndex = 0;
    // we start at slot index 1, because this occupies
    int localIndex = 1;
    // slot 0
    if (paramsContainReceiver && !parameters.isEmpty()) {
        Type param = parameters.get(0);
        mv.visitVarInsn(loadOpcodeForType(param), localIndex);
        castOrWiden(mv, caster, param, implMethod.getMethodRef().declaringClass().getType());
        localIndex += slotsForType(param);
        paramsIndex++;
    }
    int samParamsOffset = implMethod.getMethodRef().parameterTypes().size() - parameters.size() + (paramsContainReceiver ? 1 : 0);
    for (int i = 0; paramsIndex < parameters.size(); paramsIndex++, i++) {
        Type param = parameters.get(paramsIndex);
        mv.visitVarInsn(loadOpcodeForType(param), localIndex);
        castOrWiden(mv, caster, param, (Type) implMethod.getMethodRef().parameterTypes().get(samParamsOffset + i));
        localIndex += slotsForType(param);
    }
}
Also used : RefType(soot.RefType) DoubleType(soot.DoubleType) FloatType(soot.FloatType) Type(soot.Type) PrimType(soot.PrimType) VoidType(soot.VoidType) LongType(soot.LongType) SootMethodType(soot.SootMethodType)

Example 2 with Type

use of soot.Type 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);
                    }
                }
            }
        }
    }
}
Also used : SootMethodHandle(soot.SootMethodHandle) ArrayList(java.util.ArrayList) Unit(soot.Unit) IntConstant(soot.jimple.IntConstant) CompilerException(org.robovm.compiler.CompilerException) Body(soot.Body) SootMethodRef(soot.SootMethodRef) SootMethodType(soot.SootMethodType) Local(soot.Local) SootClass(soot.SootClass) LinkedList(java.util.LinkedList) RefType(soot.RefType) SootMethodType(soot.SootMethodType) Type(soot.Type) Value(soot.Value) SootMethod(soot.SootMethod) SootField(soot.SootField) DynamicInvokeExpr(soot.jimple.DynamicInvokeExpr) DefinitionStmt(soot.jimple.DefinitionStmt) File(java.io.File) ClassConstant(soot.jimple.ClassConstant)

Example 3 with Type

use of soot.Type 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());
    }
}
Also used : SootMethodRef(soot.SootMethodRef) Local(soot.Local) Unit(soot.Unit) LinkedList(java.util.LinkedList) RefType(soot.RefType) 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) InvokeExpr(soot.jimple.InvokeExpr) StaticInvokeExpr(soot.jimple.StaticInvokeExpr) Value(soot.Value) SootMethod(soot.SootMethod) CompilerException(org.robovm.compiler.CompilerException) Jimple(soot.jimple.Jimple) Body(soot.Body)

Example 4 with Type

use of soot.Type in project robovm by robovm.

the class ObjCMemberPlugin method getMsgSendMethod.

@SuppressWarnings("unchecked")
private SootMethod getMsgSendMethod(String selectorName, SootMethod method, SootMethod annotatedMethod, boolean isCallback, Type receiverType, boolean extensions) {
    List<Type> paramTypes = new ArrayList<>();
    if (extensions) {
        paramTypes.add(method.getParameterType(0));
    } else if (method.isStatic()) {
        paramTypes.add(org_robovm_objc_ObjCClass.getType());
    } else {
        paramTypes.add(receiverType == null ? method.getDeclaringClass().getType() : receiverType);
    }
    paramTypes.add(org_robovm_objc_Selector.getType());
    if (extensions) {
        paramTypes.addAll(method.getParameterTypes().subList(1, method.getParameterTypes().size()));
    } else {
        paramTypes.addAll(method.getParameterTypes());
    }
    SootMethod m = new SootMethod((isCallback ? "$cb$" : "$m$") + selectorName.replace(':', '$'), paramTypes, method.getReturnType(), STATIC | PRIVATE | (isCallback ? 0 : NATIVE));
    copyAnnotations(annotatedMethod, m, extensions);
    createGenericSignatureForMsgSend(annotatedMethod, m, paramTypes, extensions);
    return m;
}
Also used : 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) ArrayList(java.util.ArrayList) SootMethod(soot.SootMethod)

Example 5 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)

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