Search in sources :

Example 1 with Type

use of org.robovm.compiler.util.generic.Type in project robovm by robovm.

the class ObjCBlockPlugin method resolveTargetMethodSignature.

protected static Type[] resolveTargetMethodSignature(SootMethod blockMethod, SootMethod targetMethod, Type blockParamType) {
    if (targetMethod.getTag("SignatureTag") == null) {
        // Not a generic method.
        Type[] result = new Type[targetMethod.getParameterCount() + 1];
        result[0] = new SootTypeType(targetMethod.getReturnType());
        for (int i = 1; i < result.length; i++) {
            result[i] = new SootTypeType(targetMethod.getParameterType(i - 1));
        }
        return result;
    }
    SootClassType base = new SootClassType(targetMethod.getDeclaringClass());
    TypeVariable<?>[] typeParameters = base.getTypeParameters();
    SootClassType offspring = null;
    Type[] actualArgs = null;
    if (blockParamType instanceof SootClassType) {
        offspring = (SootClassType) blockParamType;
        actualArgs = new Type[0];
    } else if (blockParamType instanceof ParameterizedType) {
        offspring = (SootClassType) ((ParameterizedType) blockParamType).getRawType();
        actualArgs = ((ParameterizedType) blockParamType).getActualTypeArguments();
    }
    Type[] resolvedArgs = resolveActualTypeArgs(offspring, base, actualArgs);
    Type[] result = new Type[targetMethod.getParameterCount() + 1];
    SootMethodType targetMethodType = new SootMethodType(targetMethod);
    result[0] = resolveMethodType(blockMethod, -1, targetMethodType.getGenericReturnType(), resolvedArgs, typeParameters);
    Type[] genericParameterTypes = targetMethodType.getGenericParameterTypes();
    for (int i = 1; i < result.length; i++) {
        result[i] = resolveMethodType(blockMethod, i - 1, genericParameterTypes[i - 1], resolvedArgs, typeParameters);
    }
    return result;
}
Also used : ParameterizedType(org.robovm.compiler.util.generic.ParameterizedType) SootClassType(org.robovm.compiler.util.generic.SootClassType) RefType(soot.RefType) ShortType(soot.ShortType) BooleanType(soot.BooleanType) SootTypeType(org.robovm.compiler.util.generic.SootTypeType) WildcardType(org.robovm.compiler.util.generic.WildcardType) SootMethodType(org.robovm.compiler.util.generic.SootMethodType) SootClassType(org.robovm.compiler.util.generic.SootClassType) ByteType(soot.ByteType) Type(org.robovm.compiler.util.generic.Type) DoubleType(soot.DoubleType) GenericArrayType(org.robovm.compiler.util.generic.GenericArrayType) FloatType(soot.FloatType) IntType(soot.IntType) ImplForType(org.robovm.compiler.util.generic.ImplForType) CharType(soot.CharType) LongType(soot.LongType) ParameterizedType(org.robovm.compiler.util.generic.ParameterizedType) PrimType(soot.PrimType) VoidType(soot.VoidType) SootTypeType(org.robovm.compiler.util.generic.SootTypeType) TypeVariable(org.robovm.compiler.util.generic.TypeVariable) SootMethodType(org.robovm.compiler.util.generic.SootMethodType)

Example 2 with Type

use of org.robovm.compiler.util.generic.Type in project robovm by robovm.

the class ObjCBlockPlugin method resolveMethodType.

/**
     * 
     */
private static Type resolveMethodType(SootMethod blockMethod, int paramIndex, Type t, Type[] resolvedArgs, TypeVariable<?>[] typeParameters) {
    if (t instanceof SootClassType) {
        return t;
    }
    if (t instanceof SootTypeType) {
        return t;
    }
    if (t instanceof TypeVariable) {
        int idx = indexOf(((TypeVariable<?>) t).getName(), typeParameters);
        if (idx != -1) {
            Type u = resolvedArgs[idx];
            if (u instanceof TypeVariable) {
                if (((TypeVariable<?>) t).getName().equals(((TypeVariable<?>) u).getName())) {
                    return resolveMethodType(blockMethod, paramIndex, ((TypeVariable<?>) t).getBounds()[0], resolvedArgs, typeParameters);
                }
            }
            return resolveMethodType(blockMethod, paramIndex, resolvedArgs[idx], resolvedArgs, typeParameters);
        }
        throw new CompilerException("Unresolved type variable " + t + " in " + (paramIndex == -1 ? "return type" : "parameter " + (paramIndex + 1)) + " of @Block method " + blockMethod);
    }
    if (t instanceof WildcardType) {
        Type[] upperBounds = ((WildcardType) t).getUpperBounds();
        return resolveMethodType(blockMethod, paramIndex, upperBounds[0], resolvedArgs, typeParameters);
    }
    if (t instanceof ParameterizedType) {
        ImplForType pType = (ImplForType) t;
        ListOfTypes types = new ListOfTypes(pType.getActualTypeArguments().length);
        for (Type arg : pType.getActualTypeArguments()) {
            types.add(resolveMethodType(blockMethod, paramIndex, arg, resolvedArgs, typeParameters));
        }
        return new ImplForType((ImplForType) pType.getOwnerType(), pType.getRawType().getSootClass().getName(), types);
    }
    if (t instanceof GenericArrayType) {
        Type componentType = resolveMethodType(blockMethod, paramIndex, ((GenericArrayType) t).getGenericComponentType(), resolvedArgs, typeParameters);
        return new ImplForArray(componentType);
    }
    throw new CompilerException("Unresolved type " + t + " in " + (paramIndex == -1 ? "return type" : "parameter " + (paramIndex + 1)) + " of @Block method " + blockMethod);
}
Also used : SootClassType(org.robovm.compiler.util.generic.SootClassType) GenericArrayType(org.robovm.compiler.util.generic.GenericArrayType) ParameterizedType(org.robovm.compiler.util.generic.ParameterizedType) ImplForArray(org.robovm.compiler.util.generic.ImplForArray) SootTypeType(org.robovm.compiler.util.generic.SootTypeType) RefType(soot.RefType) ShortType(soot.ShortType) BooleanType(soot.BooleanType) SootTypeType(org.robovm.compiler.util.generic.SootTypeType) WildcardType(org.robovm.compiler.util.generic.WildcardType) SootMethodType(org.robovm.compiler.util.generic.SootMethodType) SootClassType(org.robovm.compiler.util.generic.SootClassType) ByteType(soot.ByteType) Type(org.robovm.compiler.util.generic.Type) DoubleType(soot.DoubleType) GenericArrayType(org.robovm.compiler.util.generic.GenericArrayType) FloatType(soot.FloatType) IntType(soot.IntType) ImplForType(org.robovm.compiler.util.generic.ImplForType) CharType(soot.CharType) LongType(soot.LongType) ParameterizedType(org.robovm.compiler.util.generic.ParameterizedType) PrimType(soot.PrimType) VoidType(soot.VoidType) WildcardType(org.robovm.compiler.util.generic.WildcardType) TypeVariable(org.robovm.compiler.util.generic.TypeVariable) CompilerException(org.robovm.compiler.CompilerException) ListOfTypes(org.robovm.compiler.util.generic.ListOfTypes) ImplForType(org.robovm.compiler.util.generic.ImplForType)

Example 3 with Type

use of org.robovm.compiler.util.generic.Type in project robovm by robovm.

the class ObjCBlockPlugin method transformMethod.

private void transformMethod(Config config, Clazz clazz, SootMethod blockMethod, int[] blockParamIndexes, Map<String, Integer> blockTypeIds) throws IOException {
    SootMethodType blockMethodType = new SootMethodType(blockMethod);
    if (blockParamIndexes != null) {
        Type[] genericParameterTypes = blockMethodType.getGenericParameterTypes();
        for (int i = 0; i < blockParamIndexes.length; i++) {
            int idx = blockParamIndexes[i];
            if (idx == -1) {
                break;
            }
            SootMethod targetMethod = getBlockTargetMethod(blockMethod, idx);
            Type[] actualGenericTypes = resolveTargetMethodSignature(blockMethod, targetMethod, genericParameterTypes[idx]);
            soot.Type[] actualRawTypes = toRawTypes(actualGenericTypes);
            soot.Type[] unboxedTypes = unboxTypes(actualRawTypes);
            String[][] targetMethodAnnotations = parseTargetMethodAnnotations(targetMethod, readStringElem(getParameterAnnotation(blockMethod, idx, BLOCK), "value", ""));
            // Create the marshaler class associated with this block type
            String marshaler = createBlockMarshaler(config, clazz, targetMethod, actualGenericTypes, actualRawTypes, unboxedTypes, blockTypeIds, targetMethodAnnotations);
            addMarshalerAnnotation(blockMethod, idx, marshaler);
        }
    }
    if (hasAnnotation(blockMethod, BLOCK)) {
        SootMethod targetMethod = getBlockTargetMethod(blockMethod);
        Type[] actualGenericTypes = resolveTargetMethodSignature(blockMethod, targetMethod, blockMethodType.getGenericReturnType());
        soot.Type[] actualRawTypes = toRawTypes(actualGenericTypes);
        soot.Type[] unboxedTypes = unboxTypes(actualRawTypes);
        String[][] targetMethodAnnotations = parseTargetMethodAnnotations(targetMethod, readStringElem(getAnnotation(blockMethod, BLOCK), "value", ""));
        String marshaler = createBlockMarshaler(config, clazz, targetMethod, actualGenericTypes, actualRawTypes, unboxedTypes, blockTypeIds, targetMethodAnnotations);
        addMarshalerAnnotation(blockMethod, marshaler);
    }
}
Also used : RefType(soot.RefType) ShortType(soot.ShortType) BooleanType(soot.BooleanType) SootTypeType(org.robovm.compiler.util.generic.SootTypeType) WildcardType(org.robovm.compiler.util.generic.WildcardType) SootMethodType(org.robovm.compiler.util.generic.SootMethodType) SootClassType(org.robovm.compiler.util.generic.SootClassType) ByteType(soot.ByteType) Type(org.robovm.compiler.util.generic.Type) DoubleType(soot.DoubleType) GenericArrayType(org.robovm.compiler.util.generic.GenericArrayType) FloatType(soot.FloatType) IntType(soot.IntType) ImplForType(org.robovm.compiler.util.generic.ImplForType) CharType(soot.CharType) LongType(soot.LongType) ParameterizedType(org.robovm.compiler.util.generic.ParameterizedType) PrimType(soot.PrimType) VoidType(soot.VoidType) SootMethodType(org.robovm.compiler.util.generic.SootMethodType) SootMethod(soot.SootMethod)

Example 4 with Type

use of org.robovm.compiler.util.generic.Type in project robovm by robovm.

the class ObjCBlockPlugin method generateTargetMethod.

private void generateTargetMethod(String owner, SootMethod targetMethod, Type[] actualGenericTypes, soot.Type[] actualRawTypes, soot.Type[] unboxedTypes, Set<String> usedBoxMethods, Set<String> usedUnboxMethods, ClassWriter cw) {
    String name = targetMethod.getName();
    String signature = getGenericSignature(Arrays.asList(actualGenericTypes).subList(1, actualGenericTypes.length), actualGenericTypes[0]);
    String desc = getDescriptor(targetMethod);
    MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, name, desc, signature, null);
    mv.visitCode();
    mv.visitVarInsn(ALOAD, 0);
    mv.visitFieldInsn(GETFIELD, owner, "objCBlock", "L" + getInternalName(org_robovm_objc_ObjCBlock) + ";");
    mv.visitMethodInsn(INVOKEVIRTUAL, getInternalName(org_robovm_objc_ObjCBlock), "invoke", "()J");
    mv.visitVarInsn(ALOAD, 0);
    mv.visitFieldInsn(GETFIELD, owner, "objCBlock", "L" + getInternalName(org_robovm_objc_ObjCBlock) + ";");
    for (int i = 1, var = 1; i < actualRawTypes.length; i++, var++) {
        soot.Type from = actualRawTypes[i];
        if (from == LongType.v()) {
            mv.visitVarInsn(LLOAD, var);
            // longs need 2 slots
            var++;
        } else if (from == FloatType.v()) {
            mv.visitVarInsn(FLOAD, var);
        } else if (from == DoubleType.v()) {
            mv.visitVarInsn(DLOAD, var);
            // doubles need 2 slots
            var++;
        } else if (from instanceof PrimType) {
            // boolean, byte, short, char and int are loaded using ILOAD
            mv.visitVarInsn(ILOAD, var);
        } else {
            // Reference
            mv.visitVarInsn(ALOAD, var);
        }
        soot.Type to = unboxedTypes[i];
        if (from != to) {
            mv.visitTypeInsn(CHECKCAST, getInternalName(from));
            // Unbox the value on the top of the stack.
            String unboxDesc = getDescriptor(Collections.singletonList(from), to);
            usedUnboxMethods.add(unboxDesc);
            mv.visitMethodInsn(INVOKESTATIC, owner, "unbox", unboxDesc);
        }
    }
    // Now the function pointer, block and all arguments are on the stack 
    // (unboxed if needed). Call the invoke() bridge method.
    List<soot.Type> paramTypes = new ArrayList<>();
    paramTypes.add(LongType.v());
    paramTypes.add(org_robovm_objc_ObjCBlock.getType());
    paramTypes.addAll(Arrays.asList(unboxedTypes).subList(1, unboxedTypes.length));
    mv.visitMethodInsn(INVOKESTATIC, owner, "invoke", getDescriptor(paramTypes, unboxedTypes[0]));
    if (unboxedTypes[0] != actualRawTypes[0]) {
        // Box the value on the top of the stack.
        String boxDesc = getDescriptor(Collections.singletonList(unboxedTypes[0]), actualRawTypes[0]);
        usedBoxMethods.add(boxDesc);
        mv.visitMethodInsn(INVOKESTATIC, owner, "box", boxDesc);
    }
    if (actualRawTypes[0] == VoidType.v()) {
        mv.visitInsn(RETURN);
    } else if (actualRawTypes[0] == LongType.v()) {
        mv.visitInsn(LRETURN);
    } else if (actualRawTypes[0] == FloatType.v()) {
        mv.visitInsn(FRETURN);
    } else if (actualRawTypes[0] == DoubleType.v()) {
        mv.visitInsn(DRETURN);
    } else if (actualRawTypes[0] instanceof PrimType) {
        mv.visitInsn(IRETURN);
    } else {
        mv.visitInsn(ARETURN);
    }
    mv.visitMaxs(0, 0);
    mv.visitEnd();
}
Also used : RefType(soot.RefType) ShortType(soot.ShortType) BooleanType(soot.BooleanType) SootTypeType(org.robovm.compiler.util.generic.SootTypeType) WildcardType(org.robovm.compiler.util.generic.WildcardType) SootMethodType(org.robovm.compiler.util.generic.SootMethodType) SootClassType(org.robovm.compiler.util.generic.SootClassType) ByteType(soot.ByteType) Type(org.robovm.compiler.util.generic.Type) DoubleType(soot.DoubleType) GenericArrayType(org.robovm.compiler.util.generic.GenericArrayType) FloatType(soot.FloatType) IntType(soot.IntType) ImplForType(org.robovm.compiler.util.generic.ImplForType) CharType(soot.CharType) LongType(soot.LongType) ParameterizedType(org.robovm.compiler.util.generic.ParameterizedType) PrimType(soot.PrimType) VoidType(soot.VoidType) ArrayList(java.util.ArrayList) PrimType(soot.PrimType) MethodVisitor(org.objectweb.asm.MethodVisitor)

Example 5 with Type

use of org.robovm.compiler.util.generic.Type in project robovm by robovm.

the class ObjCBlockPlugin method createBlockMarshaler.

private String createBlockMarshaler(Config config, Clazz clazz, final SootMethod targetMethod, Type[] actualGenericTypes, soot.Type[] actualRawTypes, soot.Type[] unboxedTypes, Map<String, Integer> blockTypeIds, String[][] targetMethodAnnotations) throws IOException {
    if (targetMethod.getDeclaringClass().getName().equals("java.lang.Runnable") && targetMethod.getName().equals("run")) {
        return RUNNABLE_AS_OBJC_BLOCK_MARSHALER;
    }
    String targetMethodKey = getTargetMethodKey(targetMethod, actualRawTypes, targetMethodAnnotations);
    Integer id = blockTypeIds.get(targetMethodKey);
    if (id != null) {
        // Already generated
        return getBlockMarshalerName(clazz, id);
    }
    id = blockTypeIds.size();
    blockTypeIds.put(targetMethodKey, id);
    final String blockMarshalerName = getBlockMarshalerName(clazz, id);
    final String targetInterfaceName = Types.getInternalName(targetMethod.getDeclaringClass());
    // We use RunnableAsObjCBlockMarshaler as template
    Clazz templateMarshaler = config.getClazzes().load(RUNNABLE_AS_OBJC_BLOCK_MARSHALER);
    final Set<String> usedBoxMethods = new HashSet<>();
    final Set<String> usedUnboxMethods = new HashSet<>();
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    generateTargetMethod(blockMarshalerName, targetMethod, actualGenericTypes, actualRawTypes, unboxedTypes, usedBoxMethods, usedUnboxMethods, cw);
    generateBridgeMethod(actualGenericTypes, unboxedTypes, targetMethodAnnotations, cw);
    generateCallbackMethod(blockMarshalerName, targetMethod, actualGenericTypes, actualRawTypes, unboxedTypes, usedBoxMethods, usedUnboxMethods, targetMethodAnnotations, cw);
    ClassReader classReader = new ClassReader(templateMarshaler.getBytes());
    classReader.accept(new ClassVisitor(ASM4, cw) {

        @Override
        public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
            super.visit(version, access, blockMarshalerName, signature, superName, new String[] { targetInterfaceName });
        }

        @Override
        public void visitInnerClass(String name, String outerName, String innerName, int access) {
        // Ignore
        }

        @Override
        public void visitSource(String source, String debug) {
        // Ignore
        }

        @Override
        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
            switch(name) {
                case "run":
                case "invoke":
                case "invoked":
                    // Skip all these
                    return null;
                case "box":
                    if (!usedBoxMethods.contains(desc)) {
                        return null;
                    }
                    break;
                case "unbox":
                    if (!usedUnboxMethods.contains(desc)) {
                        return null;
                    }
                    break;
            }
            desc = desc.replace("java/lang/Runnable", targetInterfaceName);
            signature = null;
            // RunnableAsObjCBlockMarshaler to the blockMarshalerName
            return new MethodVisitor(ASM4, super.visitMethod(access, name, desc, signature, exceptions)) {

                @Override
                public void visitLdcInsn(Object cst) {
                    if (cst instanceof org.objectweb.asm.Type) {
                        if (((org.objectweb.asm.Type) cst).getSort() == org.objectweb.asm.Type.OBJECT) {
                            String internalName = ((org.objectweb.asm.Type) cst).getInternalName();
                            if (RUNNABLE_AS_OBJC_BLOCK_MARSHALER.equals(internalName)) {
                                cst = org.objectweb.asm.Type.getObjectType(blockMarshalerName);
                            }
                        }
                    }
                    super.visitLdcInsn(cst);
                }

                @Override
                public void visitTypeInsn(int opcode, String type) {
                    if (RUNNABLE_AS_OBJC_BLOCK_MARSHALER.equals(type)) {
                        type = blockMarshalerName;
                    } else if ("java/lang/Runnable".equals(type)) {
                        type = targetInterfaceName;
                    }
                    super.visitTypeInsn(opcode, type);
                }

                @Override
                public void visitFieldInsn(int opcode, String owner, String name, String desc) {
                    if (RUNNABLE_AS_OBJC_BLOCK_MARSHALER.equals(owner)) {
                        owner = blockMarshalerName;
                    }
                    super.visitFieldInsn(opcode, owner, name, desc);
                }

                @Override
                public void visitMethodInsn(int opcode, String owner, String name, String desc) {
                    if (RUNNABLE_AS_OBJC_BLOCK_MARSHALER.equals(owner)) {
                        owner = blockMarshalerName;
                    }
                    super.visitMethodInsn(opcode, owner, name, desc);
                }

                @Override
                public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
                // Ignored
                }

                @Override
                public void visitLineNumber(int line, Label start) {
                // Ignored
                }
            };
        }
    }, 0);
    cw.visitInnerClass(blockMarshalerName, clazz.getInternalName(), blockMarshalerName.substring(clazz.getInternalName().length() + 1), ACC_PUBLIC + ACC_STATIC);
    cw.visitEnd();
    File f = clazz.getPath().getGeneratedClassFile(blockMarshalerName);
    FileUtils.writeByteArrayToFile(f, cw.toByteArray());
    // The marshaler class is created after the class is compiled.
    // This prevents the triggering of a recompile of the class.
    f.setLastModified(clazz.lastModified());
    return blockMarshalerName;
}
Also used : Label(org.objectweb.asm.Label) ClassVisitor(org.objectweb.asm.ClassVisitor) ClassWriter(org.objectweb.asm.ClassWriter) MethodVisitor(org.objectweb.asm.MethodVisitor) RefType(soot.RefType) ShortType(soot.ShortType) BooleanType(soot.BooleanType) SootTypeType(org.robovm.compiler.util.generic.SootTypeType) WildcardType(org.robovm.compiler.util.generic.WildcardType) SootMethodType(org.robovm.compiler.util.generic.SootMethodType) SootClassType(org.robovm.compiler.util.generic.SootClassType) ByteType(soot.ByteType) Type(org.robovm.compiler.util.generic.Type) DoubleType(soot.DoubleType) GenericArrayType(org.robovm.compiler.util.generic.GenericArrayType) FloatType(soot.FloatType) IntType(soot.IntType) ImplForType(org.robovm.compiler.util.generic.ImplForType) CharType(soot.CharType) LongType(soot.LongType) ParameterizedType(org.robovm.compiler.util.generic.ParameterizedType) PrimType(soot.PrimType) VoidType(soot.VoidType) ClassReader(org.objectweb.asm.ClassReader) Clazz(org.robovm.compiler.clazz.Clazz) File(java.io.File) HashSet(java.util.HashSet)

Aggregations

SootClassType (org.robovm.compiler.util.generic.SootClassType)11 SootMethodType (org.robovm.compiler.util.generic.SootMethodType)11 SootTypeType (org.robovm.compiler.util.generic.SootTypeType)11 Type (org.robovm.compiler.util.generic.Type)11 BooleanType (soot.BooleanType)11 VoidType (soot.VoidType)11 GenericArrayType (org.robovm.compiler.util.generic.GenericArrayType)10 ImplForType (org.robovm.compiler.util.generic.ImplForType)10 ParameterizedType (org.robovm.compiler.util.generic.ParameterizedType)10 WildcardType (org.robovm.compiler.util.generic.WildcardType)10 ByteType (soot.ByteType)10 CharType (soot.CharType)10 DoubleType (soot.DoubleType)10 FloatType (soot.FloatType)10 IntType (soot.IntType)10 LongType (soot.LongType)10 PrimType (soot.PrimType)10 RefType (soot.RefType)10 ShortType (soot.ShortType)10 MethodVisitor (org.objectweb.asm.MethodVisitor)4