Search in sources :

Example 1 with InvokeExpr

use of soot.jimple.InvokeExpr in project robovm by robovm.

the class MethodCompiler method assign.

private void assign(DefinitionStmt stmt) {
    /*
         * leftOp is either a Local, an ArrayRef or a FieldRef
         * rightOp is either a Local, a Ref, or an Expr
         */
    soot.Value rightOp = stmt.getRightOp();
    Value result;
    if (rightOp instanceof Immediate) {
        Immediate immediate = (Immediate) rightOp;
        result = immediate(stmt, immediate);
    } else if (rightOp instanceof ThisRef) {
        result = function.getParameterRef(1);
    } else if (rightOp instanceof ParameterRef) {
        ParameterRef ref = (ParameterRef) rightOp;
        int index = (sootMethod.isStatic() ? 1 : 2) + ref.getIndex();
        Value p = new VariableRef("p" + index, getType(ref.getType()));
        result = widenToI32Value(stmt, p, isUnsigned(ref.getType()));
    } else if (rightOp instanceof CaughtExceptionRef) {
        result = call(stmt, BC_EXCEPTION_CLEAR, env);
    } else if (rightOp instanceof ArrayRef) {
        ArrayRef ref = (ArrayRef) rightOp;
        VariableRef base = (VariableRef) immediate(stmt, (Immediate) ref.getBase());
        if (ref.getType() instanceof NullType) {
            // The base value is always null. Do a null check which will
            // always throw NPE.
            checkNull(stmt, base);
            return;
        } else {
            Value index = immediate(stmt, (Immediate) ref.getIndex());
            checkNull(stmt, base);
            checkBounds(stmt, base, index);
            result = call(stmt, getArrayLoad(ref.getType()), base, index);
            result = widenToI32Value(stmt, result, isUnsigned(ref.getType()));
        }
    } else if (rightOp instanceof InstanceFieldRef) {
        InstanceFieldRef ref = (InstanceFieldRef) rightOp;
        Value base = immediate(stmt, (Immediate) ref.getBase());
        checkNull(stmt, base);
        FunctionRef fn = null;
        if (canAccessDirectly(ref)) {
            fn = new FunctionRef(Symbols.getterSymbol(ref.getFieldRef()), new FunctionType(getType(ref.getType()), ENV_PTR, OBJECT_PTR));
        } else {
            soot.Type runtimeType = ref.getBase().getType();
            String targetClassName = getInternalName(ref.getFieldRef().declaringClass());
            String runtimeClassName = runtimeType == NullType.v() ? targetClassName : getInternalName(runtimeType);
            Trampoline trampoline = new GetField(this.className, targetClassName, ref.getFieldRef().name(), getDescriptor(ref.getFieldRef().type()), runtimeClassName);
            trampolines.add(trampoline);
            fn = trampoline.getFunctionRef();
        }
        result = call(stmt, fn, env, base);
        result = widenToI32Value(stmt, result, isUnsigned(ref.getType()));
    } else if (rightOp instanceof StaticFieldRef) {
        StaticFieldRef ref = (StaticFieldRef) rightOp;
        FunctionRef fn = config.isDebug() ? null : Intrinsics.getIntrinsic(sootMethod, stmt);
        if (fn == null) {
            if (canAccessDirectly(ref)) {
                fn = new FunctionRef(Symbols.getterSymbol(ref.getFieldRef()), new FunctionType(getType(ref.getType()), ENV_PTR));
            } else {
                String targetClassName = getInternalName(ref.getFieldRef().declaringClass());
                Trampoline trampoline = new GetStatic(this.className, targetClassName, ref.getFieldRef().name(), getDescriptor(ref.getFieldRef().type()));
                trampolines.add(trampoline);
                fn = trampoline.getFunctionRef();
            }
        }
        result = call(stmt, fn, env);
        result = widenToI32Value(stmt, result, isUnsigned(ref.getType()));
    } else if (rightOp instanceof Expr) {
        if (rightOp instanceof BinopExpr) {
            BinopExpr expr = (BinopExpr) rightOp;
            Type rightType = getLocalType(expr.getType());
            Variable resultVar = function.newVariable(rightType);
            result = resultVar.ref();
            Value op1 = immediate(stmt, (Immediate) expr.getOp1());
            Value op2 = immediate(stmt, (Immediate) expr.getOp2());
            if (rightOp instanceof AddExpr) {
                if (rightType instanceof IntegerType) {
                    function.add(new Add(resultVar, op1, op2)).attach(stmt);
                } else {
                    function.add(new Fadd(resultVar, op1, op2)).attach(stmt);
                }
            } else if (rightOp instanceof AndExpr) {
                function.add(new And(resultVar, op1, op2)).attach(stmt);
            } else if (rightOp instanceof CmpExpr) {
                Variable t1 = function.newVariable(I1);
                Variable t2 = function.newVariable(I1);
                Variable t3 = function.newVariable(resultVar.getType());
                Variable t4 = function.newVariable(resultVar.getType());
                function.add(new Icmp(t1, Condition.slt, op1, op2)).attach(stmt);
                function.add(new Icmp(t2, Condition.sgt, op1, op2)).attach(stmt);
                function.add(new Zext(t3, new VariableRef(t1), resultVar.getType())).attach(stmt);
                function.add(new Zext(t4, new VariableRef(t2), resultVar.getType())).attach(stmt);
                function.add(new Sub(resultVar, new VariableRef(t4), new VariableRef(t3))).attach(stmt);
            } else if (rightOp instanceof DivExpr) {
                if (rightType instanceof IntegerType) {
                    FunctionRef f = rightType == I64 ? LDIV : IDIV;
                    result = call(stmt, f, env, op1, op2);
                } else {
                    // float or double
                    function.add(new Fdiv(resultVar, op1, op2)).attach(stmt);
                }
            } else if (rightOp instanceof MulExpr) {
                if (rightType instanceof IntegerType) {
                    function.add(new Mul(resultVar, op1, op2)).attach(stmt);
                } else {
                    function.add(new Fmul(resultVar, op1, op2)).attach(stmt);
                }
            } else if (rightOp instanceof OrExpr) {
                function.add(new Or(resultVar, op1, op2)).attach(stmt);
            } else if (rightOp instanceof RemExpr) {
                if (rightType instanceof IntegerType) {
                    FunctionRef f = rightType == I64 ? LREM : IREM;
                    result = call(stmt, f, env, op1, op2);
                } else {
                    FunctionRef f = rightType == DOUBLE ? DREM : FREM;
                    result = call(stmt, f, env, op1, op2);
                }
            } else if (rightOp instanceof ShlExpr || rightOp instanceof ShrExpr || rightOp instanceof UshrExpr) {
                IntegerType type = (IntegerType) op1.getType();
                int bits = type.getBits();
                Variable t = function.newVariable(op2.getType());
                function.add(new And(t, op2, new IntegerConstant(bits - 1, (IntegerType) op2.getType()))).attach(stmt);
                Value shift = t.ref();
                if (((IntegerType) shift.getType()).getBits() < bits) {
                    Variable tmp = function.newVariable(type);
                    function.add(new Zext(tmp, shift, type)).attach(stmt);
                    shift = tmp.ref();
                }
                if (rightOp instanceof ShlExpr) {
                    function.add(new Shl(resultVar, op1, shift)).attach(stmt);
                } else if (rightOp instanceof ShrExpr) {
                    function.add(new Ashr(resultVar, op1, shift)).attach(stmt);
                } else {
                    function.add(new Lshr(resultVar, op1, shift)).attach(stmt);
                }
            } else if (rightOp instanceof SubExpr) {
                if (rightType instanceof IntegerType) {
                    function.add(new Sub(resultVar, op1, op2)).attach(stmt);
                } else {
                    function.add(new Fsub(resultVar, op1, op2)).attach(stmt);
                }
            } else if (rightOp instanceof XorExpr) {
                function.add(new Xor(resultVar, op1, op2)).attach(stmt);
            } else if (rightOp instanceof XorExpr) {
                function.add(new Xor(resultVar, op1, op2)).attach(stmt);
            } else if (rightOp instanceof CmplExpr) {
                FunctionRef f = op1.getType() == FLOAT ? FCMPL : DCMPL;
                function.add(new Call(resultVar, f, op1, op2)).attach(stmt);
            } else if (rightOp instanceof CmpgExpr) {
                FunctionRef f = op1.getType() == FLOAT ? FCMPG : DCMPG;
                function.add(new Call(resultVar, f, op1, op2)).attach(stmt);
            } else {
                throw new IllegalArgumentException("Unknown type for rightOp: " + rightOp.getClass());
            }
        } else if (rightOp instanceof CastExpr) {
            Value op = immediate(stmt, (Immediate) ((CastExpr) rightOp).getOp());
            soot.Type sootTargetType = ((CastExpr) rightOp).getCastType();
            soot.Type sootSourceType = ((CastExpr) rightOp).getOp().getType();
            if (sootTargetType instanceof PrimType) {
                Type targetType = getType(sootTargetType);
                Type sourceType = getType(sootSourceType);
                if (targetType instanceof IntegerType && sourceType instanceof IntegerType) {
                    // op is at least I32 and has already been widened if source type had fewer bits then I32
                    IntegerType toType = (IntegerType) targetType;
                    IntegerType fromType = (IntegerType) op.getType();
                    Variable v = function.newVariable(toType);
                    if (fromType.getBits() < toType.getBits()) {
                        // Widening
                        if (isUnsigned(sootSourceType)) {
                            function.add(new Zext(v, op, toType)).attach(stmt);
                        } else {
                            function.add(new Sext(v, op, toType)).attach(stmt);
                        }
                    } else if (fromType.getBits() == toType.getBits()) {
                        function.add(new Bitcast(v, op, toType)).attach(stmt);
                    } else {
                        // Narrow
                        function.add(new Trunc(v, op, toType)).attach(stmt);
                    }
                    result = widenToI32Value(stmt, v.ref(), isUnsigned(sootTargetType));
                } else if (targetType instanceof FloatingPointType && sourceType instanceof IntegerType) {
                    // we always to a signed conversion since if op is char it has already been zero extended to I32
                    Variable v = function.newVariable(targetType);
                    function.add(new Sitofp(v, op, targetType)).attach(stmt);
                    result = v.ref();
                } else if (targetType instanceof FloatingPointType && sourceType instanceof FloatingPointType) {
                    Variable v = function.newVariable(targetType);
                    if (targetType == FLOAT && sourceType == DOUBLE) {
                        function.add(new Fptrunc(v, op, targetType)).attach(stmt);
                    } else if (targetType == DOUBLE && sourceType == FLOAT) {
                        function.add(new Fpext(v, op, targetType)).attach(stmt);
                    } else {
                        function.add(new Bitcast(v, op, targetType)).attach(stmt);
                    }
                    result = v.ref();
                } else {
                    // F2I, F2L, D2I, D2L
                    FunctionRef f = null;
                    if (targetType == I32 && sourceType == FLOAT) {
                        f = F2I;
                    } else if (targetType == I64 && sourceType == FLOAT) {
                        f = F2L;
                    } else if (targetType == I32 && sourceType == DOUBLE) {
                        f = D2I;
                    } else if (targetType == I64 && sourceType == DOUBLE) {
                        f = D2L;
                    } else {
                        throw new IllegalArgumentException();
                    }
                    Variable v = function.newVariable(targetType);
                    function.add(new Call(v, f, op)).attach(stmt);
                    result = v.ref();
                }
            } else {
                if (sootTargetType instanceof soot.ArrayType && ((soot.ArrayType) sootTargetType).getElementType() instanceof PrimType) {
                    soot.Type primType = ((soot.ArrayType) sootTargetType).getElementType();
                    GlobalRef arrayClassPtr = new GlobalRef("array_" + getDescriptor(primType), CLASS_PTR);
                    Variable arrayClass = function.newVariable(CLASS_PTR);
                    function.add(new Load(arrayClass, arrayClassPtr)).attach(stmt);
                    result = call(stmt, CHECKCAST_PRIM_ARRAY, env, arrayClass.ref(), op);
                } else {
                    String targetClassName = getInternalName(sootTargetType);
                    Trampoline trampoline = new Checkcast(this.className, targetClassName);
                    trampolines.add(trampoline);
                    result = call(stmt, trampoline.getFunctionRef(), env, op);
                }
            }
        } else if (rightOp instanceof InstanceOfExpr) {
            Value op = immediate(stmt, (Immediate) ((InstanceOfExpr) rightOp).getOp());
            soot.Type checkType = ((InstanceOfExpr) rightOp).getCheckType();
            if (checkType instanceof soot.ArrayType && ((soot.ArrayType) checkType).getElementType() instanceof PrimType) {
                soot.Type primType = ((soot.ArrayType) checkType).getElementType();
                GlobalRef arrayClassPtr = new GlobalRef("array_" + getDescriptor(primType), CLASS_PTR);
                Variable arrayClass = function.newVariable(CLASS_PTR);
                function.add(new Load(arrayClass, arrayClassPtr)).attach(stmt);
                result = call(stmt, INSTANCEOF_PRIM_ARRAY, env, arrayClass.ref(), op);
            } else {
                String targetClassName = getInternalName(checkType);
                Trampoline trampoline = new Instanceof(this.className, targetClassName);
                trampolines.add(trampoline);
                result = call(stmt, trampoline.getFunctionRef(), env, op);
            }
        } else if (rightOp instanceof NewExpr) {
            String targetClassName = getInternalName(((NewExpr) rightOp).getBaseType());
            FunctionRef fn = null;
            if (targetClassName.equals(this.className)) {
                fn = FunctionBuilder.allocator(sootMethod.getDeclaringClass()).ref();
            } else {
                Trampoline trampoline = new New(this.className, targetClassName);
                trampolines.add(trampoline);
                fn = trampoline.getFunctionRef();
            }
            result = call(stmt, fn, env);
        } else if (rightOp instanceof NewArrayExpr) {
            NewArrayExpr expr = (NewArrayExpr) rightOp;
            Value size = immediate(stmt, (Immediate) expr.getSize());
            if (expr.getBaseType() instanceof PrimType) {
                result = call(stmt, getNewArray(expr.getBaseType()), env, size);
            } else {
                String targetClassName = getInternalName(expr.getType());
                Trampoline trampoline = new Anewarray(this.className, targetClassName);
                trampolines.add(trampoline);
                result = call(stmt, trampoline.getFunctionRef(), env, size);
            }
        } else if (rightOp instanceof NewMultiArrayExpr) {
            NewMultiArrayExpr expr = (NewMultiArrayExpr) rightOp;
            if (expr.getBaseType().numDimensions == 1 && expr.getBaseType().getElementType() instanceof PrimType) {
                Value size = immediate(stmt, (Immediate) expr.getSize(0));
                result = call(stmt, getNewArray(expr.getBaseType().getElementType()), env, size);
            } else {
                for (int i = 0; i < expr.getSizeCount(); i++) {
                    Value size = immediate(stmt, (Immediate) expr.getSize(i));
                    Variable ptr = function.newVariable(new PointerType(I32));
                    function.add(new Getelementptr(ptr, dims.ref(), 0, i)).attach(stmt);
                    function.add(new Store(size, ptr.ref())).attach(stmt);
                }
                Variable dimsI32 = function.newVariable(new PointerType(I32));
                function.add(new Bitcast(dimsI32, dims.ref(), dimsI32.getType())).attach(stmt);
                String targetClassName = getInternalName(expr.getType());
                Trampoline trampoline = new Multianewarray(this.className, targetClassName);
                trampolines.add(trampoline);
                result = call(stmt, trampoline.getFunctionRef(), env, new IntegerConstant(expr.getSizeCount()), dimsI32.ref());
            }
        } else if (rightOp instanceof InvokeExpr) {
            result = invokeExpr(stmt, (InvokeExpr) rightOp);
        } else if (rightOp instanceof LengthExpr) {
            Value op = immediate(stmt, (Immediate) ((LengthExpr) rightOp).getOp());
            checkNull(stmt, op);
            Variable v = function.newVariable(I32);
            function.add(new Call(v, ARRAY_LENGTH, op)).attach(stmt);
            result = v.ref();
        } else if (rightOp instanceof NegExpr) {
            NegExpr expr = (NegExpr) rightOp;
            Value op = immediate(stmt, (Immediate) expr.getOp());
            Type rightType = op.getType();
            Variable v = function.newVariable(op.getType());
            if (rightType instanceof IntegerType) {
                function.add(new Sub(v, new IntegerConstant(0, (IntegerType) rightType), op)).attach(stmt);
            } else {
                function.add(new Fmul(v, new FloatingPointConstant(-1.0, (FloatingPointType) rightType), op)).attach(stmt);
            }
            result = v.ref();
        } else {
            throw new IllegalArgumentException("Unknown type for rightOp: " + rightOp.getClass());
        }
    } else {
        throw new IllegalArgumentException("Unknown type for rightOp: " + rightOp.getClass());
    }
    soot.Value leftOp = stmt.getLeftOp();
    if (leftOp instanceof Local) {
        Local local = (Local) leftOp;
        VariableRef v = new VariableRef(local.getName(), new PointerType(getLocalType(leftOp.getType())));
        function.add(new Store(result, v, !sootMethod.getActiveBody().getTraps().isEmpty())).attach(stmt);
    } else {
        Type leftType = getType(leftOp.getType());
        Value narrowedResult = narrowFromI32Value(stmt, leftType, result);
        if (leftOp instanceof ArrayRef) {
            ArrayRef ref = (ArrayRef) leftOp;
            VariableRef base = (VariableRef) immediate(stmt, (Immediate) ref.getBase());
            Value index = immediate(stmt, (Immediate) ref.getIndex());
            checkNull(stmt, base);
            checkBounds(stmt, base, index);
            if (leftOp.getType() instanceof RefLikeType) {
                call(stmt, BC_SET_OBJECT_ARRAY_ELEMENT, env, base, index, narrowedResult);
            } else {
                call(stmt, getArrayStore(leftOp.getType()), base, index, narrowedResult);
            }
        } else if (leftOp instanceof InstanceFieldRef) {
            InstanceFieldRef ref = (InstanceFieldRef) leftOp;
            Value base = immediate(stmt, (Immediate) ref.getBase());
            checkNull(stmt, base);
            FunctionRef fn = null;
            if (canAccessDirectly(ref)) {
                fn = new FunctionRef(Symbols.setterSymbol(ref.getFieldRef()), new FunctionType(VOID, ENV_PTR, OBJECT_PTR, getType(ref.getType())));
            } else {
                soot.Type runtimeType = ref.getBase().getType();
                String targetClassName = getInternalName(ref.getFieldRef().declaringClass());
                String runtimeClassName = runtimeType == NullType.v() ? targetClassName : getInternalName(runtimeType);
                Trampoline trampoline = new PutField(this.className, targetClassName, ref.getFieldRef().name(), getDescriptor(ref.getFieldRef().type()), runtimeClassName);
                trampolines.add(trampoline);
                fn = trampoline.getFunctionRef();
            }
            call(stmt, fn, env, base, narrowedResult);
        } else if (leftOp instanceof StaticFieldRef) {
            StaticFieldRef ref = (StaticFieldRef) leftOp;
            FunctionRef fn = null;
            if (canAccessDirectly(ref)) {
                fn = new FunctionRef(Symbols.setterSymbol(ref.getFieldRef()), new FunctionType(VOID, ENV_PTR, getType(ref.getType())));
            } else {
                String targetClassName = getInternalName(ref.getFieldRef().declaringClass());
                Trampoline trampoline = new PutStatic(this.className, targetClassName, ref.getFieldRef().name(), getDescriptor(ref.getFieldRef().type()));
                trampolines.add(trampoline);
                fn = trampoline.getFunctionRef();
            }
            call(stmt, fn, env, narrowedResult);
        } else {
            throw new IllegalArgumentException("Unknown type for leftOp: " + leftOp.getClass());
        }
    }
}
Also used : Add(org.robovm.compiler.llvm.Add) AndExpr(soot.jimple.AndExpr) New(org.robovm.compiler.trampoline.New) Or(org.robovm.compiler.llvm.Or) Store(org.robovm.compiler.llvm.Store) FloatingPointType(org.robovm.compiler.llvm.FloatingPointType) ArrayType(org.robovm.compiler.llvm.ArrayType) RefLikeType(soot.RefLikeType) GetStatic(org.robovm.compiler.trampoline.GetStatic) InterfaceInvokeExpr(soot.jimple.InterfaceInvokeExpr) SpecialInvokeExpr(soot.jimple.SpecialInvokeExpr) InstanceInvokeExpr(soot.jimple.InstanceInvokeExpr) VirtualInvokeExpr(soot.jimple.VirtualInvokeExpr) InvokeExpr(soot.jimple.InvokeExpr) StaticInvokeExpr(soot.jimple.StaticInvokeExpr) Shl(org.robovm.compiler.llvm.Shl) CastExpr(soot.jimple.CastExpr) PrimType(soot.PrimType) Fsub(org.robovm.compiler.llvm.Fsub) ShlExpr(soot.jimple.ShlExpr) Checkcast(org.robovm.compiler.trampoline.Checkcast) FunctionRef(org.robovm.compiler.llvm.FunctionRef) Fmul(org.robovm.compiler.llvm.Fmul) Sub(org.robovm.compiler.llvm.Sub) GetField(org.robovm.compiler.trampoline.GetField) Load(org.robovm.compiler.llvm.Load) FloatingPointConstant(org.robovm.compiler.llvm.FloatingPointConstant) Mul(org.robovm.compiler.llvm.Mul) XorExpr(soot.jimple.XorExpr) Fptrunc(org.robovm.compiler.llvm.Fptrunc) Local(soot.Local) AddExpr(soot.jimple.AddExpr) Fdiv(org.robovm.compiler.llvm.Fdiv) Zext(org.robovm.compiler.llvm.Zext) InstanceOfExpr(soot.jimple.InstanceOfExpr) OrExpr(soot.jimple.OrExpr) IntegerConstant(org.robovm.compiler.llvm.IntegerConstant) StaticFieldRef(soot.jimple.StaticFieldRef) NegExpr(soot.jimple.NegExpr) UshrExpr(soot.jimple.UshrExpr) InterfaceInvokeExpr(soot.jimple.InterfaceInvokeExpr) GeExpr(soot.jimple.GeExpr) DivExpr(soot.jimple.DivExpr) ConditionExpr(soot.jimple.ConditionExpr) SubExpr(soot.jimple.SubExpr) NewMultiArrayExpr(soot.jimple.NewMultiArrayExpr) OrExpr(soot.jimple.OrExpr) Expr(soot.jimple.Expr) SpecialInvokeExpr(soot.jimple.SpecialInvokeExpr) LengthExpr(soot.jimple.LengthExpr) ShlExpr(soot.jimple.ShlExpr) NeExpr(soot.jimple.NeExpr) InstanceInvokeExpr(soot.jimple.InstanceInvokeExpr) CmpExpr(soot.jimple.CmpExpr) MulExpr(soot.jimple.MulExpr) BinopExpr(soot.jimple.BinopExpr) LtExpr(soot.jimple.LtExpr) ShrExpr(soot.jimple.ShrExpr) CmpgExpr(soot.jimple.CmpgExpr) EqExpr(soot.jimple.EqExpr) NewArrayExpr(soot.jimple.NewArrayExpr) VirtualInvokeExpr(soot.jimple.VirtualInvokeExpr) AndExpr(soot.jimple.AndExpr) LeExpr(soot.jimple.LeExpr) CastExpr(soot.jimple.CastExpr) InvokeExpr(soot.jimple.InvokeExpr) NewExpr(soot.jimple.NewExpr) CmplExpr(soot.jimple.CmplExpr) InstanceOfExpr(soot.jimple.InstanceOfExpr) StaticInvokeExpr(soot.jimple.StaticInvokeExpr) RemExpr(soot.jimple.RemExpr) XorExpr(soot.jimple.XorExpr) AddExpr(soot.jimple.AddExpr) GtExpr(soot.jimple.GtExpr) Bitcast(org.robovm.compiler.llvm.Bitcast) ConstantBitcast(org.robovm.compiler.llvm.ConstantBitcast) NewArrayExpr(soot.jimple.NewArrayExpr) And(org.robovm.compiler.llvm.And) CmpExpr(soot.jimple.CmpExpr) RemExpr(soot.jimple.RemExpr) ShrExpr(soot.jimple.ShrExpr) Value(org.robovm.compiler.llvm.Value) NewExpr(soot.jimple.NewExpr) Fadd(org.robovm.compiler.llvm.Fadd) Xor(org.robovm.compiler.llvm.Xor) NullType(soot.NullType) CmplExpr(soot.jimple.CmplExpr) BinopExpr(soot.jimple.BinopExpr) MulExpr(soot.jimple.MulExpr) GlobalRef(org.robovm.compiler.llvm.GlobalRef) VariableRef(org.robovm.compiler.llvm.VariableRef) Variable(org.robovm.compiler.llvm.Variable) Ashr(org.robovm.compiler.llvm.Ashr) CaughtExceptionRef(soot.jimple.CaughtExceptionRef) NewMultiArrayExpr(soot.jimple.NewMultiArrayExpr) Sext(org.robovm.compiler.llvm.Sext) NegExpr(soot.jimple.NegExpr) PointerType(org.robovm.compiler.llvm.PointerType) Getelementptr(org.robovm.compiler.llvm.Getelementptr) Multianewarray(org.robovm.compiler.trampoline.Multianewarray) UshrExpr(soot.jimple.UshrExpr) ArrayRef(soot.jimple.ArrayRef) Lshr(org.robovm.compiler.llvm.Lshr) InstanceFieldRef(soot.jimple.InstanceFieldRef) Trunc(org.robovm.compiler.llvm.Trunc) ConstantTrunc(org.robovm.compiler.llvm.ConstantTrunc) Instanceof(org.robovm.compiler.trampoline.Instanceof) Sitofp(org.robovm.compiler.llvm.Sitofp) PutField(org.robovm.compiler.trampoline.PutField) Call(org.robovm.compiler.llvm.Call) Trampoline(org.robovm.compiler.trampoline.Trampoline) LengthExpr(soot.jimple.LengthExpr) Immediate(soot.Immediate) FunctionType(org.robovm.compiler.llvm.FunctionType) SubExpr(soot.jimple.SubExpr) Anewarray(org.robovm.compiler.trampoline.Anewarray) PutStatic(org.robovm.compiler.trampoline.PutStatic) IntegerType(org.robovm.compiler.llvm.IntegerType) 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) DivExpr(soot.jimple.DivExpr) ParameterRef(soot.jimple.ParameterRef) ThisRef(soot.jimple.ThisRef) CmpgExpr(soot.jimple.CmpgExpr) Fpext(org.robovm.compiler.llvm.Fpext) Icmp(org.robovm.compiler.llvm.Icmp)

Example 2 with InvokeExpr

use of soot.jimple.InvokeExpr 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 3 with InvokeExpr

use of soot.jimple.InvokeExpr in project robovm by robovm.

the class ObjCMemberPlugin method createCallback.

private void createCallback(SootClass sootClass, SootMethod method, SootMethod annotatedMethod, String selectorName, Type receiverType) {
    Jimple j = Jimple.v();
    SootMethod callbackMethod = getCallbackMethod(selectorName, method, annotatedMethod, receiverType);
    sootClass.addMethod(callbackMethod);
    addCallbackAnnotation(callbackMethod);
    addBindSelectorAnnotation(callbackMethod, selectorName);
    if (!hasAnnotation(annotatedMethod, TYPE_ENCODING) && (isCustomClass(sootClass) || ObjCProtocolProxyPlugin.isObjCProxy(sootClass))) {
        String encoding = generateTypeEncoding(callbackMethod);
        try {
            addTypeEncodingAnnotation(callbackMethod, encoding);
        } catch (IllegalArgumentException e) {
            throw new CompilerException("Failed to determine method type encoding for method " + method + ": " + e.getMessage());
        }
    }
    Body body = j.newBody(callbackMethod);
    callbackMethod.setActiveBody(body);
    PatchingChain<Unit> units = body.getUnits();
    Local thiz = null;
    if (!method.isStatic()) {
        thiz = j.newLocal("$this", receiverType);
        body.getLocals().add(thiz);
        units.add(j.newIdentityStmt(thiz, j.newParameterRef(receiverType, 0)));
    }
    LinkedList<Value> args = new LinkedList<>();
    for (int i = 0; i < method.getParameterCount(); i++) {
        Type t = method.getParameterType(i);
        Local p = j.newLocal("$p" + i, t);
        body.getLocals().add(p);
        units.add(j.newIdentityStmt(p, j.newParameterRef(t, i + 2)));
        args.add(p);
    }
    Local ret = null;
    if (method.getReturnType() != VoidType.v()) {
        ret = j.newLocal("$ret", method.getReturnType());
        body.getLocals().add(ret);
    }
    SootMethodRef targetMethod = method.makeRef();
    if (((RefType) receiverType).getSootClass().isInterface()) {
        @SuppressWarnings("unchecked") List<Type> parameterTypes = method.getParameterTypes();
        targetMethod = Scene.v().makeMethodRef(((RefType) receiverType).getSootClass(), method.getName(), parameterTypes, method.getReturnType(), false);
    }
    InvokeExpr expr = method.isStatic() ? j.newStaticInvokeExpr(targetMethod, args) : (((RefType) receiverType).getSootClass().isInterface() ? j.newInterfaceInvokeExpr(thiz, targetMethod, args) : j.newVirtualInvokeExpr(thiz, targetMethod, args));
    units.add(ret == null ? j.newInvokeStmt(expr) : j.newAssignStmt(ret, expr));
    if (ret != null) {
        units.add(j.newReturnStmt(ret));
    } else {
        units.add(j.newReturnVoidStmt());
    }
}
Also used : SootMethodRef(soot.SootMethodRef) Local(soot.Local) Unit(soot.Unit) LinkedList(java.util.LinkedList) RefType(soot.RefType) RefType(soot.RefType) BooleanType(soot.BooleanType) SootMethodType(org.robovm.compiler.util.generic.SootMethodType) Type(soot.Type) DoubleType(soot.DoubleType) FloatType(soot.FloatType) LongType(soot.LongType) RefLikeType(soot.RefLikeType) PrimType(soot.PrimType) VoidType(soot.VoidType) InvokeExpr(soot.jimple.InvokeExpr) StaticInvokeExpr(soot.jimple.StaticInvokeExpr) Value(soot.Value) SootMethod(soot.SootMethod) CompilerException(org.robovm.compiler.CompilerException) Jimple(soot.jimple.Jimple) Body(soot.Body)

Aggregations

Local (soot.Local)3 PrimType (soot.PrimType)3 RefLikeType (soot.RefLikeType)3 InvokeExpr (soot.jimple.InvokeExpr)3 StaticInvokeExpr (soot.jimple.StaticInvokeExpr)3 ArrayType (org.robovm.compiler.llvm.ArrayType)2 Bitcast (org.robovm.compiler.llvm.Bitcast)2 Call (org.robovm.compiler.llvm.Call)2 ConstantBitcast (org.robovm.compiler.llvm.ConstantBitcast)2 FloatingPointType (org.robovm.compiler.llvm.FloatingPointType)2 FunctionType (org.robovm.compiler.llvm.FunctionType)2 Getelementptr (org.robovm.compiler.llvm.Getelementptr)2 IntegerConstant (org.robovm.compiler.llvm.IntegerConstant)2 IntegerType (org.robovm.compiler.llvm.IntegerType)2 PointerType (org.robovm.compiler.llvm.PointerType)2 Store (org.robovm.compiler.llvm.Store)2 Type (org.robovm.compiler.llvm.Type)2 Value (org.robovm.compiler.llvm.Value)2 Variable (org.robovm.compiler.llvm.Variable)2 Body (soot.Body)2