Search in sources :

Example 11 with Clazz

use of org.robovm.compiler.clazz.Clazz in project robovm by robovm.

the class AnnotationImplPluginTest method createAnnoImpl.

private File createAnnoImpl(Class<? extends Annotation> annoClass) {
    AnnotationImplPlugin plugin = new AnnotationImplPlugin();
    Clazz clazz = toClazz(annoClass);
    clazz.resetClazzInfo();
    plugin.beforeClass(config, clazz, new ModuleBuilder());
    assertFalse(clazz.getClazzInfo().getAllDependencies().isEmpty());
    Dependency dep = clazz.getClazzInfo().getAllDependencies().iterator().next();
    assertEquals(clazz.getInternalName() + "$Impl", dep.getClassName());
    final File implFile = new File(config.getGeneratedClassDir(clazz.getPath()), clazz.getInternalName() + "$Impl.class");
    assertTrue(implFile.exists());
    return implFile;
}
Also used : ModuleBuilder(org.robovm.compiler.ModuleBuilder) Clazz(org.robovm.compiler.clazz.Clazz) Dependency(org.robovm.compiler.clazz.Dependency) File(java.io.File)

Example 12 with Clazz

use of org.robovm.compiler.clazz.Clazz in project robovm by robovm.

the class AnnotationImplPluginTest method testNotVisibleAnno.

@Test
public void testNotVisibleAnno() throws Exception {
    AnnotationImplPlugin plugin = new AnnotationImplPlugin();
    Clazz clazz = toClazz(Anno1.class);
    clazz.resetClazzInfo();
    plugin.beforeClass(config, clazz, new ModuleBuilder());
    assertFalse(clazz.getClazzInfo().getAllDependencies().isEmpty());
}
Also used : ModuleBuilder(org.robovm.compiler.ModuleBuilder) Clazz(org.robovm.compiler.clazz.Clazz) Test(org.junit.Test)

Example 13 with Clazz

use of org.robovm.compiler.clazz.Clazz 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)

Example 14 with Clazz

use of org.robovm.compiler.clazz.Clazz in project robovm by robovm.

the class TrampolineCompiler method compile.

public void compile(ModuleBuilder mb, Clazz currentClass, Trampoline t, Set<String> dependencies, Set<Triple<String, String, String>> methodDependencies) {
    this.mb = mb;
    addDependencyIfNeeded(dependencies, currentClass, t);
    /*
         * Check if the target class exists and is accessible. Also check that
         * field accesses and method calls are compatible with the target 
         * field/method and that the field/method is accessible to the caller.
         * If any of the tests fail the weak trampoline function created by the
         * ClassCompiler will be overridden with a function which throws an
         * appropriate exception.
         */
    Function errorFn = new FunctionBuilder(t).linkage(external).build();
    if (!checkClassExists(errorFn, t) || !checkClassAccessible(errorFn, t)) {
        mb.addFunction(errorFn);
        return;
    }
    if (t instanceof New) {
        SootClass target = config.getClazzes().load(t.getTarget()).getSootClass();
        if (target.isAbstract() || target.isInterface()) {
            call(errorFn, BC_THROW_INSTANTIATION_ERROR, errorFn.getParameterRef(0), mb.getString(t.getTarget().replace('/', '.')));
            errorFn.add(new Unreachable());
            mb.addFunction(errorFn);
            return;
        }
        String fnName = Symbols.clinitWrapperSymbol(Symbols.allocatorSymbol(t.getTarget()));
        alias(t, fnName);
    } else if (t instanceof Instanceof) {
        if (isArray(t.getTarget())) {
            FunctionRef fnRef = createInstanceofArray((Instanceof) t);
            alias(t, fnRef.getName());
        } else {
            String fnName = Symbols.instanceofSymbol(t.getTarget());
            alias(t, fnName);
        }
    } else if (t instanceof Checkcast) {
        if (isArray(t.getTarget())) {
            FunctionRef fnRef = createCheckcastArray((Checkcast) t);
            alias(t, fnRef.getName());
        } else {
            String fnName = Symbols.checkcastSymbol(t.getTarget());
            alias(t, fnName);
        }
    } else if (t instanceof LdcClass) {
        if (isArray(t.getTarget())) {
            FunctionRef fnRef = createLdcArray((LdcClass) t);
            alias(t, fnRef.getName());
        } else {
            String fnName = Symbols.ldcExternalSymbol(t.getTarget());
            alias(t, fnName);
        }
    } else if (t instanceof Anewarray) {
        FunctionRef fnRef = createAnewarray((Anewarray) t);
        alias(t, fnRef.getName());
    } else if (t instanceof Multianewarray) {
        FunctionRef fnRef = createMultianewarray((Multianewarray) t);
        alias(t, fnRef.getName());
    } else if (t instanceof FieldAccessor) {
        SootField field = resolveField(errorFn, (FieldAccessor) t);
        if (field != null) {
            dependencies.add(getInternalName(field.getDeclaringClass()));
        }
        if (field == null || !checkMemberAccessible(errorFn, t, field)) {
            mb.addFunction(errorFn);
            return;
        }
        Clazz caller = config.getClazzes().load(t.getCallingClass());
        Clazz target = config.getClazzes().load(t.getTarget());
        if (!((FieldAccessor) t).isGetter() && field.isFinal() && caller != target) {
            // Only the class declaring a final field may write to it.
            // (Actually only <init>/<clinit> methods may write to it but we 
            // don't know which method is accessing the field at this point)
            throwIllegalAccessError(errorFn, ATTEMPT_TO_WRITE_TO_FINAL_FIELD, target, field.getName(), caller);
            mb.addFunction(errorFn);
            return;
        }
        if (!field.isStatic()) {
            createInlinedAccessorForInstanceField((FieldAccessor) t, field);
        } else {
            createTrampolineAliasForField((FieldAccessor) t, field);
        }
    } else if (t instanceof Invokeinterface) {
        SootMethod rm = resolveInterfaceMethod(errorFn, (Invokeinterface) t);
        if (rm != null) {
            methodDependencies.add(new ImmutableTriple<String, String, String>(getInternalName(rm.getDeclaringClass()), rm.getName(), getDescriptor(rm)));
        }
        if (rm == null || !checkMemberAccessible(errorFn, t, rm)) {
            mb.addFunction(errorFn);
            return;
        }
        createTrampolineAliasForMethod((Invoke) t, rm);
    } else if (t instanceof Invoke) {
        SootMethod method = resolveMethod(errorFn, (Invoke) t);
        if (method != null) {
            methodDependencies.add(new ImmutableTriple<String, String, String>(getInternalName(method.getDeclaringClass()), method.getName(), getDescriptor(method)));
        }
        if (method == null || !checkMemberAccessible(errorFn, t, method)) {
            mb.addFunction(errorFn);
            return;
        }
        if (t instanceof Invokespecial && method.isAbstract()) {
            call(errorFn, BC_THROW_ABSTRACT_METHOD_ERROR, errorFn.getParameterRef(0), mb.getString(String.format(NO_SUCH_METHOD_ERROR, method.getDeclaringClass(), method.getName(), getDescriptor(method))));
            errorFn.add(new Unreachable());
            mb.addFunction(errorFn);
            return;
        }
        createTrampolineAliasForMethod((Invoke) t, method);
    }
}
Also used : New(org.robovm.compiler.trampoline.New) ImmutableTriple(org.apache.commons.lang3.tuple.ImmutableTriple) Anewarray(org.robovm.compiler.trampoline.Anewarray) Multianewarray(org.robovm.compiler.trampoline.Multianewarray) SootClass(soot.SootClass) FieldAccessor(org.robovm.compiler.trampoline.FieldAccessor) Invokeinterface(org.robovm.compiler.trampoline.Invokeinterface) Invoke(org.robovm.compiler.trampoline.Invoke) Invokespecial(org.robovm.compiler.trampoline.Invokespecial) Function(org.robovm.compiler.llvm.Function) Unreachable(org.robovm.compiler.llvm.Unreachable) LdcClass(org.robovm.compiler.trampoline.LdcClass) Instanceof(org.robovm.compiler.trampoline.Instanceof) SootMethod(soot.SootMethod) SootField(soot.SootField) Clazz(org.robovm.compiler.clazz.Clazz) Checkcast(org.robovm.compiler.trampoline.Checkcast) FunctionRef(org.robovm.compiler.llvm.FunctionRef)

Example 15 with Clazz

use of org.robovm.compiler.clazz.Clazz in project robovm by robovm.

the class TrampolineCompiler method checkClassExists.

private boolean checkClassExists(Function f, Trampoline t) {
    String targetClassName = t.getTarget();
    if (isArray(targetClassName)) {
        if (isPrimitiveBaseType(targetClassName)) {
            return true;
        }
        targetClassName = getBaseType(targetClassName);
    }
    Clazz target = config.getClazzes().load(targetClassName);
    if (target != null) {
        Clazz caller = config.getClazzes().load(t.getCallingClass());
        // If caller is in the bootclasspath it only sees classes in the bootclasspath
        if (!caller.isInBootClasspath() || target.isInBootClasspath()) {
            return true;
        }
    }
    call(f, BC_THROW_NO_CLASS_DEF_FOUND_ERROR, f.getParameterRef(0), mb.getString(t.getTarget()));
    f.add(new Unreachable());
    return false;
}
Also used : Unreachable(org.robovm.compiler.llvm.Unreachable) Clazz(org.robovm.compiler.clazz.Clazz)

Aggregations

Clazz (org.robovm.compiler.clazz.Clazz)23 HashSet (java.util.HashSet)9 Test (org.junit.Test)6 Clazzes (org.robovm.compiler.clazz.Clazzes)6 Path (org.robovm.compiler.clazz.Path)6 LinkedHashSet (java.util.LinkedHashSet)5 Unreachable (org.robovm.compiler.llvm.Unreachable)5 File (java.io.File)4 IOException (java.io.IOException)3 TreeSet (java.util.TreeSet)3 Function (org.robovm.compiler.llvm.Function)3 FunctionRef (org.robovm.compiler.llvm.FunctionRef)3 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 ClassReader (org.objectweb.asm.ClassReader)2 ClassVisitor (org.objectweb.asm.ClassVisitor)2 MethodVisitor (org.objectweb.asm.MethodVisitor)2 ModuleBuilder (org.robovm.compiler.ModuleBuilder)2 ClazzInfo (org.robovm.compiler.clazz.ClazzInfo)2 Dependency (org.robovm.compiler.clazz.Dependency)2