NewRelocatorMethodAdapter extends AnalyzingMethodNode { @Override public void visitEnd() { AbstractInsnNode next = instructions.getFirst(); boolean removeFrame = false; int stackSize = 0; while (next != null) { AbstractInsnNode node = next; next = next.getNext(); Object[] stack; switch (node.getOpcode()) { case -1: if (node instanceof FrameNode) { if (removeFrame) { instructions.remove(node); } else { stackSize = handleFrame((FrameNode) node); removeFrame = true; } } break; case NOP: case LALOAD: case DALOAD: case INEG: case LNEG: case FNEG: case DNEG: case IINC: case I2F: case L2D: case F2I: case D2L: case I2B: case I2C: case I2S: case GOTO: case RET: case NEWARRAY: case ANEWARRAY: case ARRAYLENGTH: case CHECKCAST: case INSTANCEOF: removeFrame = false; break; case ACONST_NULL: case ICONST_M1: case ICONST_0: case ICONST_1: case ICONST_2: case ICONST_3: case ICONST_4: case ICONST_5: case FCONST_0: case FCONST_1: case FCONST_2: case BIPUSH: case SIPUSH: case ILOAD: case FLOAD: case I2L: case I2D: case F2L: case F2D: case JSR: stackSize += 1; updateMaxStack(stackSize); removeFrame = false; break; case LCONST_0: case LCONST_1: case DCONST_0: case DCONST_1: case LLOAD: case DLOAD: stackSize += 2; updateMaxStack(stackSize); removeFrame = false; break; case LDC: Object cst = ((LdcInsnNode) node).cst; stackSize += cst instanceof Long || cst instanceof Double ? 2 : 1; updateMaxStack(stackSize); removeFrame = false; break; case ALOAD: if (frames.get(node).locals[((VarInsnNode) node).var] instanceof AbstractInsnNode) { instructions.remove(node); } else { stackSize += 1; updateMaxStack(stackSize); removeFrame = false; } break; case IALOAD: case FALOAD: case AALOAD: case BALOAD: case CALOAD: case SALOAD: case ISTORE: case FSTORE: case IADD: case FADD: case ISUB: case FSUB: case IMUL: case FMUL: case IDIV: case FDIV: case IREM: case FREM: case ISHL: case ISHR: case IUSHR: case IAND: case IOR: case IXOR: case L2I: case L2F: case D2I: case D2F: case IFEQ: case IFNE: case IFLT: case IFGE: case IFGT: case IFLE: case TABLESWITCH: case LOOKUPSWITCH: case MONITORENTER: case MONITOREXIT: stackSize -= 1; removeFrame = false; break; case LSTORE: case DSTORE: case LADD: case DADD: case LSUB: case DSUB: case LMUL: case DMUL: case LDIV: case DDIV: case LREM: case DREM: case LSHL: case LSHR: case LUSHR: case LAND: case LOR: case LXOR: case FCMPL: case FCMPG: case IF_ICMPEQ: case IF_ICMPNE: case IF_ICMPLT: case IF_ICMPGE: case IF_ICMPGT: case IF_ICMPLE: stackSize -= 2; removeFrame = false; break; case ASTORE: stack = frames.get(node).stack; if (stack[stack.length - 1] instanceof AbstractInsnNode) { instructions.remove(node); } else { stackSize -= 1; removeFrame = false; } break; case IASTORE: case FASTORE: case AASTORE: case BASTORE: case CASTORE: case SASTORE: case LCMP: case DCMPL: case DCMPG: stackSize -= 3; removeFrame = false; break; case LASTORE: case DASTORE: stackSize -= 4; removeFrame = false; break; case POP: stack = frames.get(node).stack; if (stack[stack.length - 1] instanceof AbstractInsnNode) { instructions.remove(node); } else { stackSize -= 1; removeFrame = false; } break; case POP2: stack = frames.get(node).stack; if (stack[stack.length - 1] instanceof AbstractInsnNode) { if (stack[stack.length - 2] instanceof AbstractInsnNode) { instructions.remove(node); } else { instructions.set(node, new InsnNode(POP)); stackSize -= 1; removeFrame = false; } } else { if (stack[stack.length - 2] instanceof AbstractInsnNode) { instructions.set(node, new InsnNode(POP)); stackSize -= 1; } else { stackSize -= 2; } removeFrame = false; } break; case DUP: stack = frames.get(node).stack; if (stack[stack.length - 1] instanceof AbstractInsnNode) { instructions.remove(node); } else { stackSize += 1; updateMaxStack(stackSize); removeFrame = false; } break; case DUP_X1: stack = frames.get(node).stack; if (stack[stack.length - 1] instanceof AbstractInsnNode) { instructions.remove(node); } else { if (stack[stack.length - 2] instanceof AbstractInsnNode) { instructions.set(node, new InsnNode(DUP)); } stackSize += 1; updateMaxStack(stackSize); removeFrame = false; } break; case DUP_X2: stack = frames.get(node).stack; if (stack[stack.length - 1] instanceof AbstractInsnNode) { instructions.remove(node); } else { if (stack[stack.length - 2] instanceof AbstractInsnNode) { if (stack[stack.length - 3] instanceof AbstractInsnNode) { instructions.set(node, new InsnNode(DUP)); } else { instructions.set(node, new InsnNode(DUP_X1)); } } else { if (stack[stack.length - 3] instanceof AbstractInsnNode) { instructions.set(node, new InsnNode(DUP_X1)); } } stackSize += 1; updateMaxStack(stackSize); removeFrame = false; } break; case DUP2: stack = frames.get(node).stack; if (stack[stack.length - 1] instanceof AbstractInsnNode) { if (stack[stack.length - 2] instanceof AbstractInsnNode) { instructions.remove(node); } else { instructions.set(node, new InsnNode(DUP)); stackSize += 1; updateMaxStack(stackSize); removeFrame = false; } } else { if (stack[stack.length - 2] instanceof AbstractInsnNode) { instructions.set(node, new InsnNode(DUP)); stackSize += 1; } else { stackSize += 2; } updateMaxStack(stackSize); removeFrame = false; } break; case DUP2_X1: stack = frames.get(node).stack; if (stack[stack.length - 1] instanceof AbstractInsnNode) { if (stack[stack.length - 2] instanceof AbstractInsnNode) { instructions.remove(node); } else { if (stack[stack.length - 3] instanceof AbstractInsnNode) { instructions.set(node, new InsnNode(DUP)); } else { instructions.set(node, new InsnNode(DUP_X1)); } stackSize += 1; updateMaxStack(stackSize); removeFrame = false; } } else { if (stack[stack.length - 2] instanceof AbstractInsnNode) { if (stack[stack.length - 3] instanceof AbstractInsnNode) { instructions.set(node, new InsnNode(DUP)); } else { instructions.set(node, new InsnNode(DUP_X1)); } stackSize += 1; } else { if (stack[stack.length - 3] instanceof AbstractInsnNode) { instructions.set(node, new InsnNode(DUP2)); } stackSize += 2; } updateMaxStack(stackSize); removeFrame = false; } break; case DUP2_X2: stack = frames.get(node).stack; if (stack[stack.length - 1] instanceof AbstractInsnNode) { if (stack[stack.length - 2] instanceof AbstractInsnNode) { instructions.remove(node); } else { if (stack[stack.length - 3] instanceof AbstractInsnNode) { if (stack[stack.length - 4] instanceof AbstractInsnNode) { instructions.set(node, new InsnNode(DUP)); } else { instructions.set(node, new InsnNode(DUP_X1)); } } else { if (stack[stack.length - 3] instanceof AbstractInsnNode) { instructions.set(node, new InsnNode(DUP_X1)); } else { instructions.set(node, new InsnNode(DUP_X2)); } } stackSize += 1; updateMaxStack(stackSize); removeFrame = false; } } else { if (stack[stack.length - 2] instanceof AbstractInsnNode) { if (stack[stack.length - 3] instanceof AbstractInsnNode) { if (stack[stack.length - 4] instanceof AbstractInsnNode) { instructions.set(node, new InsnNode(DUP)); } else { instructions.set(node, new InsnNode(DUP_X1)); } } else { if (stack[stack.length - 4] instanceof AbstractInsnNode) { instructions.set(node, new InsnNode(DUP_X1)); } else { instructions.set(node, new InsnNode(DUP_X2)); } } stackSize += 1; } else { if (stack[stack.length - 3] instanceof AbstractInsnNode) { if (stack[stack.length - 4] instanceof AbstractInsnNode) { instructions.set(node, new InsnNode(DUP2)); } else { instructions.set(node, new InsnNode(DUP2_X1)); } } else { if (stack[stack.length - 4] instanceof AbstractInsnNode) { instructions.set(node, new InsnNode(DUP2_X1)); } } stackSize += 2; } updateMaxStack(stackSize); removeFrame = false; } break; case SWAP: stack = frames.get(node).stack; if (stack[stack.length - 1] instanceof AbstractInsnNode || stack[stack.length - 2] instanceof AbstractInsnNode) { instructions.remove(node); } else { removeFrame = false; } break; case IF_ACMPEQ: stack = frames.get(node).stack; if (stack[stack.length - 1] instanceof AbstractInsnNode) { if (stack[stack.length - 2] instanceof AbstractInsnNode) { if (stack[stack.length - 1] == stack[stack.length - 2]) { instructions.set(node, new JumpInsnNode(GOTO, ((JumpInsnNode) node).label)); removeFrame = false; } else { instructions.remove(node); } } else { instructions.set(node, new InsnNode(POP)); stackSize -= 1; removeFrame = false; } } else { if (stack[stack.length - 2] instanceof AbstractInsnNode) { instructions.set(node, new InsnNode(POP)); stackSize -= 1; } else { stackSize -= 2; } removeFrame = false; } break; case IF_ACMPNE: stack = frames.get(node).stack; if (stack[stack.length - 1] instanceof AbstractInsnNode) { if (stack[stack.length - 2] instanceof AbstractInsnNode) { if (stack[stack.length - 1] == stack[stack.length - 2]) { instructions.remove(node); } else { instructions.set(node, new JumpInsnNode(GOTO, ((JumpInsnNode) node).label)); removeFrame = false; } } else { instructions.insertBefore(node, new InsnNode(POP)); stackSize -= 1; instructions.set(node, new JumpInsnNode(GOTO, ((JumpInsnNode) node).label)); removeFrame = false; } } else { if (stack[stack.length - 2] instanceof AbstractInsnNode) { instructions.insertBefore(node, new InsnNode(POP)); stackSize -= 1; instructions.set(node, new JumpInsnNode(GOTO, ((JumpInsnNode) node).label)); } else { stackSize -= 2; } removeFrame = false; } break; case IRETURN: case LRETURN: case FRETURN: case DRETURN: case ARETURN: case RETURN: stackSize = 0; removeFrame = false; break; case GETSTATIC: stackSize += getTypeSize(((FieldInsnNode) node).desc); updateMaxStack(stackSize); removeFrame = false; break; case PUTSTATIC: stackSize -= getTypeSize(((FieldInsnNode) node).desc); removeFrame = false; break; case GETFIELD: stackSize += getTypeSize(((FieldInsnNode) node).desc) - 1; updateMaxStack(stackSize); removeFrame = false; break; case PUTFIELD: stackSize -= getTypeSize(((FieldInsnNode) node).desc) + 1; removeFrame = false; break; case INVOKEVIRTUAL: case INVOKEINTERFACE: stackSize += getInvokeDelta(((MethodInsnNode) node).desc); updateMaxStack(stackSize); removeFrame = false; break; case INVOKESPECIAL: stackSize = handleInvokeSpecial((MethodInsnNode) node, stackSize); removeFrame = false; break; case INVOKESTATIC: stackSize += getInvokeDelta(((MethodInsnNode) node).desc) + 1; updateMaxStack(stackSize); removeFrame = false; break; case INVOKEDYNAMIC: stackSize += getInvokeDelta(((InvokeDynamicInsnNode) node).desc) + 1; updateMaxStack(stackSize); removeFrame = false; break; case NEW: instructions.remove(node); break; case ATHROW: stackSize += 1 - stackSize; updateMaxStack(stackSize); removeFrame = false; break; case MULTIANEWARRAY: stackSize += 1 - ((MultiANewArrayInsnNode) node).dims; updateMaxStack(stackSize); removeFrame = false; break; case IFNULL: stack = frames.get(node).stack; if (!(stack[stack.length - 1] instanceof AbstractInsnNode)) { stackSize -= 1; removeFrame = false; } break; default: stack = frames.get(node).stack; if (stack[stack.length - 1] instanceof AbstractInsnNode) { instructions.set(node, new JumpInsnNode(GOTO, ((JumpInsnNode) node).label)); } else { stackSize -= 1; } removeFrame = false; } } accept(mv); } private  NewRelocatorMethodAdapter(int access, String name, String desc, String signature, String[] exceptions,
            MethodVisitor mv); @Override void visitEnd();  }
@Test public void testVisitEndNop() throws Exception { adapter.visitCode(); adapter.visitFrame(F_NEW, 0, EMPTY_OBJECTS, 0, EMPTY_OBJECTS); adapter.visitInsn(NOP); adapter.visitFrame(F_NEW, 0, EMPTY_OBJECTS, 0, EMPTY_OBJECTS); adapter.visitInsn(RETURN); adapter.visitMaxs(0, 0); adapter.visitEnd(); InOrder inOrder = inOrder(mv); inOrder.verify(mv).visitCode(); inOrder.verify(mv).visitFrame(F_NEW, 0, EMPTY_OBJECTS, 0, EMPTY_OBJECTS); inOrder.verify(mv).visitInsn(NOP); inOrder.verify(mv).visitFrame(F_NEW, 0, EMPTY_OBJECTS, 0, EMPTY_OBJECTS); inOrder.verify(mv).visitInsn(RETURN); inOrder.verify(mv).visitMaxs(0, 0); inOrder.verify(mv).visitEnd(); verifyNoMoreInteractions(mv); }
@Test public void testVisitEndInvokespecialInit() throws Exception { adapter.visitCode(); adapter.visitInsn(ICONST_0); adapter.visitTypeInsn(NEW, "C"); adapter.visitInsn(DUP); adapter.visitVarInsn(ASTORE, 0); adapter.visitInsn(ICONST_0); adapter.visitInsn(FCONST_0); adapter.visitInsn(LCONST_0); adapter.visitInsn(DCONST_0); adapter.visitInsn(ACONST_NULL); adapter.visitLdcInsn("test"); adapter.visitMethodInsn(INVOKESPECIAL, "C", "<init>", "(IFJDLjava/lang/String;[I)V", false); adapter.visitInsn(RETURN); adapter.visitMaxs(10, 1); adapter.visitEnd(); InOrder inOrder = inOrder(mv); inOrder.verify(mv).visitCode(); inOrder.verify(mv).visitInsn(ICONST_0); inOrder.verify(mv).visitLabel(any(Label.class)); inOrder.verify(mv).visitInsn(ICONST_0); inOrder.verify(mv).visitInsn(FCONST_0); inOrder.verify(mv).visitInsn(LCONST_0); inOrder.verify(mv).visitInsn(DCONST_0); inOrder.verify(mv).visitInsn(ACONST_NULL); inOrder.verify(mv).visitLdcInsn("test"); inOrder.verify(mv).visitVarInsn(ASTORE, 2); inOrder.verify(mv).visitInsn(POP); inOrder.verify(mv).visitVarInsn(DSTORE, 3); inOrder.verify(mv).visitVarInsn(LSTORE, 5); inOrder.verify(mv).visitVarInsn(FSTORE, 7); inOrder.verify(mv).visitVarInsn(ISTORE, 8); inOrder.verify(mv).visitTypeInsn(NEW, "C"); inOrder.verify(mv).visitVarInsn(ASTORE, 1); inOrder.verify(mv).visitVarInsn(ALOAD, 1); inOrder.verify(mv).visitVarInsn(ASTORE, 0); inOrder.verify(mv).visitVarInsn(ALOAD, 1); inOrder.verify(mv).visitVarInsn(ILOAD, 8); inOrder.verify(mv).visitVarInsn(FLOAD, 7); inOrder.verify(mv).visitVarInsn(LLOAD, 5); inOrder.verify(mv).visitVarInsn(DLOAD, 3); inOrder.verify(mv).visitInsn(ACONST_NULL); inOrder.verify(mv).visitVarInsn(ALOAD, 2); inOrder.verify(mv).visitMethodInsn(INVOKESPECIAL, "C", "<init>", "(IFJDLjava/lang/String;[I)V", false); inOrder.verify(mv).visitInsn(RETURN); inOrder.verify(mv).visitMaxs(10, 9); inOrder.verify(mv).visitEnd(); verifyNoMoreInteractions(mv); }
@Test public void testVisitEndInvokespecialInitOptimization1() throws Exception { adapter.visitCode(); adapter.visitInsn(ICONST_0); adapter.visitTypeInsn(NEW, "C"); adapter.visitInsn(DUP); adapter.visitMethodInsn(INVOKESPECIAL, "C", "<init>", "()V", false); adapter.visitInsn(RETURN); adapter.visitMaxs(3, 0); adapter.visitEnd(); InOrder inOrder = inOrder(mv); inOrder.verify(mv).visitCode(); inOrder.verify(mv).visitInsn(ICONST_0); inOrder.verify(mv).visitLabel(any(Label.class)); inOrder.verify(mv).visitTypeInsn(NEW, "C"); inOrder.verify(mv).visitInsn(DUP); inOrder.verify(mv).visitMethodInsn(INVOKESPECIAL, "C", "<init>", "()V", false); inOrder.verify(mv).visitInsn(RETURN); inOrder.verify(mv).visitMaxs(3, 0); inOrder.verify(mv).visitEnd(); verifyNoMoreInteractions(mv); }
@Test public void testVisitEndInvokespecialInitOptimization2() throws Exception { adapter.visitCode(); adapter.visitInsn(ICONST_0); adapter.visitTypeInsn(NEW, "C"); adapter.visitInsn(DUP); adapter.visitInsn(ICONST_0); adapter.visitInsn(LCONST_0); adapter.visitInsn(ICONST_0); adapter.visitInsn(LCONST_0); adapter.visitInsn(FCONST_0); adapter.visitInsn(DCONST_0); adapter.visitInsn(ACONST_NULL); adapter.visitLdcInsn("test"); adapter.visitMethodInsn(INVOKESPECIAL, "C", "<init>", "(IJIJFDLjava/lang/String;[I)V", false); adapter.visitInsn(RETURN); adapter.visitMaxs(14, 0); adapter.visitEnd(); InOrder inOrder = inOrder(mv); inOrder.verify(mv).visitCode(); inOrder.verify(mv).visitInsn(ICONST_0); inOrder.verify(mv).visitLabel(any(Label.class)); inOrder.verify(mv).visitInsn(ICONST_0); inOrder.verify(mv).visitInsn(LCONST_0); inOrder.verify(mv).visitInsn(ICONST_0); inOrder.verify(mv).visitInsn(LCONST_0); inOrder.verify(mv).visitInsn(FCONST_0); inOrder.verify(mv).visitInsn(DCONST_0); inOrder.verify(mv).visitInsn(ACONST_NULL); inOrder.verify(mv).visitLdcInsn("test"); inOrder.verify(mv).visitVarInsn(ASTORE, 0); inOrder.verify(mv).visitInsn(POP); inOrder.verify(mv).visitVarInsn(DSTORE, 1); inOrder.verify(mv).visitVarInsn(FSTORE, 3); inOrder.verify(mv).visitVarInsn(LSTORE, 4); inOrder.verify(mv).visitVarInsn(ISTORE, 6); inOrder.verify(mv).visitVarInsn(LSTORE, 7); inOrder.verify(mv).visitTypeInsn(NEW, "C"); inOrder.verify(mv).visitInsn(DUP); inOrder.verify(mv).visitInsn(DUP2_X1); inOrder.verify(mv).visitInsn(POP2); inOrder.verify(mv).visitVarInsn(LLOAD, 7); inOrder.verify(mv).visitVarInsn(ILOAD, 6); inOrder.verify(mv).visitVarInsn(LLOAD, 4); inOrder.verify(mv).visitVarInsn(FLOAD, 3); inOrder.verify(mv).visitVarInsn(DLOAD, 1); inOrder.verify(mv).visitInsn(ACONST_NULL); inOrder.verify(mv).visitVarInsn(ALOAD, 0); inOrder.verify(mv).visitMethodInsn(INVOKESPECIAL, "C", "<init>", "(IJIJFDLjava/lang/String;[I)V", false); inOrder.verify(mv).visitInsn(RETURN); inOrder.verify(mv).visitMaxs(14, 9); inOrder.verify(mv).visitEnd(); verifyNoMoreInteractions(mv); }
@Test public void testVisitEndInvokespecialInitOptimization3() throws Exception { adapter.visitCode(); adapter.visitInsn(ICONST_0); adapter.visitTypeInsn(NEW, "C"); adapter.visitInsn(DUP); adapter.visitInsn(ICONST_0); adapter.visitInsn(FCONST_0); adapter.visitInsn(ICONST_0); adapter.visitInsn(LCONST_0); adapter.visitInsn(FCONST_0); adapter.visitInsn(DCONST_0); adapter.visitInsn(ACONST_NULL); adapter.visitLdcInsn("test"); adapter.visitMethodInsn(INVOKESPECIAL, "C", "<init>", "(IFIJFDLjava/lang/String;[I)V", false); adapter.visitInsn(RETURN); adapter.visitMaxs(13, 0); adapter.visitEnd(); InOrder inOrder = inOrder(mv); inOrder.verify(mv).visitCode(); inOrder.verify(mv).visitInsn(ICONST_0); inOrder.verify(mv).visitLabel(any(Label.class)); inOrder.verify(mv).visitInsn(ICONST_0); inOrder.verify(mv).visitInsn(FCONST_0); inOrder.verify(mv).visitInsn(ICONST_0); inOrder.verify(mv).visitInsn(LCONST_0); inOrder.verify(mv).visitInsn(FCONST_0); inOrder.verify(mv).visitInsn(DCONST_0); inOrder.verify(mv).visitInsn(ACONST_NULL); inOrder.verify(mv).visitLdcInsn("test"); inOrder.verify(mv).visitVarInsn(ASTORE, 0); inOrder.verify(mv).visitInsn(POP); inOrder.verify(mv).visitVarInsn(DSTORE, 1); inOrder.verify(mv).visitVarInsn(FSTORE, 3); inOrder.verify(mv).visitVarInsn(LSTORE, 4); inOrder.verify(mv).visitVarInsn(ISTORE, 6); inOrder.verify(mv).visitTypeInsn(NEW, "C"); inOrder.verify(mv).visitInsn(DUP); inOrder.verify(mv).visitInsn(DUP2_X2); inOrder.verify(mv).visitInsn(POP2); inOrder.verify(mv).visitVarInsn(ILOAD, 6); inOrder.verify(mv).visitVarInsn(LLOAD, 4); inOrder.verify(mv).visitVarInsn(FLOAD, 3); inOrder.verify(mv).visitVarInsn(DLOAD, 1); inOrder.verify(mv).visitInsn(ACONST_NULL); inOrder.verify(mv).visitVarInsn(ALOAD, 0); inOrder.verify(mv).visitMethodInsn(INVOKESPECIAL, "C", "<init>", "(IFIJFDLjava/lang/String;[I)V", false); inOrder.verify(mv).visitInsn(RETURN); inOrder.verify(mv).visitMaxs(13, 7); inOrder.verify(mv).visitEnd(); verifyNoMoreInteractions(mv); }