< prev index next >

src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java

Print this page
rev 47452 : imported patch jdk-new-asmv6.patch

@@ -85,12 +85,12 @@
      * Flag to automatically compute the stack map frames of methods from
      * scratch. If this flag is set, then the calls to the
      * {@link MethodVisitor#visitFrame} method are ignored, and the stack map
      * frames are recomputed from the methods bytecode. The arguments of the
      * {@link MethodVisitor#visitMaxs visitMaxs} method are also ignored and
-     * recomputed from the bytecode. In other words, computeFrames implies
-     * computeMaxs.
+     * recomputed from the bytecode. In other words, COMPUTE_FRAMES implies
+     * COMPUTE_MAXS.
      *
      * @see #ClassWriter(int)
      */
     public static final int COMPUTE_FRAMES = 2;
 

@@ -195,10 +195,31 @@
      * The type of the WIDE instruction.
      */
     static final int WIDE_INSN = 17;
 
     /**
+     * The type of the ASM pseudo instructions with an unsigned 2 bytes offset
+     * label (see Label#resolve).
+     */
+    static final int ASM_LABEL_INSN = 18;
+
+    /**
+     * The type of the ASM pseudo instructions with a 4 bytes offset label.
+     */
+    static final int ASM_LABELW_INSN = 19;
+
+    /**
+     * Represents a frame inserted between already existing frames. This kind of
+     * frame can only be used if the frame content can be computed from the
+     * previous existing frame and from the instructions between this existing
+     * frame and the inserted one, without any knowledge of the type hierarchy.
+     * This kind of frame is only used when an unconditional jump is inserted in
+     * a method while expanding an ASM pseudo instruction (see ClassReader).
+     */
+    static final int F_INSERT = 256;
+
+    /**
      * The instruction types of all JVM opcodes.
      */
     static final byte[] TYPE;
 
     /**

@@ -282,11 +303,11 @@
     static final int PACKAGE = 20;
 
     /**
      * The base value for all CONSTANT_MethodHandle constant pool items.
      * Internally, ASM store the 9 variations of CONSTANT_MethodHandle into 9
-     * different items.
+     * different items (from 21 to 29).
      */
     static final int HANDLE_BASE = 20;
 
     /**
      * Normal type Item stored in the ClassWriter {@link ClassWriter#typeTable},

@@ -432,10 +453,15 @@
      * The SourceDebug attribute of this class.
      */
     private ByteVector sourceDebug;
 
     /**
+     * The module attribute of this class.
+     */
+    private ModuleWriter moduleWriter;
+
+    /**
      * The constant pool item that contains the name of the enclosing class of
      * this class.
      */
     private int enclosingMethodOwner;
 

@@ -521,44 +547,38 @@
      * list.
      */
     MethodWriter lastMethod;
 
     /**
-     * <tt>true</tt> if the maximum stack size and number of local variables
-     * must be automatically computed.
+     * Indicates what must be automatically computed.
+     *
+     * @see MethodWriter#compute
      */
-    private boolean computeMaxs;
+    private int compute;
 
     /**
-     * <tt>true</tt> if the stack map frames must be recomputed from scratch.
+     * <tt>true</tt> if some methods have wide forward jumps using ASM pseudo
+     * instructions, which need to be expanded into sequences of standard
+     * bytecode instructions. In this case the class is re-read and re-written
+     * with a ClassReader -> ClassWriter chain to perform this transformation.
      */
-    private boolean computeFrames;
+    boolean hasAsmInsns;
 
-    /**
-     * <tt>true</tt> if the stack map tables of this class are invalid. The
-     * {@link MethodWriter#resizeInstructions} method cannot transform existing
-     * stack map tables, and so produces potentially invalid classes when it is
-     * executed. In this case the class is reread and rewritten with the
-     * {@link #COMPUTE_FRAMES} option (the resizeInstructions method can resize
-     * stack map tables when this option is used).
-     */
-    boolean invalidFrames;
-
     // ------------------------------------------------------------------------
     // Static initializer
     // ------------------------------------------------------------------------
 
     /**
      * Computes the instruction types of JVM opcodes.
      */
     static {
         int i;
-        byte[] b = new byte[220];
+        byte[] b = new byte[221];
         String s = "AAAAAAAAAAAAAAAABCLMMDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD"
                 + "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
                 + "AAAAAAAAAAAAAAAAANAAAAAAAAAAAAAAAAAAAAJJJJJJJJJJJJJJJJDOPAA"
-                + "AAAAGGGGGGGHIFBFAAFFAARQJJKKJJJJJJJJJJJJJJJJJJ";
+                + "AAAAGGGGGGGHIFBFAAFFAARQJJKKSSSSSSSSSSSSSSSSSST";
         for (i = 0; i < b.length; ++i) {
             b[i] = (byte) (s.charAt(i) - 'A');
         }
         TYPE = b;
 

@@ -608,12 +628,13 @@
         // b[200] = LABELW_INSN; // GOTO_W
         // b[201] = LABELW_INSN; // JSR_W
         // // temporary opcodes used internally by ASM - see Label and
         // MethodWriter
         // for (i = 202; i < 220; ++i) {
-        // b[i] = LABEL_INSN;
+        // b[i] = ASM_LABEL_INSN;
         // }
+        // b[220] = ASM_LABELW_INSN;
         //
         // // LDC(_W) instructions
         // b[Constants.LDC] = LDC_INSN;
         // b[19] = LDCW_INSN; // LDC_W
         // b[20] = LDCW_INSN; // LDC2_W

@@ -642,21 +663,22 @@
      *            option flags that can be used to modify the default behavior
      *            of this class. See {@link #COMPUTE_MAXS},
      *            {@link #COMPUTE_FRAMES}.
      */
     public ClassWriter(final int flags) {
-        super(Opcodes.ASM5);
+        super(Opcodes.ASM6);
         index = 1;
         pool = new ByteVector();
         items = new Item[256];
         threshold = (int) (0.75d * items.length);
         key = new Item();
         key2 = new Item();
         key3 = new Item();
         key4 = new Item();
-        this.computeMaxs = (flags & COMPUTE_MAXS) != 0;
-        this.computeFrames = (flags & COMPUTE_FRAMES) != 0;
+        this.compute = (flags & COMPUTE_FRAMES) != 0 ? MethodWriter.FRAMES
+                : ((flags & COMPUTE_MAXS) != 0 ? MethodWriter.MAXS
+                        : MethodWriter.NOTHING);
     }
 
     /**
      * Constructs a new {@link ClassWriter} object and enables optimizations for
      * "mostly add" bytecode transformations. These optimizations are the

@@ -682,13 +704,13 @@
      *            original class and also to copy other fragments of original
      *            bytecode where applicable.
      * @param flags
      *            option flags that can be used to modify the default behavior
      *            of this class. <i>These option flags do not affect methods
-     *            that are copied as is in the new class. This means that the
-     *            maximum stack size nor the stack frames will be computed for
-     *            these methods</i>. See {@link #COMPUTE_MAXS},
+     *            that are copied as is in the new class. This means that
+     *            neither the maximum stack size nor the stack frames will be
+     *            computed for these methods</i>. See {@link #COMPUTE_MAXS},
      *            {@link #COMPUTE_FRAMES}.
      */
     public ClassWriter(final ClassReader classReader, final int flags) {
         this(flags);
         classReader.copyPool(this);

@@ -703,13 +725,13 @@
     public final void visit(final int version, final int access,
             final String name, final String signature, final String superName,
             final String[] interfaces) {
         this.version = version;
         this.access = access;
-        this.name = (name == null) ? 0 : newClass(name);
+        this.name = newClass(name);
         thisName = name;
-        if (ClassReader.SIGNATURES && signature != null) {
+        if (signature != null) {
             this.signature = newUTF8(signature);
         }
         this.superName = superName == null ? 0 : newClass(superName);
         if (interfaces != null && interfaces.length > 0) {
             interfaceCount = interfaces.length;

@@ -730,10 +752,18 @@
                     Integer.MAX_VALUE);
         }
     }
 
     @Override
+    public final ModuleVisitor visitModule(final String name,
+            final int access, final String version) {
+        return moduleWriter = new ModuleWriter(this,
+                newModule(name), access,
+                version == null ? 0 : newUTF8(version));
+    }
+
+    @Override
     public final void visitOuterClass(final String owner, final String name,
             final String desc) {
         enclosingMethodOwner = newClass(owner);
         if (name != null && desc != null) {
             enclosingMethod = newNameType(name, desc);

@@ -741,13 +771,10 @@
     }
 
     @Override
     public final AnnotationVisitor visitAnnotation(final String desc,
             final boolean visible) {
-        if (!ClassReader.ANNOTATIONS) {
-            return null;
-        }
         ByteVector bv = new ByteVector();
         // write type, and reserve space for values count
         bv.putShort(newUTF8(desc)).putShort(0);
         AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, 2);
         if (visible) {

@@ -761,13 +788,10 @@
     }
 
     @Override
     public final AnnotationVisitor visitTypeAnnotation(int typeRef,
             TypePath typePath, final String desc, final boolean visible) {
-        if (!ClassReader.ANNOTATIONS) {
-            return null;
-        }
         ByteVector bv = new ByteVector();
         // write target_type and target_info
         AnnotationWriter.putTarget(typeRef, typePath, bv);
         // write type, and reserve space for values count
         bv.putShort(newUTF8(desc)).putShort(0);

@@ -803,11 +827,11 @@
         // class entry has already been added for C (this field is unused for
         // class entries, and changing its value does not change the hashcode
         // and equality tests). If so we store the index of this inner class
         // entry (plus one) in intVal. This hack allows duplicate detection in
         // O(1) time.
-        Item nameItem = newClassItem(name);
+        Item nameItem = newStringishItem(CLASS, name);
         if (nameItem.intVal == 0) {
             ++innerClassesCount;
             innerClasses.putShort(nameItem.index);
             innerClasses.putShort(outerName == null ? 0 : newClass(outerName));
             innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName));

@@ -828,11 +852,11 @@
 
     @Override
     public final MethodVisitor visitMethod(final int access, final String name,
             final String desc, final String signature, final String[] exceptions) {
         return new MethodWriter(this, access, name, desc, signature,
-                exceptions, computeMaxs, computeFrames);
+                exceptions, compute);
     }
 
     @Override
     public final void visitEnd() {
     }

@@ -872,11 +896,11 @@
             // ClassReader.copyBootstrapMethods
             ++attributeCount;
             size += 8 + bootstrapMethods.length;
             newUTF8("BootstrapMethods");
         }
-        if (ClassReader.SIGNATURES && signature != 0) {
+        if (signature != 0) {
             ++attributeCount;
             size += 8;
             newUTF8("Signature");
         }
         if (sourceFile != 0) {

@@ -910,30 +934,35 @@
         if (innerClasses != null) {
             ++attributeCount;
             size += 8 + innerClasses.length;
             newUTF8("InnerClasses");
         }
-        if (ClassReader.ANNOTATIONS && anns != null) {
+        if (anns != null) {
             ++attributeCount;
             size += 8 + anns.getSize();
             newUTF8("RuntimeVisibleAnnotations");
         }
-        if (ClassReader.ANNOTATIONS && ianns != null) {
+        if (ianns != null) {
             ++attributeCount;
             size += 8 + ianns.getSize();
             newUTF8("RuntimeInvisibleAnnotations");
         }
-        if (ClassReader.ANNOTATIONS && tanns != null) {
+        if (tanns != null) {
             ++attributeCount;
             size += 8 + tanns.getSize();
             newUTF8("RuntimeVisibleTypeAnnotations");
         }
-        if (ClassReader.ANNOTATIONS && itanns != null) {
+        if (itanns != null) {
             ++attributeCount;
             size += 8 + itanns.getSize();
             newUTF8("RuntimeInvisibleTypeAnnotations");
         }
+        if (moduleWriter != null) {
+            attributeCount += 1 + moduleWriter.attributeCount;
+            size += 6 + moduleWriter.size + moduleWriter.attributesSize;
+            newUTF8("Module");
+        }
         if (attrs != null) {
             attributeCount += attrs.getCount();
             size += attrs.getSize(this, null, 0, -1, -1);
         }
         size += pool.length;

@@ -966,11 +995,11 @@
             out.putShort(newUTF8("BootstrapMethods"));
             out.putInt(bootstrapMethods.length + 2).putShort(
                     bootstrapMethodsCount);
             out.putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length);
         }
-        if (ClassReader.SIGNATURES && signature != 0) {
+        if (signature != 0) {
             out.putShort(newUTF8("Signature")).putInt(2).putShort(signature);
         }
         if (sourceFile != 0) {
             out.putShort(newUTF8("SourceFile")).putInt(2).putShort(sourceFile);
         }

@@ -977,10 +1006,15 @@
         if (sourceDebug != null) {
             int len = sourceDebug.length;
             out.putShort(newUTF8("SourceDebugExtension")).putInt(len);
             out.putByteArray(sourceDebug.data, 0, len);
         }
+        if (moduleWriter != null) {
+            out.putShort(newUTF8("Module"));
+            moduleWriter.put(out);
+            moduleWriter.putAttributes(out);
+        }
         if (enclosingMethodOwner != 0) {
             out.putShort(newUTF8("EnclosingMethod")).putInt(4);
             out.putShort(enclosingMethodOwner).putShort(enclosingMethod);
         }
         if ((access & Opcodes.ACC_DEPRECATED) != 0) {

@@ -995,45 +1029,50 @@
         if (innerClasses != null) {
             out.putShort(newUTF8("InnerClasses"));
             out.putInt(innerClasses.length + 2).putShort(innerClassesCount);
             out.putByteArray(innerClasses.data, 0, innerClasses.length);
         }
-        if (ClassReader.ANNOTATIONS && anns != null) {
+        if (anns != null) {
             out.putShort(newUTF8("RuntimeVisibleAnnotations"));
             anns.put(out);
         }
-        if (ClassReader.ANNOTATIONS && ianns != null) {
+        if (ianns != null) {
             out.putShort(newUTF8("RuntimeInvisibleAnnotations"));
             ianns.put(out);
         }
-        if (ClassReader.ANNOTATIONS && tanns != null) {
+        if (tanns != null) {
             out.putShort(newUTF8("RuntimeVisibleTypeAnnotations"));
             tanns.put(out);
         }
-        if (ClassReader.ANNOTATIONS && itanns != null) {
+        if (itanns != null) {
             out.putShort(newUTF8("RuntimeInvisibleTypeAnnotations"));
             itanns.put(out);
         }
         if (attrs != null) {
             attrs.put(this, null, 0, -1, -1, out);
         }
-        if (invalidFrames) {
+        if (hasAsmInsns) {
+            boolean hasFrames = false;
+            mb = firstMethod;
+            while (mb != null) {
+                hasFrames |= mb.frameCount > 0;
+                mb = (MethodWriter) mb.mv;
+            }
             anns = null;
             ianns = null;
             attrs = null;
-            innerClassesCount = 0;
-            innerClasses = null;
-            bootstrapMethodsCount = 0;
-            bootstrapMethods = null;
+            moduleWriter = null;
             firstField = null;
             lastField = null;
             firstMethod = null;
             lastMethod = null;
-            computeMaxs = false;
-            computeFrames = true;
-            invalidFrames = false;
-            new ClassReader(out.data).accept(this, ClassReader.SKIP_FRAMES);
+            compute =
+                hasFrames ? MethodWriter.INSERTED_FRAMES : MethodWriter.NOTHING;
+            hasAsmInsns = false;
+            new ClassReader(out.data).accept(this,
+                    (hasFrames ? ClassReader.EXPAND_FRAMES : 0)
+                    | ClassReader.EXPAND_ASM_INSNS);
             return toByteArray();
         }
         return out.data;
     }
 

@@ -1076,20 +1115,20 @@
             return newLong(val);
         } else if (cst instanceof Double) {
             double val = ((Double) cst).doubleValue();
             return newDouble(val);
         } else if (cst instanceof String) {
-            return newString((String) cst);
+            return newStringishItem(STR, (String) cst);
         } else if (cst instanceof Type) {
             Type t = (Type) cst;
             int s = t.getSort();
             if (s == Type.OBJECT) {
-                return newClassItem(t.getInternalName());
+                return newStringishItem(CLASS, t.getInternalName());
             } else if (s == Type.METHOD) {
-                return newMethodTypeItem(t.getDescriptor());
+                return newStringishItem(MTYPE, t.getDescriptor());
             } else { // s == primitive type or array
-                return newClassItem(t.getDescriptor());
+                return newStringishItem(CLASS, t.getDescriptor());
             }
         } else if (cst instanceof Handle) {
             Handle h = (Handle) cst;
             return newHandleItem(h.tag, h.owner, h.name, h.desc, h.itf);
         } else {

@@ -1134,24 +1173,25 @@
         }
         return result.index;
     }
 
     /**
-     * Adds a class reference to the constant pool of the class being build.
+     * Adds a string reference, a class reference, a method type, a module
+     * or a package to the constant pool of the class being build.
      * Does nothing if the constant pool already contains a similar item.
-     * <i>This method is intended for {@link Attribute} sub classes, and is
-     * normally not needed by class generators or adapters.</i>
      *
+     * @param type
+     *            a type among STR, CLASS, MTYPE, MODULE or PACKAGE
      * @param value
-     *            the internal name of the class.
-     * @return a new or already existing class reference item.
+     *            string value of the reference.
+     * @return a new or already existing reference item.
      */
-    Item newClassItem(final String value) {
-        key2.set(CLASS, value, null, null);
+    Item newStringishItem(final int type, final String value) {
+        key2.set(type, value, null, null);
         Item result = get(key2);
         if (result == null) {
-            pool.put12(CLASS, newUTF8(value));
+            pool.put12(type, newUTF8(value));
             result = new Item(index++, key2);
             put(result);
         }
         return result;
     }

@@ -1165,91 +1205,56 @@
      * @param value
      *            the internal name of the class.
      * @return the index of a new or already existing class reference item.
      */
     public int newClass(final String value) {
-        return newClassItem(value).index;
+        return newStringishItem(CLASS, value).index;
     }
 
     /**
-     * Adds a module name to the constant pool.
-     *
-     * Does nothing if the constant pool already contains a similar item.
+     * Adds a method type reference to the constant pool of the class being
+     * build. Does nothing if the constant pool already contains a similar item.
      * <i>This method is intended for {@link Attribute} sub classes, and is
      * normally not needed by class generators or adapters.</i>
      *
-     * @param  value
-     *         the module name
-     * @return the index of a new or already existing module reference item.
+     * @param methodDesc
+     *            method descriptor of the method type.
+     * @return the index of a new or already existing method type reference
+     *         item.
      */
-    public int newModule(String value) {
-        key2.set(MODULE, value, null, null);
-        Item result = get(key2);
-        if (result == null) {
-            pool.put12(MODULE, newUTF8(value));
-            result = new Item(index++, key2);
-            put(result);
+    public int newMethodType(final String methodDesc) {
+        return newStringishItem(MTYPE, methodDesc).index;
         }
-        return result.index;
-    }
 
     /**
-     * Adds a package name to the constant pool.
-     *
-     * Does nothing if the constant pool already contains a similar item.
-     * <i>This method is intended for {@link Attribute} sub classes, and is
-     * normally not needed by class generators or adapters.</i>
-     *
-     * @param  value
-     *         the internal name of the package.
-     * @return the index of a new or already existing package reference item.
-     */
-    public int newPackage(String value) {
-        key2.set(PACKAGE, value, null, null);
-        Item result = get(key2);
-        if (result == null) {
-            pool.put12(PACKAGE, newUTF8(value));
-            result = new Item(index++, key2);
-            put(result);
-        }
-        return result.index;
-    }
-
-    /**
-     * Adds a method type reference to the constant pool of the class being
+     * Adds a module reference to the constant pool of the class being
      * build. Does nothing if the constant pool already contains a similar item.
      * <i>This method is intended for {@link Attribute} sub classes, and is
      * normally not needed by class generators or adapters.</i>
      *
-     * @param methodDesc
-     *            method descriptor of the method type.
-     * @return a new or already existing method type reference item.
+     * @param moduleName
+     *            name of the module.
+     * @return the index of a new or already existing module reference
+     *         item.
      */
-    Item newMethodTypeItem(final String methodDesc) {
-        key2.set(MTYPE, methodDesc, null, null);
-        Item result = get(key2);
-        if (result == null) {
-            pool.put12(MTYPE, newUTF8(methodDesc));
-            result = new Item(index++, key2);
-            put(result);
+    public int newModule(final String moduleName) {
+        return newStringishItem(MODULE, moduleName).index;
         }
-        return result;
-    }
 
     /**
-     * Adds a method type reference to the constant pool of the class being
+     * Adds a package reference to the constant pool of the class being
      * build. Does nothing if the constant pool already contains a similar item.
      * <i>This method is intended for {@link Attribute} sub classes, and is
      * normally not needed by class generators or adapters.</i>
      *
-     * @param methodDesc
-     *            method descriptor of the method type.
-     * @return the index of a new or already existing method type reference
+     * @param packageName
+     *            name of the package in its internal form.
+     * @return the index of a new or already existing module reference
      *         item.
      */
-    public int newMethodType(final String methodDesc) {
-        return newMethodTypeItem(methodDesc).index;
+    public int newPackage(final String packageName) {
+        return newStringishItem(PACKAGE, packageName).index;
     }
 
     /**
      * Adds a handle to the constant pool of the class being build. Does nothing
      * if the constant pool already contains a similar item. <i>This method is

@@ -1623,29 +1628,10 @@
             pool.putByte(DOUBLE).putLong(key.longVal);
             result = new Item(index, key);
             index += 2;
             put(result);
         }
-        return result;
-    }
-
-    /**
-     * Adds a string to the constant pool of the class being build. Does nothing
-     * if the constant pool already contains a similar item.
-     *
-     * @param value
-     *            the String value.
-     * @return a new or already existing string item.
-     */
-    private Item newString(final String value) {
-        key2.set(STR, value, null, null);
-        Item result = get(key2);
-        if (result == null) {
-            pool.put12(STR, newUTF8(value));
-            result = new Item(index++, key2);
-            put(result);
-        }
         return result;
     }
 
     /**
      * Adds a name and type to the constant pool of the class being build. Does
< prev index next >