| package annotations.io.classfile; |
| |
| import org.objectweb.asm.ClassReader; |
| import org.objectweb.asm.Handle; |
| import org.objectweb.asm.Label; |
| import org.objectweb.asm.MethodAdapter; |
| import org.objectweb.asm.MethodVisitor; |
| import org.objectweb.asm.Opcodes; |
| |
| class MethodCodeOffsetAdapter extends MethodAdapter { |
| private final ClassReader cr; |
| private final int methodStart; |
| private int offset = 0; |
| private int codeStart = 0; |
| private int attrCount = 0; |
| |
| public MethodCodeOffsetAdapter(ClassReader classReader, |
| MethodVisitor methodVisitor, int start) { |
| super(methodVisitor); |
| char[] buf = new char[classReader.header]; |
| this.methodStart = start; |
| cr = classReader; |
| // const pool size is (not lowest) upper bound of string length |
| codeStart = start; |
| attrCount = classReader.readUnsignedShort(codeStart + 6); |
| |
| // find code attribute |
| codeStart += 8; |
| while (attrCount > 0) { |
| String attrName = classReader.readUTF8(codeStart, buf); |
| if ("Code".equals(attrName)) { break; } |
| codeStart += 6 + classReader.readInt(codeStart + 2); |
| --attrCount; |
| } |
| } |
| |
| private int readInt(int i) { |
| return cr.readInt(codeStart + i); |
| } |
| |
| public int getMethodCodeStart() { return methodStart; } |
| |
| public int getMethodCodeOffset() { return offset; } |
| |
| public int getClassCodeOffset() { return codeStart + offset; } |
| |
| @Override |
| public void visitFieldInsn(int opcode, |
| String owner, String name, String desc) { |
| super.visitFieldInsn(opcode, owner, name, desc); |
| offset += 3; |
| } |
| |
| @Override |
| public void visitIincInsn(int var, int increment) { |
| super.visitIincInsn(var, increment); |
| offset += 3; |
| } |
| |
| @Override |
| public void visitInsn(int opcode) { |
| super.visitInsn(opcode); |
| ++offset; |
| } |
| |
| @Override |
| public void visitIntInsn(int opcode, int operand) { |
| super.visitIntInsn(opcode, operand); |
| offset += opcode == Opcodes.SIPUSH ? 3 : 2; |
| } |
| |
| @Override |
| public void visitInvokeDynamicInsn(String name, String desc, |
| Handle bsm, Object... bsmArgs) { |
| super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); |
| offset += 5; |
| } |
| |
| @Override |
| public void visitJumpInsn(int opcode, Label label) { |
| super.visitJumpInsn(opcode, label); |
| offset += 3; |
| } |
| |
| @Override |
| public void visitLdcInsn(Object cst) { |
| super.visitLdcInsn(cst); |
| offset += 2; |
| } |
| |
| @Override |
| public void visitLookupSwitchInsn(Label dflt, int[] keys, |
| Label[] labels) { |
| super.visitLookupSwitchInsn(dflt, keys, labels); |
| offset += 8 - ((offset - codeStart) & 3); |
| offset += 4 + 8 * readInt(offset); |
| } |
| |
| @Override |
| public void visitMethodInsn(int opcode, |
| String owner, String name, String desc) { |
| super.visitMethodInsn(opcode, owner, name, desc); |
| offset += opcode == Opcodes.INVOKEINTERFACE ? 5 : 3; |
| } |
| |
| @Override |
| public void visitMultiANewArrayInsn(String desc, int dims) { |
| super.visitMultiANewArrayInsn(desc, dims); |
| offset += 4; |
| } |
| |
| @Override |
| public void visitTableSwitchInsn(int min, int max, |
| Label dflt, Label[] labels) { |
| super.visitTableSwitchInsn(min, max, dflt, labels); |
| offset += 8 - ((offset - codeStart) & 3); |
| offset += 4 * (readInt(offset + 4) - readInt(offset) + 3); |
| } |
| |
| @Override |
| public void visitTypeInsn(int opcode, String desc) { |
| super.visitTypeInsn(opcode, desc); |
| offset += 3; |
| } |
| |
| @Override |
| public void visitVarInsn(int opcode, int var) { |
| super.visitVarInsn(opcode, var); |
| offset += var < 4 ? 1 : 2; |
| } |
| |
| @Override |
| public void visitEnd() { |
| offset = -1; // invalidated |
| } |
| } |