Home | History | Annotate | Download | only in classfile
      1 package annotations.io.classfile;
      2 
      3 import org.objectweb.asm.ClassAdapter;
      4 import org.objectweb.asm.ClassReader;
      5 import org.objectweb.asm.ClassVisitor;
      6 import org.objectweb.asm.Handle;
      7 import org.objectweb.asm.Label;
      8 import org.objectweb.asm.MethodAdapter;
      9 import org.objectweb.asm.MethodVisitor;
     10 import org.objectweb.asm.Opcodes;
     11 
     12 import annotations.io.DebugWriter;
     13 import annotations.util.AbstractClassVisitor;
     14 
     15 public class CodeOffsetAdapter extends ClassAdapter {
     16   static final DebugWriter debug;
     17   final ClassReader cr;
     18   final char[] buf;
     19   int methodStart;
     20   int codeStart;
     21   int offset;
     22 
     23   static {
     24     debug = new DebugWriter();
     25     debug.setEnabled(false);
     26   }
     27 
     28   public CodeOffsetAdapter(ClassReader cr) {
     29     this(cr, new AbstractClassVisitor());
     30   }
     31 
     32   public CodeOffsetAdapter(ClassReader cr, ClassVisitor v) {
     33     super(v);
     34     this.cr = cr;
     35     // const pool size is (not lowest) upper bound of string length
     36     buf = new char[cr.header];
     37     methodStart = cr.header + 6;
     38     methodStart += 4 + 2 * cr.readUnsignedShort(methodStart);
     39     for (int i = cr.readUnsignedShort(methodStart-2); i > 0; --i) {
     40       methodStart += 8;
     41       for (int j = cr.readUnsignedShort(methodStart-2); j > 0; --j) {
     42         methodStart += 6 + cr.readInt(methodStart+2);
     43       }
     44     }
     45     methodStart += 2;
     46   }
     47 
     48   @Override
     49   public MethodVisitor visitMethod(int access,
     50       String name, String desc,
     51       String signature, String[] exceptions) {
     52     MethodVisitor v =
     53         super.visitMethod(access, name, desc, signature, exceptions);
     54     return new MethodAdapter(v) {
     55       private int methodEnd;
     56 
     57       {
     58         String name = cr.readUTF8(methodStart + 2, buf);
     59         String desc = cr.readUTF8(methodStart + 4, buf);
     60         int attrCount = cr.readUnsignedShort(methodStart + 6);
     61         debug.debug("visiting %s%s (%d)%n", name, desc, methodStart);
     62         debug.debug("%d attributes%n", attrCount);
     63         methodEnd = methodStart + 8;
     64 
     65         // find code attribute
     66         codeStart = methodEnd;
     67         if (attrCount > 0) {
     68           while (--attrCount >= 0) {
     69             String attrName = cr.readUTF8(codeStart, buf);
     70             debug.debug("attribute %s%n", attrName);
     71             if ("Code".equals(attrName)) {
     72               codeStart += 6;
     73               offset = codeStart + cr.readInt(codeStart - 4);
     74               codeStart += 8;
     75               while (--attrCount >= 0) {
     76                 debug.debug("attribute %s%n", cr.readUTF8(offset, buf));
     77                 offset += 6 + cr.readInt(offset + 2);
     78               }
     79               methodEnd = offset;
     80               break;
     81             }
     82             codeStart += 6 + cr.readInt(codeStart + 2);
     83             methodEnd = codeStart;
     84           }
     85         }
     86         offset = 0;
     87       }
     88 
     89       private int readInt(int i) {
     90         return cr.readInt(codeStart + i);
     91       }
     92 
     93       @Override
     94       public void visitFieldInsn(int opcode,
     95           String owner, String name, String desc) {
     96         super.visitFieldInsn(opcode, owner, name, desc);
     97         debug.debug("%d visitFieldInsn(%d, %s, %s, %s)%n", offset,
     98             opcode, owner, name, desc);
     99         offset += 3;
    100       }
    101 
    102       @Override
    103       public void visitIincInsn(int var, int increment) {
    104         super.visitIincInsn(var, increment);
    105         debug.debug("%d visitIincInsn(%d, %d)%n", offset, var, increment);
    106         offset += 3;
    107       }
    108 
    109       @Override
    110       public void visitInsn(int opcode) {
    111         super.visitInsn(opcode);
    112         debug.debug("%d visitInsn(%d)%n", offset, opcode);
    113         ++offset;
    114       }
    115 
    116       @Override
    117       public void visitIntInsn(int opcode, int operand) {
    118         super.visitIntInsn(opcode, operand);
    119         debug.debug("%d visitIntInsn(%d, %d)%n", offset, opcode, operand);
    120         offset += opcode == Opcodes.SIPUSH ? 3 : 2;
    121       }
    122 
    123       @Override
    124       public void visitInvokeDynamicInsn(String name, String desc,
    125           Handle bsm, Object... bsmArgs) {
    126         super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
    127         debug.debug("%d visitInvokeDynamicInsn(%s, %s)%n", offset,
    128             name, desc, bsm, bsmArgs);
    129         offset += 5;
    130       }
    131 
    132       @Override
    133       public void visitJumpInsn(int opcode, Label label) {
    134         super.visitJumpInsn(opcode, label);
    135         debug.debug("%d visitJumpInsn(%d, %s)%n", offset, opcode, label);
    136         // account for wide instructions goto_w (200) and jsr_w (201)
    137         offset += cr.readByte(codeStart + offset) < 200 ? 3 : 4;
    138         assert offset > 0 && methodEnd > codeStart + offset;
    139       }
    140 
    141       @Override
    142       public void visitLdcInsn(Object cst) {
    143         super.visitLdcInsn(cst);
    144         debug.debug("%d visitLdcInsn(%s)%n", offset, cst);
    145         // account for wide instructions ldc_w (19) and ldc2_w (20)
    146         offset += cr.readByte(codeStart + offset) > 18 ? 3 : 2;
    147         assert offset > 0 && methodEnd > codeStart + offset;
    148       }
    149 
    150       @Override
    151       public void visitLookupSwitchInsn(Label dflt, int[] keys,
    152           Label[] labels) {
    153         super.visitLookupSwitchInsn(dflt, keys, labels);
    154         debug.debug("%d visitLookupSwitchInsn(%s)%n", offset,
    155             dflt, keys, labels);
    156         offset += 8 - (offset & 3);
    157         offset += 4 + 8 * readInt(offset);
    158         assert offset > 0 && methodEnd > codeStart + offset;
    159       }
    160 
    161       @Override
    162       public void visitMethodInsn(int opcode,
    163           String owner, String name, String desc) {
    164         super.visitMethodInsn(opcode, owner, name, desc);
    165         debug.debug("%d visitMethodInsn(%d, %s, %s, %s)%n", offset,
    166             opcode, owner, name, desc);
    167         offset += opcode == Opcodes.INVOKEINTERFACE ? 5 : 3;
    168       }
    169 
    170       @Override
    171       public void visitMultiANewArrayInsn(String desc, int dims) {
    172         super.visitMultiANewArrayInsn(desc, dims);
    173         debug.debug("%d visitMultiANewArrayInsn(%s, %d)%n", offset,
    174             desc, dims);
    175         offset += 4;
    176       }
    177 
    178       @Override
    179       public void visitTableSwitchInsn(int min, int max,
    180           Label dflt, Label[] labels) {
    181         super.visitTableSwitchInsn(min, max, dflt, labels);
    182         debug.debug("%d visitTableSwitchInsn(%d, %d, %s)%n", offset,
    183             min, max, dflt, labels);
    184         offset += 8 - (offset & 3);
    185         offset += 4 * (readInt(offset + 4) - readInt(offset) + 3);
    186         assert offset > 0 && methodEnd > codeStart + offset;
    187       }
    188 
    189       @Override
    190       public void visitTypeInsn(int opcode, String desc) {
    191         super.visitTypeInsn(opcode, desc);
    192         debug.debug("%d visitTypeInsn(%d, %s)%n", offset, opcode, desc);
    193         offset += 3;
    194       }
    195 
    196       @Override
    197       public void visitVarInsn(int opcode, int var) {
    198         super.visitVarInsn(opcode, var);
    199         debug.debug("%d visitVarInsn(%d, %d)%n", offset, opcode, var);
    200         offset += var < 4 ? 1 : 2;
    201       }
    202 
    203       @Override
    204       public void visitEnd() {
    205         methodStart = methodEnd;
    206       }
    207     };
    208   }
    209 
    210   public int getMethodCodeOffset() { return offset; }
    211 
    212   public int getBytecodeOffset() { return codeStart + offset; }
    213 }
    214