Search in sources :

Example 6 with Type

use of org.robovm.compiler.llvm.Type in project robovm by robovm.

the class MethodCompiler method immediate.

private Value immediate(Unit unit, Immediate v) {
    // v is either a soot.Local or a soot.jimple.Constant
    if (v instanceof soot.Local) {
        Local local = (Local) v;
        Type type = getLocalType(v.getType());
        VariableRef var = new VariableRef(local.getName(), new PointerType(type));
        Variable tmp = function.newVariable(type);
        function.add(new Load(tmp, var, !sootMethod.getActiveBody().getTraps().isEmpty())).attach(unit);
        return new VariableRef(tmp);
    } else if (v instanceof soot.jimple.IntConstant) {
        return new IntegerConstant(((soot.jimple.IntConstant) v).value);
    } else if (v instanceof soot.jimple.LongConstant) {
        return new IntegerConstant(((soot.jimple.LongConstant) v).value);
    } else if (v instanceof soot.jimple.FloatConstant) {
        return new FloatingPointConstant(((soot.jimple.FloatConstant) v).value);
    } else if (v instanceof soot.jimple.DoubleConstant) {
        return new FloatingPointConstant(((soot.jimple.DoubleConstant) v).value);
    } else if (v instanceof soot.jimple.NullConstant) {
        return new NullConstant(OBJECT_PTR);
    } else if (v instanceof soot.jimple.StringConstant) {
        String s = ((soot.jimple.StringConstant) v).value;
        return call(unit, ldcString(s), env);
    } else if (v instanceof soot.jimple.ClassConstant) {
        // ClassConstant is either the internal name of a class or the descriptor of an array
        String targetClassName = ((soot.jimple.ClassConstant) v).getValue();
        if (isArray(targetClassName) && isPrimitiveComponentType(targetClassName)) {
            String primitiveDesc = targetClassName.substring(1);
            Variable result = function.newVariable(OBJECT_PTR);
            function.add(new Load(result, new ConstantBitcast(new GlobalRef("array_" + primitiveDesc, CLASS_PTR), new PointerType(OBJECT_PTR)))).attach(unit);
            return result.ref();
        } else {
            FunctionRef fn = null;
            if (targetClassName.equals(this.className)) {
                fn = FunctionBuilder.ldcInternal(sootMethod.getDeclaringClass()).ref();
            } else {
                Trampoline trampoline = new LdcClass(className, ((soot.jimple.ClassConstant) v).getValue());
                trampolines.add(trampoline);
                fn = trampoline.getFunctionRef();
            }
            return call(unit, fn, env);
        }
    }
    throw new IllegalArgumentException("Unknown Immediate type: " + v.getClass());
}
Also used : GlobalRef(org.robovm.compiler.llvm.GlobalRef) VariableRef(org.robovm.compiler.llvm.VariableRef) Variable(org.robovm.compiler.llvm.Variable) ConstantBitcast(org.robovm.compiler.llvm.ConstantBitcast) PointerType(org.robovm.compiler.llvm.PointerType) FunctionRef(org.robovm.compiler.llvm.FunctionRef) Load(org.robovm.compiler.llvm.Load) FloatingPointConstant(org.robovm.compiler.llvm.FloatingPointConstant) Trampoline(org.robovm.compiler.trampoline.Trampoline) Local(soot.Local) NullConstant(org.robovm.compiler.llvm.NullConstant) IntegerConstant(org.robovm.compiler.llvm.IntegerConstant) FloatingPointType(org.robovm.compiler.llvm.FloatingPointType) IntegerType(org.robovm.compiler.llvm.IntegerType) PointerType(org.robovm.compiler.llvm.PointerType) NullType(soot.NullType) FunctionType(org.robovm.compiler.llvm.FunctionType) ArrayType(org.robovm.compiler.llvm.ArrayType) CharType(soot.CharType) RefLikeType(soot.RefLikeType) Type(org.robovm.compiler.llvm.Type) PrimType(soot.PrimType) LdcClass(org.robovm.compiler.trampoline.LdcClass)

Example 7 with Type

use of org.robovm.compiler.llvm.Type in project robovm by robovm.

the class CallbackMethodCompiler method compileCallback.

private Function compileCallback(ModuleBuilder moduleBuilder, SootMethod method) {
    Function callbackFn = null;
    FunctionType nativeFnType = null;
    boolean useCWrapper = requiresCWrapper(method);
    if (useCWrapper) {
        // The C wrapper is the function which is called by native code. It
        // handles structs passed/returned by value. It calls an LLVM function 
        // which has the same signature but all structs passed/returned by value
        // replaced by pointers (i8*).
        FunctionRef callbackCWrapperRef = getCallbackCWrapperRef(method, Symbols.callbackCSymbol(method));
        getCWrapperFunctions().add(createCallbackCWrapper(callbackCWrapperRef.getType(), callbackCWrapperRef.getName(), Symbols.callbackInnerCSymbol(method)));
        moduleBuilder.addFunctionDeclaration(new FunctionDeclaration(callbackCWrapperRef));
        Type callbackRetType = callbackCWrapperRef.getType().getReturnType() instanceof StructureType ? I8_PTR : callbackCWrapperRef.getType().getReturnType();
        Type[] callbackParamTypes = new Type[callbackCWrapperRef.getType().getParameterTypes().length];
        for (int i = 0; i < callbackParamTypes.length; i++) {
            Type t = callbackCWrapperRef.getType().getParameterTypes()[i];
            if (t instanceof StructureType) {
                t = I8_PTR;
            }
            callbackParamTypes[i] = t;
        }
        moduleBuilder.addAlias(new Alias(Symbols.callbackPtrSymbol(method), Linkage._private, new ConstantBitcast(callbackCWrapperRef, I8_PTR)));
        callbackFn = new FunctionBuilder(Symbols.callbackInnerCSymbol(method), new FunctionType(callbackRetType, callbackParamTypes)).build();
        nativeFnType = callbackCWrapperRef.getType();
    } else {
        FunctionType callbackFnType = getCallbackFunctionType(method, false);
        callbackFn = FunctionBuilder.callback(method, callbackFnType);
        moduleBuilder.addAlias(new Alias(Symbols.callbackPtrSymbol(method), Linkage._private, new ConstantBitcast(callbackFn.ref(), I8_PTR)));
        nativeFnType = callbackFnType;
    }
    moduleBuilder.addFunction(callbackFn);
    String targetName = method.isSynchronized() ? Symbols.synchronizedWrapperSymbol(method) : Symbols.methodSymbol(method);
    FunctionRef targetFn = new FunctionRef(targetName, getFunctionType(method));
    // Increase the attach count for the current thread (attaches the thread
    // if not attached)
    Value env = call(callbackFn, BC_ATTACH_THREAD_FROM_CALLBACK);
    BasicBlockRef bbSuccess = callbackFn.newBasicBlockRef(new Label("success"));
    BasicBlockRef bbFailure = callbackFn.newBasicBlockRef(new Label("failure"));
    pushCallbackFrame(callbackFn, env);
    trycatchAllEnter(callbackFn, env, bbSuccess, bbFailure);
    callbackFn.newBasicBlock(bbSuccess.getLabel());
    List<MarshaledArg> marshaledArgs = new ArrayList<MarshaledArg>();
    ArrayList<Value> args = new ArrayList<Value>();
    args.add(env);
    if (!method.isStatic()) {
        MarshalerMethod marshalerMethod = config.getMarshalerLookup().findMarshalerMethod(new MarshalSite(method, MarshalSite.RECEIVER));
        MarshaledArg marshaledArg = new MarshaledArg();
        marshaledArg.paramIndex = MarshalSite.RECEIVER;
        marshaledArgs.add(marshaledArg);
        Value arg = callbackFn.getParameterRef(0);
        String targetClassName = getInternalName(method.getDeclaringClass());
        arg = marshalNativeToObject(callbackFn, marshalerMethod, marshaledArg, env, targetClassName, arg, MarshalerFlags.CALL_TYPE_CALLBACK);
        args.add(arg);
    }
    for (int i = 0, argIdx = 0; i < method.getParameterCount(); i++, argIdx++) {
        if (!method.isStatic() && argIdx == 0) {
            argIdx++;
        }
        Value arg = callbackFn.getParameterRef(argIdx);
        soot.Type type = method.getParameterType(i);
        if (needsMarshaler(type)) {
            MarshalerMethod marshalerMethod = config.getMarshalerLookup().findMarshalerMethod(new MarshalSite(method, i));
            String targetClassName = getInternalName(type);
            if (arg.getType() instanceof PrimitiveType) {
                arg = marshalNativeToValueObject(callbackFn, marshalerMethod, env, targetClassName, arg, MarshalerFlags.CALL_TYPE_CALLBACK);
            } else {
                MarshaledArg marshaledArg = new MarshaledArg();
                marshaledArg.paramIndex = i;
                marshaledArgs.add(marshaledArg);
                Type nativeType = nativeFnType.getParameterTypes()[argIdx];
                if (nativeType instanceof StructureType) {
                    // Struct passed by value on the stack. Make a heap copy of the data and marshal that.
                    DataLayout dataLayout = config.getDataLayout();
                    Value heapCopy = call(callbackFn, BC_COPY_STRUCT, env, arg, new IntegerConstant(dataLayout.getAllocSize(nativeType)));
                    arg = marshalNativeToObject(callbackFn, marshalerMethod, marshaledArg, env, targetClassName, heapCopy, MarshalerFlags.CALL_TYPE_CALLBACK);
                } else {
                    arg = marshalNativeToObject(callbackFn, marshalerMethod, marshaledArg, env, targetClassName, arg, MarshalerFlags.CALL_TYPE_CALLBACK);
                }
            }
        } else {
            arg = marshalNativeToPrimitive(callbackFn, method, i, arg);
        }
        args.add(arg);
    }
    Value result = call(callbackFn, targetFn, args);
    // Call Marshaler.updateNative() for each object that was marshaled before
    // the call.
    updateNative(method, callbackFn, env, MarshalerFlags.CALL_TYPE_CALLBACK, marshaledArgs);
    // Marshal the returned value to a native value before returning
    if (needsMarshaler(method.getReturnType())) {
        MarshalerMethod marshalerMethod = config.getMarshalerLookup().findMarshalerMethod(new MarshalSite(method));
        Type nativeType = callbackFn.getType().getReturnType();
        if (nativeType instanceof PrimitiveType) {
            result = marshalValueObjectToNative(callbackFn, marshalerMethod, nativeType, env, result, MarshalerFlags.CALL_TYPE_CALLBACK);
        } else {
            result = marshalObjectToNative(callbackFn, marshalerMethod, null, nativeType, env, result, MarshalerFlags.CALL_TYPE_CALLBACK);
        }
    } else {
        result = marshalPrimitiveToNative(callbackFn, method, result);
    }
    trycatchLeave(callbackFn, env);
    popCallbackFrame(callbackFn, env);
    call(callbackFn, BC_DETACH_THREAD_FROM_CALLBACK, env);
    callbackFn.add(new Ret(result));
    callbackFn.newBasicBlock(bbFailure.getLabel());
    trycatchLeave(callbackFn, env);
    popCallbackFrame(callbackFn, env);
    Value ex = call(callbackFn, BC_EXCEPTION_CLEAR, env);
    // Call Marshaler.updateNative() for each object that was marshaled before
    // the call.
    updateNative(method, callbackFn, env, MarshalerFlags.CALL_TYPE_CALLBACK, marshaledArgs);
    call(callbackFn, BC_DETACH_THREAD_FROM_CALLBACK, env);
    call(callbackFn, BC_THROW, env, ex);
    callbackFn.add(new Unreachable());
    return callbackFn;
}
Also used : MarshalSite(org.robovm.compiler.MarshalerLookup.MarshalSite) Ret(org.robovm.compiler.llvm.Ret) ConstantBitcast(org.robovm.compiler.llvm.ConstantBitcast) Label(org.robovm.compiler.llvm.Label) ArrayList(java.util.ArrayList) Function(org.robovm.compiler.llvm.Function) FunctionDeclaration(org.robovm.compiler.llvm.FunctionDeclaration) BasicBlockRef(org.robovm.compiler.llvm.BasicBlockRef) Unreachable(org.robovm.compiler.llvm.Unreachable) PrimitiveType(org.robovm.compiler.llvm.PrimitiveType) FunctionRef(org.robovm.compiler.llvm.FunctionRef) DataLayout(org.robovm.compiler.llvm.DataLayout) FunctionType(org.robovm.compiler.llvm.FunctionType) IntegerConstant(org.robovm.compiler.llvm.IntegerConstant) StructureType(org.robovm.compiler.llvm.StructureType) Type(org.robovm.compiler.llvm.Type) PrimitiveType(org.robovm.compiler.llvm.PrimitiveType) FunctionType(org.robovm.compiler.llvm.FunctionType) Alias(org.robovm.compiler.llvm.Alias) StructureType(org.robovm.compiler.llvm.StructureType) Value(org.robovm.compiler.llvm.Value) MarshalerMethod(org.robovm.compiler.MarshalerLookup.MarshalerMethod) PointerMarshalerMethod(org.robovm.compiler.MarshalerLookup.PointerMarshalerMethod)

Example 8 with Type

use of org.robovm.compiler.llvm.Type in project robovm by robovm.

the class ClassCompiler method compile.

private void compile(Clazz clazz, OutputStream out) throws IOException {
    javaMethodCompiler.reset(clazz);
    bridgeMethodCompiler.reset(clazz);
    callbackMethodCompiler.reset(clazz);
    nativeMethodCompiler.reset(clazz);
    structMemberMethodCompiler.reset(clazz);
    globalValueMethodCompiler.reset(clazz);
    ClazzInfo ci = clazz.resetClazzInfo();
    mb = new ModuleBuilder();
    for (CompilerPlugin compilerPlugin : config.getCompilerPlugins()) {
        compilerPlugin.beforeClass(config, clazz, mb);
    }
    sootClass = clazz.getSootClass();
    trampolines = new HashMap<>();
    catches = new HashSet<String>();
    classFields = getClassFields(config.getOs(), config.getArch(), sootClass);
    instanceFields = getInstanceFields(config.getOs(), config.getArch(), sootClass);
    classType = getClassType(config.getOs(), config.getArch(), sootClass);
    instanceType = getInstanceType(config.getOs(), config.getArch(), sootClass);
    attributesEncoder.encode(mb, sootClass);
    // will never be initialized.
    if (!sootClass.declaresMethodByName("<clinit>") && hasConstantValueTags(classFields)) {
        SootMethod clinit = new SootMethod("<clinit>", Collections.EMPTY_LIST, VoidType.v(), Modifier.STATIC);
        JimpleBody body = Jimple.v().newBody(clinit);
        clinit.setActiveBody(body);
        body.getUnits().add(new JReturnVoidStmt());
        this.sootClass.addMethod(clinit);
    }
    if (isStruct(sootClass)) {
        SootMethod _sizeOf = new SootMethod("_sizeOf", Collections.EMPTY_LIST, IntType.v(), Modifier.PROTECTED | Modifier.NATIVE);
        sootClass.addMethod(_sizeOf);
        SootMethod sizeOf = new SootMethod("sizeOf", Collections.EMPTY_LIST, IntType.v(), Modifier.PUBLIC | Modifier.STATIC | Modifier.NATIVE);
        sootClass.addMethod(sizeOf);
    }
    mb.addInclude(getClass().getClassLoader().getResource(String.format("header-%s-%s.ll", config.getOs().getFamily(), config.getArch())));
    mb.addInclude(getClass().getClassLoader().getResource("header.ll"));
    mb.addFunction(createLdcClass());
    mb.addFunction(createLdcClassWrapper());
    Function allocator = createAllocator();
    mb.addFunction(allocator);
    mb.addFunction(createClassInitWrapperFunction(allocator.ref()));
    for (SootField f : sootClass.getFields()) {
        Function getter = createFieldGetter(f, classFields, classType, instanceFields, instanceType);
        Function setter = createFieldSetter(f, classFields, classType, instanceFields, instanceType);
        mb.addFunction(getter);
        mb.addFunction(setter);
        if (f.isStatic() && !f.isPrivate()) {
            mb.addFunction(createClassInitWrapperFunction(getter.ref()));
            if (!f.isFinal()) {
                mb.addFunction(createClassInitWrapperFunction(setter.ref()));
            }
        }
    }
    // After this point no changes to methods/fields may be done by CompilerPlugins.
    ci.initClassInfo();
    for (SootMethod method : sootClass.getMethods()) {
        for (CompilerPlugin compilerPlugin : config.getCompilerPlugins()) {
            compilerPlugin.beforeMethod(config, clazz, method, mb);
        }
        String name = method.getName();
        Function function = null;
        if (hasBridgeAnnotation(method)) {
            function = bridgeMethod(method);
        } else if (hasGlobalValueAnnotation(method)) {
            function = globalValueMethod(method);
        } else if (isStruct(sootClass) && ("_sizeOf".equals(name) || "sizeOf".equals(name) || hasStructMemberAnnotation(method))) {
            function = structMember(method);
        } else if (method.isNative()) {
            function = nativeMethod(method);
        } else if (!method.isAbstract()) {
            function = method(method);
        }
        if (hasCallbackAnnotation(method)) {
            callbackMethod(method);
        }
        if (!name.equals("<clinit>") && !name.equals("<init>") && !method.isPrivate() && !method.isStatic() && !Modifier.isFinal(method.getModifiers()) && !Modifier.isFinal(sootClass.getModifiers())) {
            createLookupFunction(method);
        }
        if (method.isStatic() && !name.equals("<clinit>")) {
            String fnName = method.isSynchronized() ? Symbols.synchronizedWrapperSymbol(method) : Symbols.methodSymbol(method);
            FunctionRef fn = new FunctionRef(fnName, getFunctionType(method));
            mb.addFunction(createClassInitWrapperFunction(fn));
        }
        for (CompilerPlugin compilerPlugin : config.getCompilerPlugins()) {
            if (function != null) {
                compilerPlugin.afterMethod(config, clazz, method, mb, function);
            }
        }
    }
    for (Trampoline trampoline : trampolines.keySet()) {
        Set<String> deps = new HashSet<String>();
        Set<Triple<String, String, String>> mDeps = new HashSet<>();
        trampolineResolver.compile(mb, clazz, trampoline, deps, mDeps);
        for (SootMethod m : trampolines.get(trampoline)) {
            MethodInfo mi = ci.getMethod(m.getName(), getDescriptor(m));
            mi.addClassDependencies(deps, false);
            mi.addInvokeMethodDependencies(mDeps, false);
        }
    }
    /*
         * Add method dependencies from overriding methods to the overridden
         * super method(s). These will be reversed by the DependencyGraph to
         * create edges from the super/interface method to the overriding
         * method.
         */
    Map<SootMethod, Set<SootMethod>> overriddenMethods = getOverriddenMethods(this.sootClass);
    for (SootMethod from : overriddenMethods.keySet()) {
        MethodInfo mi = ci.getMethod(from.getName(), getDescriptor(from));
        for (SootMethod to : overriddenMethods.get(from)) {
            mi.addSuperMethodDependency(getInternalName(to.getDeclaringClass()), to.getName(), getDescriptor(to), false);
        }
    }
    /*
         * Edge case. A method in a superclass might satisfy an interface method
         * in the interfaces implemented by this class. See e.g. the abstract
         * class HashMap$HashIterator which doesn't implement Iterator but has
         * the hasNext() and other methods. We add a dependency from the current
         * class to the super method to ensure it's included if the current
         * class is linked in.
         */
    if (sootClass.hasSuperclass()) {
        for (SootClass interfaze : getImmediateInterfaces(sootClass)) {
            for (SootMethod m : interfaze.getMethods()) {
                if (!m.isStatic()) {
                    try {
                        this.sootClass.getMethod(m.getName(), m.getParameterTypes());
                    } catch (RuntimeException e) {
                        /*
                             * Not found. Find the implementation in
                             * superclasses.
                             */
                        SootMethod superMethod = null;
                        for (SootClass sc = sootClass.getSuperclass(); sc.hasSuperclass(); sc = sc.getSuperclass()) {
                            try {
                                SootMethod candidate = sc.getMethod(m.getName(), m.getParameterTypes());
                                if (!candidate.isStatic()) {
                                    superMethod = candidate;
                                    break;
                                }
                            } catch (RuntimeException e2) {
                            // Not found.
                            }
                        }
                        if (superMethod != null) {
                            ci.addSuperMethodDependency(getInternalName(superMethod.getDeclaringClass()), superMethod.getName(), getDescriptor(superMethod), false);
                        }
                    }
                }
            }
        }
    }
    Global classInfoStruct = null;
    try {
        if (!sootClass.isInterface()) {
            config.getVTableCache().get(sootClass);
        }
        classInfoStruct = new Global(Symbols.infoStructSymbol(clazz.getInternalName()), Linkage.weak, createClassInfoStruct());
    } catch (IllegalArgumentException e) {
        // VTable throws this if any of the superclasses of the class is actually an interface.
        // Shouldn't happen frequently but the DRLVM test suite has some tests for this.
        // The Linker will take care of making sure the class cannot be loaded at runtime.
        classInfoStruct = new Global(Symbols.infoStructSymbol(clazz.getInternalName()), I8_PTR, true);
    }
    mb.addGlobal(classInfoStruct);
    /*
         * Emit an internal i8* alias for the info struct which MethodCompiler
         * can use when referencing this info struct in exception landing pads
         * in methods in the same class. See #1007.
         */
    mb.addAlias(new Alias(classInfoStruct.getName() + "_i8ptr", Linkage._private, new ConstantBitcast(classInfoStruct.ref(), I8_PTR)));
    Function infoFn = FunctionBuilder.infoStruct(sootClass);
    infoFn.add(new Ret(new ConstantBitcast(classInfoStruct.ref(), I8_PTR_PTR)));
    mb.addFunction(infoFn);
    for (CompilerPlugin compilerPlugin : config.getCompilerPlugins()) {
        compilerPlugin.afterClass(config, clazz, mb);
    }
    OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8");
    mb.build().write(writer);
    writer.flush();
    ci.setCatchNames(catches);
    // Make sure no class or interface has zero dependencies
    ci.addClassDependency("java/lang/Object", false);
    if (sootClass.hasSuperclass() && !sootClass.isInterface()) {
        ci.addClassDependency(getInternalName(sootClass.getSuperclass()), false);
    }
    for (SootClass iface : sootClass.getInterfaces()) {
        ci.addClassDependency(getInternalName(iface), false);
    }
    for (SootField f : sootClass.getFields()) {
        addClassDependencyIfNeeded(clazz, f.getType(), false);
    }
    for (SootMethod m : sootClass.getMethods()) {
        MethodInfo mi = ci.getMethod(m.getName(), getDescriptor(m));
        addClassDependencyIfNeeded(clazz, mi, m.getReturnType(), false);
        @SuppressWarnings("unchecked") List<soot.Type> paramTypes = (List<soot.Type>) m.getParameterTypes();
        for (soot.Type type : paramTypes) {
            addClassDependencyIfNeeded(clazz, mi, type, false);
        }
    }
    ci.addClassDependencies(attributesEncoder.getDependencies(), false);
    ci.addClassDependencies(catches, false);
    for (Trampoline t : trampolines.keySet()) {
        if (t instanceof Checkcast) {
            ci.addCheckcast(t.getTarget());
        } else if (t instanceof Instanceof) {
            ci.addInstanceof(t.getTarget());
        } else if (t instanceof Invokevirtual || t instanceof Invokeinterface) {
            ci.addInvoke(t.getTarget() + "." + ((Invoke) t).getMethodName() + ((Invoke) t).getMethodDesc());
        }
    }
    clazz.saveClazzInfo();
}
Also used : Ret(org.robovm.compiler.llvm.Ret) Set(java.util.Set) HashSet(java.util.HashSet) CompilerPlugin(org.robovm.compiler.plugin.CompilerPlugin) ConstantBitcast(org.robovm.compiler.llvm.ConstantBitcast) Global(org.robovm.compiler.llvm.Global) Invoke(org.robovm.compiler.trampoline.Invoke) Function(org.robovm.compiler.llvm.Function) Instanceof(org.robovm.compiler.trampoline.Instanceof) ArrayList(java.util.ArrayList) List(java.util.List) JimpleBody(soot.jimple.JimpleBody) Checkcast(org.robovm.compiler.trampoline.Checkcast) Invokevirtual(org.robovm.compiler.trampoline.Invokevirtual) FunctionRef(org.robovm.compiler.llvm.FunctionRef) HashSet(java.util.HashSet) JReturnVoidStmt(soot.jimple.internal.JReturnVoidStmt) Trampoline(org.robovm.compiler.trampoline.Trampoline) ClazzInfo(org.robovm.compiler.clazz.ClazzInfo) SootClass(soot.SootClass) Invokeinterface(org.robovm.compiler.trampoline.Invokeinterface) Triple(org.apache.commons.lang3.tuple.Triple) CodeGenFileType(org.robovm.llvm.binding.CodeGenFileType) BooleanType(soot.BooleanType) StructureType(org.robovm.compiler.llvm.StructureType) PointerType(org.robovm.compiler.llvm.PointerType) ShortType(soot.ShortType) ByteType(soot.ByteType) DoubleType(soot.DoubleType) FloatType(soot.FloatType) IntType(soot.IntType) CharType(soot.CharType) LongType(soot.LongType) RefLikeType(soot.RefLikeType) Type(org.robovm.compiler.llvm.Type) PrimType(soot.PrimType) VoidType(soot.VoidType) Alias(org.robovm.compiler.llvm.Alias) SootMethod(soot.SootMethod) SootField(soot.SootField) MethodInfo(org.robovm.compiler.clazz.MethodInfo) OutputStreamWriter(java.io.OutputStreamWriter)

Example 9 with Type

use of org.robovm.compiler.llvm.Type in project robovm by robovm.

the class MethodCompiler method doCompile.

protected Function doCompile(ModuleBuilder moduleBuilder, SootMethod method) {
    function = createMethodFunction(method);
    moduleBuilder.addFunction(function);
    this.moduleBuilder = moduleBuilder;
    env = function.getParameterRef(0);
    trapsAt = new HashMap<Unit, List<Trap>>();
    Body body = method.retrieveActiveBody();
    NopStmt prependedNop = null;
    if (method.isStatic() && !body.getUnits().getFirst().getBoxesPointingToThis().isEmpty()) {
        // Fix for issue #1. This prevents an NPE in Soot's ArrayBoundsCheckerAnalysis. The NPE
        // occurs for static methods which start with a unit that is the target of some other
        // unit. We work around this by inserting a nop statement as the first unit in such 
        // methods. See http://www.sable.mcgill.ca/listarchives/soot-list/msg01397.html.
        Unit insertionPoint = body.getUnits().getFirst();
        prependedNop = Jimple.v().newNopStmt();
        body.getUnits().getNonPatchingChain().insertBefore(prependedNop, insertionPoint);
    }
    PackManager.v().getPack("jtp").apply(body);
    PackManager.v().getPack("jop").apply(body);
    PackManager.v().getPack("jap").apply(body);
    if (body.getUnits().getFirst() == prependedNop && prependedNop.getBoxesPointingToThis().isEmpty()) {
        // Remove the nop we inserted above to work around the bug in Soot's 
        // ArrayBoundsCheckerAnalysis which has now been run.
        body.getUnits().getNonPatchingChain().removeFirst();
    }
    PatchingChain<Unit> units = body.getUnits();
    Map<Unit, List<Unit>> branchTargets = getBranchTargets(body);
    Map<Unit, Integer> trapHandlers = getTrapHandlers(body);
    Map<Unit, Integer> selChanges = new HashMap<Unit, Integer>();
    int multiANewArrayMaxDims = 0;
    Set<Local> locals = new HashSet<Local>();
    boolean emitCheckStackOverflow = false;
    for (Unit unit : units) {
        if (unit instanceof DefinitionStmt) {
            DefinitionStmt stmt = (DefinitionStmt) unit;
            if (stmt.getLeftOp() instanceof Local) {
                Local local = (Local) stmt.getLeftOp();
                if (!locals.contains(local)) {
                    Type type = getLocalType(local.getType());
                    Alloca alloca = new Alloca(function.newVariable(local.getName(), type), type);
                    alloca.attach(local);
                    function.add(alloca);
                    locals.add(local);
                }
            }
            if (stmt.getRightOp() instanceof NewMultiArrayExpr) {
                NewMultiArrayExpr expr = (NewMultiArrayExpr) stmt.getRightOp();
                multiANewArrayMaxDims = Math.max(multiANewArrayMaxDims, expr.getSizeCount());
            }
            if (stmt.getRightOp() instanceof InvokeExpr) {
                emitCheckStackOverflow = true;
            }
        }
        if (unit instanceof InvokeStmt) {
            emitCheckStackOverflow = true;
        }
    }
    dims = null;
    if (multiANewArrayMaxDims > 0) {
        dims = function.newVariable("dims", new PointerType(new ArrayType(multiANewArrayMaxDims, I32)));
        function.add(new Alloca(dims, new ArrayType(multiANewArrayMaxDims, I32)));
    }
    if (emitCheckStackOverflow) {
        call(CHECK_STACK_OVERFLOW);
    }
    Value trycatchContext = null;
    if (!body.getTraps().isEmpty()) {
        List<List<Trap>> recordedTraps = new ArrayList<List<Trap>>();
        for (Unit unit : units) {
            // Calculate the predecessor units of unit 
            Set<Unit> incoming = new HashSet<Unit>();
            if (units.getFirst() != unit && units.getPredOf(unit).fallsThrough()) {
                incoming.add(units.getPredOf(unit));
            }
            if (branchTargets.keySet().contains(unit)) {
                incoming.addAll(branchTargets.get(unit));
            }
            if (unit == units.getFirst() || trapHandlers.containsKey(unit) || trapsDiffer(unit, incoming)) {
                List<Trap> traps = getTrapsAt(unit);
                if (traps.isEmpty()) {
                    selChanges.put(unit, 0);
                } else {
                    int index = recordedTraps.indexOf(traps);
                    if (index == -1) {
                        index = recordedTraps.size();
                        recordedTraps.add(traps);
                    }
                    selChanges.put(unit, index + 1);
                }
            }
        }
        StructureConstantBuilder landingPadsPtrs = new StructureConstantBuilder();
        for (List<Trap> traps : recordedTraps) {
            StructureConstantBuilder landingPads = new StructureConstantBuilder();
            for (Trap trap : traps) {
                SootClass exClass = trap.getException();
                StructureConstantBuilder landingPad = new StructureConstantBuilder();
                if ("java.lang.Throwable".equals(exClass.getName()) || exClass.isPhantom()) {
                    landingPad.add(new NullConstant(I8_PTR));
                } else {
                    catches.add(getInternalName(exClass));
                    if (exClass == sootClass) {
                        /*
                             * The class being compiled is an exception class
                             * with a catch clause which catches itself. We
                             * cannot reference the info struct directly since
                             * we don't know the type of it and it hasn't been
                             * emitted by ClassCompiler yet. Use the internal
                             * i8* alias instead which ClassCompiler will emit.
                             * See #1007.
                             */
                        landingPad.add(new AliasRef(Symbols.infoStructSymbol(getInternalName(exClass)) + "_i8ptr", I8_PTR));
                    } else {
                        Global g = new Global(Symbols.infoStructSymbol(getInternalName(exClass)), I8_PTR, true);
                        if (!moduleBuilder.hasSymbol(g.getName())) {
                            moduleBuilder.addGlobal(g);
                        }
                        landingPad.add(g.ref());
                    }
                }
                landingPad.add(new IntegerConstant(trapHandlers.get(trap.getHandlerUnit()) + 1));
                landingPads.add(landingPad.build());
            }
            landingPads.add(new StructureConstantBuilder().add(new NullConstant(I8_PTR)).add(new IntegerConstant(0)).build());
            Global g = moduleBuilder.newGlobal(landingPads.build(), true);
            landingPadsPtrs.add(new ConstantBitcast(g.ref(), I8_PTR));
        }
        Global g = moduleBuilder.newGlobal(landingPadsPtrs.build(), true);
        Variable ctx = function.newVariable(TRYCATCH_CONTEXT_PTR);
        Variable bcCtx = function.newVariable(BC_TRYCATCH_CONTEXT_PTR);
        function.add(new Alloca(bcCtx, BC_TRYCATCH_CONTEXT));
        Variable selPtr = function.newVariable(new PointerType(I32));
        function.add(new Getelementptr(selPtr, bcCtx.ref(), 0, 0, 1));
        function.add(new Store(new IntegerConstant(0), selPtr.ref()));
        Variable bcCtxLandingPadsPtr = function.newVariable(I8_PTR_PTR);
        function.add(new Getelementptr(bcCtxLandingPadsPtr, bcCtx.ref(), 0, 1));
        function.add(new Store(new ConstantBitcast(g.ref(), I8_PTR), bcCtxLandingPadsPtr.ref()));
        function.add(new Bitcast(ctx, bcCtx.ref(), TRYCATCH_CONTEXT_PTR));
        trycatchContext = ctx.ref();
        Value result = call(RVM_TRYCATCH_ENTER, env, trycatchContext);
        Map<IntegerConstant, BasicBlockRef> alt = new TreeMap<IntegerConstant, BasicBlockRef>();
        for (Entry<Unit, Integer> entry : trapHandlers.entrySet()) {
            alt.put(new IntegerConstant(entry.getValue() + 1), function.newBasicBlockRef(new Label(entry.getKey())));
        }
        function.add(new Switch(result, function.newBasicBlockRef(new Label(units.getFirst())), alt));
        if (!branchTargets.containsKey(units.getFirst())) {
            function.newBasicBlock(new Label(units.getFirst()));
        }
    }
    if ("<clinit>".equals(method.getName())) {
        initializeClassFields();
    }
    for (Unit unit : units) {
        if (branchTargets.containsKey(unit) || trapHandlers.containsKey(unit)) {
            BasicBlock oldBlock = function.getCurrentBasicBlock();
            function.newBasicBlock(new Label(unit));
            if (oldBlock != null) {
                Instruction last = oldBlock.last();
                if (last == null || !isTerminator(last)) {
                    oldBlock.add(new Br(function.newBasicBlockRef(new Label(unit))));
                }
            }
        }
        if (selChanges.containsKey(unit)) {
            int sel = selChanges.get(unit);
            // trycatchContext->sel = sel
            Variable selPtr = function.newVariable(new PointerType(I32));
            function.add(new Getelementptr(selPtr, trycatchContext, 0, 1)).attach(unit);
            function.add(new Store(new IntegerConstant(sel), selPtr.ref())).attach(unit);
        }
        if (unit instanceof DefinitionStmt) {
            assign((DefinitionStmt) unit);
        } else if (unit instanceof ReturnStmt) {
            if (!body.getTraps().isEmpty()) {
                trycatchLeave(function);
            }
            return_((ReturnStmt) unit);
        } else if (unit instanceof ReturnVoidStmt) {
            if (!body.getTraps().isEmpty()) {
                trycatchLeave(function);
            }
            returnVoid((ReturnVoidStmt) unit);
        } else if (unit instanceof IfStmt) {
            if_((IfStmt) unit);
        } else if (unit instanceof LookupSwitchStmt) {
            lookupSwitch((LookupSwitchStmt) unit);
        } else if (unit instanceof TableSwitchStmt) {
            tableSwitch((TableSwitchStmt) unit);
        } else if (unit instanceof GotoStmt) {
            goto_((GotoStmt) unit);
        } else if (unit instanceof ThrowStmt) {
            throw_((ThrowStmt) unit);
        } else if (unit instanceof InvokeStmt) {
            invoke((InvokeStmt) unit);
        } else if (unit instanceof EnterMonitorStmt) {
            enterMonitor((EnterMonitorStmt) unit);
        } else if (unit instanceof ExitMonitorStmt) {
            exitMonitor((ExitMonitorStmt) unit);
        } else if (unit instanceof NopStmt) {
            nop((NopStmt) unit);
        } else {
            throw new IllegalArgumentException("Unknown Unit type: " + unit.getClass());
        }
    }
    if (this.className.equals("java/lang/Object") && "<init>".equals(method.getName())) {
        // If it is the object will be registered for finalization.
        for (BasicBlock bb : function.getBasicBlocks()) {
            if (bb.last() instanceof Ret) {
                // Insert a call to register_finalizable() before this ret
                Call call = new Call(REGISTER_FINALIZABLE, env, function.getParameterRef(1));
                call.attach(bb.last().getAttachment(Unit.class));
                bb.insertBefore(bb.last(), call);
            }
        }
    }
    return function;
}
Also used : Ret(org.robovm.compiler.llvm.Ret) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Label(org.robovm.compiler.llvm.Label) Store(org.robovm.compiler.llvm.Store) Unit(soot.Unit) Instruction(org.robovm.compiler.llvm.Instruction) Global(org.robovm.compiler.llvm.Global) ArrayType(org.robovm.compiler.llvm.ArrayType) TableSwitchStmt(soot.jimple.TableSwitchStmt) InterfaceInvokeExpr(soot.jimple.InterfaceInvokeExpr) SpecialInvokeExpr(soot.jimple.SpecialInvokeExpr) InstanceInvokeExpr(soot.jimple.InstanceInvokeExpr) VirtualInvokeExpr(soot.jimple.VirtualInvokeExpr) InvokeExpr(soot.jimple.InvokeExpr) StaticInvokeExpr(soot.jimple.StaticInvokeExpr) GotoStmt(soot.jimple.GotoStmt) ArrayList(java.util.ArrayList) List(java.util.List) EnterMonitorStmt(soot.jimple.EnterMonitorStmt) HashSet(java.util.HashSet) BasicBlock(org.robovm.compiler.llvm.BasicBlock) Local(soot.Local) StructureConstantBuilder(org.robovm.compiler.llvm.StructureConstantBuilder) IntegerConstant(org.robovm.compiler.llvm.IntegerConstant) Switch(org.robovm.compiler.llvm.Switch) Bitcast(org.robovm.compiler.llvm.Bitcast) ConstantBitcast(org.robovm.compiler.llvm.ConstantBitcast) Value(org.robovm.compiler.llvm.Value) DefinitionStmt(soot.jimple.DefinitionStmt) ReturnStmt(soot.jimple.ReturnStmt) ThrowStmt(soot.jimple.ThrowStmt) ExitMonitorStmt(soot.jimple.ExitMonitorStmt) Variable(org.robovm.compiler.llvm.Variable) InvokeStmt(soot.jimple.InvokeStmt) AliasRef(org.robovm.compiler.llvm.AliasRef) NewMultiArrayExpr(soot.jimple.NewMultiArrayExpr) ConstantBitcast(org.robovm.compiler.llvm.ConstantBitcast) ReturnVoidStmt(soot.jimple.ReturnVoidStmt) PointerType(org.robovm.compiler.llvm.PointerType) Getelementptr(org.robovm.compiler.llvm.Getelementptr) BasicBlockRef(org.robovm.compiler.llvm.BasicBlockRef) Body(soot.Body) Call(org.robovm.compiler.llvm.Call) Alloca(org.robovm.compiler.llvm.Alloca) NullConstant(org.robovm.compiler.llvm.NullConstant) Trap(soot.Trap) LookupSwitchStmt(soot.jimple.LookupSwitchStmt) SootClass(soot.SootClass) TreeMap(java.util.TreeMap) Br(org.robovm.compiler.llvm.Br) FloatingPointType(org.robovm.compiler.llvm.FloatingPointType) IntegerType(org.robovm.compiler.llvm.IntegerType) PointerType(org.robovm.compiler.llvm.PointerType) NullType(soot.NullType) FunctionType(org.robovm.compiler.llvm.FunctionType) ArrayType(org.robovm.compiler.llvm.ArrayType) CharType(soot.CharType) RefLikeType(soot.RefLikeType) Type(org.robovm.compiler.llvm.Type) PrimType(soot.PrimType) IfStmt(soot.jimple.IfStmt) NopStmt(soot.jimple.NopStmt)

Example 10 with Type

use of org.robovm.compiler.llvm.Type in project robovm by robovm.

the class Types method getFields.

public static List<SootField> getFields(final OS os, final Arch arch, SootClass clazz, boolean ztatic) {
    List<SootField> l = new ArrayList<SootField>();
    for (SootField f : clazz.getFields()) {
        if (ztatic == f.isStatic()) {
            l.add(f);
        }
    }
    // Sort the fields. references, volatile long, double, long, float, int, char, short, boolean, byte.
    // Fields of same type are sorted by name.
    Collections.sort(l, new Comparator<SootField>() {

        @Override
        public int compare(SootField o1, SootField o2) {
            soot.Type t1 = o1.getType();
            soot.Type t2 = o2.getType();
            if (t1 instanceof RefLikeType) {
                if (!(t2 instanceof RefLikeType)) {
                    return -1;
                }
            }
            if (t2 instanceof RefLikeType) {
                if (!(t1 instanceof RefLikeType)) {
                    return 1;
                }
            }
            // Compare alignment. Higher first.
            int align1 = getFieldAlignment(os, arch, o1);
            int align2 = getFieldAlignment(os, arch, o2);
            int c = new Integer(align2).compareTo(align1);
            if (c == 0) {
                // Compare size. Larger first.
                int size1 = getFieldSize(arch, o1);
                int size2 = getFieldSize(arch, o2);
                c = new Integer(size2).compareTo(size1);
                if (c == 0) {
                    // Compare type name.
                    c = t1.getClass().getSimpleName().compareTo(t2.getClass().getSimpleName());
                    if (c == 0) {
                        // Compare name.
                        c = o1.getName().compareTo(o2.getName());
                    }
                }
            }
            return c;
        }
    });
    return l;
}
Also used : RefLikeType(soot.RefLikeType) PointerType(org.robovm.compiler.llvm.PointerType) RefType(soot.RefType) DoubleType(soot.DoubleType) FloatType(soot.FloatType) IntType(soot.IntType) ShortType(soot.ShortType) PackedStructureType(org.robovm.compiler.llvm.PackedStructureType) CharType(soot.CharType) LongType(soot.LongType) IntegerType(org.robovm.compiler.llvm.IntegerType) BooleanType(soot.BooleanType) OpaqueType(org.robovm.compiler.llvm.OpaqueType) StructureType(org.robovm.compiler.llvm.StructureType) RefLikeType(soot.RefLikeType) ByteType(soot.ByteType) Type(org.robovm.compiler.llvm.Type) BottomType(soot.jimple.toolkits.typing.fast.BottomType) AggregateType(org.robovm.compiler.llvm.AggregateType) PrimType(soot.PrimType) VoidType(soot.VoidType) FunctionType(org.robovm.compiler.llvm.FunctionType) ArrayList(java.util.ArrayList) SootField(soot.SootField)

Aggregations

Type (org.robovm.compiler.llvm.Type)25 PointerType (org.robovm.compiler.llvm.PointerType)23 FunctionType (org.robovm.compiler.llvm.FunctionType)21 StructureType (org.robovm.compiler.llvm.StructureType)15 PrimType (soot.PrimType)15 IntegerType (org.robovm.compiler.llvm.IntegerType)14 LongType (soot.LongType)13 VoidType (soot.VoidType)13 ArrayList (java.util.ArrayList)12 Variable (org.robovm.compiler.llvm.Variable)11 DoubleType (soot.DoubleType)11 FloatType (soot.FloatType)11 ArrayType (org.robovm.compiler.llvm.ArrayType)10 CharType (soot.CharType)10 RefLikeType (soot.RefLikeType)10 AggregateType (org.robovm.compiler.llvm.AggregateType)8 PrimitiveType (org.robovm.compiler.llvm.PrimitiveType)8 RefType (soot.RefType)8 Value (org.robovm.compiler.llvm.Value)7 FunctionRef (org.robovm.compiler.llvm.FunctionRef)6