更新asm版本

This commit is contained in:
Redkale
2018-04-04 13:46:27 +08:00
parent e64a75cfab
commit 5a0eff2b67
20 changed files with 1986 additions and 1481 deletions

View File

@@ -70,7 +70,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;
@@ -85,7 +85,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);
@@ -96,13 +96,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;
@@ -118,7 +118,7 @@ public abstract class AnnotationVisitor {
* the actual value, whose type must be {@link Byte}, * the actual value, whose type must be {@link Byte},
* {@link Boolean}, {@link Character}, {@link Short}, * {@link Boolean}, {@link Character}, {@link Short},
* {@link Integer} , {@link Long}, {@link Float}, {@link Double}, * {@link Integer} , {@link Long}, {@link Float}, {@link Double},
* {@link String} or {@link Type} or OBJECT or ARRAY sort. This * {@link String} or {@link Type} of OBJECT or ARRAY sort. This
* value can also be an array of byte, boolean, short, char, int, * value can also be an array of byte, boolean, short, char, int,
* long, float or double values (this is equivalent to using * long, float or double values (this is equivalent to using
* {@link #visitArray visitArray} and visiting each array element * {@link #visitArray visitArray} and visiting each array element

View File

@@ -133,7 +133,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

@@ -64,7 +64,7 @@ package org.redkale.asm;
* @author Eric Bruneton * @author Eric Bruneton
* @author Eugene Kuleshov * @author Eugene Kuleshov
*/ */
public class Attribute { class Attribute {
/** /**
* The type of this attribute. * The type of this attribute.

View File

@@ -72,31 +72,6 @@ import java.io.InputStream;
*/ */
public class ClassReader { public class ClassReader {
/**
* True to enable signatures support.
*/
static final boolean SIGNATURES = true;
/**
* True to enable annotations support.
*/
static final boolean ANNOTATIONS = true;
/**
* True to enable stack map frames support.
*/
static final boolean FRAMES = true;
/**
* True to enable bytecode writing support.
*/
static final boolean WRITER = true;
/**
* True to enable JSR_W and GOTO_W support.
*/
static final boolean RESIZE = true;
/** /**
* Flag to skip method code. If this class is set <code>CODE</code> * Flag to skip method code. If this class is set <code>CODE</code>
* attribute won't be visited. This can be used, for example, to retrieve * attribute won't be visited. This can be used, for example, to retrieve
@@ -133,6 +108,21 @@ public class ClassReader {
*/ */
public static final int EXPAND_FRAMES = 8; public static final int EXPAND_FRAMES = 8;
/**
* Flag to expand the ASM pseudo instructions into an equivalent sequence of
* standard bytecode instructions. When resolving a forward jump it may
* happen that the signed 2 bytes offset reserved for it is not sufficient
* to store the bytecode offset. In this case the jump instruction is
* replaced with a temporary ASM pseudo instruction using an unsigned 2
* bytes offset (see Label#resolve). This internal flag is used to re-read
* classes containing such instructions, in order to replace them with
* standard instructions. In addition, when this flag is used, GOTO_W and
* JSR_W are <i>not</i> converted into GOTO and JSR, to make sure that
* infinite loops where a GOTO_W is replaced with a GOTO in ClassReader and
* converted back to a GOTO_W in ClassWriter cannot occur.
*/
static final int EXPAND_ASM_INSNS = 256;
/** /**
* The class to be parsed. <i>The content of this array must not be * The class to be parsed. <i>The content of this array must not be
* modified. This field is intended for {@link Attribute} sub classes, and * modified. This field is intended for {@link Attribute} sub classes, and
@@ -195,8 +185,8 @@ public class ClassReader {
public ClassReader(final byte[] b, final int off, final int len) { public ClassReader(final byte[] b, final int off, final int len) {
this.b = b; this.b = b;
// checks the class version // checks the class version
if (readShort(off + 6) > Opcodes.V1_9) { if (readShort(off + 6) > Opcodes.V10) {
throw new IllegalArgumentException(); //throw new IllegalArgumentException();
} }
// parses the constant pool // parses the constant pool
items = new int[readUnsignedShort(off + 8)]; items = new int[readUnsignedShort(off + 8)];
@@ -234,6 +224,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;
@@ -377,7 +369,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;
@@ -584,11 +578,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();
@@ -607,13 +604,11 @@ public class ClassReader {
enclosingName = readUTF8(items[item], c); enclosingName = readUTF8(items[item], c);
enclosingDesc = readUTF8(items[item] + 2, c); enclosingDesc = readUTF8(items[item] + 2, c);
} }
} else if (SIGNATURES && "Signature".equals(attrName)) { } else if ("Signature".equals(attrName)) {
signature = readUTF8(u + 8, c); signature = readUTF8(u + 8, c);
} else if (ANNOTATIONS } else if ("RuntimeVisibleAnnotations".equals(attrName)) {
&& "RuntimeVisibleAnnotations".equals(attrName)) {
anns = u + 8; anns = u + 8;
} else if (ANNOTATIONS } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
&& "RuntimeVisibleTypeAnnotations".equals(attrName)) {
tanns = u + 8; tanns = u + 8;
} else if ("Deprecated".equals(attrName)) { } else if ("Deprecated".equals(attrName)) {
access |= Opcodes.ACC_DEPRECATED; access |= Opcodes.ACC_DEPRECATED;
@@ -623,12 +618,16 @@ public class ClassReader {
} else if ("SourceDebugExtension".equals(attrName)) { } else if ("SourceDebugExtension".equals(attrName)) {
int len = readInt(u + 4); int len = readInt(u + 4);
sourceDebug = readUTF(u + 8, len, new char[len]); sourceDebug = readUTF(u + 8, len, new char[len]);
} else if (ANNOTATIONS } else if ("RuntimeInvisibleAnnotations".equals(attrName)) {
&& "RuntimeInvisibleAnnotations".equals(attrName)) {
ianns = u + 8; ianns = u + 8;
} else if (ANNOTATIONS } else if ("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++) {
@@ -657,6 +656,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,
@@ -664,19 +669,19 @@ public class ClassReader {
} }
// visits the class annotations and type annotations // visits the class annotations and type annotations
if (ANNOTATIONS && anns != 0) { if (anns != 0) {
for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
v = readAnnotationValues(v + 2, c, true, v = readAnnotationValues(v + 2, c, true,
classVisitor.visitAnnotation(readUTF8(v, c), true)); classVisitor.visitAnnotation(readUTF8(v, c), true));
} }
} }
if (ANNOTATIONS && ianns != 0) { if (ianns != 0) {
for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
v = readAnnotationValues(v + 2, c, true, v = readAnnotationValues(v + 2, c, true,
classVisitor.visitAnnotation(readUTF8(v, c), false)); classVisitor.visitAnnotation(readUTF8(v, c), false));
} }
} }
if (ANNOTATIONS && tanns != 0) { if (tanns != 0) {
for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
v = readAnnotationTarget(context, v); v = readAnnotationTarget(context, v);
v = readAnnotationValues(v + 2, c, true, v = readAnnotationValues(v + 2, c, true,
@@ -684,7 +689,7 @@ public class ClassReader {
context.typePath, readUTF8(v, c), true)); context.typePath, readUTF8(v, c), true));
} }
} }
if (ANNOTATIONS && itanns != 0) { if (itanns != 0) {
for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
v = readAnnotationTarget(context, v); v = readAnnotationTarget(context, v);
v = readAnnotationValues(v + 2, c, true, v = readAnnotationValues(v + 2, c, true,
@@ -726,6 +731,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.
* *
@@ -762,24 +881,20 @@ public class ClassReader {
if ("ConstantValue".equals(attrName)) { if ("ConstantValue".equals(attrName)) {
int item = readUnsignedShort(u + 8); int item = readUnsignedShort(u + 8);
value = item == 0 ? null : readConst(item, c); value = item == 0 ? null : readConst(item, c);
} else if (SIGNATURES && "Signature".equals(attrName)) { } else if ("Signature".equals(attrName)) {
signature = readUTF8(u + 8, c); signature = readUTF8(u + 8, c);
} else if ("Deprecated".equals(attrName)) { } else if ("Deprecated".equals(attrName)) {
access |= Opcodes.ACC_DEPRECATED; access |= Opcodes.ACC_DEPRECATED;
} else if ("Synthetic".equals(attrName)) { } else if ("Synthetic".equals(attrName)) {
access |= Opcodes.ACC_SYNTHETIC access |= Opcodes.ACC_SYNTHETIC
| ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
} else if (ANNOTATIONS } else if ("RuntimeVisibleAnnotations".equals(attrName)) {
&& "RuntimeVisibleAnnotations".equals(attrName)) {
anns = u + 8; anns = u + 8;
} else if (ANNOTATIONS } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
&& "RuntimeVisibleTypeAnnotations".equals(attrName)) {
tanns = u + 8; tanns = u + 8;
} else if (ANNOTATIONS } else if ("RuntimeInvisibleAnnotations".equals(attrName)) {
&& "RuntimeInvisibleAnnotations".equals(attrName)) {
ianns = u + 8; ianns = u + 8;
} else if (ANNOTATIONS } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
&& "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
itanns = u + 8; itanns = u + 8;
} else { } else {
Attribute attr = readAttribute(context.attrs, attrName, u + 8, Attribute attr = readAttribute(context.attrs, attrName, u + 8,
@@ -801,19 +916,19 @@ public class ClassReader {
} }
// visits the field annotations and type annotations // visits the field annotations and type annotations
if (ANNOTATIONS && anns != 0) { if (anns != 0) {
for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
v = readAnnotationValues(v + 2, c, true, v = readAnnotationValues(v + 2, c, true,
fv.visitAnnotation(readUTF8(v, c), true)); fv.visitAnnotation(readUTF8(v, c), true));
} }
} }
if (ANNOTATIONS && ianns != 0) { if (ianns != 0) {
for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
v = readAnnotationValues(v + 2, c, true, v = readAnnotationValues(v + 2, c, true,
fv.visitAnnotation(readUTF8(v, c), false)); fv.visitAnnotation(readUTF8(v, c), false));
} }
} }
if (ANNOTATIONS && tanns != 0) { if (tanns != 0) {
for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
v = readAnnotationTarget(context, v); v = readAnnotationTarget(context, v);
v = readAnnotationValues(v + 2, c, true, v = readAnnotationValues(v + 2, c, true,
@@ -821,7 +936,7 @@ public class ClassReader {
context.typePath, readUTF8(v, c), true)); context.typePath, readUTF8(v, c), true));
} }
} }
if (ANNOTATIONS && itanns != 0) { if (itanns != 0) {
for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
v = readAnnotationTarget(context, v); v = readAnnotationTarget(context, v);
v = readAnnotationValues(v + 2, c, true, v = readAnnotationValues(v + 2, c, true,
@@ -895,32 +1010,26 @@ public class ClassReader {
exceptions[j] = readClass(exception, c); exceptions[j] = readClass(exception, c);
exception += 2; exception += 2;
} }
} else if (SIGNATURES && "Signature".equals(attrName)) { } else if ("Signature".equals(attrName)) {
signature = readUTF8(u + 8, c); signature = readUTF8(u + 8, c);
} else if ("Deprecated".equals(attrName)) { } else if ("Deprecated".equals(attrName)) {
context.access |= Opcodes.ACC_DEPRECATED; context.access |= Opcodes.ACC_DEPRECATED;
} else if (ANNOTATIONS } else if ("RuntimeVisibleAnnotations".equals(attrName)) {
&& "RuntimeVisibleAnnotations".equals(attrName)) {
anns = u + 8; anns = u + 8;
} else if (ANNOTATIONS } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
&& "RuntimeVisibleTypeAnnotations".equals(attrName)) {
tanns = u + 8; tanns = u + 8;
} else if (ANNOTATIONS && "AnnotationDefault".equals(attrName)) { } else if ("AnnotationDefault".equals(attrName)) {
dann = u + 8; dann = u + 8;
} else if ("Synthetic".equals(attrName)) { } else if ("Synthetic".equals(attrName)) {
context.access |= Opcodes.ACC_SYNTHETIC context.access |= Opcodes.ACC_SYNTHETIC
| ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
} else if (ANNOTATIONS } else if ("RuntimeInvisibleAnnotations".equals(attrName)) {
&& "RuntimeInvisibleAnnotations".equals(attrName)) {
ianns = u + 8; ianns = u + 8;
} else if (ANNOTATIONS } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
&& "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
itanns = u + 8; itanns = u + 8;
} else if (ANNOTATIONS } else if ("RuntimeVisibleParameterAnnotations".equals(attrName)) {
&& "RuntimeVisibleParameterAnnotations".equals(attrName)) {
mpanns = u + 8; mpanns = u + 8;
} else if (ANNOTATIONS } else if ("RuntimeInvisibleParameterAnnotations".equals(attrName)) {
&& "RuntimeInvisibleParameterAnnotations".equals(attrName)) {
impanns = u + 8; impanns = u + 8;
} else if ("MethodParameters".equals(attrName)) { } else if ("MethodParameters".equals(attrName)) {
methodParameters = u + 8; methodParameters = u + 8;
@@ -953,7 +1062,7 @@ public class ClassReader {
* access, name and descriptor can have been changed, this is not * access, name and descriptor can have been changed, this is not
* important since they are not copied as is from the reader). * important since they are not copied as is from the reader).
*/ */
if (WRITER && mv instanceof MethodWriter) { if (mv instanceof MethodWriter) {
MethodWriter mw = (MethodWriter) mv; MethodWriter mw = (MethodWriter) mv;
if (mw.cw.cr == this && signature == mw.signature) { if (mw.cw.cr == this && signature == mw.signature) {
boolean sameExceptions = false; boolean sameExceptions = false;
@@ -990,26 +1099,26 @@ public class ClassReader {
} }
// visits the method annotations // visits the method annotations
if (ANNOTATIONS && dann != 0) { if (dann != 0) {
AnnotationVisitor dv = mv.visitAnnotationDefault(); AnnotationVisitor dv = mv.visitAnnotationDefault();
readAnnotationValue(dann, c, null, dv); readAnnotationValue(dann, c, null, dv);
if (dv != null) { if (dv != null) {
dv.visitEnd(); dv.visitEnd();
} }
} }
if (ANNOTATIONS && anns != 0) { if (anns != 0) {
for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
v = readAnnotationValues(v + 2, c, true, v = readAnnotationValues(v + 2, c, true,
mv.visitAnnotation(readUTF8(v, c), true)); mv.visitAnnotation(readUTF8(v, c), true));
} }
} }
if (ANNOTATIONS && ianns != 0) { if (ianns != 0) {
for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
v = readAnnotationValues(v + 2, c, true, v = readAnnotationValues(v + 2, c, true,
mv.visitAnnotation(readUTF8(v, c), false)); mv.visitAnnotation(readUTF8(v, c), false));
} }
} }
if (ANNOTATIONS && tanns != 0) { if (tanns != 0) {
for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
v = readAnnotationTarget(context, v); v = readAnnotationTarget(context, v);
v = readAnnotationValues(v + 2, c, true, v = readAnnotationValues(v + 2, c, true,
@@ -1017,7 +1126,7 @@ public class ClassReader {
context.typePath, readUTF8(v, c), true)); context.typePath, readUTF8(v, c), true));
} }
} }
if (ANNOTATIONS && itanns != 0) { if (itanns != 0) {
for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
v = readAnnotationTarget(context, v); v = readAnnotationTarget(context, v);
v = readAnnotationValues(v + 2, c, true, v = readAnnotationValues(v + 2, c, true,
@@ -1025,10 +1134,10 @@ public class ClassReader {
context.typePath, readUTF8(v, c), false)); context.typePath, readUTF8(v, c), false));
} }
} }
if (ANNOTATIONS && mpanns != 0) { if (mpanns != 0) {
readParameterAnnotations(mv, context, mpanns, true); readParameterAnnotations(mv, context, mpanns, true);
} }
if (ANNOTATIONS && impanns != 0) { if (impanns != 0) {
readParameterAnnotations(mv, context, impanns, false); readParameterAnnotations(mv, context, impanns, false);
} }
@@ -1075,7 +1184,7 @@ public class ClassReader {
int codeStart = u; int codeStart = u;
int codeEnd = u + codeLength; int codeEnd = u + codeLength;
Label[] labels = context.labels = new Label[codeLength + 2]; Label[] labels = context.labels = new Label[codeLength + 2];
readLabel(codeLength + 1, labels); createLabel(codeLength + 1, labels);
while (u < codeEnd) { while (u < codeEnd) {
int offset = u - codeStart; int offset = u - codeStart;
int opcode = b[u] & 0xFF; int opcode = b[u] & 0xFF;
@@ -1085,11 +1194,16 @@ public class ClassReader {
u += 1; u += 1;
break; break;
case ClassWriter.LABEL_INSN: case ClassWriter.LABEL_INSN:
readLabel(offset + readShort(u + 1), labels); createLabel(offset + readShort(u + 1), labels);
u += 3;
break;
case ClassWriter.ASM_LABEL_INSN:
createLabel(offset + readUnsignedShort(u + 1), labels);
u += 3; u += 3;
break; break;
case ClassWriter.LABELW_INSN: case ClassWriter.LABELW_INSN:
readLabel(offset + readInt(u + 1), labels); case ClassWriter.ASM_LABELW_INSN:
createLabel(offset + readInt(u + 1), labels);
u += 5; u += 5;
break; break;
case ClassWriter.WIDE_INSN: case ClassWriter.WIDE_INSN:
@@ -1104,9 +1218,9 @@ public class ClassReader {
// skips 0 to 3 padding bytes // skips 0 to 3 padding bytes
u = u + 4 - (offset & 3); u = u + 4 - (offset & 3);
// reads instruction // reads instruction
readLabel(offset + readInt(u), labels); createLabel(offset + readInt(u), labels);
for (int i = readInt(u + 8) - readInt(u + 4) + 1; i > 0; --i) { for (int i = readInt(u + 8) - readInt(u + 4) + 1; i > 0; --i) {
readLabel(offset + readInt(u + 12), labels); createLabel(offset + readInt(u + 12), labels);
u += 4; u += 4;
} }
u += 12; u += 12;
@@ -1115,9 +1229,9 @@ public class ClassReader {
// skips 0 to 3 padding bytes // skips 0 to 3 padding bytes
u = u + 4 - (offset & 3); u = u + 4 - (offset & 3);
// reads instruction // reads instruction
readLabel(offset + readInt(u), labels); createLabel(offset + readInt(u), labels);
for (int i = readInt(u + 4); i > 0; --i) { for (int i = readInt(u + 4); i > 0; --i) {
readLabel(offset + readInt(u + 12), labels); createLabel(offset + readInt(u + 12), labels);
u += 8; u += 8;
} }
u += 8; u += 8;
@@ -1147,9 +1261,9 @@ public class ClassReader {
// reads the try catch entries to find the labels, and also visits them // reads the try catch entries to find the labels, and also visits them
for (int i = readUnsignedShort(u); i > 0; --i) { for (int i = readUnsignedShort(u); i > 0; --i) {
Label start = readLabel(readUnsignedShort(u + 2), labels); Label start = createLabel(readUnsignedShort(u + 2), labels);
Label end = readLabel(readUnsignedShort(u + 4), labels); Label end = createLabel(readUnsignedShort(u + 4), labels);
Label handler = readLabel(readUnsignedShort(u + 6), labels); Label handler = createLabel(readUnsignedShort(u + 6), labels);
String type = readUTF8(items[readUnsignedShort(u + 8)], c); String type = readUTF8(items[readUnsignedShort(u + 8)], c);
mv.visitTryCatchBlock(start, end, handler, type); mv.visitTryCatchBlock(start, end, handler, type);
u += 8; u += 8;
@@ -1180,13 +1294,9 @@ public class ClassReader {
varTable = u + 8; varTable = u + 8;
for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) { for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) {
int label = readUnsignedShort(v + 10); int label = readUnsignedShort(v + 10);
if (labels[label] == null) { createDebugLabel(label, labels);
readLabel(label, labels).status |= Label.DEBUG;
}
label += readUnsignedShort(v + 12); label += readUnsignedShort(v + 12);
if (labels[label] == null) { createDebugLabel(label, labels);
readLabel(label, labels).status |= Label.DEBUG;
}
v += 10; v += 10;
} }
} }
@@ -1196,9 +1306,7 @@ public class ClassReader {
if ((context.flags & SKIP_DEBUG) == 0) { if ((context.flags & SKIP_DEBUG) == 0) {
for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) { for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) {
int label = readUnsignedShort(v + 10); int label = readUnsignedShort(v + 10);
if (labels[label] == null) { createDebugLabel(label, labels);
readLabel(label, labels).status |= Label.DEBUG;
}
Label l = labels[label]; Label l = labels[label];
while (l.line > 0) { while (l.line > 0) {
if (l.next == null) { if (l.next == null) {
@@ -1210,17 +1318,15 @@ public class ClassReader {
v += 4; v += 4;
} }
} }
} else if (ANNOTATIONS } else if ("RuntimeVisibleTypeAnnotations".equals(attrName)) {
&& "RuntimeVisibleTypeAnnotations".equals(attrName)) {
tanns = readTypeAnnotations(mv, context, u + 8, true); tanns = readTypeAnnotations(mv, context, u + 8, true);
ntoff = tanns.length == 0 || readByte(tanns[0]) < 0x43 ? -1 ntoff = tanns.length == 0 || readByte(tanns[0]) < 0x43 ? -1
: readUnsignedShort(tanns[0] + 1); : readUnsignedShort(tanns[0] + 1);
} else if (ANNOTATIONS } else if ("RuntimeInvisibleTypeAnnotations".equals(attrName)) {
&& "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
itanns = readTypeAnnotations(mv, context, u + 8, false); itanns = readTypeAnnotations(mv, context, u + 8, false);
nitoff = itanns.length == 0 || readByte(itanns[0]) < 0x43 ? -1 nitoff = itanns.length == 0 || readByte(itanns[0]) < 0x43 ? -1
: readUnsignedShort(itanns[0] + 1); : readUnsignedShort(itanns[0] + 1);
} else if (FRAMES && "StackMapTable".equals(attrName)) { } else if ("StackMapTable".equals(attrName)) {
if ((context.flags & SKIP_FRAMES) == 0) { if ((context.flags & SKIP_FRAMES) == 0) {
stackMap = u + 10; stackMap = u + 10;
stackMapSize = readInt(u + 4); stackMapSize = readInt(u + 4);
@@ -1244,7 +1350,7 @@ public class ClassReader {
* this by parsing the stack map table without a full decoding * this by parsing the stack map table without a full decoding
* (see below). * (see below).
*/ */
} else if (FRAMES && "StackMap".equals(attrName)) { } else if ("StackMap".equals(attrName)) {
if ((context.flags & SKIP_FRAMES) == 0) { if ((context.flags & SKIP_FRAMES) == 0) {
zip = false; zip = false;
stackMap = u + 10; stackMap = u + 10;
@@ -1273,7 +1379,7 @@ public class ClassReader {
u += 2; u += 2;
// generates the first (implicit) stack map frame // generates the first (implicit) stack map frame
if (FRAMES && stackMap != 0) { if (stackMap != 0) {
/* /*
* for the first explicit frame the offset is not offset_delta + 1 * for the first explicit frame the offset is not offset_delta + 1
* but only offset_delta; setting the implicit frame offset to -1 * but only offset_delta; setting the implicit frame offset to -1
@@ -1306,14 +1412,31 @@ public class ClassReader {
int v = readUnsignedShort(i + 1); int v = readUnsignedShort(i + 1);
if (v >= 0 && v < codeLength) { if (v >= 0 && v < codeLength) {
if ((b[codeStart + v] & 0xFF) == Opcodes.NEW) { if ((b[codeStart + v] & 0xFF) == Opcodes.NEW) {
readLabel(v, labels); createLabel(v, labels);
} }
} }
} }
} }
} }
if ((context.flags & EXPAND_ASM_INSNS) != 0
&& (context.flags & EXPAND_FRAMES) != 0) {
// Expanding the ASM pseudo instructions can introduce F_INSERT
// frames, even if the method does not currently have any frame.
// Also these inserted frames must be computed by simulating the
// effect of the bytecode instructions one by one, starting from the
// first one and the last existing frame (or the implicit first
// one). Finally, due to the way MethodWriter computes this (with
// the compute = INSERTED_FRAMES option), MethodWriter needs to know
// maxLocals before the first instruction is visited. For all these
// reasons we always visit the implicit first frame in this case
// (passing only maxLocals - the rest can be and is computed in
// MethodWriter).
mv.visitFrame(Opcodes.F_NEW, maxLocals, null, 0, null);
}
// visits the instructions // visits the instructions
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;
@@ -1334,7 +1457,7 @@ public class ClassReader {
} }
// visits the frame for this offset, if any // visits the frame for this offset, if any
while (FRAMES && frame != null while (frame != null
&& (frame.offset == offset || frame.offset == -1)) { && (frame.offset == offset || frame.offset == -1)) {
// if there is a frame for this offset, makes the visitor visit // if there is a frame for this offset, makes the visitor visit
// it, and reads the next frame if there is one. // it, and reads the next frame if there is one.
@@ -1346,6 +1469,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);
@@ -1354,6 +1480,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 (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;
@@ -1378,9 +1511,47 @@ public class ClassReader {
u += 3; u += 3;
break; break;
case ClassWriter.LABELW_INSN: case ClassWriter.LABELW_INSN:
mv.visitJumpInsn(opcode - 33, labels[offset + readInt(u + 1)]); mv.visitJumpInsn(opcode + opcodeDelta, labels[offset
+ readInt(u + 1)]);
u += 5; u += 5;
break; break;
case ClassWriter.ASM_LABEL_INSN: {
// changes temporary opcodes 202 to 217 (inclusive), 218
// and 219 to IFEQ ... JSR (inclusive), IFNULL and
// IFNONNULL
opcode = opcode < 218 ? opcode - 49 : opcode - 20;
Label target = labels[offset + readUnsignedShort(u + 1)];
// replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx
// <l> with IFNOTxxx <L> GOTO_W <l> L:..., where IFNOTxxx is
// the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ)
// and where <L> designates the instruction just after
// the GOTO_W.
if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) {
mv.visitJumpInsn(opcode + 33, target);
} else {
opcode = opcode <= 166 ? ((opcode + 1) ^ 1) - 1
: opcode ^ 1;
Label endif = createLabel(offset + 3, labels);
mv.visitJumpInsn(opcode, endif);
mv.visitJumpInsn(200, target); // GOTO_W
// endif designates the instruction just after GOTO_W,
// and is visited as part of the next instruction. Since
// it is a jump target, we need to insert a frame here.
insertFrame = true;
}
u += 3;
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) {
@@ -1636,8 +1807,8 @@ public class ClassReader {
for (int j = readUnsignedShort(u + 1); j > 0; --j) { for (int j = readUnsignedShort(u + 1); j > 0; --j) {
int start = readUnsignedShort(u + 3); int start = readUnsignedShort(u + 3);
int length = readUnsignedShort(u + 5); int length = readUnsignedShort(u + 5);
readLabel(start, context.labels); createLabel(start, context.labels);
readLabel(start + length, context.labels); createLabel(start + length, context.labels);
u += 6; u += 6;
} }
u += 3; u += 3;
@@ -1716,8 +1887,8 @@ public class ClassReader {
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
int start = readUnsignedShort(u); int start = readUnsignedShort(u);
int length = readUnsignedShort(u + 2); int length = readUnsignedShort(u + 2);
context.start[i] = readLabel(start, context.labels); context.start[i] = createLabel(start, context.labels);
context.end[i] = readLabel(start + length, context.labels); context.end[i] = createLabel(start + length, context.labels);
context.index[i] = readUnsignedShort(u + 4); context.index[i] = readUnsignedShort(u + 4);
u += 6; u += 6;
} }
@@ -2137,7 +2308,7 @@ public class ClassReader {
} }
} }
frame.offset += delta + 1; frame.offset += delta + 1;
readLabel(frame.offset, labels); createLabel(frame.offset, labels);
return stackMap; return stackMap;
} }
@@ -2190,7 +2361,7 @@ public class ClassReader {
v += 2; v += 2;
break; break;
default: // Uninitialized default: // Uninitialized
frame[index] = readLabel(readUnsignedShort(v), labels); frame[index] = createLabel(readUnsignedShort(v), labels);
v += 2; v += 2;
} }
return v; return v;
@@ -2216,6 +2387,39 @@ public class ClassReader {
return labels[offset]; return labels[offset];
} }
/**
* Creates a label without the Label.DEBUG flag set, for the given offset.
* The label is created with a call to {@link #readLabel} and its
* Label.DEBUG flag is cleared.
*
* @param offset
* a bytecode offset in a method.
* @param labels
* the already created labels, indexed by their offset.
* @return a Label without the Label.DEBUG flag set.
*/
private Label createLabel(int offset, Label[] labels) {
Label label = readLabel(offset, labels);
label.status &= ~Label.DEBUG;
return label;
}
/**
* Creates a label with the Label.DEBUG flag set, if there is no already
* existing label for the given offset (otherwise does nothing). The label
* is created with a call to {@link #readLabel}.
*
* @param offset
* a bytecode offset in a method.
* @param labels
* the already created labels, indexed by their offset.
*/
private void createDebugLabel(int offset, Label[] labels) {
if (labels[offset] == null) {
readLabel(offset, labels).status |= Label.DEBUG;
}
}
/** /**
* Returns the start index of the attribute_info structure of this class. * Returns the start index of the attribute_info structure of this class.
* *
@@ -2470,6 +2674,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
@@ -2484,16 +2702,13 @@ 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
return readUTF8(items[readUnsignedShort(index)], buf);
} }
/** /**
* Reads a CONSTANT_Module_info item in {@code b}. This method is intended * Reads a module constant pool item in {@link #b b}. <i>This method is
* for {@link Attribute} sub classes, and is normally not needed by class * intended for {@link Attribute} sub classes, and is normally not needed by
* generators or adapters. * class generators or adapters.</i>
* *
* @param index * @param index
* the start index of an unsigned short value in {@link #b b}, * the start index of an unsigned short value in {@link #b b},
@@ -2503,25 +2718,25 @@ public class ClassReader {
* sufficiently large. It is not automatically resized. * sufficiently large. It is not automatically resized.
* @return the String corresponding to the specified module item. * @return the String corresponding to the specified module item.
*/ */
public String readModule(int index, char[] buf) { public String readModule(final int index, final char[] buf) {
return readUTF8(items[readUnsignedShort(index)], buf); return readStringish(index, buf);
} }
/** /**
* Reads a CONSTANT_Package_info item in {@code b}. This method is * Reads a module constant pool item in {@link #b b}. <i>This method is
* intended for {@link Attribute} sub slasses, and is normally not needed * intended for {@link Attribute} sub classes, and is normally not needed by
* by class generators or adapters. * class generators or adapters.</i>
* *
* @param index * @param index
* the start index of an unsigned short value in {@link #b b}, * the start index of an unsigned short value in {@link #b b},
* whose value is the index of a package constant pool item. * whose value is the index of a module constant pool item.
* @param buf * @param buf
* buffer to be used to read the item. This buffer must be * buffer to be used to read the item. This buffer must be
* sufficiently large. It is not automatically resized. * sufficiently large. It is not automatically resized.
* @return the String corresponding to the specified package item. * @return the String corresponding to the specified module item.
*/ */
public String readPackage(int index, char[] buf) { public String readPackage(final int index, final char[] buf) {
return readUTF8(items[readUnsignedShort(index)], buf); return readStringish(index, buf);
} }
/** /**
@@ -2550,8 +2765,6 @@ public class ClassReader {
case ClassWriter.DOUBLE: case ClassWriter.DOUBLE:
return Double.longBitsToDouble(readLong(index)); return Double.longBitsToDouble(readLong(index));
case ClassWriter.CLASS: case ClassWriter.CLASS:
case ClassWriter.MODULE:
case ClassWriter.PACKAGE:
return Type.getObjectType(readUTF8(index, buf)); return Type.getObjectType(readUTF8(index, buf));
case ClassWriter.STR: case ClassWriter.STR:
return readUTF8(index, buf); return readUTF8(index, buf);

View File

@@ -61,7 +61,7 @@ package org.redkale.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>.
@@ -72,7 +72,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;
@@ -87,7 +87,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);
@@ -98,13 +98,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;
@@ -160,6 +160,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

@@ -87,8 +87,8 @@ public class ClassWriter extends ClassVisitor {
* {@link MethodVisitor#visitFrame} method are ignored, and the stack map * {@link MethodVisitor#visitFrame} method are ignored, and the stack map
* frames are recomputed from the methods bytecode. The arguments of the * frames are recomputed from the methods bytecode. The arguments of the
* {@link MethodVisitor#visitMaxs visitMaxs} method are also ignored and * {@link MethodVisitor#visitMaxs visitMaxs} method are also ignored and
* recomputed from the bytecode. In other words, computeFrames implies * recomputed from the bytecode. In other words, COMPUTE_FRAMES implies
* computeMaxs. * COMPUTE_MAXS.
* *
* @see #ClassWriter(int) * @see #ClassWriter(int)
*/ */
@@ -196,6 +196,27 @@ public class ClassWriter extends ClassVisitor {
*/ */
static final int WIDE_INSN = 17; 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. * The instruction types of all JVM opcodes.
*/ */
@@ -284,7 +305,7 @@ public class ClassWriter extends ClassVisitor {
/** /**
* 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;
@@ -433,6 +454,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,25 +549,19 @@ public class ClassWriter extends ClassVisitor {
MethodWriter lastMethod; MethodWriter lastMethod;
/** /**
* <tt>true</tt> if the maximum stack size and number of local variables * Indicates what must be automatically computed.
* 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 // Static initializer
@@ -552,11 +572,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"
+ "AAAAGGGGGGGHIFBFAAFFAARQJJKKJJJJJJJJJJJJJJJJJJ"; + "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');
} }
@@ -610,8 +630,9 @@ public class ClassWriter extends ClassVisitor {
// // temporary opcodes used internally by ASM - see Label and // // temporary opcodes used internally by ASM - see Label and
// MethodWriter // MethodWriter
// for (i = 202; i < 220; ++i) { // for (i = 202; i < 220; ++i) {
// b[i] = 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;
@@ -644,7 +665,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];
@@ -653,8 +674,9 @@ public class ClassWriter extends ClassVisitor {
key2 = new Item(); key2 = new Item();
key3 = new Item(); key3 = new Item();
key4 = new Item(); key4 = new Item();
this.computeMaxs = (flags & COMPUTE_MAXS) != 0; this.compute = (flags & COMPUTE_FRAMES) != 0 ? MethodWriter.FRAMES
this.computeFrames = (flags & COMPUTE_FRAMES) != 0; : ((flags & COMPUTE_MAXS) != 0 ? MethodWriter.MAXS
: MethodWriter.NOTHING);
} }
/** /**
@@ -684,9 +706,9 @@ public class ClassWriter extends ClassVisitor {
* @param flags * @param flags
* option flags that can be used to modify the default behavior * option flags that can be used to modify the default behavior
* of this class. <i>These option flags do not affect methods * of this class. <i>These option flags do not affect methods
* that are copied as is in the new class. This means that the * that are copied as is in the new class. This means that
* maximum stack size nor the stack frames will be computed for * neither the maximum stack size nor the stack frames will be
* these methods</i>. See {@link #COMPUTE_MAXS}, * computed for these methods</i>. See {@link #COMPUTE_MAXS},
* {@link #COMPUTE_FRAMES}. * {@link #COMPUTE_FRAMES}.
*/ */
public ClassWriter(final ClassReader classReader, final int flags) { public ClassWriter(final ClassReader classReader, final int flags) {
@@ -705,9 +727,9 @@ public class ClassWriter extends ClassVisitor {
final String[] interfaces) { final String[] interfaces) {
this.version = version; this.version = version;
this.access = access; this.access = access;
this.name = (name == null) ? 0 : newClass(name); this.name = newClass(name);
thisName = name; thisName = name;
if (ClassReader.SIGNATURES && signature != null) { if (signature != null) {
this.signature = newUTF8(signature); this.signature = newUTF8(signature);
} }
this.superName = superName == null ? 0 : newClass(superName); this.superName = superName == null ? 0 : newClass(superName);
@@ -731,6 +753,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) {
@@ -743,9 +773,6 @@ public class ClassWriter extends ClassVisitor {
@Override @Override
public final AnnotationVisitor visitAnnotation(final String desc, public final AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) { final boolean visible) {
if (!ClassReader.ANNOTATIONS) {
return null;
}
ByteVector bv = new ByteVector(); ByteVector bv = new ByteVector();
// write type, and reserve space for values count // write type, and reserve space for values count
bv.putShort(newUTF8(desc)).putShort(0); bv.putShort(newUTF8(desc)).putShort(0);
@@ -763,9 +790,6 @@ public class ClassWriter extends ClassVisitor {
@Override @Override
public final AnnotationVisitor visitTypeAnnotation(int typeRef, public final AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, final String desc, final boolean visible) { TypePath typePath, final String desc, final boolean visible) {
if (!ClassReader.ANNOTATIONS) {
return null;
}
ByteVector bv = new ByteVector(); ByteVector bv = new ByteVector();
// write target_type and target_info // write target_type and target_info
AnnotationWriter.putTarget(typeRef, typePath, bv); AnnotationWriter.putTarget(typeRef, typePath, bv);
@@ -805,7 +829,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);
@@ -830,7 +854,7 @@ public class ClassWriter extends ClassVisitor {
public final MethodVisitor visitMethod(final int access, final String name, public final MethodVisitor visitMethod(final int access, final String name,
final String desc, final String signature, final String[] exceptions) { final String desc, final String signature, final String[] exceptions) {
return new MethodWriter(this, access, name, desc, signature, return new MethodWriter(this, access, name, desc, signature,
exceptions, computeMaxs, computeFrames); exceptions, compute);
} }
@Override @Override
@@ -874,7 +898,7 @@ public class ClassWriter extends ClassVisitor {
size += 8 + bootstrapMethods.length; size += 8 + bootstrapMethods.length;
newUTF8("BootstrapMethods"); newUTF8("BootstrapMethods");
} }
if (ClassReader.SIGNATURES && signature != 0) { if (signature != 0) {
++attributeCount; ++attributeCount;
size += 8; size += 8;
newUTF8("Signature"); newUTF8("Signature");
@@ -912,26 +936,31 @@ public class ClassWriter extends ClassVisitor {
size += 8 + innerClasses.length; size += 8 + innerClasses.length;
newUTF8("InnerClasses"); newUTF8("InnerClasses");
} }
if (ClassReader.ANNOTATIONS && anns != null) { if (anns != null) {
++attributeCount; ++attributeCount;
size += 8 + anns.getSize(); size += 8 + anns.getSize();
newUTF8("RuntimeVisibleAnnotations"); newUTF8("RuntimeVisibleAnnotations");
} }
if (ClassReader.ANNOTATIONS && ianns != null) { if (ianns != null) {
++attributeCount; ++attributeCount;
size += 8 + ianns.getSize(); size += 8 + ianns.getSize();
newUTF8("RuntimeInvisibleAnnotations"); newUTF8("RuntimeInvisibleAnnotations");
} }
if (ClassReader.ANNOTATIONS && tanns != null) { if (tanns != null) {
++attributeCount; ++attributeCount;
size += 8 + tanns.getSize(); size += 8 + tanns.getSize();
newUTF8("RuntimeVisibleTypeAnnotations"); newUTF8("RuntimeVisibleTypeAnnotations");
} }
if (ClassReader.ANNOTATIONS && itanns != null) { if (itanns != null) {
++attributeCount; ++attributeCount;
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);
@@ -968,7 +997,7 @@ public class ClassWriter extends ClassVisitor {
bootstrapMethodsCount); bootstrapMethodsCount);
out.putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length); out.putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length);
} }
if (ClassReader.SIGNATURES && signature != 0) { if (signature != 0) {
out.putShort(newUTF8("Signature")).putInt(2).putShort(signature); out.putShort(newUTF8("Signature")).putInt(2).putShort(signature);
} }
if (sourceFile != 0) { if (sourceFile != 0) {
@@ -979,6 +1008,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);
@@ -997,41 +1031,46 @@ public class ClassWriter extends ClassVisitor {
out.putInt(innerClasses.length + 2).putShort(innerClassesCount); out.putInt(innerClasses.length + 2).putShort(innerClassesCount);
out.putByteArray(innerClasses.data, 0, innerClasses.length); out.putByteArray(innerClasses.data, 0, innerClasses.length);
} }
if (ClassReader.ANNOTATIONS && anns != null) { if (anns != null) {
out.putShort(newUTF8("RuntimeVisibleAnnotations")); out.putShort(newUTF8("RuntimeVisibleAnnotations"));
anns.put(out); anns.put(out);
} }
if (ClassReader.ANNOTATIONS && ianns != null) { if (ianns != null) {
out.putShort(newUTF8("RuntimeInvisibleAnnotations")); out.putShort(newUTF8("RuntimeInvisibleAnnotations"));
ianns.put(out); ianns.put(out);
} }
if (ClassReader.ANNOTATIONS && tanns != null) { if (tanns != null) {
out.putShort(newUTF8("RuntimeVisibleTypeAnnotations")); out.putShort(newUTF8("RuntimeVisibleTypeAnnotations"));
tanns.put(out); tanns.put(out);
} }
if (ClassReader.ANNOTATIONS && itanns != null) { if (itanns != null) {
out.putShort(newUTF8("RuntimeInvisibleTypeAnnotations")); out.putShort(newUTF8("RuntimeInvisibleTypeAnnotations"));
itanns.put(out); itanns.put(out);
} }
if (attrs != null) { if (attrs != null) {
attrs.put(this, null, 0, -1, -1, out); 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; anns = null;
ianns = null; ianns = null;
attrs = null; attrs = null;
innerClassesCount = 0; moduleWriter = null;
innerClasses = null;
bootstrapMethodsCount = 0;
bootstrapMethods = null;
firstField = null; firstField = null;
lastField = null; lastField = null;
firstMethod = null; firstMethod = null;
lastMethod = null; lastMethod = null;
computeMaxs = false; compute =
computeFrames = true; hasFrames ? MethodWriter.INSERTED_FRAMES : MethodWriter.NOTHING;
invalidFrames = false; hasAsmInsns = false;
new ClassReader(out.data).accept(this, ClassReader.SKIP_FRAMES); new ClassReader(out.data).accept(this,
(hasFrames ? ClassReader.EXPAND_FRAMES : 0)
| ClassReader.EXPAND_ASM_INSNS);
return toByteArray(); return toByteArray();
} }
return out.data; return out.data;
@@ -1078,16 +1117,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;
@@ -1136,20 +1175,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);
} }
@@ -1167,72 +1207,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 module 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 module name
* @return the index of a new or already existing module 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);
}
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
* 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;
} }
/** /**
@@ -1247,7 +1222,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;
} }
/** /**
@@ -1628,25 +1633,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

@@ -0,0 +1,85 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* 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.redkale.asm;
/**
* Information about the input stack map frame at the "current" instruction of a
* method. This is implemented as a Frame subclass for a "basic block"
* containing only one instruction.
*
* @author Eric Bruneton
*/
class CurrentFrame extends Frame {
/**
* Sets this CurrentFrame to the input stack map frame of the next "current"
* instruction, i.e. the instruction just after the given one. It is assumed
* that the value of this object when this method is called is the stack map
* frame status just before the given instruction is executed.
*/
@Override
void execute(int opcode, int arg, ClassWriter cw, Item item) {
super.execute(opcode, arg, cw, item);
Frame successor = new Frame();
merge(cw, successor, 0);
set(successor);
owner.inputStackTop = 0;
}
}

View File

@@ -69,7 +69,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;
@@ -84,7 +84,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);
@@ -95,13 +95,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

@@ -147,7 +147,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 {
@@ -158,7 +158,7 @@ final class FieldWriter extends FieldVisitor {
this.access = access; this.access = access;
this.name = cw.newUTF8(name); this.name = cw.newUTF8(name);
this.desc = cw.newUTF8(desc); this.desc = cw.newUTF8(desc);
if (ClassReader.SIGNATURES && signature != null) { if (signature != null) {
this.signature = cw.newUTF8(signature); this.signature = cw.newUTF8(signature);
} }
if (value != null) { if (value != null) {
@@ -173,9 +173,6 @@ final class FieldWriter extends FieldVisitor {
@Override @Override
public AnnotationVisitor visitAnnotation(final String desc, public AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) { final boolean visible) {
if (!ClassReader.ANNOTATIONS) {
return null;
}
ByteVector bv = new ByteVector(); ByteVector bv = new ByteVector();
// write type, and reserve space for values count // write type, and reserve space for values count
bv.putShort(cw.newUTF8(desc)).putShort(0); bv.putShort(cw.newUTF8(desc)).putShort(0);
@@ -193,9 +190,6 @@ final class FieldWriter extends FieldVisitor {
@Override @Override
public AnnotationVisitor visitTypeAnnotation(final int typeRef, public AnnotationVisitor visitTypeAnnotation(final int typeRef,
final TypePath typePath, final String desc, final boolean visible) { final TypePath typePath, final String desc, final boolean visible) {
if (!ClassReader.ANNOTATIONS) {
return null;
}
ByteVector bv = new ByteVector(); ByteVector bv = new ByteVector();
// write target_type and target_info // write target_type and target_info
AnnotationWriter.putTarget(typeRef, typePath, bv); AnnotationWriter.putTarget(typeRef, typePath, bv);
@@ -249,23 +243,23 @@ final class FieldWriter extends FieldVisitor {
cw.newUTF8("Deprecated"); cw.newUTF8("Deprecated");
size += 6; size += 6;
} }
if (ClassReader.SIGNATURES && signature != 0) { if (signature != 0) {
cw.newUTF8("Signature"); cw.newUTF8("Signature");
size += 8; size += 8;
} }
if (ClassReader.ANNOTATIONS && anns != null) { if (anns != null) {
cw.newUTF8("RuntimeVisibleAnnotations"); cw.newUTF8("RuntimeVisibleAnnotations");
size += 8 + anns.getSize(); size += 8 + anns.getSize();
} }
if (ClassReader.ANNOTATIONS && ianns != null) { if (ianns != null) {
cw.newUTF8("RuntimeInvisibleAnnotations"); cw.newUTF8("RuntimeInvisibleAnnotations");
size += 8 + ianns.getSize(); size += 8 + ianns.getSize();
} }
if (ClassReader.ANNOTATIONS && tanns != null) { if (tanns != null) {
cw.newUTF8("RuntimeVisibleTypeAnnotations"); cw.newUTF8("RuntimeVisibleTypeAnnotations");
size += 8 + tanns.getSize(); size += 8 + tanns.getSize();
} }
if (ClassReader.ANNOTATIONS && itanns != null) { if (itanns != null) {
cw.newUTF8("RuntimeInvisibleTypeAnnotations"); cw.newUTF8("RuntimeInvisibleTypeAnnotations");
size += 8 + itanns.getSize(); size += 8 + itanns.getSize();
} }
@@ -299,19 +293,19 @@ final class FieldWriter extends FieldVisitor {
if ((access & Opcodes.ACC_DEPRECATED) != 0) { if ((access & Opcodes.ACC_DEPRECATED) != 0) {
++attributeCount; ++attributeCount;
} }
if (ClassReader.SIGNATURES && signature != 0) { if (signature != 0) {
++attributeCount; ++attributeCount;
} }
if (ClassReader.ANNOTATIONS && anns != null) { if (anns != null) {
++attributeCount; ++attributeCount;
} }
if (ClassReader.ANNOTATIONS && ianns != null) { if (ianns != null) {
++attributeCount; ++attributeCount;
} }
if (ClassReader.ANNOTATIONS && tanns != null) { if (tanns != null) {
++attributeCount; ++attributeCount;
} }
if (ClassReader.ANNOTATIONS && itanns != null) { if (itanns != null) {
++attributeCount; ++attributeCount;
} }
if (attrs != null) { if (attrs != null) {
@@ -331,23 +325,23 @@ final class FieldWriter extends FieldVisitor {
if ((access & Opcodes.ACC_DEPRECATED) != 0) { if ((access & Opcodes.ACC_DEPRECATED) != 0) {
out.putShort(cw.newUTF8("Deprecated")).putInt(0); out.putShort(cw.newUTF8("Deprecated")).putInt(0);
} }
if (ClassReader.SIGNATURES && signature != 0) { if (signature != 0) {
out.putShort(cw.newUTF8("Signature")); out.putShort(cw.newUTF8("Signature"));
out.putInt(2).putShort(signature); out.putInt(2).putShort(signature);
} }
if (ClassReader.ANNOTATIONS && anns != null) { if (anns != null) {
out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
anns.put(out); anns.put(out);
} }
if (ClassReader.ANNOTATIONS && ianns != null) { if (ianns != null) {
out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
ianns.put(out); ianns.put(out);
} }
if (ClassReader.ANNOTATIONS && tanns != null) { if (tanns != null) {
out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations")); out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
tanns.put(out); tanns.put(out);
} }
if (ClassReader.ANNOTATIONS && itanns != null) { if (itanns != null) {
out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations")); out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
itanns.put(out); itanns.put(out);
} }

View File

@@ -63,7 +63,7 @@ package org.redkale.asm;
* *
* @author Eric Bruneton * @author Eric Bruneton
*/ */
final class Frame { class Frame {
/* /*
* Frames are computed in a two steps process: during the visit of each * Frames are computed in a two steps process: during the visit of each
@@ -192,7 +192,7 @@ final class Frame {
private static final int LOCAL = 0x2000000; private static final int LOCAL = 0x2000000;
/** /**
* Kind of the the types that are relative to the stack of an input stack * Kind of the types that are relative to the stack of an input stack
* map frame. The value of such types is a position relatively to the top of * map frame. The value of such types is a position relatively to the top of
* this stack. * this stack.
*/ */
@@ -525,7 +525,7 @@ final class Frame {
* When the stack map frames are completely computed, this field is the * When the stack map frames are completely computed, this field is the
* actual number of types in {@link #outputStack}. * actual number of types in {@link #outputStack}.
*/ */
private int outputStackTop; int outputStackTop;
/** /**
* Number of types that are initialized in the basic block. * Number of types that are initialized in the basic block.
@@ -549,6 +549,110 @@ final class Frame {
*/ */
private int[] initializations; private int[] initializations;
/**
* Sets this frame to the given value.
*
* @param cw
* the ClassWriter to which this label belongs.
* @param nLocal
* the number of local variables.
* @param local
* the local variable types. Primitive types are represented by
* {@link Opcodes#TOP}, {@link Opcodes#INTEGER},
* {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
* {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
* {@link Opcodes#UNINITIALIZED_THIS} (long and double are
* represented by a single element). Reference types are
* represented by String objects (representing internal names),
* and uninitialized types by Label objects (this label
* designates the NEW instruction that created this uninitialized
* value).
* @param nStack
* the number of operand stack elements.
* @param stack
* the operand stack types (same format as the "local" array).
*/
final void set(ClassWriter cw, final int nLocal, final Object[] local,
final int nStack, final Object[] stack) {
int i = convert(cw, nLocal, local, inputLocals);
while (i < local.length) {
inputLocals[i++] = TOP;
}
int nStackTop = 0;
for (int j = 0; j < nStack; ++j) {
if (stack[j] == Opcodes.LONG || stack[j] == Opcodes.DOUBLE) {
++nStackTop;
}
}
inputStack = new int[nStack + nStackTop];
convert(cw, nStack, stack, inputStack);
outputStackTop = 0;
initializationCount = 0;
}
/**
* Converts types from the MethodWriter.visitFrame() format to the Frame
* format.
*
* @param cw
* the ClassWriter to which this label belongs.
* @param nInput
* the number of types to convert.
* @param input
* the types to convert. Primitive types are represented by
* {@link Opcodes#TOP}, {@link Opcodes#INTEGER},
* {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
* {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
* {@link Opcodes#UNINITIALIZED_THIS} (long and double are
* represented by a single element). Reference types are
* represented by String objects (representing internal names),
* and uninitialized types by Label objects (this label
* designates the NEW instruction that created this uninitialized
* value).
* @param output
* where to store the converted types.
* @return the number of output elements.
*/
private static int convert(ClassWriter cw, int nInput, Object[] input,
int[] output) {
int i = 0;
for (int j = 0; j < nInput; ++j) {
if (input[j] instanceof Integer) {
output[i++] = BASE | ((Integer) input[j]).intValue();
if (input[j] == Opcodes.LONG || input[j] == Opcodes.DOUBLE) {
output[i++] = TOP;
}
} else if (input[j] instanceof String) {
output[i++] = type(cw, Type.getObjectType((String) input[j])
.getDescriptor());
} else {
output[i++] = UNINITIALIZED
| cw.addUninitializedType("",
((Label) input[j]).position);
}
}
return i;
}
/**
* Sets this frame to the value of the given frame. WARNING: after this
* method is called the two frames share the same data structures. It is
* recommended to discard the given frame f to avoid unexpected side
* effects.
*
* @param f
* The new frame value.
*/
final void set(final Frame f) {
inputLocals = f.inputLocals;
inputStack = f.inputStack;
outputLocals = f.outputLocals;
outputStack = f.outputStack;
outputStackTop = f.outputStackTop;
initializationCount = f.initializationCount;
initializations = f.initializations;
}
/** /**
* Returns the output frame local variable type at the given index. * Returns the output frame local variable type at the given index.
* *
@@ -614,7 +718,7 @@ final class Frame {
} }
// pushes the type on the output stack // pushes the type on the output stack
outputStack[outputStackTop++] = type; outputStack[outputStackTop++] = type;
// updates the maximun height reached by the output stack, if needed // updates the maximum height reached by the output stack, if needed
int top = owner.inputStackTop + outputStackTop; int top = owner.inputStackTop + outputStackTop;
if (top > owner.outputStackMax) { if (top > owner.outputStackMax) {
owner.outputStackMax = top; owner.outputStackMax = top;
@@ -650,7 +754,7 @@ final class Frame {
* a type descriptor. * a type descriptor.
* @return the int encoding of the given type. * @return the int encoding of the given type.
*/ */
private static int type(final ClassWriter cw, final String desc) { static int type(final ClassWriter cw, final String desc) {
String t; String t;
int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0; int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0;
switch (desc.charAt(index)) { switch (desc.charAt(index)) {
@@ -838,7 +942,7 @@ final class Frame {
* @param maxLocals * @param maxLocals
* the maximum number of local variables of this method. * the maximum number of local variables of this method.
*/ */
void initInputFrame(final ClassWriter cw, final int access, final void initInputFrame(final ClassWriter cw, final int access,
final Type[] args, final int maxLocals) { final Type[] args, final int maxLocals) {
inputLocals = new int[maxLocals]; inputLocals = new int[maxLocals];
inputStack = new int[0]; inputStack = new int[0];
@@ -981,7 +1085,7 @@ final class Frame {
case Opcodes.AALOAD: case Opcodes.AALOAD:
pop(1); pop(1);
t1 = pop(); t1 = pop();
push(ELEMENT_OF + t1); push(t1 == NULL ? t1 : ELEMENT_OF + t1);
break; break;
case Opcodes.ISTORE: case Opcodes.ISTORE:
case Opcodes.FSTORE: case Opcodes.FSTORE:
@@ -1312,7 +1416,7 @@ final class Frame {
* @return <tt>true</tt> if the input frame of the given label has been * @return <tt>true</tt> if the input frame of the given label has been
* changed by this operation. * changed by this operation.
*/ */
boolean merge(final ClassWriter cw, final Frame frame, final int edge) { final boolean merge(final ClassWriter cw, final Frame frame, final int edge) {
boolean changed = false; boolean changed = false;
int i, s, dim, kind, t; int i, s, dim, kind, t;

View File

@@ -80,6 +80,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
@@ -239,12 +240,12 @@ final class Item {
this.strVal3 = strVal3; this.strVal3 = strVal3;
switch (type) { switch (type) {
case ClassWriter.CLASS: case ClassWriter.CLASS:
case ClassWriter.MODULE:
case ClassWriter.PACKAGE:
this.intVal = 0; // intVal of a class must be zero, see visitInnerClass this.intVal = 0; // intVal of a class must be zero, see visitInnerClass
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;

View File

@@ -139,7 +139,8 @@ public class Label {
/** /**
* Field used to associate user information to a label. Warning: this field * Field used to associate user information to a label. Warning: this field
* is used by the ASM tree package. In order to use it with the ASM tree * is used by the ASM tree package. In order to use it with the ASM tree
* package you must override the method. * package you must override the
* {@link org.redkale.asm.tree.MethodNode#getLabelNode} method.
*/ */
public Object info; public Object info;
@@ -388,13 +389,12 @@ public class Label {
* the position of this label in the bytecode. * the position of this label in the bytecode.
* @param data * @param data
* the bytecode of the method. * the bytecode of the method.
* @return <tt>true</tt> if a blank that was left for this label was to * @return <tt>true</tt> if a blank that was left for this label was too
* small to store the offset. In such a case the corresponding jump * small to store the offset. In such a case the corresponding jump
* instruction is replaced with a pseudo instruction (using unused * instruction is replaced with a pseudo instruction (using unused
* opcodes) using an unsigned two bytes offset. These pseudo * opcodes) using an unsigned two bytes offset. These pseudo
* instructions will need to be replaced with true instructions with * instructions will be replaced with standard bytecode instructions
* wider offsets (4 bytes instead of 2). This is done in * with wider offsets (4 bytes instead of 2), in ClassReader.
* {@link MethodWriter#resizeInstructions}.
* @throws IllegalArgumentException * @throws IllegalArgumentException
* if this label has already been resolved, or if it has not * if this label has already been resolved, or if it has not
* been created by the given code writer. * been created by the given code writer.
@@ -453,7 +453,7 @@ public class Label {
* @return the first label of the series to which this label belongs. * @return the first label of the series to which this label belongs.
*/ */
Label getFirst() { Label getFirst() {
return !ClassReader.FRAMES || frame == null ? this : frame.owner; return frame == null ? this : frame.owner;
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

View File

@@ -86,7 +86,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;
@@ -101,7 +101,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);
@@ -112,13 +112,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;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,219 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* 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.redkale.asm;
/**
* A visitor to visit a Java module. The methods of this class must be called in
* the following order: <tt>visitMainClass</tt> | ( <tt>visitPackage</tt> |
* <tt>visitRequire</tt> | <tt>visitExport</tt> | <tt>visitOpen</tt> |
* <tt>visitUse</tt> | <tt>visitProvide</tt> )* <tt>visitEnd</tt>.
*
* The methods {@link #visitRequire(String, int, String)}, {@link #visitExport(String, int, String...)},
* {@link #visitOpen(String, int, String...)} and {@link #visitPackage(String)}
* take as parameter a package name or a module name. Unlike the other names which are internal names
* (names separated by slash), module and package names are qualified names (names separated by dot).
*
* @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;
/**
* Constructs a new {@link ModuleVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
*/
public ModuleVisitor(final int api) {
this(api, null);
}
/**
* Constructs a new {@link ModuleVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
* @param mv
* the module 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 internal name of the main class of the current module.
*/
public void visitMainClass(String mainClass) {
if (mv != null) {
mv.visitMainClass(mainClass);
}
}
/**
* Visit a package of the current module.
*
* @param packaze the qualified name of a package.
*/
public void visitPackage(String packaze) {
if (mv != null) {
mv.visitPackage(packaze);
}
}
/**
* Visits a dependence of the current module.
*
* @param module the qualified 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 qualified 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 the qualified 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 qualified 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 the qualified 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 internal name of an interface or a 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);
}
}
/**
* Visits the end of the module. This method, which is the last one to be
* called, is used to inform the visitor that everything have been visited.
*/
public void visitEnd() {
if (mv != null) {
mv.visitEnd();
}
}
}

View File

@@ -0,0 +1,322 @@
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* 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.redkale.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

@@ -1,4 +1,33 @@
/* /*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework * ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom * Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved. * All rights reserved.
@@ -41,13 +70,13 @@ package org.redkale.asm;
* @author Eric Bruneton * @author Eric Bruneton
* @author Eugene Kuleshov * @author Eugene Kuleshov
*/ */
@SuppressWarnings("deprecation") // for Integer(int) constructor
public interface Opcodes { public interface Opcodes {
// ASM API versions // ASM API versions
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
@@ -59,7 +88,8 @@ 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; int V9 = 0 << 16 | 53;
int V10 = 0 << 16 | 54;
// access flags // access flags
@@ -70,18 +100,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
@@ -148,15 +183,17 @@ public interface Opcodes {
*/ */
int F_SAME1 = 4; int F_SAME1 = 4;
// For reference comparison purposes, construct new instances // Do not try to change the following code to use auto-boxing,
// instead of using valueOf() or autoboxing. // these values are compared by reference and not by value
Integer TOP = new Integer(0); // The constructor of Integer was deprecated in 9
Integer INTEGER = new Integer(1); // but we are stuck with it by backward compatibility
Integer FLOAT = new Integer(2); @SuppressWarnings("deprecation") Integer TOP = new Integer(0);
Integer DOUBLE = new Integer(3); @SuppressWarnings("deprecation") Integer INTEGER = new Integer(1);
Integer LONG = new Integer(4); @SuppressWarnings("deprecation") Integer FLOAT = new Integer(2);
Integer NULL = new Integer(5); @SuppressWarnings("deprecation") Integer DOUBLE = new Integer(3);
Integer UNINITIALIZED_THIS = new Integer(6); @SuppressWarnings("deprecation") Integer LONG = new Integer(4);
@SuppressWarnings("deprecation") Integer NULL = new Integer(5);
@SuppressWarnings("deprecation") Integer UNINITIALIZED_THIS = new Integer(6);
// opcodes // visit method (- = idem) // opcodes // visit method (- = idem)

View File

@@ -406,7 +406,16 @@ public class Type {
*/ */
public static Type getReturnType(final String methodDescriptor) { public static Type getReturnType(final String methodDescriptor) {
char[] buf = methodDescriptor.toCharArray(); char[] buf = methodDescriptor.toCharArray();
return getType(buf, methodDescriptor.indexOf(')') + 1); int off = 1;
while (true) {
char car = buf[off++];
if (car == ')') {
return getType(buf, off);
} else if (car == 'L') {
while (buf[off++] != ';') {
}
}
}
} }
/** /**

View File

@@ -1,8 +1,62 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
* To change this template file, choose Tools | Templates *
* and open the template in the editor. *
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/ */
/*
*
*
*
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2013 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.redkale.asm; package org.redkale.asm;
/** /**

View File

@@ -16,7 +16,7 @@ public class AsmCreator {
public static void main(String[] args) throws Throwable { public static void main(String[] args) throws Throwable {
boolean realasm = false; //从http://forge.ow2.org/projects/asm/ 下载最新asm的src放在 srcasmroot 目录下 boolean realasm = false; //从http://forge.ow2.org/projects/asm/ 下载最新asm的src放在 srcasmroot 目录下
File srcasmroot = new File("D:/JAVA/JDK源码/JDK9源码/java.base/jdk/internal/org/objectweb/asm"); File srcasmroot = new File("D:/JAVA/JDK源码/jdk/internal/org/objectweb/asm");
if (realasm) srcasmroot = new File("D:/JAVA/JDK源码/org/objectweb/asm"); if (realasm) srcasmroot = new File("D:/JAVA/JDK源码/org/objectweb/asm");
File destasmroot = new File("D:/Java-Projects/RedkaleProject/src/org/redkale/asm"); File destasmroot = new File("D:/Java-Projects/RedkaleProject/src/org/redkale/asm");
String line = null; String line = null;
@@ -32,5 +32,6 @@ public class AsmCreator {
out.write(content.replace("jdk.internal.org.objectweb", "org.redkale").replace("org.objectweb", "org.redkale").getBytes()); out.write(content.replace("jdk.internal.org.objectweb", "org.redkale").replace("org.objectweb", "org.redkale").getBytes());
out.close(); out.close();
} }
//需要屏蔽ClassReader中判断checks the class version的部分
} }
} }