Mercurial > hg > icedrobot > daneel
changeset 73:15cfcc7a8756
This patch implements the opcode corresponding to:
- instanceof
- test condition ==, !=, <=, >= for ints
- conversions (int -> double etc.)
And fix 2 bugs:
- null as a constant (bug found by Volker).
- Register.load must not change its type if not untyped
Reviewed by: Michael Starzinger
src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
src/main/java/org/icedrobot/daneel/rewriter/Register.java | 13 ++++--
2 files changed, 132 insertions(+), 32 deletions(-)
author | forax |
---|---|
date | Thu, 24 Mar 2011 18:15:14 +0100 |
parents | 57fe21b3757e |
children | 4ccee27bea05 |
files | src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java src/main/java/org/icedrobot/daneel/rewriter/Register.java |
diffstat | 2 files changed, 132 insertions(+), 32 deletions(-) [+] |
line wrap: on
line diff
--- a/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java Wed Mar 23 23:18:49 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java Thu Mar 24 18:15:14 2011 +0100 @@ -59,6 +59,7 @@ import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.VarInsnNode; @@ -270,6 +271,17 @@ } } + private void visitNotInstr(int type) { + org.objectweb.asm.Label falsePart = new org.objectweb.asm.Label(); + org.objectweb.asm.Label endPart = new org.objectweb.asm.Label(); + mv.visitJumpInsn(IFNE, falsePart); + mv.visitInsn((type == INT_TYPE)? ICONST_1: LCONST_1); + mv.visitJumpInsn(GOTO, endPart); + mv.visitLabel(falsePart); + mv.visitInsn((type == INT_TYPE)? ICONST_0: LCONST_0); + mv.visitLabel(endPart); + } + private static AssertionError newAssertionError(Opcode opcode) { return new AssertionError("Invalid opcode: " + opcode); } @@ -487,6 +499,12 @@ mv.patch(ldc, new LdcInsnNode(Float .intBitsToFloat(value))); mv.patch(istore, new VarInsnNode(FSTORE, sdest)); + return; + } + if (registerType == OBJECT_TYPE || Register.isArray(registerType)) { + mv.patch(ldc, new InsnNode(ACONST_NULL)); + mv.patch(istore, new VarInsnNode(ASTORE, sdest)); + return; } } }); @@ -509,6 +527,7 @@ mv.patch(ldc, new LdcInsnNode(Double.longBitsToDouble(value))); mv.patch(lstore, new VarInsnNode(DSTORE, sdest)); + return; } } }); @@ -540,8 +559,12 @@ } break; } - default: + case MOVE_EXCEPTION: throw new UnsupportedOperationException("NYI " + opcode); + default: //MONITOR_ENTER, MONITOR_EXIT, THROW. + mv.visitVarInsn(ALOAD, srcOrDst); + interpreter.load(srcOrDst, OBJECT_TYPE); + mv.visitInsn(toJavaOpcode[opcode.ordinal()]); } } @@ -550,6 +573,7 @@ fixStackAfterAMethodCall(); final int vdest = registerToSlot(dest); final int vsrc = registerToSlot(src); + int srcType = INT_TYPE, dstType; switch(opcode) { case MOVE: case MOVE_FROM16: @@ -584,6 +608,11 @@ mv.patch(store, new VarInsnNode(DSTORE, vdest)); return; } + if (registerType == OBJECT_TYPE || Register.isArray(registerType)) { + mv.patch(load, new VarInsnNode(ALOAD, vsrc)); + mv.patch(store, new VarInsnNode(ASTORE, vdest)); + return; + } } }); } else { @@ -594,10 +623,44 @@ } return; } - default: + + case NEG_INT: case NOT_INT: + dstType = INT_TYPE; + break; + case NEG_LONG: case NOT_LONG: + srcType = dstType = LONG_TYPE; + break; + case NEG_FLOAT: + srcType = dstType = FLOAT_TYPE; + break; + case NEG_DOUBLE: + srcType = dstType = DOUBLE_TYPE; + break; + + case INT_TO_BYTE: + case INT_TO_CHAR: + case INT_TO_SHORT: + dstType = BYTE_TYPE + opcode.ordinal() - Opcode.INT_TO_BYTE.ordinal(); + break; + + default: { + int conversion = opcode.ordinal() - Opcode.INT_TO_LONG.ordinal(); + int div = conversion / 3; + int modulo = conversion % 3; + srcType = INT_TYPE + div; + dstType = INT_TYPE + ((modulo < div)? modulo: modulo + 1); + } } - throw new UnsupportedOperationException("NYI " + opcode); + mv.visitVarInsn(Register.getJavaOpcode(srcType, ILOAD), vsrc); + interpreter.load(vsrc, srcType); + if (opcode == Opcode.NOT_INT || opcode == Opcode.NOT_LONG) { + visitNotInstr(srcType); + } else { + mv.visitInsn(toJavaOpcode[opcode.ordinal()]); + } + mv.visitVarInsn(Register.getJavaOpcode(dstType, ISTORE), vdest); + interpreter.store(vdest, dstType); } @Override @@ -614,37 +677,42 @@ opcode = Opcode.getOpcode(opcode.ordinal() + OP_2ADDR_SHIFT); } - int type; + int srcType, dstType; switch(opcode) { case CMPL_FLOAT: case CMPG_FLOAT: case ADD_FLOAT: case SUB_FLOAT: case MUL_FLOAT: case DIV_FLOAT: case REM_FLOAT: - type = FLOAT_TYPE; + srcType = FLOAT_TYPE; + dstType = (opcode == Opcode.CMPL_FLOAT || + opcode == Opcode.CMPG_FLOAT) ? INT_TYPE : FLOAT_TYPE; break; case CMPL_DOUBLE: case CMPG_DOUBLE: case ADD_DOUBLE: case SUB_DOUBLE: case MUL_DOUBLE: case DIV_DOUBLE: case REM_DOUBLE: - type = DOUBLE_TYPE; + srcType = DOUBLE_TYPE; + dstType = (opcode == Opcode.CMPL_DOUBLE || + opcode == Opcode.CMPG_DOUBLE) ? INT_TYPE : DOUBLE_TYPE; break; case CMP_LONG: case ADD_LONG: case SUB_LONG: case MUL_LONG: case DIV_LONG: case REM_LONG: case AND_LONG: case OR_LONG: case XOR_LONG: case SHL_LONG: case SHR_LONG: case USHR_LONG: - type = LONG_TYPE; + srcType = LONG_TYPE; + dstType = (opcode == Opcode.CMP_LONG) ? INT_TYPE : LONG_TYPE; break; // ADD_INT, SUB_INT, MUL_INT, DIV_INT, REM_INT, // AND_INT, OR_INT, XOR_INT, SHL_INT, SHR_INT, USHR_INT, default: - type = INT_TYPE; + srcType = dstType = INT_TYPE; } - mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD), vsrc1); - interpreter.load(vsrc1, type); - mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD), vsrc2); - interpreter.load(vsrc2, type); + mv.visitVarInsn(Register.getJavaOpcode(srcType, ILOAD), vsrc1); + interpreter.load(vsrc1, srcType); + mv.visitVarInsn(Register.getJavaOpcode(srcType, ILOAD), vsrc2); + interpreter.load(vsrc2, srcType); mv.visitInsn(toJavaOpcode[opcode.ordinal()]); - mv.visitVarInsn(Register.getJavaOpcode(type, ISTORE), vdest); - interpreter.store(vdest, type); + mv.visitVarInsn(Register.getJavaOpcode(dstType, ISTORE), vdest); + interpreter.store(vdest, dstType); } private static final int OP_2ADDR_SHIFT = @@ -758,8 +826,19 @@ } } - - // unimplemented + @Override + public void visitInstrInstanceof(Opcode opcode, int vdest, int vsrc, + String type) { + fixStackAfterAMethodCall(); + vdest = registerToSlot(vdest); + vsrc = registerToSlot(vsrc); + mv.visitVarInsn(ALOAD, vsrc); + Type asmType = Type.getType(type); + interpreter.load(vsrc, getTypeFromASMType(asmType)); + mv.visitTypeInsn(INSTANCEOF, asmType.getInternalName()); + mv.visitVarInsn(ISTORE, vdest); + interpreter.store(vdest, BOOLEAN_TYPE); + } @Override public void visitInstrIfTest(Opcode opcode, int vsrc1, int vsrc2, @@ -767,9 +846,36 @@ fixStackAfterAMethodCall(); vsrc1 = registerToSlot(vsrc1); vsrc2 = registerToSlot(vsrc2); - throw new UnsupportedOperationException("NYI " + opcode); + org.objectweb.asm.Label asmLabel = getASMLabel(label); + if (opcode == Opcode.IF_EQ || opcode == Opcode.IF_NE) { + int src1Type = interpreter.getRegister(vsrc1).getType(); + int src2Type = interpreter.getRegister(vsrc2).getType(); + int javaOpcode; + int type; + if (src1Type == INT_TYPE || src2Type == INT_TYPE) { + type = INT_TYPE; + javaOpcode = (opcode == Opcode.IF_EQ)? IF_ICMPEQ: IF_ICMPNE; + } else { // OBJECT_TYPE or array + type = OBJECT_TYPE; + javaOpcode = (opcode == Opcode.IF_EQ)? IF_ACMPEQ: IF_ACMPNE; + } + mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD), vsrc1); + interpreter.load(vsrc1, OBJECT_TYPE); + mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD), vsrc2); + interpreter.load(vsrc2, OBJECT_TYPE); + mv.visitJumpInsn(javaOpcode, asmLabel); + } else { // IF_LT, IF_GE, IF_GT, IF_LE + mv.visitVarInsn(ILOAD, vsrc1); + interpreter.load(vsrc1, INT_TYPE); + mv.visitVarInsn(ILOAD, vsrc2); + interpreter.load(vsrc2, INT_TYPE); + mv.visitJumpInsn(toJavaOpcode[opcode.ordinal()], asmLabel); + } } - + + + // unimplemented + @Override public void visitInstrFillArrayData(Opcode opcode, int vsrc, Object arrayData) { @@ -787,15 +893,6 @@ } @Override - public void visitInstrInstanceof(Opcode opcode, int vdest, int vsrc, - String type) { - fixStackAfterAMethodCall(); - vdest = registerToSlot(vdest); - vsrc = registerToSlot(vsrc); - throw new UnsupportedOperationException("NYI " + opcode); - } - - @Override public void visitInstrSwitch(Opcode opcode, int vsrc, Map<Integer, Label> labels) { fixStackAfterAMethodCall();
--- a/src/main/java/org/icedrobot/daneel/rewriter/Register.java Wed Mar 23 23:18:49 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/rewriter/Register.java Thu Mar 24 18:15:14 2011 +0100 @@ -124,12 +124,14 @@ return patchable; } - /** Simulate a load from the current register. - * If the type of the current register is {@link #isUntyped(int) untyped} - * the corresponding {@link Patchable patchable} will be called. + /** + * Simulate a load from the current register. If the type of the current + * register is {@link #isUntyped(int) untyped} the corresponding + * {@link Patchable patchable} will be called. * * @param expectedType the expected type of the register - * @return a new register with the expected type + * @return if the current register is untyped, a new register with the + * expected type otherwise the current register. */ public Register load(int expectedType) { if (isUntyped(expectedType)) { @@ -138,8 +140,9 @@ if (patchable != null) { patchable.doPatch(expectedType); + return new Register(expectedType, null); } - return new Register(expectedType, null); + return this; } /** Merge two registers and compute the type of the resulting register.