@Override public void visitMaxs(final int maxStack, final int maxLocals) { checkStartCode(); checkEndCode(); endCode = true; for (Label l : usedLabels) { if (labels.get(l) == null) { throw new IllegalStateException("Undefined label used"); } } for (int i = 0; i < handlers.size();) { Integer start = labels.get(handlers.get(i++)); Integer end = labels.get(handlers.get(i++)); if (start == null || end == null) { throw new IllegalStateException( "Undefined try catch block labels"); } if (end.intValue() <= start.intValue()) { throw new IllegalStateException( "Emty try catch block handler range"); } } checkUnsignedShort(maxStack, "Invalid max stack"); checkUnsignedShort(maxLocals, "Invalid max locals"); super.visitMaxs(maxStack, maxLocals); }
@Override public void visitTableSwitchInsn(final int min, final int max, final Label dflt, final Label... labels) { checkStartCode(); checkEndCode(); if (max < min) { throw new IllegalArgumentException("Max = " + max + " must be greater than or equal to min = " + min); } checkLabel(dflt, false, "default label"); checkNonDebugLabel(dflt); if (labels == null || labels.length != max - min + 1) { throw new IllegalArgumentException( "There must be max - min + 1 labels"); } for (int i = 0; i < labels.length; ++i) { checkLabel(labels[i], false, "label at index " + i); checkNonDebugLabel(labels[i]); } super.visitTableSwitchInsn(min, max, dflt, labels); for (Label label : labels) { usedLabels.add(label); } ++insnCount; }
@Override public void visitLineNumber(final int line, final Label start) { checkStartCode(); checkEndCode(); checkUnsignedShort(line, "Invalid line number"); checkLabel(start, true, "start label"); super.visitLineNumber(line, start); }
@Override public void visitInsn(final int opcode) { checkStartCode(); checkEndCode(); checkOpcode(opcode, 0); super.visitInsn(opcode); ++insnCount; }
@Override public void visitCode() { if ((access & Opcodes.ACC_ABSTRACT) != 0) { throw new RuntimeException("Abstract methods cannot have code"); } startCode = true; super.visitCode(); }
@Override public void visitLdcInsn(final Object cst) { checkStartCode(); checkEndCode(); checkLDCConstant(cst); super.visitLdcInsn(cst); ++insnCount; }
@Override public void visitVarInsn(final int opcode, final int var) { checkStartCode(); checkEndCode(); checkOpcode(opcode, 2); checkUnsignedShort(var, "Invalid variable index"); super.visitVarInsn(opcode, var); ++insnCount; }
@Override public void visitAttribute(final Attribute attr) { checkEndMethod(); if (attr == null) { throw new IllegalArgumentException( "Invalid attribute (must not be null)"); } super.visitAttribute(attr); }
@Override public void visitIincInsn(final int var, final int increment) { checkStartCode(); checkEndCode(); checkUnsignedShort(var, "Invalid variable index"); checkSignedShort(increment, "Invalid increment"); super.visitIincInsn(var, increment); ++insnCount; }
@Override public void visitLabel(final Label label) { checkStartCode(); checkEndCode(); checkLabel(label, false, "label"); if (labels.get(label) != null) { throw new IllegalArgumentException("Already visited label"); } labels.put(label, new Integer(insnCount)); super.visitLabel(label); }
@Override public void visitJumpInsn(final int opcode, final Label label) { checkStartCode(); checkEndCode(); checkOpcode(opcode, 6); checkLabel(label, false, "label"); checkNonDebugLabel(label); super.visitJumpInsn(opcode, label); usedLabels.add(label); ++insnCount; }
@Override public void accept(final MethodVisitor mv) { int[] keys = new int[this.keys.size()]; for (int i = 0; i < keys.length; ++i) { keys[i] = this.keys.get(i).intValue(); } Label[] labels = new Label[this.labels.size()]; for (int i = 0; i < labels.length; ++i) { labels[i] = this.labels.get(i).getLabel(); } mv.visitLookupSwitchInsn(dflt.getLabel(), keys, labels); }
@Override public void visitFieldInsn(final int opcode, final String owner, final String name, final String desc) { checkStartCode(); checkEndCode(); checkOpcode(opcode, 4); checkInternalName(owner, "owner"); checkUnqualifiedName(version, name, "name"); checkDesc(desc, false); super.visitFieldInsn(opcode, owner, name, desc); ++insnCount; }
@Override public void visitTypeInsn(final int opcode, final String type) { checkStartCode(); checkEndCode(); checkOpcode(opcode, 3); checkInternalName(type, "type"); if (opcode == Opcodes.NEW && type.charAt(0) == '[') { throw new IllegalArgumentException( "NEW cannot be used to create arrays: " + type); } super.visitTypeInsn(opcode, type); ++insnCount; }
@Override public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) { checkStartCode(); checkEndCode(); checkOpcode(opcode, 5); if (opcode != Opcodes.INVOKESPECIAL || !"<init>".equals(name)) { checkMethodIdentifier(version, name, "name"); } checkInternalName(owner, "owner"); checkMethodDesc(desc); super.visitMethodInsn(opcode, owner, name, desc); ++insnCount; }
@Override public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) { checkStartCode(); checkEndCode(); checkMethodIdentifier(version, name, "name"); checkMethodDesc(desc); if (bsm.getTag() != Opcodes.H_INVOKESTATIC && bsm.getTag() != Opcodes.H_NEWINVOKESPECIAL) { throw new IllegalArgumentException("invalid handle tag " + bsm.getTag()); } for (Object bsmArg : bsmArgs) { checkLDCConstant(bsmArg); } super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); ++insnCount; }
@Override public void visitLocalVariable(final String name, final String desc, final String signature, final Label start, final Label end, final int index) { checkStartCode(); checkEndCode(); checkUnqualifiedName(version, name, "name"); checkDesc(desc, false); checkLabel(start, true, "start label"); checkLabel(end, true, "end label"); checkUnsignedShort(index, "Invalid variable index"); int s = labels.get(start).intValue(); int e = labels.get(end).intValue(); if (e < s) { throw new IllegalArgumentException( "Invalid start and end labels (end must be greater than start)"); } super.visitLocalVariable(name, desc, signature, start, end, index); }
@Override public void visitMultiANewArrayInsn(final String desc, final int dims) { checkStartCode(); checkEndCode(); checkDesc(desc, false); if (desc.charAt(0) != '[') { throw new IllegalArgumentException( "Invalid descriptor (must be an array type descriptor): " + desc); } if (dims < 1) { throw new IllegalArgumentException( "Invalid dimensions (must be greater than 0): " + dims); } if (dims > desc.lastIndexOf('[') + 1) { throw new IllegalArgumentException( "Invalid dimensions (must not be greater than dims(desc)): " + dims); } super.visitMultiANewArrayInsn(desc, dims); ++insnCount; }
@Override public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { checkEndCode(); checkStartCode(); checkLabel(dflt, false, "default label"); checkNonDebugLabel(dflt); if (keys == null || labels == null || keys.length != labels.length) { throw new IllegalArgumentException( "There must be the same number of keys and labels"); } for (int i = 0; i < labels.length; ++i) { checkLabel(labels[i], false, "label at index " + i); checkNonDebugLabel(labels[i]); } super.visitLookupSwitchInsn(dflt, keys, labels); usedLabels.add(dflt); for (Label label : labels) { usedLabels.add(label); } ++insnCount; }
@Override public void visitIntInsn(final int opcode, final int operand) { checkStartCode(); checkEndCode(); checkOpcode(opcode, 1); switch (opcode) { case Opcodes.BIPUSH: checkSignedByte(operand, "Invalid operand"); break; case Opcodes.SIPUSH: checkSignedShort(operand, "Invalid operand"); break; // case Constants.NEWARRAY: default: if (operand < Opcodes.T_BOOLEAN || operand > Opcodes.T_LONG) { throw new IllegalArgumentException( "Invalid operand (must be an array type code T_...): " + operand); } } super.visitIntInsn(opcode, operand); ++insnCount; }
@Override public void visitTryCatchBlock(final Label start, final Label end, final Label handler, final String type) { checkStartCode(); checkEndCode(); checkLabel(start, false, "start label"); checkLabel(end, false, "end label"); checkLabel(handler, false, "handler label"); checkNonDebugLabel(start); checkNonDebugLabel(end); checkNonDebugLabel(handler); if (labels.get(start) != null || labels.get(end) != null || labels.get(handler) != null) { throw new IllegalStateException( "Try catch blocks must be visited before their labels"); } if (type != null) { checkInternalName(type, "type"); } super.visitTryCatchBlock(start, end, handler, type); handlers.add(start); handlers.add(end); }
@Override public void accept(final MethodVisitor mv) { mv.visitLineNumber(line, start.getLabel()); }
@Override public void visitEnd() { checkEndMethod(); endMethod = true; super.visitEnd(); }
@Override public void visitFrame(final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack) { if (insnCount == lastFrame) { throw new IllegalStateException( "At most one frame can be visited at a given code location."); } lastFrame = insnCount; int mLocal; int mStack; switch (type) { case Opcodes.F_NEW: case Opcodes.F_FULL: mLocal = Integer.MAX_VALUE; mStack = Integer.MAX_VALUE; break; case Opcodes.F_SAME: mLocal = 0; mStack = 0; break; case Opcodes.F_SAME1: mLocal = 0; mStack = 1; break; case Opcodes.F_APPEND: case Opcodes.F_CHOP: mLocal = 3; mStack = 0; break; default: throw new IllegalArgumentException("Invalid frame type " + type); } if (nLocal > mLocal) { throw new IllegalArgumentException("Invalid nLocal=" + nLocal + " for frame type " + type); } if (nStack > mStack) { throw new IllegalArgumentException("Invalid nStack=" + nStack + " for frame type " + type); } if (type != Opcodes.F_CHOP) { if (nLocal > 0 && (local == null || local.length < nLocal)) { throw new IllegalArgumentException( "Array local[] is shorter than nLocal"); } for (int i = 0; i < nLocal; ++i) { checkFrameValue(local[i]); } } if (nStack > 0 && (stack == null || stack.length < nStack)) { throw new IllegalArgumentException( "Array stack[] is shorter than nStack"); } for (int i = 0; i < nStack; ++i) { checkFrameValue(stack[i]); } if (type == Opcodes.F_NEW) { ++expandedFrames; } else { ++compressedFrames; } if (expandedFrames > 0 && compressedFrames > 0) { throw new RuntimeException( "Expanded and compressed frames must not be mixed."); } super.visitFrame(type, nLocal, local, nStack, stack); }