📄 codewriter.java
字号:
-2, //DRETURN, // - -1, //ARETURN, // - 0, //RETURN, // - NA, //GETSTATIC, // visitFieldInsn NA, //PUTSTATIC, // - NA, //GETFIELD, // - NA, //PUTFIELD, // - NA, //INVOKEVIRTUAL, // visitMethodInsn NA, //INVOKESPECIAL, // - NA, //INVOKESTATIC, // - NA, //INVOKEINTERFACE, // - NA, //UNUSED, // NOT VISITED 1, //NEW, // visitTypeInsn 0, //NEWARRAY, // visitIntInsn 0, //ANEWARRAY, // visitTypeInsn 0, //ARRAYLENGTH, // visitInsn NA, //ATHROW, // - 0, //CHECKCAST, // visitTypeInsn 0, //INSTANCEOF, // - -1, //MONITORENTER, // visitInsn -1, //MONITOREXIT, // - NA, //WIDE, // NOT VISITED NA, //MULTIANEWARRAY, // visitMultiANewArrayInsn -1, //IFNULL, // visitJumpInsn -1, //IFNONNULL, // - NA, //GOTO_W, // - NA, //JSR_W, // - }; for (i = 0; i < b.length; ++i) { System.err.print((char)('E' + b[i])); } System.err.println(); */ } // -------------------------------------------------------------------------- // Constructor // -------------------------------------------------------------------------- /** * Constructs a CodeWriter. * * @param cw the class writer in which the method must be added. * @param computeMaxs <tt>true</tt> if the maximum stack size and number of * local variables must be automatically computed. */ protected CodeWriter (final ClassWriter cw, final boolean computeMaxs) { if (cw.firstMethod == null) { cw.firstMethod = this; cw.lastMethod = this; } else { cw.lastMethod.next = this; cw.lastMethod = this; } this.cw = cw; this.computeMaxs = computeMaxs; if (computeMaxs) { // pushes the first block onto the stack of blocks to be visited currentBlock = new Label(); currentBlock.pushed = true; blockStack = currentBlock; } } /** * Initializes this CodeWriter to define the bytecode of the specified method. * * @param access the method's access flags (see {@link Constants}). * @param name the method's name. * @param desc the method's descriptor (see {@link Type Type}). * @param exceptions the internal names of the method's exceptions. May be * <tt>null</tt>. */ protected void init ( final int access, final String name, final String desc, final String[] exceptions) { this.access = access; this.name = cw.newUTF8(name); this.desc = cw.newUTF8(desc); if (exceptions != null && exceptions.length > 0) { exceptionCount = exceptions.length; this.exceptions = new int[exceptionCount]; for (int i = 0; i < exceptionCount; ++i) { this.exceptions[i] = cw.newClass(exceptions[i]).index; } } if (computeMaxs) { // updates maxLocals int size = getArgumentsAndReturnSizes(desc) >> 2; if ((access & Constants.ACC_STATIC) != 0) { --size; } if (size > maxLocals) { maxLocals = size; } } } // -------------------------------------------------------------------------- // Implementation of the CodeVisitor interface // -------------------------------------------------------------------------- public void visitInsn (final int opcode) { if (computeMaxs) { // updates current and max stack sizes int size = stackSize + SIZE[opcode]; if (size > maxStackSize) { maxStackSize = size; } stackSize = size; // if opcode == ATHROW or xRETURN, ends current block (no successor) if ((opcode >= Constants.IRETURN && opcode <= Constants.RETURN) || opcode == Constants.ATHROW) { if (currentBlock != null) { currentBlock.maxStackSize = maxStackSize; currentBlock = null; } } } // adds the instruction to the bytecode of the method code.put1(opcode); } public void visitIntInsn (final int opcode, final int operand) { if (computeMaxs && opcode != Constants.NEWARRAY) { // updates current and max stack sizes only if opcode == NEWARRAY // (stack size variation = 0 for BIPUSH or SIPUSH) int size = stackSize + 1; if (size > maxStackSize) { maxStackSize = size; } stackSize = size; } // adds the instruction to the bytecode of the method if (opcode == Constants.SIPUSH) { code.put12(opcode, operand); } else { // BIPUSH or NEWARRAY code.put11(opcode, operand); } } public void visitVarInsn (final int opcode, final int var) { if (computeMaxs) { // updates current and max stack sizes if (opcode == Constants.RET) { // no stack change, but end of current block (no successor) if (currentBlock != null) { currentBlock.maxStackSize = maxStackSize; currentBlock = null; } } else { // xLOAD or xSTORE int size = stackSize + SIZE[opcode]; if (size > maxStackSize) { maxStackSize = size; } stackSize = size; } // updates max locals int n; if (opcode == Constants.LLOAD || opcode == Constants.DLOAD || opcode == Constants.LSTORE || opcode == Constants.DSTORE) { n = var + 2; } else { n = var + 1; } if (n > maxLocals) { maxLocals = n; } } // adds the instruction to the bytecode of the method if (var < 4 && opcode != Constants.RET) { int opt; if (opcode < Constants.ISTORE) { opt = 26 /*ILOAD_0*/ + ((opcode - Constants.ILOAD) << 2) + var; } else { opt = 59 /*ISTORE_0*/ + ((opcode - Constants.ISTORE) << 2) + var; } code.put1(opt); } else if (var >= 256) { code.put1(196 /*WIDE*/).put12(opcode, var); } else { code.put11(opcode, var); } } public void visitTypeInsn (final int opcode, final String desc) { if (computeMaxs && opcode == Constants.NEW) { // updates current and max stack sizes only if opcode == NEW // (stack size variation = 0 for ANEWARRAY, CHECKCAST, INSTANCEOF) int size = stackSize + 1; if (size > maxStackSize) { maxStackSize = size; } stackSize = size; } // adds the instruction to the bytecode of the method code.put12(opcode, cw.newClass(desc).index); } public void visitFieldInsn ( final int opcode, final String owner, final String name, final String desc) { if (computeMaxs) { int size; // computes the stack size variation char c = desc.charAt(0); switch (opcode) { case Constants.GETSTATIC: size = stackSize + (c == 'D' || c == 'J' ? 2 : 1); break; case Constants.PUTSTATIC: size = stackSize + (c == 'D' || c == 'J' ? -2 : -1); break; case Constants.GETFIELD: size = stackSize + (c == 'D' || c == 'J' ? 1 : 0); break; //case Constants.PUTFIELD: default: size = stackSize + (c == 'D' || c == 'J' ? -3 : -2); break; } // updates current and max stack sizes if (size > maxStackSize) { maxStackSize = size; } stackSize = size; } // adds the instruction to the bytecode of the method code.put12(opcode, cw.newField(owner, name, desc).index); } public void visitMethodInsn ( final int opcode, final String owner, final String name, final String desc) { Item i; if (opcode == Constants.INVOKEINTERFACE) { i = cw.newItfMethod(owner, name, desc); } else { i = cw.newMethod(owner, name, desc); } int argSize = i.intVal; if (computeMaxs) { // computes the stack size variation. In order not to recompute several // times this variation for the same Item, we use the intVal field of // this item to store this variation, once it has been computed. More // precisely this intVal field stores the sizes of the arguments and of // the return value corresponding to desc. if (argSize == 0) { // the above sizes have not been computed yet, so we compute them... argSize = getArgumentsAndReturnSizes(desc); // ... and we save them in order not to recompute them in the future i.intVal = argSize; } int size; if (opcode == Constants.INVOKESTATIC) { size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1; } else { size = stackSize - (argSize >> 2) + (argSize & 0x03); } // updates current and max stack sizes if (size > maxStackSize) { maxStackSize = size; } stackSize = size; } // adds the instruction to the bytecode of the method if (opcode == Constants.INVOKEINTERFACE) { if (!computeMaxs) { if (argSize == 0) { argSize = getArgumentsAndReturnSizes(desc); i.intVal = argSize; } } code.put12(Constants.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0); } else { code.put12(opcode, i.index); } } public void visitJumpInsn (final int opcode, final Label label) { if (CHECK) { if (label.owner == null) { label.owner = this; } else if (label.owner != this) { throw new IllegalArgumentException(); } } if (computeMaxs) { if (opcode == Constants.GOTO) { // no stack change, but end of current block (with one new successor) if (currentBlock != null) { currentBlock.maxStackSize = maxStackSize; addSuccessor(stackSize, label); currentBlock = null; } } else if (opcode == Constants.JSR) { if (currentBlock != null) { addSuccessor(stackSize + 1, label); } } else { // updates current stack size (max stack size unchanged because stack // size variation always negative in this case) stackSize += SIZE[opcode]; if (currentBlock != null) { addSuccessor(stackSize, label); } } } // adds the instruction to the bytecode of the method if (label.resolved && label.position - code.length < Short.MIN_VALUE) { // case of a backward jump with an offset < -32768. In this case we // automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx <l> // with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the "opposite" opcode // of IFxxx (i.e., IFNE for IFEQ) and where <l'> designates the // instruction just after the GOTO_W. if (opcode == Constants.GOTO) { code.put1(200); // GOTO_W } else if (opcode == Constants.JSR) { code.put1(201); // JSR_W } else { code.put1(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1); code.put2(8); // jump offset code.put1(200); // GOTO_W } label.put(this, code, code.length - 1, true); } else { // case of a backward jump with an offset >= -32768, or of a forward jump // with, of course, an unknown offset. In these cases we store the offset // in 2 bytes (which will be increased in resizeInstructions, if needed). code.put1(opcode); label.put(this, code, code.length - 1, false); } } public void visitLabel (final Label label) { if (CHECK) { if (label.owner == null) { label.owner = this; } else if (label.owner != this) { throw new IllegalArgumentException(); } } if (computeMaxs) { if (currentBlock != null) { // ends current block (with one new successor) currentBlock.maxStackSize = maxStackSize; addSuccessor(stackSize, label); } // begins a new current block, // resets the relative current and max stack sizes currentBlock = label; stackSize = 0; maxStackSize = 0; } // resolves previous forward references to label, if any resize |= label.resolve(this, code.length, code.data); } public void visitLdcInsn (final Object cst) { Item i = cw.newCst(cst); if (computeMaxs) { int size; // computes the stack size variation if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { size = stackSize + 2; } else { size = stackSize + 1; } // updates current and max stack sizes if (size > maxStackSize) { maxStackSize = size; } stackSize = size; } // adds the instruction to the bytecode of the method int index = i.index; if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { code.put12(20 /*LDC2_W*/, index); } else if (index >= 256) { code.put12(19 /*LDC_W*/, index); } else { code.put11(Constants.LDC, index); } } public void visitIincInsn (final int var, final int increment) { if (computeMaxs) { // updates max locals only (no stack change) int n = var + 1; if (n > maxLocals) { maxLocals = n; } } // adds the instruction to the bytecode of the method if ((var > 255) || (increment > 127) || (increment < -128)) { code.put1(196 /*WIDE*/).put12(Constants.IINC, var).put2(increment); } else { code.put1(Constants.IINC).put11(var, increment); } } public void visitTableSwitchInsn ( final int min, final int max, final Label dflt, final Label labels[]) { if (computeMaxs) { // updates current stack size (max stack size unchanged) --stackSize; // ends current block (with many new successors) if (currentBlock != null) { currentBlock.maxStackSize = maxStackSize; addSuccessor(stackSize, dflt); for (int i = 0; i < labels.length; ++i) { addSuccessor(stackSize, labels[i]); } currentBlock = null; } } // adds the instruction to the bytecode of the method int source = code.length; code.put1(Constants.TABLESWITCH); while (code.length % 4 != 0) { code.put1(0); } dflt.put(this, code, source, true); code.put4(min).put4(max); for (int i = 0; i < labels.length; ++i) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -