Upgrade to ASM 6.0

Issue: SPR-14514
This commit is contained in:
Juergen Hoeller 2017-09-19 13:49:32 +02:00
parent ac9cfefaff
commit 185c2bf5b6
14 changed files with 853 additions and 111 deletions

View File

@ -41,7 +41,7 @@ public abstract class AnnotationVisitor {
/** /**
* The ASM API version implemented by this visitor. The value of this field * The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. * must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/ */
protected final int api; protected final int api;
@ -56,7 +56,7 @@ public abstract class AnnotationVisitor {
* *
* @param api * @param api
* the ASM API version implemented by this visitor. Must be one * the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/ */
public AnnotationVisitor(final int api) { public AnnotationVisitor(final int api) {
this(api, null); this(api, null);
@ -67,13 +67,13 @@ public abstract class AnnotationVisitor {
* *
* @param api * @param api
* the ASM API version implemented by this visitor. Must be one * the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* @param av * @param av
* the annotation visitor to which this visitor must delegate * the annotation visitor to which this visitor must delegate
* method calls. May be null. * method calls. May be null.
*/ */
public AnnotationVisitor(final int api, final AnnotationVisitor av) { public AnnotationVisitor(final int api, final AnnotationVisitor av) {
if (api != Opcodes.ASM4 && api != Opcodes.ASM5) { if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
this.api = api; this.api = api;

View File

@ -104,7 +104,7 @@ final class AnnotationWriter extends AnnotationVisitor {
*/ */
AnnotationWriter(final ClassWriter cw, final boolean named, AnnotationWriter(final ClassWriter cw, final boolean named,
final ByteVector bv, final ByteVector parent, final int offset) { final ByteVector bv, final ByteVector parent, final int offset) {
super(Opcodes.ASM5); super(Opcodes.ASM6);
this.cw = cw; this.cw = cw;
this.named = named; this.named = named;
this.bv = bv; this.bv = bv;

View File

@ -222,6 +222,8 @@ public class ClassReader {
// case ClassWriter.CLASS: // case ClassWriter.CLASS:
// case ClassWriter.STR: // case ClassWriter.STR:
// case ClassWriter.MTYPE // case ClassWriter.MTYPE
// case ClassWriter.PACKAGE:
// case ClassWriter.MODULE:
default: default:
size = 3; size = 3;
break; break;
@ -365,7 +367,9 @@ public class ClassReader {
break; break;
// case ClassWriter.STR: // case ClassWriter.STR:
// case ClassWriter.CLASS: // case ClassWriter.CLASS:
// case ClassWriter.MTYPE // case ClassWriter.MTYPE:
// case ClassWriter.MODULE:
// case ClassWriter.PACKAGE:
default: default:
item.set(tag, readUTF8(index, buf), null, null); item.set(tag, readUTF8(index, buf), null, null);
break; break;
@ -572,11 +576,14 @@ public class ClassReader {
String enclosingOwner = null; String enclosingOwner = null;
String enclosingName = null; String enclosingName = null;
String enclosingDesc = null; String enclosingDesc = null;
String moduleMainClass = null;
int anns = 0; int anns = 0;
int ianns = 0; int ianns = 0;
int tanns = 0; int tanns = 0;
int itanns = 0; int itanns = 0;
int innerClasses = 0; int innerClasses = 0;
int module = 0;
int packages = 0;
Attribute attributes = null; Attribute attributes = null;
u = getAttributes(); u = getAttributes();
@ -617,6 +624,12 @@ public class ClassReader {
} else if (ANNOTATIONS } else if (ANNOTATIONS
&& "RuntimeInvisibleTypeAnnotations".equals(attrName)) { && "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
itanns = u + 8; itanns = u + 8;
} else if ("Module".equals(attrName)) {
module = u + 8;
} else if ("ModuleMainClass".equals(attrName)) {
moduleMainClass = readClass(u + 8, c);
} else if ("ModulePackages".equals(attrName)) {
packages = u + 10;
} else if ("BootstrapMethods".equals(attrName)) { } else if ("BootstrapMethods".equals(attrName)) {
int[] bootstrapMethods = new int[readUnsignedShort(u + 8)]; int[] bootstrapMethods = new int[readUnsignedShort(u + 8)];
for (int j = 0, v = u + 10; j < bootstrapMethods.length; j++) { for (int j = 0, v = u + 10; j < bootstrapMethods.length; j++) {
@ -645,6 +658,12 @@ public class ClassReader {
classVisitor.visitSource(sourceFile, sourceDebug); classVisitor.visitSource(sourceFile, sourceDebug);
} }
// visits the module info and associated attributes
if (module != 0) {
readModule(classVisitor, context, module,
moduleMainClass, packages);
}
// visits the outer class // visits the outer class
if (enclosingOwner != null) { if (enclosingOwner != null) {
classVisitor.visitOuterClass(enclosingOwner, enclosingName, classVisitor.visitOuterClass(enclosingOwner, enclosingName,
@ -714,6 +733,120 @@ public class ClassReader {
classVisitor.visitEnd(); classVisitor.visitEnd();
} }
/**
* Reads the module attribute and visit it.
*
* @param classVisitor
* the current class visitor
* @param context
* information about the class being parsed.
* @param u
* start offset of the module attribute in the class file.
* @param mainClass
* name of the main class of a module or null.
* @param packages
* start offset of the concealed package attribute.
*/
private void readModule(final ClassVisitor classVisitor,
final Context context, int u,
final String mainClass, int packages) {
char[] buffer = context.buffer;
// reads module name, flags and version
String name = readModule(u, buffer);
int flags = readUnsignedShort(u + 2);
String version = readUTF8(u + 4, buffer);
u += 6;
ModuleVisitor mv = classVisitor.visitModule(name, flags, version);
if (mv == null) {
return;
}
// module attributes (main class, packages)
if (mainClass != null) {
mv.visitMainClass(mainClass);
}
if (packages != 0) {
for (int i = readUnsignedShort(packages - 2); i > 0; --i) {
String packaze = readPackage(packages, buffer);
mv.visitPackage(packaze);
packages += 2;
}
}
// reads requires
u += 2;
for (int i = readUnsignedShort(u - 2); i > 0; --i) {
String module = readModule(u, buffer);
int access = readUnsignedShort(u + 2);
String requireVersion = readUTF8(u + 4, buffer);
mv.visitRequire(module, access, requireVersion);
u += 6;
}
// reads exports
u += 2;
for (int i = readUnsignedShort(u - 2); i > 0; --i) {
String export = readPackage(u, buffer);
int access = readUnsignedShort(u + 2);
int exportToCount = readUnsignedShort(u + 4);
u += 6;
String[] tos = null;
if (exportToCount != 0) {
tos = new String[exportToCount];
for (int j = 0; j < tos.length; ++j) {
tos[j] = readModule(u, buffer);
u += 2;
}
}
mv.visitExport(export, access, tos);
}
// reads opens
u += 2;
for (int i = readUnsignedShort(u - 2); i > 0; --i) {
String open = readPackage(u, buffer);
int access = readUnsignedShort(u + 2);
int openToCount = readUnsignedShort(u + 4);
u += 6;
String[] tos = null;
if (openToCount != 0) {
tos = new String[openToCount];
for (int j = 0; j < tos.length; ++j) {
tos[j] = readModule(u, buffer);
u += 2;
}
}
mv.visitOpen(open, access, tos);
}
// read uses
u += 2;
for (int i = readUnsignedShort(u - 2); i > 0; --i) {
mv.visitUse(readClass(u, buffer));
u += 2;
}
// read provides
u += 2;
for (int i = readUnsignedShort(u - 2); i > 0; --i) {
String service = readClass(u, buffer);
int provideWithCount = readUnsignedShort(u + 2);
u += 4;
String[] withs = new String[provideWithCount];
for (int j = 0; j < withs.length; ++j) {
withs[j] = readClass(u, buffer);
u += 2;
}
mv.visitProvide(service, withs);
}
mv.visitEnd();
}
/** /**
* Reads a field and makes the given visitor visit it. * Reads a field and makes the given visitor visit it.
* *
@ -1082,6 +1215,7 @@ public class ClassReader {
u += 3; u += 3;
break; break;
case ClassWriter.LABELW_INSN: case ClassWriter.LABELW_INSN:
case ClassWriter.ASM_LABELW_INSN:
readLabel(offset + readInt(u + 1), labels); readLabel(offset + readInt(u + 1), labels);
u += 5; u += 5;
break; break;
@ -1305,7 +1439,8 @@ public class ClassReader {
} }
} }
} }
if ((context.flags & EXPAND_ASM_INSNS) != 0) { if ((context.flags & EXPAND_ASM_INSNS) != 0
&& (context.flags & EXPAND_FRAMES) != 0) {
// Expanding the ASM pseudo instructions can introduce F_INSERT // Expanding the ASM pseudo instructions can introduce F_INSERT
// frames, even if the method does not currently have any frame. // frames, even if the method does not currently have any frame.
// Also these inserted frames must be computed by simulating the // Also these inserted frames must be computed by simulating the
@ -1322,6 +1457,7 @@ public class ClassReader {
// visits the instructions // visits the instructions
int opcodeDelta = (context.flags & EXPAND_ASM_INSNS) == 0 ? -33 : 0; int opcodeDelta = (context.flags & EXPAND_ASM_INSNS) == 0 ? -33 : 0;
boolean insertFrame = false;
u = codeStart; u = codeStart;
while (u < codeEnd) { while (u < codeEnd) {
int offset = u - codeStart; int offset = u - codeStart;
@ -1354,6 +1490,9 @@ public class ClassReader {
mv.visitFrame(frame.mode, frame.localDiff, frame.local, mv.visitFrame(frame.mode, frame.localDiff, frame.local,
frame.stackCount, frame.stack); frame.stackCount, frame.stack);
} }
// if there is already a frame for this offset, there is no
// need to insert a new one.
insertFrame = false;
} }
if (frameCount > 0) { if (frameCount > 0) {
stackMap = readFrame(stackMap, zip, unzip, frame); stackMap = readFrame(stackMap, zip, unzip, frame);
@ -1362,6 +1501,13 @@ public class ClassReader {
frame = null; frame = null;
} }
} }
// inserts a frame for this offset, if requested by setting
// insertFrame to true during the previous iteration. The actual
// frame content will be computed in MethodWriter.
if (FRAMES && insertFrame) {
mv.visitFrame(ClassWriter.F_INSERT, 0, null, 0, null);
insertFrame = false;
}
// visits the instruction at this offset // visits the instruction at this offset
int opcode = b[u] & 0xFF; int opcode = b[u] & 0xFF;
@ -1397,31 +1543,36 @@ public class ClassReader {
opcode = opcode < 218 ? opcode - 49 : opcode - 20; opcode = opcode < 218 ? opcode - 49 : opcode - 20;
Label target = labels[offset + readUnsignedShort(u + 1)]; Label target = labels[offset + readUnsignedShort(u + 1)];
// replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx
// <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is // <l> with IFNOTxxx <L> GOTO_W <l> L:..., where IFNOTxxx is
// the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ)
// and where <l'> designates the instruction just after // and where <L> designates the instruction just after
// the GOTO_W. // the GOTO_W.
if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) { if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) {
mv.visitJumpInsn(opcode + 33, target); mv.visitJumpInsn(opcode + 33, target);
} else { } else {
opcode = opcode <= 166 ? ((opcode + 1) ^ 1) - 1 opcode = opcode <= 166 ? ((opcode + 1) ^ 1) - 1
: opcode ^ 1; : opcode ^ 1;
Label endif = new Label(); Label endif = readLabel(offset + 3, labels);
mv.visitJumpInsn(opcode, endif); mv.visitJumpInsn(opcode, endif);
mv.visitJumpInsn(200, target); // GOTO_W mv.visitJumpInsn(200, target); // GOTO_W
mv.visitLabel(endif); // endif designates the instruction just after GOTO_W,
// since we introduced an unconditional jump instruction we // and is visited as part of the next instruction. Since
// also need to insert a stack map frame here, unless there // it is a jump target, we need to insert a frame here.
// is already one. The actual frame content will be computed insertFrame = true;
// in MethodWriter.
if (FRAMES && stackMap != 0
&& (frame == null || frame.offset != offset + 3)) {
mv.visitFrame(ClassWriter.F_INSERT, 0, null, 0, null);
}
} }
u += 3; u += 3;
break; break;
} }
case ClassWriter.ASM_LABELW_INSN: {
// replaces the pseudo GOTO_W instruction with a real one.
mv.visitJumpInsn(200, labels[offset + readInt(u + 1)]);
// The instruction just after is a jump target (because pseudo
// GOTO_W are used in patterns IFNOTxxx <L> GOTO_W <l> L:...,
// see MethodWriter), so we need to insert a frame here.
insertFrame = true;
u += 5;
break;
}
case ClassWriter.WIDE_INSN: case ClassWriter.WIDE_INSN:
opcode = b[u + 1] & 0xFF; opcode = b[u + 1] & 0xFF;
if (opcode == Opcodes.IINC) { if (opcode == Opcodes.IINC) {
@ -2516,6 +2667,20 @@ public class ClassReader {
return new String(buf, 0, strLen); return new String(buf, 0, strLen);
} }
/**
* Read a stringish constant item (CONSTANT_Class, CONSTANT_String,
* CONSTANT_MethodType, CONSTANT_Module or CONSTANT_Package
* @param index
* @param buf
* @return
*/
private String readStringish(final int index, final char[] buf) {
// computes the start index of the item in b
// and reads the CONSTANT_Utf8 item designated by
// the first two bytes of this item
return readUTF8(items[readUnsignedShort(index)], buf);
}
/** /**
* Reads a class constant pool item in {@link #b b}. <i>This method is * Reads a class constant pool item in {@link #b b}. <i>This method is
* intended for {@link Attribute} sub classes, and is normally not needed by * intended for {@link Attribute} sub classes, and is normally not needed by
@ -2530,11 +2695,41 @@ public class ClassReader {
* @return the String corresponding to the specified class item. * @return the String corresponding to the specified class item.
*/ */
public String readClass(final int index, final char[] buf) { public String readClass(final int index, final char[] buf) {
// computes the start index of the CONSTANT_Class item in b return readStringish(index, buf);
// and reads the CONSTANT_Utf8 item designated by }
// the first two bytes of this CONSTANT_Class item
String name = readUTF8(items[readUnsignedShort(index)], buf); /**
return (name != null ? name.intern() : null); * Reads a module constant pool item in {@link #b b}. <i>This method is
* intended for {@link Attribute} sub classes, and is normally not needed by
* class generators or adapters.</i>
*
* @param index
* the start index of an unsigned short value in {@link #b b},
* whose value is the index of a module constant pool item.
* @param buf
* buffer to be used to read the item. This buffer must be
* sufficiently large. It is not automatically resized.
* @return the String corresponding to the specified module item.
*/
public String readModule(final int index, final char[] buf) {
return readStringish(index, buf);
}
/**
* Reads a module constant pool item in {@link #b b}. <i>This method is
* intended for {@link Attribute} sub classes, and is normally not needed by
* class generators or adapters.</i>
*
* @param index
* the start index of an unsigned short value in {@link #b b},
* whose value is the index of a module constant pool item.
* @param buf
* buffer to be used to read the item. This buffer must be
* sufficiently large. It is not automatically resized.
* @return the String corresponding to the specified module item.
*/
public String readPackage(final int index, final char[] buf) {
return readStringish(index, buf);
} }
/** /**

View File

@ -32,7 +32,7 @@ package org.springframework.asm;
/** /**
* A visitor to visit a Java class. The methods of this class must be called in * A visitor to visit a Java class. The methods of this class must be called in
* the following order: <tt>visit</tt> [ <tt>visitSource</tt> ] [ * the following order: <tt>visit</tt> [ <tt>visitSource</tt> ] [
* <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> | * <tt>visitModule</tt> ][ <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> |
* <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* ( * <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* (
* <tt>visitInnerClass</tt> | <tt>visitField</tt> | <tt>visitMethod</tt> )* * <tt>visitInnerClass</tt> | <tt>visitField</tt> | <tt>visitMethod</tt> )*
* <tt>visitEnd</tt>. * <tt>visitEnd</tt>.
@ -43,7 +43,7 @@ public abstract class ClassVisitor {
/** /**
* The ASM API version implemented by this visitor. The value of this field * The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. * must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/ */
protected final int api; protected final int api;
@ -58,7 +58,7 @@ public abstract class ClassVisitor {
* *
* @param api * @param api
* the ASM API version implemented by this visitor. Must be one * the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/ */
public ClassVisitor(final int api) { public ClassVisitor(final int api) {
this(api, null); this(api, null);
@ -69,13 +69,13 @@ public abstract class ClassVisitor {
* *
* @param api * @param api
* the ASM API version implemented by this visitor. Must be one * the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* @param cv * @param cv
* the class visitor to which this visitor must delegate method * the class visitor to which this visitor must delegate method
* calls. May be null. * calls. May be null.
*/ */
public ClassVisitor(final int api, final ClassVisitor cv) { public ClassVisitor(final int api, final ClassVisitor cv) {
if (api != Opcodes.ASM4 && api != Opcodes.ASM5) { if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
this.api = api; this.api = api;
@ -131,6 +131,28 @@ public abstract class ClassVisitor {
} }
} }
/**
* Visit the module corresponding to the class.
* @param name
* module name
* @param access
* module flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC}
* and {@code ACC_MANDATED}.
* @param version
* module version or null.
* @return a visitor to visit the module values, or <tt>null</tt> if
* this visitor is not interested in visiting this module.
*/
public ModuleVisitor visitModule(String name, int access, String version) {
if (api < Opcodes.ASM6) {
throw new RuntimeException();
}
if (cv != null) {
return cv.visitModule(name, access, version);
}
return null;
}
/** /**
* Visits the enclosing class of the class. This method must be called only * Visits the enclosing class of the class. This method must be called only
* if the class has an enclosing class. * if the class has an enclosing class.

View File

@ -173,6 +173,11 @@ public class ClassWriter extends ClassVisitor {
*/ */
static final int ASM_LABEL_INSN = 18; 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 * 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 * frame can only be used if the frame content can be computed from the
@ -258,10 +263,20 @@ public class ClassWriter extends ClassVisitor {
*/ */
static final int INDY = 18; static final int INDY = 18;
/**
* The type of CONSTANT_Module constant pool items.
*/
static final int MODULE = 19;
/**
* The type of CONSTANT_Package constant pool items.
*/
static final int PACKAGE = 20;
/** /**
* The base value for all CONSTANT_MethodHandle constant pool items. * The base value for all CONSTANT_MethodHandle constant pool items.
* Internally, ASM store the 9 variations of CONSTANT_MethodHandle into 9 * 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; static final int HANDLE_BASE = 20;
@ -410,6 +425,11 @@ public class ClassWriter extends ClassVisitor {
*/ */
private ByteVector sourceDebug; 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 * The constant pool item that contains the name of the enclosing class of
* this class. * this class.
@ -523,11 +543,11 @@ public class ClassWriter extends ClassVisitor {
*/ */
static { static {
int i; int i;
byte[] b = new byte[220]; byte[] b = new byte[221];
String s = "AAAAAAAAAAAAAAAABCLMMDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD" String s = "AAAAAAAAAAAAAAAABCLMMDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD"
+ "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ "AAAAAAAAAAAAAAAAANAAAAAAAAAAAAAAAAAAAAJJJJJJJJJJJJJJJJDOPAA" + "AAAAAAAAAAAAAAAAANAAAAAAAAAAAAAAAAAAAAJJJJJJJJJJJJJJJJDOPAA"
+ "AAAAGGGGGGGHIFBFAAFFAARQJJKKSSSSSSSSSSSSSSSSSS"; + "AAAAGGGGGGGHIFBFAAFFAARQJJKKSSSSSSSSSSSSSSSSSST";
for (i = 0; i < b.length; ++i) { for (i = 0; i < b.length; ++i) {
b[i] = (byte) (s.charAt(i) - 'A'); b[i] = (byte) (s.charAt(i) - 'A');
} }
@ -583,6 +603,7 @@ public class ClassWriter extends ClassVisitor {
// for (i = 202; i < 220; ++i) { // for (i = 202; i < 220; ++i) {
// b[i] = ASM_LABEL_INSN; // b[i] = ASM_LABEL_INSN;
// } // }
// b[220] = ASM_LABELW_INSN;
// //
// // LDC(_W) instructions // // LDC(_W) instructions
// b[Constants.LDC] = LDC_INSN; // b[Constants.LDC] = LDC_INSN;
@ -615,7 +636,7 @@ public class ClassWriter extends ClassVisitor {
* {@link #COMPUTE_FRAMES}. * {@link #COMPUTE_FRAMES}.
*/ */
public ClassWriter(final int flags) { public ClassWriter(final int flags) {
super(Opcodes.ASM5); super(Opcodes.ASM6);
index = 1; index = 1;
pool = new ByteVector(); pool = new ByteVector();
items = new Item[256]; items = new Item[256];
@ -703,6 +724,14 @@ public class ClassWriter extends ClassVisitor {
} }
} }
@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 @Override
public final void visitOuterClass(final String owner, final String name, public final void visitOuterClass(final String owner, final String name,
final String desc) { final String desc) {
@ -777,7 +806,7 @@ public class ClassWriter extends ClassVisitor {
// and equality tests). If so we store the index of this inner class // and equality tests). If so we store the index of this inner class
// entry (plus one) in intVal. This hack allows duplicate detection in // entry (plus one) in intVal. This hack allows duplicate detection in
// O(1) time. // O(1) time.
Item nameItem = newClassItem(name); Item nameItem = newStringishItem(CLASS, name);
if (nameItem.intVal == 0) { if (nameItem.intVal == 0) {
++innerClassesCount; ++innerClassesCount;
innerClasses.putShort(nameItem.index); innerClasses.putShort(nameItem.index);
@ -904,6 +933,11 @@ public class ClassWriter extends ClassVisitor {
size += 8 + itanns.getSize(); size += 8 + itanns.getSize();
newUTF8("RuntimeInvisibleTypeAnnotations"); newUTF8("RuntimeInvisibleTypeAnnotations");
} }
if (moduleWriter != null) {
attributeCount += 1 + moduleWriter.attributeCount;
size += 6 + moduleWriter.size + moduleWriter.attributesSize;
newUTF8("Module");
}
if (attrs != null) { if (attrs != null) {
attributeCount += attrs.getCount(); attributeCount += attrs.getCount();
size += attrs.getSize(this, null, 0, -1, -1); size += attrs.getSize(this, null, 0, -1, -1);
@ -951,6 +985,11 @@ public class ClassWriter extends ClassVisitor {
out.putShort(newUTF8("SourceDebugExtension")).putInt(len); out.putShort(newUTF8("SourceDebugExtension")).putInt(len);
out.putByteArray(sourceDebug.data, 0, len); out.putByteArray(sourceDebug.data, 0, len);
} }
if (moduleWriter != null) {
out.putShort(newUTF8("Module"));
moduleWriter.put(out);
moduleWriter.putAttributes(out);
}
if (enclosingMethodOwner != 0) { if (enclosingMethodOwner != 0) {
out.putShort(newUTF8("EnclosingMethod")).putInt(4); out.putShort(newUTF8("EnclosingMethod")).putInt(4);
out.putShort(enclosingMethodOwner).putShort(enclosingMethod); out.putShort(enclosingMethodOwner).putShort(enclosingMethod);
@ -989,18 +1028,26 @@ public class ClassWriter extends ClassVisitor {
attrs.put(this, null, 0, -1, -1, out); attrs.put(this, null, 0, -1, -1, out);
} }
if (hasAsmInsns) { if (hasAsmInsns) {
boolean hasFrames = false;
mb = firstMethod;
while (mb != null) {
hasFrames |= mb.frameCount > 0;
mb = (MethodWriter) mb.mv;
}
anns = null; anns = null;
ianns = null; ianns = null;
attrs = null; attrs = null;
moduleWriter = null;
innerClassesCount = 0; innerClassesCount = 0;
innerClasses = null; innerClasses = null;
firstField = null; firstField = null;
lastField = null; lastField = null;
firstMethod = null; firstMethod = null;
lastMethod = null; lastMethod = null;
compute = MethodWriter.INSERTED_FRAMES; compute = hasFrames ? MethodWriter.INSERTED_FRAMES : 0;
hasAsmInsns = false; hasAsmInsns = false;
new ClassReader(out.data).accept(this, ClassReader.EXPAND_FRAMES new ClassReader(out.data).accept(this,
(hasFrames ? ClassReader.EXPAND_FRAMES : 0)
| ClassReader.EXPAND_ASM_INSNS); | ClassReader.EXPAND_ASM_INSNS);
return toByteArray(); return toByteArray();
} }
@ -1048,16 +1095,16 @@ public class ClassWriter extends ClassVisitor {
double val = ((Double) cst).doubleValue(); double val = ((Double) cst).doubleValue();
return newDouble(val); return newDouble(val);
} else if (cst instanceof String) { } else if (cst instanceof String) {
return newString((String) cst); return newStringishItem(STR, (String) cst);
} else if (cst instanceof Type) { } else if (cst instanceof Type) {
Type t = (Type) cst; Type t = (Type) cst;
int s = t.getSort(); int s = t.getSort();
if (s == Type.OBJECT) { if (s == Type.OBJECT) {
return newClassItem(t.getInternalName()); return newStringishItem(CLASS, t.getInternalName());
} else if (s == Type.METHOD) { } else if (s == Type.METHOD) {
return newMethodTypeItem(t.getDescriptor()); return newStringishItem(MTYPE, t.getDescriptor());
} else { // s == primitive type or array } else { // s == primitive type or array
return newClassItem(t.getDescriptor()); return newStringishItem(CLASS, t.getDescriptor());
} }
} else if (cst instanceof Handle) { } else if (cst instanceof Handle) {
Handle h = (Handle) cst; Handle h = (Handle) cst;
@ -1106,20 +1153,21 @@ public class ClassWriter extends ClassVisitor {
} }
/** /**
* 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. * 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 * @param value
* the internal name of the class. * string value of the reference.
* @return a new or already existing class reference item. * @return a new or already existing reference item.
*/ */
Item newClassItem(final String value) { Item newStringishItem(final int type, final String value) {
key2.set(CLASS, value, null, null); key2.set(type, value, null, null);
Item result = get(key2); Item result = get(key2);
if (result == null) { if (result == null) {
pool.put12(CLASS, newUTF8(value)); pool.put12(type, newUTF8(value));
result = new Item(index++, key2); result = new Item(index++, key2);
put(result); put(result);
} }
@ -1137,28 +1185,7 @@ public class ClassWriter extends ClassVisitor {
* @return the index of a new or already existing class reference item. * @return the index of a new or already existing class reference item.
*/ */
public int newClass(final String value) { public int newClass(final String value) {
return newClassItem(value).index; return newStringishItem(CLASS, value).index;
}
/**
* 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 methodDesc
* method descriptor of the method type.
* @return a new or already existing method type 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);
}
return result;
} }
/** /**
@ -1173,7 +1200,37 @@ public class ClassWriter extends ClassVisitor {
* item. * item.
*/ */
public int newMethodType(final String methodDesc) { public int newMethodType(final String methodDesc) {
return newMethodTypeItem(methodDesc).index; return newStringishItem(MTYPE, methodDesc).index;
}
/**
* 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 moduleName
* name of the module.
* @return the index of a new or already existing module reference
* item.
*/
public int newModule(final String moduleName) {
return newStringishItem(MODULE, moduleName).index;
}
/**
* 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 packageName
* name of the package in its internal form.
* @return the index of a new or already existing module reference
* item.
*/
public int newPackage(final String packageName) {
return newStringishItem(PACKAGE, packageName).index;
} }
/** /**
@ -1554,25 +1611,6 @@ public class ClassWriter extends ClassVisitor {
return 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 * Adds a name and type to the constant pool of the class being build. Does
* nothing if the constant pool already contains a similar item. <i>This * nothing if the constant pool already contains a similar item. <i>This

View File

@ -40,7 +40,7 @@ public abstract class FieldVisitor {
/** /**
* The ASM API version implemented by this visitor. The value of this field * The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. * must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/ */
protected final int api; protected final int api;
@ -55,7 +55,7 @@ public abstract class FieldVisitor {
* *
* @param api * @param api
* the ASM API version implemented by this visitor. Must be one * the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/ */
public FieldVisitor(final int api) { public FieldVisitor(final int api) {
this(api, null); this(api, null);
@ -66,13 +66,13 @@ public abstract class FieldVisitor {
* *
* @param api * @param api
* the ASM API version implemented by this visitor. Must be one * the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* @param fv * @param fv
* the field visitor to which this visitor must delegate method * the field visitor to which this visitor must delegate method
* calls. May be null. * calls. May be null.
*/ */
public FieldVisitor(final int api, final FieldVisitor fv) { public FieldVisitor(final int api, final FieldVisitor fv) {
if (api != Opcodes.ASM4 && api != Opcodes.ASM5) { if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
this.api = api; this.api = api;

View File

@ -118,7 +118,7 @@ final class FieldWriter extends FieldVisitor {
*/ */
FieldWriter(final ClassWriter cw, final int access, final String name, FieldWriter(final ClassWriter cw, final int access, final String name,
final String desc, final String signature, final Object value) { final String desc, final String signature, final Object value) {
super(Opcodes.ASM5); super(Opcodes.ASM6);
if (cw.firstField == null) { if (cw.firstField == null) {
cw.firstField = this; cw.firstField = this;
} else { } else {

View File

@ -51,6 +51,7 @@ final class Item {
* {@link ClassWriter#STR}, {@link ClassWriter#CLASS}, * {@link ClassWriter#STR}, {@link ClassWriter#CLASS},
* {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD}, * {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD},
* {@link ClassWriter#METH}, {@link ClassWriter#IMETH}, * {@link ClassWriter#METH}, {@link ClassWriter#IMETH},
* {@link ClassWriter#MODULE}, {@link ClassWriter#PACKAGE},
* {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}. * {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}.
* *
* MethodHandle constant 9 variations are stored using a range of 9 values * MethodHandle constant 9 variations are stored using a range of 9 values
@ -214,6 +215,8 @@ final class Item {
case ClassWriter.UTF8: case ClassWriter.UTF8:
case ClassWriter.STR: case ClassWriter.STR:
case ClassWriter.MTYPE: case ClassWriter.MTYPE:
case ClassWriter.MODULE:
case ClassWriter.PACKAGE:
case ClassWriter.TYPE_NORMAL: case ClassWriter.TYPE_NORMAL:
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()); hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
return; return;
@ -282,6 +285,8 @@ final class Item {
case ClassWriter.UTF8: case ClassWriter.UTF8:
case ClassWriter.STR: case ClassWriter.STR:
case ClassWriter.CLASS: case ClassWriter.CLASS:
case ClassWriter.MODULE:
case ClassWriter.PACKAGE:
case ClassWriter.MTYPE: case ClassWriter.MTYPE:
case ClassWriter.TYPE_NORMAL: case ClassWriter.TYPE_NORMAL:
return i.strVal1.equals(strVal1); return i.strVal1.equals(strVal1);

View File

@ -57,7 +57,7 @@ public abstract class MethodVisitor {
/** /**
* The ASM API version implemented by this visitor. The value of this field * The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. * must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/ */
protected final int api; protected final int api;
@ -72,7 +72,7 @@ public abstract class MethodVisitor {
* *
* @param api * @param api
* the ASM API version implemented by this visitor. Must be one * the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
*/ */
public MethodVisitor(final int api) { public MethodVisitor(final int api) {
this(api, null); this(api, null);
@ -83,13 +83,13 @@ public abstract class MethodVisitor {
* *
* @param api * @param api
* the ASM API version implemented by this visitor. Must be one * the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* @param mv * @param mv
* the method visitor to which this visitor must delegate method * the method visitor to which this visitor must delegate method
* calls. May be null. * calls. May be null.
*/ */
public MethodVisitor(final int api, final MethodVisitor mv) { public MethodVisitor(final int api, final MethodVisitor mv) {
if (api != Opcodes.ASM4 && api != Opcodes.ASM5) { if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
this.api = api; this.api = api;

View File

@ -260,7 +260,7 @@ class MethodWriter extends MethodVisitor {
/** /**
* Number of stack map frames in the StackMapTable attribute. * Number of stack map frames in the StackMapTable attribute.
*/ */
private int frameCount; int frameCount;
/** /**
* The StackMapTable attribute. * The StackMapTable attribute.
@ -456,7 +456,7 @@ class MethodWriter extends MethodVisitor {
MethodWriter(final ClassWriter cw, final int access, final String name, MethodWriter(final ClassWriter cw, final int access, final String name,
final String desc, final String signature, final String desc, final String signature,
final String[] exceptions, final int compute) { final String[] exceptions, final int compute) {
super(Opcodes.ASM5); super(Opcodes.ASM6);
if (cw.firstMethod == null) { if (cw.firstMethod == null) {
cw.firstMethod = this; cw.firstMethod = this;
} else { } else {
@ -848,7 +848,7 @@ class MethodWriter extends MethodVisitor {
@Override @Override
public void visitTypeInsn(final int opcode, final String type) { public void visitTypeInsn(final int opcode, final String type) {
lastCodeOffset = code.length; lastCodeOffset = code.length;
Item i = cw.newClassItem(type); Item i = cw.newStringishItem(ClassWriter.CLASS, type);
// Label currentBlock = this.currentBlock; // Label currentBlock = this.currentBlock;
if (currentBlock != null) { if (currentBlock != null) {
if (compute == FRAMES || compute == INSERTED_FRAMES) { if (compute == FRAMES || compute == INSERTED_FRAMES) {
@ -1050,8 +1050,8 @@ class MethodWriter extends MethodVisitor {
/* /*
* case of a backward jump with an offset < -32768. In this case we * case of a backward jump with an offset < -32768. In this case we
* automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx
* <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the * <l> with IFNOTxxx <L> GOTO_W <l> L:..., where IFNOTxxx is the
* "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <l'> * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <L>
* designates the instruction just after the GOTO_W. * designates the instruction just after the GOTO_W.
*/ */
if (opcode == Opcodes.GOTO) { if (opcode == Opcodes.GOTO) {
@ -1067,7 +1067,11 @@ class MethodWriter extends MethodVisitor {
code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1
: opcode ^ 1); : opcode ^ 1);
code.putShort(8); // jump offset code.putShort(8); // jump offset
code.putByte(200); // GOTO_W // ASM pseudo GOTO_W insn, see ClassReader. We don't use a real
// GOTO_W because we might need to insert a frame just after (as
// the target of the IFNOTxxx jump instruction).
code.putByte(220);
cw.hasAsmInsns = true;
} }
label.put(this, code, code.length - 1, true); label.put(this, code, code.length - 1, true);
} else if (isWide) { } else if (isWide) {
@ -1291,7 +1295,7 @@ class MethodWriter extends MethodVisitor {
@Override @Override
public void visitMultiANewArrayInsn(final String desc, final int dims) { public void visitMultiANewArrayInsn(final String desc, final int dims) {
lastCodeOffset = code.length; lastCodeOffset = code.length;
Item i = cw.newClassItem(desc); Item i = cw.newStringishItem(ClassWriter.CLASS, desc);
// Label currentBlock = this.currentBlock; // Label currentBlock = this.currentBlock;
if (currentBlock != null) { if (currentBlock != null) {
if (compute == FRAMES || compute == INSERTED_FRAMES) { if (compute == FRAMES || compute == INSERTED_FRAMES) {

View File

@ -0,0 +1,178 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.springframework.asm;
/**
* A visitor to visit a Java module. The methods of this class must be called in
* the following order: <tt>visitVersion</tt> | <tt>visitMainClass</tt> |
* <tt>visitTargetPlatform</tt> | ( <tt>visitConcealedPackage</tt> | <tt>visitRequire</tt> |
* <tt>visitExport</tt> | <tt>visitUse</tt> | <tt>visitProvide</tt> )* <tt>visitEnd</tt>.
*
* @author Remi Forax
*/
public abstract class ModuleVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
* must be {@link Opcodes#ASM6}.
*/
protected final int api;
/**
* The module visitor to which this visitor must delegate method calls. May
* be null.
*/
protected ModuleVisitor mv;
public ModuleVisitor(final int api) {
this(api, null);
}
/**
* Constructs a new {@link MethodVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
* @param mv
* the method visitor to which this visitor must delegate method
* calls. May be null.
*/
public ModuleVisitor(final int api, final ModuleVisitor mv) {
if (api != Opcodes.ASM6) {
throw new IllegalArgumentException();
}
this.api = api;
this.mv = mv;
}
/**
* Visit the main class of the current module.
*
* @param mainClass the main class of the current module.
*/
public void visitMainClass(String mainClass) {
if (mv != null) {
mv.visitMainClass(mainClass);
}
}
/**
* Visit a concealed package of the current module.
*
* @param packaze name of a concealed package
*/
public void visitPackage(String packaze) {
if (mv != null) {
mv.visitPackage(packaze);
}
}
/**
* Visits a dependence of the current module.
*
* @param module the module name of the dependence
* @param access the access flag of the dependence among
* ACC_TRANSITIVE, ACC_STATIC_PHASE, ACC_SYNTHETIC
* and ACC_MANDATED.
* @param version the module version at compile time or null.
*/
public void visitRequire(String module, int access, String version) {
if (mv != null) {
mv.visitRequire(module, access, version);
}
}
/**
* Visit an exported package of the current module.
*
* @param packaze the name of the exported package.
* @param access the access flag of the exported package,
* valid values are among {@code ACC_SYNTHETIC} and
* {@code ACC_MANDATED}.
* @param modules names of the modules that can access to
* the public classes of the exported package or
* <tt>null</tt>.
*/
public void visitExport(String packaze, int access, String... modules) {
if (mv != null) {
mv.visitExport(packaze, access, modules);
}
}
/**
* Visit an open package of the current module.
*
* @param packaze the name of the opened package.
* @param access the access flag of the opened package,
* valid values are among {@code ACC_SYNTHETIC} and
* {@code ACC_MANDATED}.
* @param modules names of the modules that can use deep
* reflection to the classes of the open package or
* <tt>null</tt>.
*/
public void visitOpen(String packaze, int access, String... modules) {
if (mv != null) {
mv.visitOpen(packaze, access, modules);
}
}
/**
* Visit a service used by the current module.
* The name must be the name of an interface or an
* abstract class.
*
* @param service the internal name of the service.
*/
public void visitUse(String service) {
if (mv != null) {
mv.visitUse(service);
}
}
/**
* Visit an implementation of a service.
*
* @param service the internal name of the service
* @param providers the internal names of the implementations
* of the service (there is at least one provider).
*/
public void visitProvide(String service, String... providers) {
if (mv != null) {
mv.visitProvide(service, providers);
}
}
public void visitEnd() {
if (mv != null) {
mv.visitEnd();
}
}
}

View File

@ -0,0 +1,293 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.springframework.asm;
/**
* @author Remi Forax
*/
final class ModuleWriter extends ModuleVisitor {
/**
* The class writer to which this Module attribute must be added.
*/
private final ClassWriter cw;
/**
* size in byte of the Module attribute.
*/
int size;
/**
* Number of attributes associated with the current module
* (Version, ConcealPackages, etc)
*/
int attributeCount;
/**
* Size in bytes of the attributes associated with the current module
*/
int attributesSize;
/**
* module name index in the constant pool
*/
private final int name;
/**
* module access flags
*/
private final int access;
/**
* module version index in the constant pool or 0
*/
private final int version;
/**
* module main class index in the constant pool or 0
*/
private int mainClass;
/**
* number of packages
*/
private int packageCount;
/**
* The packages in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in packageCount
*/
private ByteVector packages;
/**
* number of requires items
*/
private int requireCount;
/**
* The requires items in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in requireCount
*/
private ByteVector requires;
/**
* number of exports items
*/
private int exportCount;
/**
* The exports items in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in exportCount
*/
private ByteVector exports;
/**
* number of opens items
*/
private int openCount;
/**
* The opens items in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in openCount
*/
private ByteVector opens;
/**
* number of uses items
*/
private int useCount;
/**
* The uses items in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in useCount
*/
private ByteVector uses;
/**
* number of provides items
*/
private int provideCount;
/**
* The uses provides in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in provideCount
*/
private ByteVector provides;
ModuleWriter(final ClassWriter cw, final int name,
final int access, final int version) {
super(Opcodes.ASM6);
this.cw = cw;
this.size = 16; // name + access + version + 5 counts
this.name = name;
this.access = access;
this.version = version;
}
@Override
public void visitMainClass(String mainClass) {
if (this.mainClass == 0) { // protect against several calls to visitMainClass
cw.newUTF8("ModuleMainClass");
attributeCount++;
attributesSize += 8;
}
this.mainClass = cw.newClass(mainClass);
}
@Override
public void visitPackage(String packaze) {
if (packages == null) {
// protect against several calls to visitPackage
cw.newUTF8("ModulePackages");
packages = new ByteVector();
attributeCount++;
attributesSize += 8;
}
packages.putShort(cw.newPackage(packaze));
packageCount++;
attributesSize += 2;
}
@Override
public void visitRequire(String module, int access, String version) {
if (requires == null) {
requires = new ByteVector();
}
requires.putShort(cw.newModule(module))
.putShort(access)
.putShort(version == null? 0: cw.newUTF8(version));
requireCount++;
size += 6;
}
@Override
public void visitExport(String packaze, int access, String... modules) {
if (exports == null) {
exports = new ByteVector();
}
exports.putShort(cw.newPackage(packaze)).putShort(access);
if (modules == null) {
exports.putShort(0);
size += 6;
} else {
exports.putShort(modules.length);
for(String module: modules) {
exports.putShort(cw.newModule(module));
}
size += 6 + 2 * modules.length;
}
exportCount++;
}
@Override
public void visitOpen(String packaze, int access, String... modules) {
if (opens == null) {
opens = new ByteVector();
}
opens.putShort(cw.newPackage(packaze)).putShort(access);
if (modules == null) {
opens.putShort(0);
size += 6;
} else {
opens.putShort(modules.length);
for(String module: modules) {
opens.putShort(cw.newModule(module));
}
size += 6 + 2 * modules.length;
}
openCount++;
}
@Override
public void visitUse(String service) {
if (uses == null) {
uses = new ByteVector();
}
uses.putShort(cw.newClass(service));
useCount++;
size += 2;
}
@Override
public void visitProvide(String service, String... providers) {
if (provides == null) {
provides = new ByteVector();
}
provides.putShort(cw.newClass(service));
provides.putShort(providers.length);
for(String provider: providers) {
provides.putShort(cw.newClass(provider));
}
provideCount++;
size += 4 + 2 * providers.length;
}
@Override
public void visitEnd() {
// empty
}
void putAttributes(ByteVector out) {
if (mainClass != 0) {
out.putShort(cw.newUTF8("ModuleMainClass")).putInt(2).putShort(mainClass);
}
if (packages != null) {
out.putShort(cw.newUTF8("ModulePackages"))
.putInt(2 + 2 * packageCount)
.putShort(packageCount)
.putByteArray(packages.data, 0, packages.length);
}
}
void put(ByteVector out) {
out.putInt(size);
out.putShort(name).putShort(access).putShort(version);
out.putShort(requireCount);
if (requires != null) {
out.putByteArray(requires.data, 0, requires.length);
}
out.putShort(exportCount);
if (exports != null) {
out.putByteArray(exports.data, 0, exports.length);
}
out.putShort(openCount);
if (opens != null) {
out.putByteArray(opens.data, 0, opens.length);
}
out.putShort(useCount);
if (uses != null) {
out.putByteArray(uses.data, 0, uses.length);
}
out.putShort(provideCount);
if (provides != null) {
out.putByteArray(provides.data, 0, provides.length);
}
}
}

View File

@ -47,6 +47,7 @@ public interface Opcodes {
int ASM4 = 4 << 16 | 0 << 8 | 0; int ASM4 = 4 << 16 | 0 << 8 | 0;
int ASM5 = 5 << 16 | 0 << 8 | 0; int ASM5 = 5 << 16 | 0 << 8 | 0;
int ASM6 = 6 << 16 | 0 << 8 | 0;
// versions // versions
@ -58,6 +59,7 @@ public interface Opcodes {
int V1_6 = 0 << 16 | 50; int V1_6 = 0 << 16 | 50;
int V1_7 = 0 << 16 | 51; int V1_7 = 0 << 16 | 51;
int V1_8 = 0 << 16 | 52; int V1_8 = 0 << 16 | 52;
int V1_9 = 0 << 16 | 53;
// access flags // access flags
@ -68,18 +70,23 @@ public interface Opcodes {
int ACC_FINAL = 0x0010; // class, field, method, parameter int ACC_FINAL = 0x0010; // class, field, method, parameter
int ACC_SUPER = 0x0020; // class int ACC_SUPER = 0x0020; // class
int ACC_SYNCHRONIZED = 0x0020; // method int ACC_SYNCHRONIZED = 0x0020; // method
int ACC_OPEN = 0x0020; // module
int ACC_TRANSITIVE = 0x0020; // module requires
int ACC_VOLATILE = 0x0040; // field int ACC_VOLATILE = 0x0040; // field
int ACC_BRIDGE = 0x0040; // method int ACC_BRIDGE = 0x0040; // method
int ACC_STATIC_PHASE = 0x0040; // module requires
int ACC_VARARGS = 0x0080; // method int ACC_VARARGS = 0x0080; // method
int ACC_TRANSIENT = 0x0080; // field int ACC_TRANSIENT = 0x0080; // field
int ACC_NATIVE = 0x0100; // method int ACC_NATIVE = 0x0100; // method
int ACC_INTERFACE = 0x0200; // class int ACC_INTERFACE = 0x0200; // class
int ACC_ABSTRACT = 0x0400; // class, method int ACC_ABSTRACT = 0x0400; // class, method
int ACC_STRICT = 0x0800; // method int ACC_STRICT = 0x0800; // method
int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module *
int ACC_ANNOTATION = 0x2000; // class int ACC_ANNOTATION = 0x2000; // class
int ACC_ENUM = 0x4000; // class(?) field inner int ACC_ENUM = 0x4000; // class(?) field inner
int ACC_MANDATED = 0x8000; // parameter int ACC_MANDATED = 0x8000; // parameter, module, module *
int ACC_MODULE = 0x8000; // class
// ASM specific pseudo access flags // ASM specific pseudo access flags

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2014 the original author or authors. * Copyright 2002-2017 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -30,8 +30,8 @@ public final class SpringAsmInfo {
/** /**
* The ASM compatibility version for Spring's ASM visitor implementations: * The ASM compatibility version for Spring's ASM visitor implementations:
* currently {@link Opcodes#ASM5}. * currently {@link Opcodes#ASM6}.
*/ */
public static final int ASM_VERSION = Opcodes.ASM5; public static final int ASM_VERSION = Opcodes.ASM6;
} }