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
author ksrini
date Wed, 06 Nov 2013 11:22:15 -0800
parents 6ea1f9d8ec78
children dbda97d6aa3a
files src/share/classes/jdk/internal/org/objectweb/asm/ByteVector.java src/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java src/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java src/share/classes/jdk/internal/org/objectweb/asm/Handle.java src/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java src/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java src/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java src/share/classes/jdk/internal/org/objectweb/asm/commons/AnalyzerAdapter.java src/share/classes/jdk/internal/org/objectweb/asm/commons/CodeSizeEvaluator.java src/share/classes/jdk/internal/org/objectweb/asm/commons/GeneratorAdapter.java src/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java src/share/classes/jdk/internal/org/objectweb/asm/commons/JSRInlinerAdapter.java src/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java src/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java src/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java src/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java src/share/classes/jdk/internal/org/objectweb/asm/commons/StaticInitMerger.java src/share/classes/jdk/internal/org/objectweb/asm/commons/TryCatchBlockSorter.java src/share/classes/jdk/internal/org/objectweb/asm/tree/AnnotationNode.java src/share/classes/jdk/internal/org/objectweb/asm/tree/ClassNode.java src/share/classes/jdk/internal/org/objectweb/asm/tree/FieldNode.java src/share/classes/jdk/internal/org/objectweb/asm/tree/MethodInsnNode.java src/share/classes/jdk/internal/org/objectweb/asm/tree/MethodNode.java src/share/classes/jdk/internal/org/objectweb/asm/tree/TypeAnnotationNode.java src/share/classes/jdk/internal/org/objectweb/asm/tree/analysis/Frame.java src/share/classes/jdk/internal/org/objectweb/asm/util/ASMifier.java src/share/classes/jdk/internal/org/objectweb/asm/util/CheckClassAdapter.java src/share/classes/jdk/internal/org/objectweb/asm/util/CheckFieldAdapter.java src/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java src/share/classes/jdk/internal/org/objectweb/asm/util/Printer.java src/share/classes/jdk/internal/org/objectweb/asm/util/Textifier.java src/share/classes/jdk/internal/org/objectweb/asm/util/TraceMethodVisitor.java src/share/classes/jdk/internal/org/objectweb/asm/version.txt
diffstat 33 files changed, 711 insertions(+), 119 deletions(-) [+]
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)