Mercurial > hg > icedrobot > daneel
changeset 58:8cc04242b09e
Implemented rewriting of MOVE, MOVE_WIDE and MOVE_OBJECT.
Contributed-by: Remi Forax
* rewriter/DexRewriter.java (visitInstrUnaryOp): Implemented.
* rewriter/Interpreter.java: Switched to immutable registers.
* rewriter/Register.java: Made registers immutable.
author | Michael Starzinger <michi@complang.tuwien.ac.at> |
---|---|
date | Mon, 21 Mar 2011 18:24:18 +0100 |
parents | 8c9542073cf4 |
children | 09769b7503f1 |
files | src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java src/main/java/org/icedrobot/daneel/rewriter/Interpreter.java src/main/java/org/icedrobot/daneel/rewriter/Patchable.java src/main/java/org/icedrobot/daneel/rewriter/Register.java |
diffstat | 4 files changed, 144 insertions(+), 76 deletions(-) [+] |
line wrap: on
line diff
--- a/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java Sun Mar 20 21:01:31 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java Mon Mar 21 18:24:18 2011 +0100 @@ -166,6 +166,7 @@ public MethodRewriter(MethodVisitor mv, String desc) { this.mv = new PatchMethodVisitor(mv); this.desc = desc; + this.returnRegisterType = NO_TYPE; } /** @@ -234,6 +235,19 @@ } @Override + public DexAnnotationVisitor visitAnnotation(int visibility, String type) { + // XXX Ignore annotations for now. + return null; + } + + @Override + public DexAnnotationVisitor visitParameterAnnotation(int parameter, + int visibility, String type) { + // XXX Ignore annotations for now. + return null; + } + + @Override public void visitCode(int registerSize, int insSize, int outSize) { mv.visitCode(); this.locals = registerSize - insSize; @@ -460,18 +474,60 @@ throw new UnsupportedOperationException("NYI " + opcode); } } - - @Override - public DexAnnotationVisitor visitAnnotation(int visibility, String type) { - // XXX Ignore annotations for now. - return null; - } @Override - public DexAnnotationVisitor visitParameterAnnotation(int parameter, - int visibility, String type) { - // XXX Ignore annotations for now. - return null; + public void visitInstrUnaryOp(Opcode opcode, int dest, int src) { + final int vdest = registerToSlot(dest); + final int vsrc = registerToSlot(src); + + switch(opcode) { + case MOVE: + case MOVE_FROM16: + case MOVE_16: + case MOVE_WIDE: + case MOVE_WIDE_FROM16: + case MOVE_WIDE_16: + case MOVE_OBJECT: + case MOVE_OBJECT_FROM16: + case MOVE_OBJECT_16: { + final Register register = interpreter.getRegister(vsrc); + int type = register.getType(); + if (Register.isArbitrary(type)) { + int runtimeType = Register.asRuntimeType(type); + mv.setPatchMode(); + mv.visitVarInsn(Register.getJavaOpcode(runtimeType, ILOAD), vsrc); + final AbstractInsnNode load = mv.getLastInsnNode(); + mv.visitVarInsn(Register.getJavaOpcode(runtimeType, ISTORE), vdest); + final AbstractInsnNode store = mv.getLastInsnNode(); + final Patchable patchable = register.getPatchable(); + interpreter.storeArbitraryType(vdest, type, new Patchable() { + @Override + protected void patch(int registerType) { + patchable.doPatch(registerType); + if (registerType == FLOAT_TYPE) { + mv.patch(load, new VarInsnNode(FLOAD, vsrc)); + mv.patch(store, new VarInsnNode(FSTORE, vdest)); + return; + } + if (registerType == DOUBLE_TYPE) { + mv.patch(load, new VarInsnNode(DLOAD, vsrc)); + mv.patch(store, new VarInsnNode(DSTORE, vdest)); + return; + } + } + }); + } else { + mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD), vsrc); + interpreter.load(vsrc, type); + mv.visitVarInsn(Register.getJavaOpcode(type, ISTORE), vdest); + interpreter.store(vdest, type); + } + return; + } + default: + } + + throw new UnsupportedOperationException("NYI " + opcode); } @Override @@ -588,13 +644,6 @@ } @Override - public void visitInstrUnaryOp(Opcode opcode, int vdest, int vsrc) { - vdest = registerToSlot(vdest); - vsrc = registerToSlot(vsrc); - throw new UnsupportedOperationException("NYI " + opcode); - } - - @Override public void visitTryCatch(Label start, Label end, Label handler, String type) { throw new UnsupportedOperationException("NYI"); }
--- a/src/main/java/org/icedrobot/daneel/rewriter/Interpreter.java Sun Mar 20 21:01:31 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/rewriter/Interpreter.java Mon Mar 21 18:24:18 2011 +0100 @@ -48,32 +48,38 @@ public Interpreter(int maxRegisters) { Register[] registers = new Register[maxRegisters]; for (int i = 0; i < maxRegisters; i++) { - registers[i] = new Register(); + registers[i] = Register.UNINITIALIZED; } this.registers = registers; } + public Register getRegister(int vregister) { + return registers[vregister]; + } + public void load(int vregister, int expectedType) { - registers[vregister].load(expectedType); + registers[vregister] = registers[vregister].load(expectedType); } public void store(int vregister, int type) { - registers[vregister].store(type); + if (Register.isArbitrary(type)) { + throw new IllegalArgumentException("invalid type"); + } + + registers[vregister] = new Register(type, null); } public void storeArbitraryType(int vregister, int arbitraryType, Patchable patchable) { - registers[vregister].storeArbitraryType(arbitraryType, patchable); + if (!Register.isArbitrary(arbitraryType)) { + throw new IllegalArgumentException("invalid type"); + } + + registers[vregister] = new Register(arbitraryType, patchable); } public void cloneJoinPoint(Object label) { - Register[] registers = this.registers; - int length = registers.length; - Register[] clone = new Register[length]; - for (int i = 0; i < length; i++) { - clone[i] = registers[i].duplicate(); - } - joinPointMap.put(label, clone); + joinPointMap.put(label, registers.clone()); } public Register[] getJoinPoint(Object label) { @@ -99,7 +105,7 @@ } for (int i = 0; i < registers.length; i++) { - this.registers[i].merge(registers[i]); + this.registers[i] = this.registers[i].merge(registers[i]); } }
--- a/src/main/java/org/icedrobot/daneel/rewriter/Patchable.java Sun Mar 20 21:01:31 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/rewriter/Patchable.java Mon Mar 21 18:24:18 2011 +0100 @@ -38,12 +38,16 @@ package org.icedrobot.daneel.rewriter; abstract class Patchable { - private boolean patchCalled; + private int type = Register.NO_TYPE; + public int getType() { + return type; + } + void doPatch(int registerType) { - if (patchCalled) + if (type != Register.NO_TYPE) return; - patchCalled = true; + type = registerType; patch(registerType); }
--- a/src/main/java/org/icedrobot/daneel/rewriter/Register.java Sun Mar 20 21:01:31 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/rewriter/Register.java Mon Mar 21 18:24:18 2011 +0100 @@ -60,83 +60,92 @@ private static final int ARBITRARY_MASK = Integer.MIN_VALUE; - private int type; - - private Patchable patchable; - - Register() { - type = NO_TYPE; - // and patchable = null - } - - public void load(int expectedType) { - assert (expectedType & ARBITRARY_MASK) == 0; + static final Register UNINITIALIZED = new Register(NO_TYPE, null); + + private final int type; - if ((this.type & ARBITRARY_MASK) != 0 && patchable != null) { - patchable.doPatch(expectedType); - patchable = null; - } - this.type = expectedType; - } + private final Patchable patchable; - public void store(int type) { + Register(int type, Patchable patchable) { this.type = type; - this.patchable = null; - } - - public void storeArbitraryType(int arbitraryType, Patchable patchable) { - this.type = arbitraryType; this.patchable = patchable; } - public Register duplicate() { - Register register = new Register(); - register.type = type; - register.patchable = patchable; - return register; + public int getType() { + if (patchable != null) { + int patchableType = patchable.getType(); + return (patchableType != NO_TYPE)? patchableType: type; + } + return type; + } + + public Patchable getPatchable() { + return patchable; } - public void merge(Register register) { - int thisType = this.type; - int registerType = register.type; - if (thisType == registerType) { // short cut - return; + public Register load(int expectedType) { + if (isArbitrary(expectedType)) { + throw new IllegalArgumentException("invalid type"); } - boolean thisIsArbitrary = (thisType & ARBITRARY_MASK) != 0; - boolean registerIsArbitrary = (registerType & ARBITRARY_MASK) != 0; + if (patchable != null) { + patchable.doPatch(expectedType); + } + return new Register(expectedType, null); + } + + public Register merge(Register register) { + int thisType = getType(); + int registerType = register.getType(); + + if (thisType == NO_TYPE) { + return register; + } + if (registerType == NO_TYPE) { + return this; + } + + boolean thisIsArbitrary = isArbitrary(thisType); + boolean registerIsArbitrary = isArbitrary(registerType); if (thisIsArbitrary) { if (registerIsArbitrary) { // maybe there are not compatible, but this means that // the code is malformed - patchable = Patchable.union(patchable, register.patchable); - return; + return new Register(thisType, Patchable.union(patchable, register.patchable)); } if (patchable != null) { // otherwise, it's an uninitialized value patchable.doPatch(registerType); - patchable = null; } - this.type = registerType; - return; + return new Register(registerType, null); } // the two register aren't arbitrary, we don't check is they are compatible // because they can be incompatible if the register is no more used // This should not be the common case because dx remove unused registers if (!registerIsArbitrary) { - return; + return this; } if (register.patchable != null) { register.patchable.doPatch(thisType); - register.patchable = null; } - register.type = thisType; + return new Register(thisType, null); + } + + public static boolean isArbitrary(int type) { + return (type & ARBITRARY_MASK) != 0; + } + + public static int asRuntimeType(int type) { + return (type == LONG_TYPE || type == DOUBLE_TYPE) ? LONG_TYPE + : INT_TYPE; } public static int getJavaOpcode(int type, int opcode) { - assert (type & ARBITRARY_MASK) == 0; + if (isArbitrary(type)) { + throw new IllegalArgumentException("invalid type"); + } if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) { return opcode + ((type != BOOLEAN_TYPE) ? type : BYTE_TYPE);