Mercurial > hg > openjdk > jdk8 > jdk
changeset 8750:81cbdd5876e8
8027227: [asm] generate CONSTANT_InterfaceMethodref for invoke{special/static) of non-abstract methods on ifaces
Reviewed-by: ksrini, lagergren
Contributed-by: ebruneton@free.fr, forax@univ-mlv.fr, john.r.rose@oracle.com, paul.sandoz@oracle.com
line wrap: on
line diff
--- a/src/share/classes/jdk/internal/org/objectweb/asm/ByteVector.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/ByteVector.java Wed Nov 06 11:22:15 2013 -0800 @@ -233,11 +233,14 @@ * automatically enlarged if necessary. * * @param s - * a String. + * a String whose UTF8 encoded length must be less than 65536. * @return this byte vector. */ public ByteVector putUTF8(final String s) { int charLength = s.length(); + if (charLength > 65535) { + throw new IllegalArgumentException(); + } int len = length; if (len + 2 + charLength > data.length) { enlarge(2 + charLength); @@ -267,6 +270,9 @@ byteLength += 2; } } + if (byteLength > 65535) { + throw new IllegalArgumentException(); + } data[length] = (byte) (byteLength >>> 8); data[length + 1] = (byte) byteLength; if (length + 2 + byteLength > data.length) {
--- a/src/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java Wed Nov 06 11:22:15 2013 -0800 @@ -1266,7 +1266,7 @@ u += 2; // generates the first (implicit) stack map frame - if (FRAMES && (stackMap != 0 || unzip)) { + if (FRAMES && stackMap != 0) { /* * for the first explicit frame the offset is not offset_delta + 1 * but only offset_delta; setting the implicit frame offset to -1 @@ -1283,8 +1283,6 @@ if (unzip) { getImplicitFrame(context); } - } - if (FRAMES && stackMap != 0) { /* * Finds labels for UNINITIALIZED frame types. Instead of decoding * each element of the stack map table, we look for 3 consecutive @@ -1322,17 +1320,19 @@ } } - // visits the frame(s) for this offset, if any + // visits the frame for this offset, if any while (FRAMES && frame != null && (frame.offset == offset || frame.offset == -1)) { // if there is a frame for this offset, makes the visitor visit // it, and reads the next frame if there is one. - if (!zip || unzip) { - mv.visitFrame(Opcodes.F_NEW, frame.localCount, frame.local, - frame.stackCount, frame.stack); - } else if (frame.offset != -1) { - mv.visitFrame(frame.mode, frame.localDiff, frame.local, - frame.stackCount, frame.stack); + if (frame.offset != -1) { + if (!zip || unzip) { + mv.visitFrame(Opcodes.F_NEW, frame.localCount, + frame.local, frame.stackCount, frame.stack); + } else { + mv.visitFrame(frame.mode, frame.localDiff, frame.local, + frame.stackCount, frame.stack); + } } if (frameCount > 0) { stackMap = readFrame(stackMap, zip, unzip, frame); @@ -1434,6 +1434,7 @@ case ClassWriter.FIELDORMETH_INSN: case ClassWriter.ITFMETH_INSN: { int cpIndex = items[readUnsignedShort(u + 1)]; + boolean itf = b[cpIndex - 1] == ClassWriter.IMETH; String iowner = readClass(cpIndex, c); cpIndex = items[readUnsignedShort(cpIndex + 2)]; String iname = readUTF8(cpIndex, c); @@ -1441,7 +1442,7 @@ if (opcode < Opcodes.INVOKEVIRTUAL) { mv.visitFieldInsn(opcode, iowner, iname, idesc); } else { - mv.visitMethodInsn(opcode, iowner, iname, idesc); + mv.visitMethodInsn(opcode, iowner, iname, idesc, itf); } if (opcode == Opcodes.INVOKEINTERFACE) { u += 5;
--- a/src/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java Wed Nov 06 11:22:15 2013 -0800 @@ -516,12 +516,12 @@ * <tt>true</tt> if the maximum stack size and number of local variables * must be automatically computed. */ - private final boolean computeMaxs; + private boolean computeMaxs; /** * <tt>true</tt> if the stack map frames must be recomputed from scratch. */ - private final boolean computeFrames; + private boolean computeFrames; /** * <tt>true</tt> if the stack map tables of this class are invalid. The @@ -988,9 +988,22 @@ attrs.put(this, null, 0, -1, -1, out); } if (invalidFrames) { - ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); - new ClassReader(out.data).accept(cw, ClassReader.SKIP_FRAMES); - return cw.toByteArray(); + anns = null; + ianns = null; + attrs = null; + innerClassesCount = 0; + innerClasses = null; + bootstrapMethodsCount = 0; + bootstrapMethods = null; + firstField = null; + lastField = null; + firstMethod = null; + lastMethod = null; + computeMaxs = false; + computeFrames = true; + invalidFrames = false; + new ClassReader(out.data).accept(this, ClassReader.SKIP_FRAMES); + return toByteArray(); } return out.data; }
--- a/src/share/classes/jdk/internal/org/objectweb/asm/Handle.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/Handle.java Wed Nov 06 11:22:15 2013 -0800 @@ -78,7 +78,8 @@ final int tag; /** - * The internal name of the field or method designed by this handle. + * The internal name of the class that owns the field or method designated + * by this handle. */ final String owner; @@ -105,8 +106,8 @@ * {@link Opcodes#H_NEWINVOKESPECIAL} or * {@link Opcodes#H_INVOKEINTERFACE}. * @param owner - * the internal name of the field or method designed by this - * handle. + * the internal name of the class that owns the field or method + * designated by this handle. * @param name * the name of the field or method designated by this handle. * @param desc @@ -135,9 +136,11 @@ } /** - * Returns the internal name of the field or method designed by this handle. + * Returns the internal name of the class that owns the field or method + * designated by this handle. * - * @return the internal name of the field or method designed by this handle. + * @return the internal name of the class that owns the field or method + * designated by this handle. */ public String getOwner() { return owner;
--- a/src/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java Wed Nov 06 11:22:15 2013 -0800 @@ -68,11 +68,11 @@ * <tt>visitTryCatchBlock</tt> | <tt>visitTryCatchBlockAnnotation</tt> | * <tt>visitLocalVariable</tt> | <tt>visitLocalVariableAnnotation</tt> | * <tt>visitLineNumber</tt> )* <tt>visitMaxs</tt> ] <tt>visitEnd</tt>. In - * addition, the <tt>visit<i>X</i>Insn</tt> and <tt>visitLabel</tt> - * methods must be called in the sequential order of the bytecode instructions - * of the visited code, <tt>visitInsnAnnotation</tt> must be called <i>after</i> - * the annotated instruction, <tt>visitTryCatchBlock</tt> must be called - * <i>before</i> the labels passed as arguments have been visited, + * addition, the <tt>visit<i>X</i>Insn</tt> and <tt>visitLabel</tt> methods must + * be called in the sequential order of the bytecode instructions of the visited + * code, <tt>visitInsnAnnotation</tt> must be called <i>after</i> the annotated + * instruction, <tt>visitTryCatchBlock</tt> must be called <i>before</i> the + * labels passed as arguments have been visited, * <tt>visitTryCatchBlockAnnotation</tt> must be called <i>after</i> the * corresponding try catch block has been visited, and the * <tt>visitLocalVariable</tt>, <tt>visitLocalVariableAnnotation</tt> and @@ -274,13 +274,9 @@ * compressed form (all frames must use the same format, i.e. you must not * mix expanded and compressed frames within a single method): * <ul> - * <li>In expanded form, all frames must have the F_NEW type, and a first - * frame corresponding to the method signature must be explicitly visited - * before the first instruction.</li> + * <li>In expanded form, all frames must have the F_NEW type.</li> * <li>In compressed form, frames are basically "deltas" from the state of - * the previous frame (the first frame, corresponding to the method's - * parameters and access flags, is implicit in this form, and must not be - * visited): + * the previous frame: * <ul> * <li>{@link Opcodes#F_SAME} representing frame with exactly the same * locals as the previous frame and with the empty stack.</li> @@ -296,8 +292,14 @@ * same as the locals in the previous frame, except that the last 1-3 locals * are absent and with the empty stack (<code>nLocals</code> is 1, 2 or 3).</li> * <li>{@link Opcodes#F_FULL} representing complete frame data.</li> - * </ul></li> + * </ul> + * </li> * </ul> + * <br> + * In both cases the first frame, corresponding to the method's parameters + * and access flags, is implicit and must not be visited. Also, it is + * illegal to visit two or more frames for the same code location (i.e., at + * least one instruction must be visited between two calls to visitFrame). * * @param type * the type of this stack map frame. Must be @@ -466,14 +468,53 @@ * @param desc * the method's descriptor (see {@link Type Type}). */ + @Deprecated public void visitMethodInsn(int opcode, String owner, String name, String desc) { + if (api >= Opcodes.ASM5) { + boolean itf = opcode == Opcodes.INVOKEINTERFACE; + visitMethodInsn(opcode, owner, name, desc, itf); + return; + } if (mv != null) { mv.visitMethodInsn(opcode, owner, name, desc); } } /** + * Visits a method instruction. A method instruction is an instruction that + * invokes a method. + * + * @param opcode + * the opcode of the type instruction to be visited. This opcode + * is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or + * INVOKEINTERFACE. + * @param owner + * the internal name of the method's owner class (see + * {@link Type#getInternalName() getInternalName}). + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link Type Type}). + * @param itf + * if the method's owner class is an interface. + */ + public void visitMethodInsn(int opcode, String owner, String name, + String desc, boolean itf) { + if (api < Opcodes.ASM5) { + if (itf != (opcode == Opcodes.INVOKEINTERFACE)) { + throw new IllegalArgumentException( + "INVOKESPECIAL/STATIC on interfaces require ASM 5"); + } + visitMethodInsn(opcode, owner, name, desc); + return; + } + if (mv != null) { + mv.visitMethodInsn(opcode, owner, name, desc, itf); + } + } + + /** * Visits an invokedynamic instruction. * * @param name
--- a/src/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java Wed Nov 06 11:22:15 2013 -0800 @@ -71,7 +71,7 @@ /** * Pseudo access flag used to denote constructors. */ - static final int ACC_CONSTRUCTOR = 262144; + static final int ACC_CONSTRUCTOR = 0x80000; /** * Frame has exactly the same locals as the previous stack map frame and @@ -298,11 +298,6 @@ private int[] previousFrame; /** - * Index of the next element to be added in {@link #frame}. - */ - private int frameIndex; - - /** * The current stack map frame. The first element contains the offset of the * instruction to which the frame corresponds, the second element is the * number of locals and the third one is the number of stack elements. The @@ -496,6 +491,9 @@ cw.lastMethod = this; this.cw = cw; this.access = access; + if ("<init>".equals(name)) { + this.access |= ACC_CONSTRUCTOR; + } this.name = cw.newUTF8(name); this.desc = cw.newUTF8(desc); this.descriptor = desc; @@ -511,9 +509,6 @@ } this.compute = computeFrames ? FRAMES : (computeMaxs ? MAXS : NOTHING); if (computeMaxs || computeFrames) { - if (computeFrames && "<init>".equals(name)) { - this.access |= ACC_CONSTRUCTOR; - } // updates maxLocals int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2; if ((access & Opcodes.ACC_STATIC) != 0) { @@ -649,8 +644,11 @@ } if (type == Opcodes.F_NEW) { + if (previousFrame == null) { + visitImplicitFirstFrame(); + } currentLocals = nLocal; - startFrame(code.length, nLocal, nStack); + int frameIndex = startFrame(code.length, nLocal, nStack); for (int i = 0; i < nLocal; ++i) { if (local[i] instanceof String) { frame[frameIndex++] = Frame.OBJECT @@ -914,9 +912,8 @@ @Override public void visitMethodInsn(final int opcode, final String owner, - final String name, final String desc) { + final String name, final String desc, final boolean itf) { lastCodeOffset = code.length; - boolean itf = opcode == Opcodes.INVOKEINTERFACE; Item i = cw.newMethodItem(owner, name, desc, itf); int argSize = i.intVal; // Label currentBlock = this.currentBlock; @@ -954,7 +951,7 @@ } } // adds the instruction to the bytecode of the method - if (itf) { + if (opcode == Opcodes.INVOKEINTERFACE) { if (argSize == 0) { argSize = Type.getArgumentsAndReturnSizes(desc); i.intVal = argSize; @@ -1528,8 +1525,8 @@ } code.data[end] = (byte) Opcodes.ATHROW; // emits a frame for this unreachable block - startFrame(start, 0, 1); - frame[frameIndex++] = Frame.OBJECT + int frameIndex = startFrame(start, 0, 1); + frame[frameIndex] = Frame.OBJECT | cw.addType("java/lang/Throwable"); endFrame(); // removes the start-end range from the exception @@ -1756,7 +1753,7 @@ } } // visits the frame and its content - startFrame(f.owner.position, nLocal, nStack); + int frameIndex = startFrame(f.owner.position, nLocal, nStack); for (i = 0; nLocal > 0; ++i, --nLocal) { t = locals[i]; frame[frameIndex++] = t; @@ -1775,6 +1772,67 @@ } /** + * Visit the implicit first frame of this method. + */ + private void visitImplicitFirstFrame() { + // There can be at most descriptor.length() + 1 locals + int frameIndex = startFrame(0, descriptor.length() + 1, 0); + if ((access & Opcodes.ACC_STATIC) == 0) { + if ((access & ACC_CONSTRUCTOR) == 0) { + frame[frameIndex++] = Frame.OBJECT | cw.addType(cw.thisName); + } else { + frame[frameIndex++] = 6; // Opcodes.UNINITIALIZED_THIS; + } + } + int i = 1; + loop: while (true) { + int j = i; + switch (descriptor.charAt(i++)) { + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + frame[frameIndex++] = 1; // Opcodes.INTEGER; + break; + case 'F': + frame[frameIndex++] = 2; // Opcodes.FLOAT; + break; + case 'J': + frame[frameIndex++] = 4; // Opcodes.LONG; + break; + case 'D': + frame[frameIndex++] = 3; // Opcodes.DOUBLE; + break; + case '[': + while (descriptor.charAt(i) == '[') { + ++i; + } + if (descriptor.charAt(i) == 'L') { + ++i; + while (descriptor.charAt(i) != ';') { + ++i; + } + } + frame[frameIndex++] = Frame.OBJECT + | cw.addType(descriptor.substring(j, ++i)); + break; + case 'L': + while (descriptor.charAt(i) != ';') { + ++i; + } + frame[frameIndex++] = Frame.OBJECT + | cw.addType(descriptor.substring(j + 1, i++)); + break; + default: + break loop; + } + } + frame[1] = frameIndex - 3; + endFrame(); + } + + /** * Starts the visit of a stack map frame. * * @param offset @@ -1783,8 +1841,9 @@ * the number of local variables in the frame. * @param nStack * the number of stack elements in the frame. + * @return the index of the next element to be written in this frame. */ - private void startFrame(final int offset, final int nLocal, final int nStack) { + private int startFrame(final int offset, final int nLocal, final int nStack) { int n = 3 + nLocal + nStack; if (frame == null || frame.length < n) { frame = new int[n]; @@ -1792,7 +1851,7 @@ frame[0] = offset; frame[1] = nLocal; frame[2] = nStack; - frameIndex = 3; + return 3; } /** @@ -2110,7 +2169,8 @@ */ final void put(final ByteVector out) { final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC; - int mask = Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE + int mask = ACC_CONSTRUCTOR | Opcodes.ACC_DEPRECATED + | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR); out.putShort(access & ~mask).putShort(name).putShort(desc); if (classReaderOffset != 0) {
--- a/src/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java Wed Nov 06 11:22:15 2013 -0800 @@ -442,10 +442,31 @@ } } + @Deprecated @Override public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) { - mv.visitMethodInsn(opcode, owner, name, desc); + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, + opcode == Opcodes.INVOKEINTERFACE); + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, itf); + } + + private void doVisitMethodInsn(int opcode, final String owner, + final String name, final String desc, final boolean itf) { + mv.visitMethodInsn(opcode, owner, name, desc, itf); if (constructor) { Type[] types = Type.getArgumentTypes(desc); for (int i = 0; i < types.length; i++) {
--- a/src/share/classes/jdk/internal/org/objectweb/asm/commons/AnalyzerAdapter.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/commons/AnalyzerAdapter.java Wed Nov 06 11:22:15 2013 -0800 @@ -165,10 +165,15 @@ * @param mv * the method visitor to which this adapter delegates calls. May * be <tt>null</tt>. + * @throws IllegalStateException + * If a subclass calls this constructor. */ public AnalyzerAdapter(final String owner, final int access, final String name, final String desc, final MethodVisitor mv) { this(Opcodes.ASM5, owner, access, name, desc, mv); + if (getClass() != AnalyzerAdapter.class) { + throw new IllegalStateException(); + } } /** @@ -331,11 +336,32 @@ execute(opcode, 0, desc); } + @Deprecated @Override public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) { + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, + opcode == Opcodes.INVOKEINTERFACE); + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, itf); + } + + private void doVisitMethodInsn(int opcode, final String owner, + final String name, final String desc, final boolean itf) { if (mv != null) { - mv.visitMethodInsn(opcode, owner, name, desc); + mv.visitMethodInsn(opcode, owner, name, desc, itf); } if (this.locals == null) { labels = null;
--- a/src/share/classes/jdk/internal/org/objectweb/asm/commons/CodeSizeEvaluator.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/commons/CodeSizeEvaluator.java Wed Nov 06 11:22:15 2013 -0800 @@ -149,9 +149,30 @@ } } + @Deprecated @Override public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) { + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, + opcode == Opcodes.INVOKEINTERFACE); + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, itf); + } + + private void doVisitMethodInsn(int opcode, final String owner, + final String name, final String desc, final boolean itf) { if (opcode == INVOKEINTERFACE) { minSize += 5; maxSize += 5; @@ -160,7 +181,7 @@ maxSize += 3; } if (mv != null) { - mv.visitMethodInsn(opcode, owner, name, desc); + mv.visitMethodInsn(opcode, owner, name, desc, itf); } }
--- a/src/share/classes/jdk/internal/org/objectweb/asm/commons/GeneratorAdapter.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/commons/GeneratorAdapter.java Wed Nov 06 11:22:15 2013 -0800 @@ -284,10 +284,15 @@ * the method's name. * @param desc * the method's descriptor (see {@link Type Type}). + * @throws IllegalStateException + * If a subclass calls this constructor. */ public GeneratorAdapter(final MethodVisitor mv, final int access, final String name, final String desc) { this(Opcodes.ASM5, mv, access, name, desc); + if (getClass() != GeneratorAdapter.class) { + throw new IllegalStateException(); + } } /** @@ -1400,11 +1405,11 @@ * the method to be invoked. */ private void invokeInsn(final int opcode, final Type type, - final Method method) { + final Method method, final boolean itf) { String owner = type.getSort() == Type.ARRAY ? type.getDescriptor() : type.getInternalName(); mv.visitMethodInsn(opcode, owner, method.getName(), - method.getDescriptor()); + method.getDescriptor(), itf); } /** @@ -1416,7 +1421,7 @@ * the method to be invoked. */ public void invokeVirtual(final Type owner, final Method method) { - invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method); + invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method, false); } /** @@ -1428,7 +1433,7 @@ * the constructor to be invoked. */ public void invokeConstructor(final Type type, final Method method) { - invokeInsn(Opcodes.INVOKESPECIAL, type, method); + invokeInsn(Opcodes.INVOKESPECIAL, type, method, false); } /** @@ -1440,7 +1445,7 @@ * the method to be invoked. */ public void invokeStatic(final Type owner, final Method method) { - invokeInsn(Opcodes.INVOKESTATIC, owner, method); + invokeInsn(Opcodes.INVOKESTATIC, owner, method, false); } /** @@ -1452,7 +1457,7 @@ * the method to be invoked. */ public void invokeInterface(final Type owner, final Method method) { - invokeInsn(Opcodes.INVOKEINTERFACE, owner, method); + invokeInsn(Opcodes.INVOKEINTERFACE, owner, method, true); } /**
--- a/src/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java Wed Nov 06 11:22:15 2013 -0800 @@ -82,9 +82,14 @@ * * @param mv * the method visitor to which this adapter delegates calls. + * @throws IllegalStateException + * If a subclass calls this constructor. */ public InstructionAdapter(final MethodVisitor mv) { this(Opcodes.ASM5, mv); + if (getClass() != InstructionAdapter.class) { + throw new IllegalStateException(); + } } /** @@ -536,18 +541,39 @@ } } + @Deprecated @Override public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) { + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, + opcode == Opcodes.INVOKEINTERFACE); + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, itf); + } + + private void doVisitMethodInsn(int opcode, final String owner, + final String name, final String desc, final boolean itf) { switch (opcode) { case Opcodes.INVOKESPECIAL: - invokespecial(owner, name, desc); + invokespecial(owner, name, desc, itf); break; case Opcodes.INVOKEVIRTUAL: - invokevirtual(owner, name, desc); + invokevirtual(owner, name, desc, itf); break; case Opcodes.INVOKESTATIC: - invokestatic(owner, name, desc); + invokestatic(owner, name, desc, itf); break; case Opcodes.INVOKEINTERFACE: invokeinterface(owner, name, desc); @@ -1014,24 +1040,78 @@ mv.visitFieldInsn(Opcodes.PUTFIELD, owner, name, desc); } + @Deprecated public void invokevirtual(final String owner, final String name, final String desc) { + if (api >= Opcodes.ASM5) { + invokevirtual(owner, name, desc, false); + return; + } mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc); } + public void invokevirtual(final String owner, final String name, + final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + if (itf) { + throw new IllegalArgumentException( + "INVOKEVIRTUAL on interfaces require ASM 5"); + } + invokevirtual(owner, name, desc); + return; + } + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, itf); + } + + @Deprecated + public void invokespecial(final String owner, final String name, + final String desc) { + if (api >= Opcodes.ASM5) { + invokespecial(owner, name, desc, false); + return; + } + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, false); + } + public void invokespecial(final String owner, final String name, + final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + if (itf) { + throw new IllegalArgumentException( + "INVOKESPECIAL on interfaces require ASM 5"); + } + invokespecial(owner, name, desc); + return; + } + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, itf); + } + + @Deprecated + public void invokestatic(final String owner, final String name, final String desc) { - mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc); + if (api < Opcodes.ASM5) { + invokestatic(owner, name, desc, false); + return; + } + mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, false); } public void invokestatic(final String owner, final String name, - final String desc) { - mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc); + final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + if (itf) { + throw new IllegalArgumentException( + "INVOKESTATIC on interfaces require ASM 5"); + } + invokestatic(owner, name, desc); + return; + } + mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, itf); } public void invokeinterface(final String owner, final String name, final String desc) { - mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, desc); + mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, desc, true); } public void invokedynamic(String name, String desc, Handle bsm,
--- a/src/share/classes/jdk/internal/org/objectweb/asm/commons/JSRInlinerAdapter.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/commons/JSRInlinerAdapter.java Wed Nov 06 11:22:15 2013 -0800 @@ -136,11 +136,16 @@ * the internal names of the method's exception classes (see * {@link Type#getInternalName() getInternalName}). May be * <tt>null</tt>. + * @throws IllegalStateException + * If a subclass calls this constructor. */ public JSRInlinerAdapter(final MethodVisitor mv, final int access, final String name, final String desc, final String signature, final String[] exceptions) { this(Opcodes.ASM5, mv, access, name, desc, signature, exceptions); + if (getClass() != JSRInlinerAdapter.class) { + throw new IllegalStateException(); + } } /** @@ -381,6 +386,17 @@ // Use tail recursion here in the form of an outer while loop to // avoid our stack growing needlessly: index++; + + // We implicitly assumed above that execution can always fall + // through to the next instruction after a JSR. But a subroutine may + // never return, in which case the code after the JSR is unreachable + // and can be anything. In particular, it can seem to fall off the + // end of the method, so we must handle this case here (we could + // instead detect whether execution can return or not from a JSR, + // but this is more complicated). + if (index >= instructions.size()) { + return; + } } }
--- a/src/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java Wed Nov 06 11:22:15 2013 -0800 @@ -120,10 +120,15 @@ * the method's descriptor (see {@link Type Type}). * @param mv * the method visitor to which this adapter delegates calls. + * @throws IllegalStateException + * If a subclass calls this constructor. */ public LocalVariablesSorter(final int access, final String desc, final MethodVisitor mv) { this(Opcodes.ASM5, access, desc, mv); + if (getClass() != LocalVariablesSorter.class) { + throw new IllegalStateException(); + } } /** @@ -323,6 +328,7 @@ int local = newLocalMapping(type); setLocalType(local, type); setFrameLocal(local, t); + changed = true; return local; }
--- a/src/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java Wed Nov 06 11:22:15 2013 -0800 @@ -148,12 +148,41 @@ remapper.mapDesc(desc)); } + @Deprecated @Override - public void visitMethodInsn(int opcode, String owner, String name, - String desc) { - super.visitMethodInsn(opcode, remapper.mapType(owner), - remapper.mapMethodName(owner, name, desc), - remapper.mapMethodDesc(desc)); + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc) { + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, + opcode == Opcodes.INVOKEINTERFACE); + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, itf); + } + + private void doVisitMethodInsn(int opcode, String owner, String name, + String desc, boolean itf) { + // Calling super.visitMethodInsn requires to call the correct version + // depending on this.api (otherwise infinite loops can occur). To + // simplify and to make it easier to automatically remove the backward + // compatibility code, we inline the code of the overridden method here. + // IMPORTANT: THIS ASSUMES THAT visitMethodInsn IS NOT OVERRIDDEN IN + // LocalVariableSorter. + if (mv != null) { + mv.visitMethodInsn(opcode, remapper.mapType(owner), + remapper.mapMethodName(owner, name, desc), + remapper.mapMethodDesc(desc), itf); + } } @Override
--- a/src/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java Wed Nov 06 11:22:15 2013 -0800 @@ -95,10 +95,12 @@ @Override public void visitInnerClassType(String name) { + String remappedOuter = remapper.mapType(className) + '$'; className = className + '$' + name; String remappedName = remapper.mapType(className); - v.visitInnerClassType(remappedName.substring(remappedName - .lastIndexOf('$') + 1)); + int index = remappedName.startsWith(remappedOuter) ? remappedOuter + .length() : remappedName.lastIndexOf('$') + 1; + v.visitInnerClassType(remappedName.substring(index)); } @Override
--- a/src/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java Wed Nov 06 11:22:15 2013 -0800 @@ -195,9 +195,14 @@ * @param cv * a {@link ClassVisitor} to which this visitor will delegate * calls. + * @throws IllegalStateException + * If a subclass calls this constructor. */ public SerialVersionUIDAdder(final ClassVisitor cv) { this(Opcodes.ASM5, cv); + if (getClass() != SerialVersionUIDAdder.class) { + throw new IllegalStateException(); + } } /** @@ -218,7 +223,7 @@ } // ------------------------------------------------------------------------ - // Overriden methods + // Overridden methods // ------------------------------------------------------------------------ /* @@ -234,7 +239,7 @@ if (computeSVUID) { this.name = name; this.access = access; - this.interfaces = interfaces; + this.interfaces = Arrays.copyOf(interfaces, interfaces.length); } super.visit(version, access, name, signature, superName, interfaces);
--- a/src/share/classes/jdk/internal/org/objectweb/asm/commons/StaticInitMerger.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/commons/StaticInitMerger.java Wed Nov 06 11:22:15 2013 -0800 @@ -107,7 +107,8 @@ if (clinit == null) { clinit = cv.visitMethod(a, name, desc, null, null); } - clinit.visitMethodInsn(Opcodes.INVOKESTATIC, this.name, n, desc); + clinit.visitMethodInsn(Opcodes.INVOKESTATIC, this.name, n, desc, + false); } else { mv = cv.visitMethod(access, name, desc, signature, exceptions); }
--- a/src/share/classes/jdk/internal/org/objectweb/asm/commons/TryCatchBlockSorter.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/commons/TryCatchBlockSorter.java Wed Nov 06 11:22:15 2013 -0800 @@ -66,7 +66,6 @@ import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.org.objectweb.asm.tree.MethodNode; import jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode; -import jdk.internal.org.objectweb.asm.tree.TypeAnnotationNode; /** * A {@link MethodVisitor} adapter to sort the exception handlers. The handlers
--- a/src/share/classes/jdk/internal/org/objectweb/asm/tree/AnnotationNode.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/tree/AnnotationNode.java Wed Nov 06 11:22:15 2013 -0800 @@ -96,9 +96,14 @@ * * @param desc * the class descriptor of the annotation class. + * @throws IllegalStateException + * If a subclass calls this constructor. */ public AnnotationNode(final String desc) { this(Opcodes.ASM5, desc); + if (getClass() != AnnotationNode.class) { + throw new IllegalStateException(); + } } /**
--- a/src/share/classes/jdk/internal/org/objectweb/asm/tree/ClassNode.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/tree/ClassNode.java Wed Nov 06 11:22:15 2013 -0800 @@ -216,9 +216,15 @@ * Constructs a new {@link ClassNode}. <i>Subclasses must not use this * constructor</i>. Instead, they must use the {@link #ClassNode(int)} * version. + * + * @throws IllegalStateException + * If a subclass calls this constructor. */ public ClassNode() { this(Opcodes.ASM5); + if (getClass() != ClassNode.class) { + throw new IllegalStateException(); + } } /**
--- a/src/share/classes/jdk/internal/org/objectweb/asm/tree/FieldNode.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/tree/FieldNode.java Wed Nov 06 11:22:15 2013 -0800 @@ -168,16 +168,20 @@ * <tt>null</tt> if the field does not have an initial value, * must be an {@link Integer}, a {@link Float}, a {@link Long}, a * {@link Double} or a {@link String}. + * @throws IllegalStateException + * If a subclass calls this constructor. */ public FieldNode(final int access, final String name, final String desc, final String signature, final Object value) { this(Opcodes.ASM5, access, name, desc, signature, value); + if (getClass() != FieldNode.class) { + throw new IllegalStateException(); + } } /** * Constructs a new {@link FieldNode}. <i>Subclasses must not use this - * constructor</i>. Instead, they must use the - * {@link #FieldNode(int, int, String, String, String, Object)} version. + * constructor</i>. * * @param api * the ASM API version implemented by this visitor. Must be one
--- a/src/share/classes/jdk/internal/org/objectweb/asm/tree/MethodInsnNode.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/tree/MethodInsnNode.java Wed Nov 06 11:22:15 2013 -0800 @@ -61,6 +61,7 @@ import java.util.Map; import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; /** * A node that represents a method instruction. A method instruction is an @@ -87,6 +88,11 @@ public String desc; /** + * If the method's owner class if an interface. + */ + public boolean itf; + + /** * Constructs a new {@link MethodInsnNode}. * * @param opcode @@ -102,12 +108,37 @@ * @param desc * the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}). */ + @Deprecated public MethodInsnNode(final int opcode, final String owner, final String name, final String desc) { + this(opcode, owner, name, desc, opcode == Opcodes.INVOKEINTERFACE); + } + + /** + * Constructs a new {@link MethodInsnNode}. + * + * @param opcode + * the opcode of the type instruction to be constructed. This + * opcode must be INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or + * INVOKEINTERFACE. + * @param owner + * the internal name of the method's owner class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() + * getInternalName}). + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}). + * @param itf + * if the method's owner class is an interface. + */ + public MethodInsnNode(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { super(opcode); this.owner = owner; this.name = name; this.desc = desc; + this.itf = itf; } /** @@ -128,11 +159,11 @@ @Override public void accept(final MethodVisitor mv) { - mv.visitMethodInsn(opcode, owner, name, desc); + mv.visitMethodInsn(opcode, owner, name, desc, itf); } @Override public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) { - return new MethodInsnNode(opcode, owner, name, desc); + return new MethodInsnNode(opcode, owner, name, desc, itf); } }
--- a/src/share/classes/jdk/internal/org/objectweb/asm/tree/MethodNode.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/tree/MethodNode.java Wed Nov 06 11:22:15 2013 -0800 @@ -71,7 +71,6 @@ import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.org.objectweb.asm.Type; import jdk.internal.org.objectweb.asm.TypePath; -import jdk.internal.org.objectweb.asm.TypeReference; /** * A node that represents a method. @@ -245,9 +244,15 @@ * Constructs an uninitialized {@link MethodNode}. <i>Subclasses must not * use this constructor</i>. Instead, they must use the * {@link #MethodNode(int)} version. + * + * @throws IllegalStateException + * If a subclass calls this constructor. */ public MethodNode() { this(Opcodes.ASM5); + if (getClass() != MethodNode.class) { + throw new IllegalStateException(); + } } /** @@ -281,10 +286,15 @@ * the internal names of the method's exception classes (see * {@link Type#getInternalName() getInternalName}). May be * <tt>null</tt>. + * @throws IllegalStateException + * If a subclass calls this constructor. */ public MethodNode(final int access, final String name, final String desc, final String signature, final String[] exceptions) { this(Opcodes.ASM5, access, name, desc, signature, exceptions); + if (getClass() != MethodNode.class) { + throw new IllegalStateException(); + } } /** @@ -461,13 +471,28 @@ instructions.add(new FieldInsnNode(opcode, owner, name, desc)); } + @Deprecated @Override - public void visitMethodInsn(final int opcode, final String owner, - final String name, final String desc) { + public void visitMethodInsn(int opcode, String owner, String name, + String desc) { + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc); + return; + } instructions.add(new MethodInsnNode(opcode, owner, name, desc)); } @Override + public void visitMethodInsn(int opcode, String owner, String name, + String desc, boolean itf) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + return; + } + instructions.add(new MethodInsnNode(opcode, owner, name, desc, itf)); + } + + @Override public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) { instructions.add(new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs)); @@ -696,6 +721,12 @@ && insn.invisibleTypeAnnotations.size() > 0) { throw new RuntimeException(); } + if (insn instanceof MethodInsnNode) { + boolean itf = ((MethodInsnNode) insn).itf; + if (itf != (insn.opcode == Opcodes.INVOKEINTERFACE)) { + throw new RuntimeException(); + } + } } if (visibleLocalVariableAnnotations != null && visibleLocalVariableAnnotations.size() > 0) { @@ -705,7 +736,6 @@ && invisibleLocalVariableAnnotations.size() > 0) { throw new RuntimeException(); } - } }
--- a/src/share/classes/jdk/internal/org/objectweb/asm/tree/TypeAnnotationNode.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/tree/TypeAnnotationNode.java Wed Nov 06 11:22:15 2013 -0800 @@ -94,10 +94,15 @@ * <tt>null</tt> if the annotation targets 'typeRef' as a whole. * @param desc * the class descriptor of the annotation class. + * @throws IllegalStateException + * If a subclass calls this constructor. */ public TypeAnnotationNode(final int typeRef, final TypePath typePath, final String desc) { this(Opcodes.ASM5, typeRef, typePath, desc); + if (getClass() != TypeAnnotationNode.class) { + throw new IllegalStateException(); + } } /**
--- a/src/share/classes/jdk/internal/org/objectweb/asm/tree/analysis/Frame.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/tree/analysis/Frame.java Wed Nov 06 11:22:15 2013 -0800 @@ -163,6 +163,15 @@ } /** + * Returns the maximum stack size of this frame. + * + * @return the maximum stack size of this frame. + */ + public int getMaxStackSize() { + return values.length - locals; + } + + /** * Returns the value of the given local variable. * * @param i
--- a/src/share/classes/jdk/internal/org/objectweb/asm/util/ASMifier.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/util/ASMifier.java Wed Nov 06 11:22:15 2013 -0800 @@ -113,9 +113,15 @@ * Constructs a new {@link ASMifier}. <i>Subclasses must not use this * constructor</i>. Instead, they must use the * {@link #ASMifier(int, String, int)} version. + * + * @throws IllegalStateException + * If a subclass calls this constructor. */ public ASMifier() { this(Opcodes.ASM5, "cw", 0); + if (getClass() != ASMifier.class) { + throw new IllegalStateException(); + } } /** @@ -483,8 +489,9 @@ @Override public void visitParameter(String parameterName, int access) { buf.setLength(0); - buf.append(name).append(".visitParameter(").append(parameterName) - .append(", "); + buf.append(name).append(".visitParameter("); + appendString(buf, parameterName); + buf.append(", "); appendAccess(access); text.add(buf.append(");\n").toString()); } @@ -639,9 +646,30 @@ text.add(buf.toString()); } + @Deprecated @Override public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) { + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, + opcode == Opcodes.INVOKEINTERFACE); + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, itf); + } + + private void doVisitMethodInsn(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { buf.setLength(0); buf.append(this.name).append(".visitMethodInsn(") .append(OPCODES[opcode]).append(", "); @@ -650,6 +678,8 @@ appendConstant(name); buf.append(", "); appendConstant(desc); + buf.append(", "); + buf.append(itf ? "true" : "false"); buf.append(");\n"); text.add(buf.toString()); } @@ -1076,6 +1106,13 @@ buf.append("ACC_DEPRECATED"); first = false; } + if ((access & Opcodes.ACC_MANDATED) != 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_MANDATED"); + first = false; + } if (first) { buf.append('0'); }
--- a/src/share/classes/jdk/internal/org/objectweb/asm/util/CheckClassAdapter.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/util/CheckClassAdapter.java Wed Nov 06 11:22:15 2013 -0800 @@ -246,7 +246,7 @@ List<Type> interfaces = new ArrayList<Type>(); for (Iterator<String> i = cn.interfaces.iterator(); i.hasNext();) { - interfaces.add(Type.getObjectType(i.next().toString())); + interfaces.add(Type.getObjectType(i.next())); } for (int i = 0; i < methods.size(); ++i) { @@ -359,9 +359,14 @@ * <tt>false</tt> to not perform any data flow check (see * {@link CheckMethodAdapter}). This option requires valid * maxLocals and maxStack values. + * @throws IllegalStateException + * If a subclass calls this constructor. */ public CheckClassAdapter(final ClassVisitor cv, final boolean checkDataFlow) { this(Opcodes.ASM5, cv, checkDataFlow); + if (getClass() != CheckClassAdapter.class) { + throw new IllegalStateException(); + } } /** @@ -471,7 +476,15 @@ CheckMethodAdapter.checkInternalName(outerName, "outer class name"); } if (innerName != null) { - CheckMethodAdapter.checkIdentifier(innerName, "inner class name"); + int start = 0; + while (start < innerName.length() + && Character.isDigit(innerName.charAt(start))) { + start++; + } + if (start == 0 || start < innerName.length()) { + CheckMethodAdapter.checkIdentifier(innerName, start, -1, + "inner class name"); + } } checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
--- a/src/share/classes/jdk/internal/org/objectweb/asm/util/CheckFieldAdapter.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/util/CheckFieldAdapter.java Wed Nov 06 11:22:15 2013 -0800 @@ -79,9 +79,14 @@ * * @param fv * the field visitor to which this adapter must delegate calls. + * @throws IllegalStateException + * If a subclass calls this constructor. */ public CheckFieldAdapter(final FieldVisitor fv) { this(Opcodes.ASM5, fv); + if (getClass() != CheckFieldAdapter.class) { + throw new IllegalStateException(); + } } /**
--- a/src/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java Wed Nov 06 11:22:15 2013 -0800 @@ -143,11 +143,6 @@ private Set<Label> usedLabels; /** - * If an explicit first frame has been visited before the first instruction. - */ - private boolean hasExplicitFirstFrame; - - /** * Number of visited frames in expanded form. */ private int expandedFrames; @@ -158,6 +153,11 @@ private int compressedFrames; /** + * Number of instructions before the last visited frame. + */ + private int lastFrame = -1; + + /** * The exception handler ranges. Each pair of list element contains the * start and end labels of an exception handler block. */ @@ -421,10 +421,15 @@ * the method visitor to which this adapter must delegate calls. * @param labels * a map of already visited labels (in other methods). + * @throws IllegalStateException + * If a subclass calls this constructor. */ public CheckMethodAdapter(final MethodVisitor mv, final Map<Label, Integer> labels) { this(Opcodes.ASM5, mv, labels); + if (getClass() != CheckMethodAdapter.class) { + throw new IllegalStateException(); + } } /** @@ -465,7 +470,7 @@ public CheckMethodAdapter(final int access, final String name, final String desc, final MethodVisitor cmv, final Map<Label, Integer> labels) { - this(new MethodNode(access, name, desc, null, null) { + this(new MethodNode(Opcodes.ASM5, access, name, desc, null, null) { @Override public void visitEnd() { Analyzer<BasicValue> a = new Analyzer<BasicValue>( @@ -499,6 +504,7 @@ } CheckClassAdapter.checkAccess(access, Opcodes.ACC_FINAL + Opcodes.ACC_MANDATED + Opcodes.ACC_SYNTHETIC); + super.visitParameter(name, access); } @Override @@ -566,6 +572,11 @@ @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) { @@ -621,13 +632,6 @@ checkFrameValue(stack[i]); } if (type == Opcodes.F_NEW) { - if (insnCount == 0) { - hasExplicitFirstFrame = true; - } else if (!hasExplicitFirstFrame) { - throw new RuntimeException( - "In expanded form, a first frame must be explicitly " - + "visited before the first instruction."); - } ++expandedFrames; } else { ++compressedFrames; @@ -709,9 +713,30 @@ ++insnCount; } + @Deprecated @Override - public void visitMethodInsn(final int opcode, final String owner, - final String name, final String desc) { + public void visitMethodInsn(int opcode, String owner, String name, + String desc) { + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, + opcode == Opcodes.INVOKEINTERFACE); + } + + @Override + public void visitMethodInsn(int opcode, String owner, String name, + String desc, boolean itf) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, itf); + } + + private void doVisitMethodInsn(int opcode, final String owner, + final String name, final String desc, final boolean itf) { checkStartCode(); checkEndCode(); checkOpcode(opcode, 5); @@ -720,7 +745,21 @@ } checkInternalName(owner, "owner"); checkMethodDesc(desc); - super.visitMethodInsn(opcode, owner, name, desc); + if (opcode == Opcodes.INVOKEVIRTUAL && itf) { + throw new IllegalArgumentException( + "INVOKEVIRTUAL can't be used with interfaces"); + } + if (opcode == Opcodes.INVOKEINTERFACE && !itf) { + throw new IllegalArgumentException( + "INVOKEINTERFACE can't be used with classes"); + } + // Calling super.visitMethodInsn requires to call the correct version + // depending on this.api (otherwise infinite loops can occur). To + // simplify and to make it easier to automatically remove the backward + // compatibility code, we inline the code of the overridden method here. + if (mv != null) { + mv.visitMethodInsn(opcode, owner, name, desc, itf); + } ++insnCount; }
--- a/src/share/classes/jdk/internal/org/objectweb/asm/util/Printer.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/util/Printer.java Wed Nov 06 11:22:15 2013 -0800 @@ -401,8 +401,33 @@ * Method instruction. See * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMethodInsn}. */ - public abstract void visitMethodInsn(final int opcode, final String owner, - final String name, final String desc); + @Deprecated + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc) { + if (api >= Opcodes.ASM5) { + boolean itf = opcode == Opcodes.INVOKEINTERFACE; + visitMethodInsn(opcode, owner, name, desc, itf); + return; + } + throw new RuntimeException("Must be overriden"); + } + + /** + * Method instruction. See + * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMethodInsn}. + */ + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + if (itf != (opcode == Opcodes.INVOKEINTERFACE)) { + throw new IllegalArgumentException( + "INVOKESPECIAL/STATIC on interfaces require ASM 5"); + } + visitMethodInsn(opcode, owner, name, desc); + return; + } + throw new RuntimeException("Must be overriden"); + } /** * Method instruction. See
--- a/src/share/classes/jdk/internal/org/objectweb/asm/util/Textifier.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/util/Textifier.java Wed Nov 06 11:22:15 2013 -0800 @@ -172,9 +172,15 @@ * Constructs a new {@link Textifier}. <i>Subclasses must not use this * constructor</i>. Instead, they must use the {@link #Textifier(int)} * version. + * + * @throws IllegalStateException + * If a subclass calls this constructor. */ public Textifier() { this(Opcodes.ASM5); + if (getClass() != Textifier.class) { + throw new IllegalStateException(); + } } /** @@ -821,14 +827,36 @@ text.add(buf.toString()); } + @Deprecated @Override public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) { + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, + opcode == Opcodes.INVOKEINTERFACE); + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, itf); + } + + private void doVisitMethodInsn(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { buf.setLength(0); buf.append(tab2).append(OPCODES[opcode]).append(' '); appendDescriptor(INTERNAL_NAME, owner); buf.append('.').append(name).append(' '); appendDescriptor(METHOD_DESCRIPTOR, desc); + buf.append(' ').append(itf ? "itf" : ""); buf.append('\n'); text.add(buf.toString()); }
--- a/src/share/classes/jdk/internal/org/objectweb/asm/util/TraceMethodVisitor.java Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/util/TraceMethodVisitor.java Wed Nov 06 11:22:15 2013 -0800 @@ -176,11 +176,31 @@ super.visitFieldInsn(opcode, owner, name, desc); } + @Deprecated @Override - public void visitMethodInsn(final int opcode, final String owner, - final String name, final String desc) { + public void visitMethodInsn(int opcode, String owner, String name, + String desc) { + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc); + return; + } p.visitMethodInsn(opcode, owner, name, desc); - super.visitMethodInsn(opcode, owner, name, desc); + if (mv != null) { + mv.visitMethodInsn(opcode, owner, name, desc); + } + } + + @Override + public void visitMethodInsn(int opcode, String owner, String name, + String desc, boolean itf) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + return; + } + p.visitMethodInsn(opcode, owner, name, desc, itf); + if (mv != null) { + mv.visitMethodInsn(opcode, owner, name, desc, itf); + } } @Override
--- a/src/share/classes/jdk/internal/org/objectweb/asm/version.txt Wed Nov 06 13:25:24 2013 -0800 +++ b/src/share/classes/jdk/internal/org/objectweb/asm/version.txt Wed Nov 06 11:22:15 2013 -0800 @@ -1,12 +1,12 @@ Path: . -Working Copy Root Path: /w/lthudson/hudson-data/jobs/objectweb-cr-pull/workspace/ASM_5_FUTURE -URL: svn://svn.forge.objectweb.org/svnroot/asm/branches/ASM_5_FUTURE +Working Copy Root Path: /hudson/jobs/objectweb-pull/workspace/ASM_5_0_BETA +URL: svn://svn.forge.objectweb.org/svnroot/asm/trunk/asm Repository Root: svn://svn.forge.objectweb.org/svnroot/asm Repository UUID: 271bd773-ee82-43a6-9b2b-1890ed8ce7f9 -Revision: 1681 +Revision: 1700 Node Kind: directory Schedule: normal -Last Changed Author: forax -Last Changed Rev: 1681 -Last Changed Date: 2013-04-01 11:28:58 -0700 (Mon, 01 Apr 2013) +Last Changed Author: ebruneton +Last Changed Rev: 1700 +Last Changed Date: 2013-10-29 20:22:52 +0100 (Tue, 29 Oct 2013)