< 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 >