Search in sources :

Example 1 with Invokespecial

use of org.robovm.compiler.trampoline.Invokespecial in project robovm by robovm.

the class MethodCompiler method invokeExpr.

private Value invokeExpr(Stmt stmt, InvokeExpr expr) {
    SootMethodRef methodRef = expr.getMethodRef();
    ArrayList<Value> args = new ArrayList<Value>();
    args.add(env);
    if (!(expr instanceof StaticInvokeExpr)) {
        Value base = immediate(stmt, (Immediate) ((InstanceInvokeExpr) expr).getBase());
        checkNull(stmt, base);
        args.add(base);
    }
    int i = 0;
    for (soot.Value sootArg : (List<soot.Value>) expr.getArgs()) {
        Value arg = immediate(stmt, (Immediate) sootArg);
        args.add(narrowFromI32Value(stmt, getType(methodRef.parameterType(i)), arg));
        i++;
    }
    Value result = null;
    FunctionRef functionRef = config.isDebug() ? null : Intrinsics.getIntrinsic(sootMethod, stmt, expr);
    if (functionRef == null) {
        Trampoline trampoline = null;
        String targetClassName = getInternalName(methodRef.declaringClass());
        String methodName = methodRef.name();
        String methodDesc = getDescriptor(methodRef);
        if (expr instanceof SpecialInvokeExpr) {
            soot.Type runtimeType = ((SpecialInvokeExpr) expr).getBase().getType();
            String runtimeClassName = runtimeType == NullType.v() ? targetClassName : getInternalName(runtimeType);
            trampoline = new Invokespecial(this.className, targetClassName, methodName, methodDesc, runtimeClassName);
        } else if (expr instanceof StaticInvokeExpr) {
            trampoline = new Invokestatic(this.className, targetClassName, methodName, methodDesc);
        } else if (expr instanceof VirtualInvokeExpr) {
            soot.Type runtimeType = ((VirtualInvokeExpr) expr).getBase().getType();
            String runtimeClassName = runtimeType == NullType.v() ? targetClassName : getInternalName(runtimeType);
            trampoline = new Invokevirtual(this.className, targetClassName, methodName, methodDesc, runtimeClassName);
        } else if (expr instanceof InterfaceInvokeExpr) {
            trampoline = new Invokeinterface(this.className, targetClassName, methodName, methodDesc);
        }
        trampolines.add(trampoline);
        if (canCallDirectly(expr)) {
            SootMethod method = this.sootMethod.getDeclaringClass().getMethod(methodRef.name(), methodRef.parameterTypes(), methodRef.returnType());
            if (method.isSynchronized()) {
                functionRef = FunctionBuilder.synchronizedWrapper(method).ref();
            } else {
                functionRef = createMethodFunction(method).ref();
            }
        } else {
            functionRef = trampoline.getFunctionRef();
        }
    }
    result = call(stmt, functionRef, args.toArray(new Value[0]));
    if (result != null) {
        return widenToI32Value(stmt, result, methodRef.returnType().equals(CharType.v()));
    } else {
        return null;
    }
}
Also used : Trampoline(org.robovm.compiler.trampoline.Trampoline) SootMethodRef(soot.SootMethodRef) SpecialInvokeExpr(soot.jimple.SpecialInvokeExpr) ArrayList(java.util.ArrayList) InstanceInvokeExpr(soot.jimple.InstanceInvokeExpr) InterfaceInvokeExpr(soot.jimple.InterfaceInvokeExpr) Invokeinterface(org.robovm.compiler.trampoline.Invokeinterface) Invokespecial(org.robovm.compiler.trampoline.Invokespecial) StaticInvokeExpr(soot.jimple.StaticInvokeExpr) Invokestatic(org.robovm.compiler.trampoline.Invokestatic) Value(org.robovm.compiler.llvm.Value) SootMethod(soot.SootMethod) ArrayList(java.util.ArrayList) List(java.util.List) VirtualInvokeExpr(soot.jimple.VirtualInvokeExpr) Invokevirtual(org.robovm.compiler.trampoline.Invokevirtual) FunctionRef(org.robovm.compiler.llvm.FunctionRef)

Example 2 with Invokespecial

use of org.robovm.compiler.trampoline.Invokespecial in project robovm by robovm.

the class TrampolineCompiler method resolveMethod.

private SootMethod resolveMethod(Function f, Invoke t) {
    SootClass target = config.getClazzes().load(t.getTarget()).getSootClass();
    String name = t.getMethodName();
    String desc = t.getMethodDesc();
    if ("<init>".equals(name) && t instanceof Invokespecial) {
        SootMethod method = getMethod(target, name, desc);
        if (method != null) {
            return method;
        }
    }
    if ("<clinit>".equals(name) || "<init>".equals(name)) {
        // This is not part of method resolution but we 
        // need to handle it somehow.
        throwNoSuchMethodError(f, t);
        return null;
    }
    SootMethod method = resolveMethod(target, name, desc);
    if (method == null) {
        throwNoSuchMethodError(f, t);
        return null;
    }
    if (t.isStatic() && !method.isStatic()) {
        throwIncompatibleChangeError(f, EXPECTED_STATIC_METHOD, target, name, desc);
        return null;
    } else if (!t.isStatic() && method.isStatic()) {
        throwIncompatibleChangeError(f, EXPECTED_NON_STATIC_METHOD, target, name, desc);
        return null;
    }
    return method;
}
Also used : SootMethod(soot.SootMethod) SootClass(soot.SootClass) Invokespecial(org.robovm.compiler.trampoline.Invokespecial)

Example 3 with Invokespecial

use of org.robovm.compiler.trampoline.Invokespecial in project robovm by robovm.

the class TrampolineCompiler method checkMemberAccessible.

private boolean checkMemberAccessible(Function f, Trampoline t, ClassMember member) {
    Clazz caller = config.getClazzes().load(t.getCallingClass());
    Clazz target = config.getClazzes().load(member.getDeclaringClass().getName().replace('.', '/'));
    String runtimeClassName = null;
    runtimeClassName = t instanceof Invokevirtual ? ((Invokevirtual) t).getRuntimeClass() : runtimeClassName;
    runtimeClassName = t instanceof Invokespecial ? ((Invokespecial) t).getRuntimeClass() : runtimeClassName;
    runtimeClassName = t instanceof GetField ? ((GetField) t).getRuntimeClass() : runtimeClassName;
    runtimeClassName = t instanceof PutField ? ((PutField) t).getRuntimeClass() : runtimeClassName;
    SootClass runtimeClass = null;
    if (runtimeClassName != null && !isArray(runtimeClassName)) {
        Clazz c = config.getClazzes().load(runtimeClassName);
        if (c == null) {
            // just return true here.
            return true;
        }
        runtimeClass = c.getSootClass();
    }
    if (Access.checkMemberAccessible(member, caller, target, runtimeClass)) {
        return true;
    }
    if (member instanceof SootMethod) {
        SootMethod method = (SootMethod) member;
        throwIllegalAccessError(f, ILLEGAL_ACCESS_ERROR_METHOD, method.getDeclaringClass(), method.getName(), getDescriptor(method), caller.getSootClass());
    } else {
        SootField field = (SootField) member;
        throwIllegalAccessError(f, ILLEGAL_ACCESS_ERROR_FIELD, field.getDeclaringClass(), field.getName(), caller.getSootClass());
    }
    f.add(new Unreachable());
    return false;
}
Also used : GetField(org.robovm.compiler.trampoline.GetField) Unreachable(org.robovm.compiler.llvm.Unreachable) SootMethod(soot.SootMethod) Clazz(org.robovm.compiler.clazz.Clazz) SootField(soot.SootField) SootClass(soot.SootClass) Invokevirtual(org.robovm.compiler.trampoline.Invokevirtual) Invokespecial(org.robovm.compiler.trampoline.Invokespecial) PutField(org.robovm.compiler.trampoline.PutField)

Example 4 with Invokespecial

use of org.robovm.compiler.trampoline.Invokespecial 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)

Aggregations

Invokespecial (org.robovm.compiler.trampoline.Invokespecial)4 SootMethod (soot.SootMethod)4 SootClass (soot.SootClass)3 Clazz (org.robovm.compiler.clazz.Clazz)2 FunctionRef (org.robovm.compiler.llvm.FunctionRef)2 Unreachable (org.robovm.compiler.llvm.Unreachable)2 Invokeinterface (org.robovm.compiler.trampoline.Invokeinterface)2 Invokevirtual (org.robovm.compiler.trampoline.Invokevirtual)2 SootField (soot.SootField)2 ArrayList (java.util.ArrayList)1 List (java.util.List)1 ImmutableTriple (org.apache.commons.lang3.tuple.ImmutableTriple)1 Function (org.robovm.compiler.llvm.Function)1 Value (org.robovm.compiler.llvm.Value)1 Anewarray (org.robovm.compiler.trampoline.Anewarray)1 Checkcast (org.robovm.compiler.trampoline.Checkcast)1 FieldAccessor (org.robovm.compiler.trampoline.FieldAccessor)1 GetField (org.robovm.compiler.trampoline.GetField)1 Instanceof (org.robovm.compiler.trampoline.Instanceof)1 Invoke (org.robovm.compiler.trampoline.Invoke)1