Upgraded embedded ASM version to 5.0
Issue: SPR-11239
This commit is contained in:
@@ -41,7 +41,7 @@ public abstract class AnnotationVisitor {
|
||||
|
||||
/**
|
||||
* The ASM API version implemented by this visitor. The value of this field
|
||||
* must be one of {@link Opcodes#ASM4}.
|
||||
* must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
|
||||
*/
|
||||
protected final int api;
|
||||
|
||||
@@ -56,7 +56,7 @@ public abstract class AnnotationVisitor {
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4}.
|
||||
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
|
||||
*/
|
||||
public AnnotationVisitor(final int api) {
|
||||
this(api, null);
|
||||
@@ -67,13 +67,13 @@ public abstract class AnnotationVisitor {
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4}.
|
||||
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
|
||||
* @param av
|
||||
* the annotation visitor to which this visitor must delegate
|
||||
* method calls. May be null.
|
||||
*/
|
||||
public AnnotationVisitor(final int api, final AnnotationVisitor av) {
|
||||
if (api != Opcodes.ASM4) {
|
||||
if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.api = api;
|
||||
|
||||
@@ -104,7 +104,7 @@ final class AnnotationWriter extends AnnotationVisitor {
|
||||
*/
|
||||
AnnotationWriter(final ClassWriter cw, final boolean named,
|
||||
final ByteVector bv, final ByteVector parent, final int offset) {
|
||||
super(Opcodes.ASM4);
|
||||
super(Opcodes.ASM5);
|
||||
this.cw = cw;
|
||||
this.named = named;
|
||||
this.bv = bv;
|
||||
@@ -315,4 +315,57 @@ final class AnnotationWriter extends AnnotationVisitor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the given type reference and type path into the given bytevector.
|
||||
* LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported.
|
||||
*
|
||||
* @param typeRef
|
||||
* a reference to the annotated type. See {@link TypeReference}.
|
||||
* @param typePath
|
||||
* the path to the annotated type argument, wildcard bound, array
|
||||
* element type, or static inner type within 'typeRef'. May be
|
||||
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||
* @param out
|
||||
* where the type reference and type path must be put.
|
||||
*/
|
||||
static void putTarget(int typeRef, TypePath typePath, ByteVector out) {
|
||||
switch (typeRef >>> 24) {
|
||||
case 0x00: // CLASS_TYPE_PARAMETER
|
||||
case 0x01: // METHOD_TYPE_PARAMETER
|
||||
case 0x16: // METHOD_FORMAL_PARAMETER
|
||||
out.putShort(typeRef >>> 16);
|
||||
break;
|
||||
case 0x13: // FIELD
|
||||
case 0x14: // METHOD_RETURN
|
||||
case 0x15: // METHOD_RECEIVER
|
||||
out.putByte(typeRef >>> 24);
|
||||
break;
|
||||
case 0x47: // CAST
|
||||
case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
|
||||
case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
|
||||
case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
|
||||
case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
|
||||
out.putInt(typeRef);
|
||||
break;
|
||||
// case 0x10: // CLASS_EXTENDS
|
||||
// case 0x11: // CLASS_TYPE_PARAMETER_BOUND
|
||||
// case 0x12: // METHOD_TYPE_PARAMETER_BOUND
|
||||
// case 0x17: // THROWS
|
||||
// case 0x42: // EXCEPTION_PARAMETER
|
||||
// case 0x43: // INSTANCEOF
|
||||
// case 0x44: // NEW
|
||||
// case 0x45: // CONSTRUCTOR_REFERENCE
|
||||
// case 0x46: // METHOD_REFERENCE
|
||||
default:
|
||||
out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8);
|
||||
break;
|
||||
}
|
||||
if (typePath == null) {
|
||||
out.putByte(0);
|
||||
} else {
|
||||
int length = typePath.b[typePath.offset] * 2 + 1;
|
||||
out.putByteArray(typePath.b, typePath.offset, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,41 +230,68 @@ public class ByteVector {
|
||||
if (c >= '\001' && c <= '\177') {
|
||||
data[len++] = (byte) c;
|
||||
} else {
|
||||
int byteLength = i;
|
||||
for (int j = i; j < charLength; ++j) {
|
||||
c = s.charAt(j);
|
||||
if (c >= '\001' && c <= '\177') {
|
||||
byteLength++;
|
||||
} else if (c > '\u07FF') {
|
||||
byteLength += 3;
|
||||
} else {
|
||||
byteLength += 2;
|
||||
}
|
||||
}
|
||||
if (byteLength > 65535) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
data[length] = (byte) (byteLength >>> 8);
|
||||
data[length + 1] = (byte) byteLength;
|
||||
if (length + 2 + byteLength > data.length) {
|
||||
length = len;
|
||||
enlarge(2 + byteLength);
|
||||
data = this.data;
|
||||
}
|
||||
for (int j = i; j < charLength; ++j) {
|
||||
c = s.charAt(j);
|
||||
if (c >= '\001' && c <= '\177') {
|
||||
data[len++] = (byte) c;
|
||||
} else if (c > '\u07FF') {
|
||||
data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
|
||||
data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
|
||||
data[len++] = (byte) (0x80 | c & 0x3F);
|
||||
} else {
|
||||
data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
|
||||
data[len++] = (byte) (0x80 | c & 0x3F);
|
||||
}
|
||||
}
|
||||
break;
|
||||
length = len;
|
||||
return encodeUTF8(s, i, 65535);
|
||||
}
|
||||
}
|
||||
length = len;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts an UTF8 string into this byte vector. The byte vector is
|
||||
* automatically enlarged if necessary. The string length is encoded in two
|
||||
* bytes before the encoded characters, if there is space for that (i.e. if
|
||||
* this.length - i - 2 >= 0).
|
||||
*
|
||||
* @param s
|
||||
* the String to encode.
|
||||
* @param i
|
||||
* the index of the first character to encode. The previous
|
||||
* characters are supposed to have already been encoded, using
|
||||
* only one byte per character.
|
||||
* @param maxByteLength
|
||||
* the maximum byte length of the encoded string, including the
|
||||
* already encoded characters.
|
||||
* @return this byte vector.
|
||||
*/
|
||||
ByteVector encodeUTF8(final String s, int i, int maxByteLength) {
|
||||
int charLength = s.length();
|
||||
int byteLength = i;
|
||||
char c;
|
||||
for (int j = i; j < charLength; ++j) {
|
||||
c = s.charAt(j);
|
||||
if (c >= '\001' && c <= '\177') {
|
||||
byteLength++;
|
||||
} else if (c > '\u07FF') {
|
||||
byteLength += 3;
|
||||
} else {
|
||||
byteLength += 2;
|
||||
}
|
||||
}
|
||||
if (byteLength > maxByteLength) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
int start = length - i - 2;
|
||||
if (start >= 0) {
|
||||
data[start] = (byte) (byteLength >>> 8);
|
||||
data[start + 1] = (byte) byteLength;
|
||||
}
|
||||
if (length + byteLength - i > data.length) {
|
||||
enlarge(byteLength - i);
|
||||
}
|
||||
int len = length;
|
||||
for (int j = i; j < charLength; ++j) {
|
||||
c = s.charAt(j);
|
||||
if (c >= '\001' && c <= '\177') {
|
||||
data[len++] = (byte) c;
|
||||
} else if (c > '\u07FF') {
|
||||
data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
|
||||
data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
|
||||
data[len++] = (byte) (0x80 | c & 0x3F);
|
||||
} else {
|
||||
data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
|
||||
data[len++] = (byte) (0x80 | c & 0x3F);
|
||||
}
|
||||
}
|
||||
length = len;
|
||||
|
||||
@@ -166,8 +166,8 @@ public class ClassReader {
|
||||
public ClassReader(final byte[] b, final int off, final int len) {
|
||||
this.b = b;
|
||||
// checks the class version
|
||||
/* SPRING PATCH: REMOVED FOR JDK 1.8 BYTECODE COMPATIBILITY
|
||||
if (readShort(off + 6) > Opcodes.V1_7) {
|
||||
/* SPRING PATCH: REMOVED FOR FORWARD COMPATIBILITY WITH JDK 9
|
||||
if (readShort(off + 6) > Opcodes.V1_8) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
*/
|
||||
@@ -559,6 +559,8 @@ public class ClassReader {
|
||||
String enclosingDesc = null;
|
||||
int anns = 0;
|
||||
int ianns = 0;
|
||||
int tanns = 0;
|
||||
int itanns = 0;
|
||||
int innerClasses = 0;
|
||||
Attribute attributes = null;
|
||||
|
||||
@@ -583,6 +585,9 @@ public class ClassReader {
|
||||
} else if (ANNOTATIONS
|
||||
&& "RuntimeVisibleAnnotations".equals(attrName)) {
|
||||
anns = u + 8;
|
||||
} else if (ANNOTATIONS
|
||||
&& "RuntimeVisibleTypeAnnotations".equals(attrName)) {
|
||||
tanns = u + 8;
|
||||
} else if ("Deprecated".equals(attrName)) {
|
||||
access |= Opcodes.ACC_DEPRECATED;
|
||||
} else if ("Synthetic".equals(attrName)) {
|
||||
@@ -594,6 +599,9 @@ public class ClassReader {
|
||||
} else if (ANNOTATIONS
|
||||
&& "RuntimeInvisibleAnnotations".equals(attrName)) {
|
||||
ianns = u + 8;
|
||||
} else if (ANNOTATIONS
|
||||
&& "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
|
||||
itanns = u + 8;
|
||||
} else if ("BootstrapMethods".equals(attrName)) {
|
||||
int[] bootstrapMethods = new int[readUnsignedShort(u + 8)];
|
||||
for (int j = 0, v = u + 10; j < bootstrapMethods.length; j++) {
|
||||
@@ -628,7 +636,7 @@ public class ClassReader {
|
||||
enclosingDesc);
|
||||
}
|
||||
|
||||
// visits the class annotations
|
||||
// visits the class annotations and type annotations
|
||||
if (ANNOTATIONS && anns != 0) {
|
||||
for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
|
||||
v = readAnnotationValues(v + 2, c, true,
|
||||
@@ -641,6 +649,22 @@ public class ClassReader {
|
||||
classVisitor.visitAnnotation(readUTF8(v, c), false));
|
||||
}
|
||||
}
|
||||
if (ANNOTATIONS && tanns != 0) {
|
||||
for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
|
||||
v = readAnnotationTarget(context, v);
|
||||
v = readAnnotationValues(v + 2, c, true,
|
||||
classVisitor.visitTypeAnnotation(context.typeRef,
|
||||
context.typePath, readUTF8(v, c), true));
|
||||
}
|
||||
}
|
||||
if (ANNOTATIONS && itanns != 0) {
|
||||
for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
|
||||
v = readAnnotationTarget(context, v);
|
||||
v = readAnnotationValues(v + 2, c, true,
|
||||
classVisitor.visitTypeAnnotation(context.typeRef,
|
||||
context.typePath, readUTF8(v, c), false));
|
||||
}
|
||||
}
|
||||
|
||||
// visits the attributes
|
||||
while (attributes != null) {
|
||||
@@ -699,6 +723,8 @@ public class ClassReader {
|
||||
String signature = null;
|
||||
int anns = 0;
|
||||
int ianns = 0;
|
||||
int tanns = 0;
|
||||
int itanns = 0;
|
||||
Object value = null;
|
||||
Attribute attributes = null;
|
||||
|
||||
@@ -719,9 +745,15 @@ public class ClassReader {
|
||||
} else if (ANNOTATIONS
|
||||
&& "RuntimeVisibleAnnotations".equals(attrName)) {
|
||||
anns = u + 8;
|
||||
} else if (ANNOTATIONS
|
||||
&& "RuntimeVisibleTypeAnnotations".equals(attrName)) {
|
||||
tanns = u + 8;
|
||||
} else if (ANNOTATIONS
|
||||
&& "RuntimeInvisibleAnnotations".equals(attrName)) {
|
||||
ianns = u + 8;
|
||||
} else if (ANNOTATIONS
|
||||
&& "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
|
||||
itanns = u + 8;
|
||||
} else {
|
||||
Attribute attr = readAttribute(context.attrs, attrName, u + 8,
|
||||
readInt(u + 4), c, -1, null);
|
||||
@@ -741,7 +773,7 @@ public class ClassReader {
|
||||
return u;
|
||||
}
|
||||
|
||||
// visits the field annotations
|
||||
// visits the field annotations and type annotations
|
||||
if (ANNOTATIONS && anns != 0) {
|
||||
for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
|
||||
v = readAnnotationValues(v + 2, c, true,
|
||||
@@ -754,6 +786,22 @@ public class ClassReader {
|
||||
fv.visitAnnotation(readUTF8(v, c), false));
|
||||
}
|
||||
}
|
||||
if (ANNOTATIONS && tanns != 0) {
|
||||
for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
|
||||
v = readAnnotationTarget(context, v);
|
||||
v = readAnnotationValues(v + 2, c, true,
|
||||
fv.visitTypeAnnotation(context.typeRef,
|
||||
context.typePath, readUTF8(v, c), true));
|
||||
}
|
||||
}
|
||||
if (ANNOTATIONS && itanns != 0) {
|
||||
for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
|
||||
v = readAnnotationTarget(context, v);
|
||||
v = readAnnotationValues(v + 2, c, true,
|
||||
fv.visitTypeAnnotation(context.typeRef,
|
||||
context.typePath, readUTF8(v, c), false));
|
||||
}
|
||||
}
|
||||
|
||||
// visits the field attributes
|
||||
while (attributes != null) {
|
||||
@@ -784,9 +832,9 @@ public class ClassReader {
|
||||
final Context context, int u) {
|
||||
// reads the method declaration
|
||||
char[] c = context.buffer;
|
||||
int access = readUnsignedShort(u);
|
||||
String name = readUTF8(u + 2, c);
|
||||
String desc = readUTF8(u + 4, c);
|
||||
context.access = readUnsignedShort(u);
|
||||
context.name = readUTF8(u + 2, c);
|
||||
context.desc = readUTF8(u + 4, c);
|
||||
u += 6;
|
||||
|
||||
// reads the method attributes
|
||||
@@ -794,8 +842,11 @@ public class ClassReader {
|
||||
int exception = 0;
|
||||
String[] exceptions = null;
|
||||
String signature = null;
|
||||
int methodParameters = 0;
|
||||
int anns = 0;
|
||||
int ianns = 0;
|
||||
int tanns = 0;
|
||||
int itanns = 0;
|
||||
int dann = 0;
|
||||
int mpanns = 0;
|
||||
int impanns = 0;
|
||||
@@ -820,24 +871,32 @@ public class ClassReader {
|
||||
} else if (SIGNATURES && "Signature".equals(attrName)) {
|
||||
signature = readUTF8(u + 8, c);
|
||||
} else if ("Deprecated".equals(attrName)) {
|
||||
access |= Opcodes.ACC_DEPRECATED;
|
||||
context.access |= Opcodes.ACC_DEPRECATED;
|
||||
} else if (ANNOTATIONS
|
||||
&& "RuntimeVisibleAnnotations".equals(attrName)) {
|
||||
anns = u + 8;
|
||||
} else if (ANNOTATIONS
|
||||
&& "RuntimeVisibleTypeAnnotations".equals(attrName)) {
|
||||
tanns = u + 8;
|
||||
} else if (ANNOTATIONS && "AnnotationDefault".equals(attrName)) {
|
||||
dann = u + 8;
|
||||
} else if ("Synthetic".equals(attrName)) {
|
||||
access |= Opcodes.ACC_SYNTHETIC
|
||||
context.access |= Opcodes.ACC_SYNTHETIC
|
||||
| ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
|
||||
} else if (ANNOTATIONS
|
||||
&& "RuntimeInvisibleAnnotations".equals(attrName)) {
|
||||
ianns = u + 8;
|
||||
} else if (ANNOTATIONS
|
||||
&& "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
|
||||
itanns = u + 8;
|
||||
} else if (ANNOTATIONS
|
||||
&& "RuntimeVisibleParameterAnnotations".equals(attrName)) {
|
||||
mpanns = u + 8;
|
||||
} else if (ANNOTATIONS
|
||||
&& "RuntimeInvisibleParameterAnnotations".equals(attrName)) {
|
||||
impanns = u + 8;
|
||||
} else if ("MethodParameters".equals(attrName)) {
|
||||
methodParameters = u + 8;
|
||||
} else {
|
||||
Attribute attr = readAttribute(context.attrs, attrName, u + 8,
|
||||
readInt(u + 4), c, -1, null);
|
||||
@@ -851,8 +910,8 @@ public class ClassReader {
|
||||
u += 2;
|
||||
|
||||
// visits the method declaration
|
||||
MethodVisitor mv = classVisitor.visitMethod(access, name, desc,
|
||||
signature, exceptions);
|
||||
MethodVisitor mv = classVisitor.visitMethod(context.access,
|
||||
context.name, context.desc, signature, exceptions);
|
||||
if (mv == null) {
|
||||
return u;
|
||||
}
|
||||
@@ -896,6 +955,13 @@ public class ClassReader {
|
||||
}
|
||||
}
|
||||
|
||||
// visit the method parameters
|
||||
if (methodParameters != 0) {
|
||||
for (int i = b[methodParameters] & 0xFF, v = methodParameters + 1; i > 0; --i, v = v + 4) {
|
||||
mv.visitParameter(readUTF8(v, c), readUnsignedShort(v + 2));
|
||||
}
|
||||
}
|
||||
|
||||
// visits the method annotations
|
||||
if (ANNOTATIONS && dann != 0) {
|
||||
AnnotationVisitor dv = mv.visitAnnotationDefault();
|
||||
@@ -916,11 +982,27 @@ public class ClassReader {
|
||||
mv.visitAnnotation(readUTF8(v, c), false));
|
||||
}
|
||||
}
|
||||
if (ANNOTATIONS && tanns != 0) {
|
||||
for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
|
||||
v = readAnnotationTarget(context, v);
|
||||
v = readAnnotationValues(v + 2, c, true,
|
||||
mv.visitTypeAnnotation(context.typeRef,
|
||||
context.typePath, readUTF8(v, c), true));
|
||||
}
|
||||
}
|
||||
if (ANNOTATIONS && itanns != 0) {
|
||||
for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
|
||||
v = readAnnotationTarget(context, v);
|
||||
v = readAnnotationValues(v + 2, c, true,
|
||||
mv.visitTypeAnnotation(context.typeRef,
|
||||
context.typePath, readUTF8(v, c), false));
|
||||
}
|
||||
}
|
||||
if (ANNOTATIONS && mpanns != 0) {
|
||||
readParameterAnnotations(mpanns, desc, c, true, mv);
|
||||
readParameterAnnotations(mv, context, mpanns, true);
|
||||
}
|
||||
if (ANNOTATIONS && impanns != 0) {
|
||||
readParameterAnnotations(impanns, desc, c, false, mv);
|
||||
readParameterAnnotations(mv, context, impanns, false);
|
||||
}
|
||||
|
||||
// visits the method attributes
|
||||
@@ -933,9 +1015,6 @@ public class ClassReader {
|
||||
|
||||
// visits the method code
|
||||
if (code != 0) {
|
||||
context.access = access;
|
||||
context.name = name;
|
||||
context.desc = desc;
|
||||
mv.visitCode();
|
||||
readCode(mv, context, code);
|
||||
}
|
||||
@@ -968,7 +1047,7 @@ public class ClassReader {
|
||||
// reads the bytecode to find the labels
|
||||
int codeStart = u;
|
||||
int codeEnd = u + codeLength;
|
||||
Label[] labels = new Label[codeLength + 2];
|
||||
Label[] labels = context.labels = new Label[codeLength + 2];
|
||||
readLabel(codeLength + 1, labels);
|
||||
while (u < codeEnd) {
|
||||
int offset = u - codeStart;
|
||||
@@ -1051,6 +1130,12 @@ public class ClassReader {
|
||||
u += 2;
|
||||
|
||||
// reads the code attributes
|
||||
int[] tanns = null; // start index of each visible type annotation
|
||||
int[] itanns = null; // start index of each invisible type annotation
|
||||
int tann = 0; // current index in tanns array
|
||||
int itann = 0; // current index in itanns array
|
||||
int ntoff = -1; // next visible type annotation code offset
|
||||
int nitoff = -1; // next invisible type annotation code offset
|
||||
int varTable = 0;
|
||||
int varTypeTable = 0;
|
||||
boolean zip = true;
|
||||
@@ -1091,6 +1176,16 @@ public class ClassReader {
|
||||
v += 4;
|
||||
}
|
||||
}
|
||||
} else if (ANNOTATIONS
|
||||
&& "RuntimeVisibleTypeAnnotations".equals(attrName)) {
|
||||
tanns = readTypeAnnotations(mv, context, u + 8, true);
|
||||
ntoff = tanns.length == 0 || readByte(tanns[0]) < 0x43 ? -1
|
||||
: readUnsignedShort(tanns[0] + 1);
|
||||
} else if (ANNOTATIONS
|
||||
&& "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
|
||||
itanns = readTypeAnnotations(mv, context, u + 8, false);
|
||||
nitoff = itanns.length == 0 || readByte(itanns[0]) < 0x43 ? -1
|
||||
: readUnsignedShort(itanns[0] + 1);
|
||||
} else if (FRAMES && "StackMapTable".equals(attrName)) {
|
||||
if ((context.flags & SKIP_FRAMES) == 0) {
|
||||
stackMap = u + 10;
|
||||
@@ -1213,7 +1308,7 @@ public class ClassReader {
|
||||
}
|
||||
}
|
||||
if (frameCount > 0) {
|
||||
stackMap = readFrame(stackMap, zip, unzip, labels, frame);
|
||||
stackMap = readFrame(stackMap, zip, unzip, frame);
|
||||
--frameCount;
|
||||
} else {
|
||||
frame = null;
|
||||
@@ -1312,6 +1407,7 @@ public class ClassReader {
|
||||
case ClassWriter.FIELDORMETH_INSN:
|
||||
case ClassWriter.ITFMETH_INSN: {
|
||||
int cpIndex = items[readUnsignedShort(u + 1)];
|
||||
boolean itf = b[cpIndex - 1] == ClassWriter.IMETH;
|
||||
String iowner = readClass(cpIndex, c);
|
||||
cpIndex = items[readUnsignedShort(cpIndex + 2)];
|
||||
String iname = readUTF8(cpIndex, c);
|
||||
@@ -1319,7 +1415,7 @@ public class ClassReader {
|
||||
if (opcode < Opcodes.INVOKEVIRTUAL) {
|
||||
mv.visitFieldInsn(opcode, iowner, iname, idesc);
|
||||
} else {
|
||||
mv.visitMethodInsn(opcode, iowner, iname, idesc);
|
||||
mv.visitMethodInsn(opcode, iowner, iname, idesc, itf);
|
||||
}
|
||||
if (opcode == Opcodes.INVOKEINTERFACE) {
|
||||
u += 5;
|
||||
@@ -1360,6 +1456,29 @@ public class ClassReader {
|
||||
u += 4;
|
||||
break;
|
||||
}
|
||||
|
||||
// visit the instruction annotations, if any
|
||||
while (tanns != null && tann < tanns.length && ntoff <= offset) {
|
||||
if (ntoff == offset) {
|
||||
int v = readAnnotationTarget(context, tanns[tann]);
|
||||
readAnnotationValues(v + 2, c, true,
|
||||
mv.visitInsnAnnotation(context.typeRef,
|
||||
context.typePath, readUTF8(v, c), true));
|
||||
}
|
||||
ntoff = ++tann >= tanns.length || readByte(tanns[tann]) < 0x43 ? -1
|
||||
: readUnsignedShort(tanns[tann] + 1);
|
||||
}
|
||||
while (itanns != null && itann < itanns.length && nitoff <= offset) {
|
||||
if (nitoff == offset) {
|
||||
int v = readAnnotationTarget(context, itanns[itann]);
|
||||
readAnnotationValues(v + 2, c, true,
|
||||
mv.visitInsnAnnotation(context.typeRef,
|
||||
context.typePath, readUTF8(v, c), false));
|
||||
}
|
||||
nitoff = ++itann >= itanns.length
|
||||
|| readByte(itanns[itann]) < 0x43 ? -1
|
||||
: readUnsignedShort(itanns[itann] + 1);
|
||||
}
|
||||
}
|
||||
if (labels[codeLength] != null) {
|
||||
mv.visitLabel(labels[codeLength]);
|
||||
@@ -1399,6 +1518,32 @@ public class ClassReader {
|
||||
}
|
||||
}
|
||||
|
||||
// visits the local variables type annotations
|
||||
if (tanns != null) {
|
||||
for (int i = 0; i < tanns.length; ++i) {
|
||||
if ((readByte(tanns[i]) >> 1) == (0x40 >> 1)) {
|
||||
int v = readAnnotationTarget(context, tanns[i]);
|
||||
v = readAnnotationValues(v + 2, c, true,
|
||||
mv.visitLocalVariableAnnotation(context.typeRef,
|
||||
context.typePath, context.start,
|
||||
context.end, context.index, readUTF8(v, c),
|
||||
true));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (itanns != null) {
|
||||
for (int i = 0; i < itanns.length; ++i) {
|
||||
if ((readByte(itanns[i]) >> 1) == (0x40 >> 1)) {
|
||||
int v = readAnnotationTarget(context, itanns[i]);
|
||||
v = readAnnotationValues(v + 2, c, true,
|
||||
mv.visitLocalVariableAnnotation(context.typeRef,
|
||||
context.typePath, context.start,
|
||||
context.end, context.index, readUTF8(v, c),
|
||||
false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// visits the code attributes
|
||||
while (attributes != null) {
|
||||
Attribute attr = attributes.next;
|
||||
@@ -1411,25 +1556,176 @@ public class ClassReader {
|
||||
mv.visitMaxs(maxStack, maxLocals);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a type annotation table to find the labels, and to visit the try
|
||||
* catch block annotations.
|
||||
*
|
||||
* @param u
|
||||
* the start offset of a type annotation table.
|
||||
* @param mv
|
||||
* the method visitor to be used to visit the try catch block
|
||||
* annotations.
|
||||
* @param context
|
||||
* information about the class being parsed.
|
||||
* @param visible
|
||||
* if the type annotation table to parse contains runtime visible
|
||||
* annotations.
|
||||
* @return the start offset of each type annotation in the parsed table.
|
||||
*/
|
||||
private int[] readTypeAnnotations(final MethodVisitor mv,
|
||||
final Context context, int u, boolean visible) {
|
||||
char[] c = context.buffer;
|
||||
int[] offsets = new int[readUnsignedShort(u)];
|
||||
u += 2;
|
||||
for (int i = 0; i < offsets.length; ++i) {
|
||||
offsets[i] = u;
|
||||
int target = readInt(u);
|
||||
switch (target >>> 24) {
|
||||
case 0x00: // CLASS_TYPE_PARAMETER
|
||||
case 0x01: // METHOD_TYPE_PARAMETER
|
||||
case 0x16: // METHOD_FORMAL_PARAMETER
|
||||
u += 2;
|
||||
break;
|
||||
case 0x13: // FIELD
|
||||
case 0x14: // METHOD_RETURN
|
||||
case 0x15: // METHOD_RECEIVER
|
||||
u += 1;
|
||||
break;
|
||||
case 0x40: // LOCAL_VARIABLE
|
||||
case 0x41: // RESOURCE_VARIABLE
|
||||
for (int j = readUnsignedShort(u + 1); j > 0; --j) {
|
||||
int start = readUnsignedShort(u + 3);
|
||||
int length = readUnsignedShort(u + 5);
|
||||
readLabel(start, context.labels);
|
||||
readLabel(start + length, context.labels);
|
||||
u += 6;
|
||||
}
|
||||
u += 3;
|
||||
break;
|
||||
case 0x47: // CAST
|
||||
case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
|
||||
case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
|
||||
case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
|
||||
case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
|
||||
u += 4;
|
||||
break;
|
||||
// case 0x10: // CLASS_EXTENDS
|
||||
// case 0x11: // CLASS_TYPE_PARAMETER_BOUND
|
||||
// case 0x12: // METHOD_TYPE_PARAMETER_BOUND
|
||||
// case 0x17: // THROWS
|
||||
// case 0x42: // EXCEPTION_PARAMETER
|
||||
// case 0x43: // INSTANCEOF
|
||||
// case 0x44: // NEW
|
||||
// case 0x45: // CONSTRUCTOR_REFERENCE
|
||||
// case 0x46: // METHOD_REFERENCE
|
||||
default:
|
||||
u += 3;
|
||||
break;
|
||||
}
|
||||
int pathLength = readByte(u);
|
||||
if ((target >>> 24) == 0x42) {
|
||||
TypePath path = pathLength == 0 ? null : new TypePath(b, u);
|
||||
u += 1 + 2 * pathLength;
|
||||
u = readAnnotationValues(u + 2, c, true,
|
||||
mv.visitTryCatchAnnotation(target, path,
|
||||
readUTF8(u, c), visible));
|
||||
} else {
|
||||
u = readAnnotationValues(u + 3 + 2 * pathLength, c, true, null);
|
||||
}
|
||||
}
|
||||
return offsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the header of a type annotation to extract its target_type and
|
||||
* target_path (the result is stored in the given context), and returns the
|
||||
* start offset of the rest of the type_annotation structure (i.e. the
|
||||
* offset to the type_index field, which is followed by
|
||||
* num_element_value_pairs and then the name,value pairs).
|
||||
*
|
||||
* @param context
|
||||
* information about the class being parsed. This is where the
|
||||
* extracted target_type and target_path must be stored.
|
||||
* @param u
|
||||
* the start offset of a type_annotation structure.
|
||||
* @return the start offset of the rest of the type_annotation structure.
|
||||
*/
|
||||
private int readAnnotationTarget(final Context context, int u) {
|
||||
int target = readInt(u);
|
||||
switch (target >>> 24) {
|
||||
case 0x00: // CLASS_TYPE_PARAMETER
|
||||
case 0x01: // METHOD_TYPE_PARAMETER
|
||||
case 0x16: // METHOD_FORMAL_PARAMETER
|
||||
target &= 0xFFFF0000;
|
||||
u += 2;
|
||||
break;
|
||||
case 0x13: // FIELD
|
||||
case 0x14: // METHOD_RETURN
|
||||
case 0x15: // METHOD_RECEIVER
|
||||
target &= 0xFF000000;
|
||||
u += 1;
|
||||
break;
|
||||
case 0x40: // LOCAL_VARIABLE
|
||||
case 0x41: { // RESOURCE_VARIABLE
|
||||
target &= 0xFF000000;
|
||||
int n = readUnsignedShort(u + 1);
|
||||
context.start = new Label[n];
|
||||
context.end = new Label[n];
|
||||
context.index = new int[n];
|
||||
u += 3;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
int start = readUnsignedShort(u);
|
||||
int length = readUnsignedShort(u + 2);
|
||||
context.start[i] = readLabel(start, context.labels);
|
||||
context.end[i] = readLabel(start + length, context.labels);
|
||||
context.index[i] = readUnsignedShort(u + 4);
|
||||
u += 6;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x47: // CAST
|
||||
case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
|
||||
case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
|
||||
case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
|
||||
case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
|
||||
target &= 0xFF0000FF;
|
||||
u += 4;
|
||||
break;
|
||||
// case 0x10: // CLASS_EXTENDS
|
||||
// case 0x11: // CLASS_TYPE_PARAMETER_BOUND
|
||||
// case 0x12: // METHOD_TYPE_PARAMETER_BOUND
|
||||
// case 0x17: // THROWS
|
||||
// case 0x42: // EXCEPTION_PARAMETER
|
||||
// case 0x43: // INSTANCEOF
|
||||
// case 0x44: // NEW
|
||||
// case 0x45: // CONSTRUCTOR_REFERENCE
|
||||
// case 0x46: // METHOD_REFERENCE
|
||||
default:
|
||||
target &= (target >>> 24) < 0x43 ? 0xFFFFFF00 : 0xFF000000;
|
||||
u += 3;
|
||||
break;
|
||||
}
|
||||
int pathLength = readByte(u);
|
||||
context.typeRef = target;
|
||||
context.typePath = pathLength == 0 ? null : new TypePath(b, u);
|
||||
return u + 1 + 2 * pathLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads parameter annotations and makes the given visitor visit them.
|
||||
*
|
||||
* @param mv
|
||||
* the visitor that must visit the annotations.
|
||||
* @param context
|
||||
* information about the class being parsed.
|
||||
* @param v
|
||||
* start offset in {@link #b b} of the annotations to be read.
|
||||
* @param desc
|
||||
* the method descriptor.
|
||||
* @param buf
|
||||
* buffer to be used to call {@link #readUTF8 readUTF8},
|
||||
* {@link #readClass(int,char[]) readClass} or {@link #readConst
|
||||
* readConst}.
|
||||
* @param visible
|
||||
* <tt>true</tt> if the annotations to be read are visible at
|
||||
* runtime.
|
||||
* @param mv
|
||||
* the visitor that must visit the annotations.
|
||||
*/
|
||||
private void readParameterAnnotations(int v, final String desc,
|
||||
final char[] buf, final boolean visible, final MethodVisitor mv) {
|
||||
private void readParameterAnnotations(final MethodVisitor mv,
|
||||
final Context context, int v, final boolean visible) {
|
||||
int i;
|
||||
int n = b[v++] & 0xFF;
|
||||
// workaround for a bug in javac (javac compiler generates a parameter
|
||||
@@ -1438,7 +1734,7 @@ public class ClassReader {
|
||||
// equal to the number of parameters in the method descriptor - which
|
||||
// includes the synthetic parameters added by the compiler). This work-
|
||||
// around supposes that the synthetic parameters are the first ones.
|
||||
int synthetics = Type.getArgumentTypes(desc).length - n;
|
||||
int synthetics = Type.getArgumentTypes(context.desc).length - n;
|
||||
AnnotationVisitor av;
|
||||
for (i = 0; i < synthetics; ++i) {
|
||||
// virtual annotation to detect synthetic parameters in MethodWriter
|
||||
@@ -1447,12 +1743,13 @@ public class ClassReader {
|
||||
av.visitEnd();
|
||||
}
|
||||
}
|
||||
char[] c = context.buffer;
|
||||
for (; i < n + synthetics; ++i) {
|
||||
int j = readUnsignedShort(v);
|
||||
v += 2;
|
||||
for (; j > 0; --j) {
|
||||
av = mv.visitParameterAnnotation(i, readUTF8(v, buf), visible);
|
||||
v = readAnnotationValues(v + 2, buf, true, av);
|
||||
av = mv.visitParameterAnnotation(i, readUTF8(v, c), visible);
|
||||
v = readAnnotationValues(v + 2, c, true, av);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1731,17 +2028,14 @@ public class ClassReader {
|
||||
* if the stack map frame at stackMap is compressed or not.
|
||||
* @param unzip
|
||||
* if the stack map frame must be uncompressed.
|
||||
* @param labels
|
||||
* the labels of the method currently being parsed, indexed by
|
||||
* their offset. A new label for the parsed stack map frame is
|
||||
* stored in this array if it does not already exist.
|
||||
* @param frame
|
||||
* where the parsed stack map frame must be stored.
|
||||
* @return the offset of the first byte following the parsed frame.
|
||||
*/
|
||||
private int readFrame(int stackMap, boolean zip, boolean unzip,
|
||||
Label[] labels, Context frame) {
|
||||
Context frame) {
|
||||
char[] c = frame.buffer;
|
||||
Label[] labels = frame.labels;
|
||||
int tag;
|
||||
int delta;
|
||||
if (zip) {
|
||||
|
||||
@@ -33,8 +33,9 @@ package org.springframework.asm;
|
||||
* 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> ] [
|
||||
* <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> |
|
||||
* <tt>visitAttribute</tt> )* ( <tt>visitInnerClass</tt> | <tt>visitField</tt> |
|
||||
* <tt>visitMethod</tt> )* <tt>visitEnd</tt>.
|
||||
* <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* (
|
||||
* <tt>visitInnerClass</tt> | <tt>visitField</tt> | <tt>visitMethod</tt> )*
|
||||
* <tt>visitEnd</tt>.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
@@ -42,7 +43,7 @@ public abstract class ClassVisitor {
|
||||
|
||||
/**
|
||||
* The ASM API version implemented by this visitor. The value of this field
|
||||
* must be one of {@link Opcodes#ASM4}.
|
||||
* must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
|
||||
*/
|
||||
protected final int api;
|
||||
|
||||
@@ -57,7 +58,7 @@ public abstract class ClassVisitor {
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4}.
|
||||
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
|
||||
*/
|
||||
public ClassVisitor(final int api) {
|
||||
this(api, null);
|
||||
@@ -68,17 +69,15 @@ public abstract class ClassVisitor {
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4}.
|
||||
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
|
||||
* @param cv
|
||||
* the class visitor to which this visitor must delegate method
|
||||
* calls. May be null.
|
||||
*/
|
||||
public ClassVisitor(final int api, final ClassVisitor cv) {
|
||||
/* SPRING PATCH: REMOVED FOR CGLIB 3.0 COMPATIBILITY
|
||||
if (api != Opcodes.ASM4) {
|
||||
if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
*/
|
||||
this.api = api;
|
||||
this.cv = cv;
|
||||
}
|
||||
@@ -170,6 +169,39 @@ public abstract class ClassVisitor {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an annotation on a type in the class signature.
|
||||
*
|
||||
* @param typeRef
|
||||
* a reference to the annotated type. The sort of this type
|
||||
* reference must be {@link TypeReference#CLASS_TYPE_PARAMETER
|
||||
* CLASS_TYPE_PARAMETER},
|
||||
* {@link TypeReference#CLASS_TYPE_PARAMETER_BOUND
|
||||
* CLASS_TYPE_PARAMETER_BOUND} or
|
||||
* {@link TypeReference#CLASS_EXTENDS CLASS_EXTENDS}. See
|
||||
* {@link TypeReference}.
|
||||
* @param typePath
|
||||
* the path to the annotated type argument, wildcard bound, array
|
||||
* element type, or static inner type within 'typeRef'. May be
|
||||
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||
* @param desc
|
||||
* the class descriptor of the annotation class.
|
||||
* @param visible
|
||||
* <tt>true</tt> if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
||||
* this visitor is not interested in visiting this annotation.
|
||||
*/
|
||||
public AnnotationVisitor visitTypeAnnotation(int typeRef,
|
||||
TypePath typePath, String desc, boolean visible) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
if (cv != null) {
|
||||
return cv.visitTypeAnnotation(typeRef, typePath, desc, visible);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a non standard attribute of the class.
|
||||
*
|
||||
|
||||
@@ -416,6 +416,16 @@ public class ClassWriter extends ClassVisitor {
|
||||
*/
|
||||
private AnnotationWriter ianns;
|
||||
|
||||
/**
|
||||
* The runtime visible type annotations of this class.
|
||||
*/
|
||||
private AnnotationWriter tanns;
|
||||
|
||||
/**
|
||||
* The runtime invisible type annotations of this class.
|
||||
*/
|
||||
private AnnotationWriter itanns;
|
||||
|
||||
/**
|
||||
* The non standard attributes of this class.
|
||||
*/
|
||||
@@ -595,7 +605,7 @@ public class ClassWriter extends ClassVisitor {
|
||||
* {@link #COMPUTE_FRAMES}.
|
||||
*/
|
||||
public ClassWriter(final int flags) {
|
||||
super(Opcodes.ASM4);
|
||||
super(Opcodes.ASM5);
|
||||
index = 1;
|
||||
pool = new ByteVector();
|
||||
items = new Item[256];
|
||||
@@ -677,7 +687,8 @@ public class ClassWriter extends ClassVisitor {
|
||||
sourceFile = newUTF8(file);
|
||||
}
|
||||
if (debug != null) {
|
||||
sourceDebug = new ByteVector().putUTF8(debug);
|
||||
sourceDebug = new ByteVector().encodeUTF8(debug, 0,
|
||||
Integer.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -710,6 +721,29 @@ public class ClassWriter extends ClassVisitor {
|
||||
return aw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AnnotationVisitor visitTypeAnnotation(int typeRef,
|
||||
TypePath typePath, final String desc, final boolean visible) {
|
||||
if (!ClassReader.ANNOTATIONS) {
|
||||
return null;
|
||||
}
|
||||
ByteVector bv = new ByteVector();
|
||||
// write target_type and target_info
|
||||
AnnotationWriter.putTarget(typeRef, typePath, bv);
|
||||
// write type, and reserve space for values count
|
||||
bv.putShort(newUTF8(desc)).putShort(0);
|
||||
AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv,
|
||||
bv.length - 2);
|
||||
if (visible) {
|
||||
aw.next = tanns;
|
||||
tanns = aw;
|
||||
} else {
|
||||
aw.next = itanns;
|
||||
itanns = aw;
|
||||
}
|
||||
return aw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void visitAttribute(final Attribute attr) {
|
||||
attr.next = attrs;
|
||||
@@ -795,7 +829,7 @@ public class ClassWriter extends ClassVisitor {
|
||||
}
|
||||
if (sourceDebug != null) {
|
||||
++attributeCount;
|
||||
size += sourceDebug.length + 4;
|
||||
size += sourceDebug.length + 6;
|
||||
newUTF8("SourceDebugExtension");
|
||||
}
|
||||
if (enclosingMethodOwner != 0) {
|
||||
@@ -831,6 +865,16 @@ public class ClassWriter extends ClassVisitor {
|
||||
size += 8 + ianns.getSize();
|
||||
newUTF8("RuntimeInvisibleAnnotations");
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && tanns != null) {
|
||||
++attributeCount;
|
||||
size += 8 + tanns.getSize();
|
||||
newUTF8("RuntimeVisibleTypeAnnotations");
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && itanns != null) {
|
||||
++attributeCount;
|
||||
size += 8 + itanns.getSize();
|
||||
newUTF8("RuntimeInvisibleTypeAnnotations");
|
||||
}
|
||||
if (attrs != null) {
|
||||
attributeCount += attrs.getCount();
|
||||
size += attrs.getSize(this, null, 0, -1, -1);
|
||||
@@ -874,9 +918,9 @@ public class ClassWriter extends ClassVisitor {
|
||||
out.putShort(newUTF8("SourceFile")).putInt(2).putShort(sourceFile);
|
||||
}
|
||||
if (sourceDebug != null) {
|
||||
int len = sourceDebug.length - 2;
|
||||
int len = sourceDebug.length;
|
||||
out.putShort(newUTF8("SourceDebugExtension")).putInt(len);
|
||||
out.putByteArray(sourceDebug.data, 2, len);
|
||||
out.putByteArray(sourceDebug.data, 0, len);
|
||||
}
|
||||
if (enclosingMethodOwner != 0) {
|
||||
out.putShort(newUTF8("EnclosingMethod")).putInt(4);
|
||||
@@ -904,6 +948,14 @@ public class ClassWriter extends ClassVisitor {
|
||||
out.putShort(newUTF8("RuntimeInvisibleAnnotations"));
|
||||
ianns.put(out);
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && tanns != null) {
|
||||
out.putShort(newUTF8("RuntimeVisibleTypeAnnotations"));
|
||||
tanns.put(out);
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && itanns != null) {
|
||||
out.putShort(newUTF8("RuntimeInvisibleTypeAnnotations"));
|
||||
itanns.put(out);
|
||||
}
|
||||
if (attrs != null) {
|
||||
attrs.put(this, null, 0, -1, -1, out);
|
||||
}
|
||||
@@ -1590,7 +1642,7 @@ public class ClassWriter extends ClassVisitor {
|
||||
|
||||
/**
|
||||
* Returns the common super type of the two given types. The default
|
||||
* implementation of this method <i>loads<i> the two given classes and uses
|
||||
* implementation of this method <i>loads</i> the two given classes and uses
|
||||
* the java.lang.Class methods to find the common super class. It can be
|
||||
* overridden to compute this common super type in other ways, in particular
|
||||
* without actually loading any class, or to take into account the class
|
||||
|
||||
@@ -72,11 +72,46 @@ class Context {
|
||||
*/
|
||||
String desc;
|
||||
|
||||
/**
|
||||
* The label objects, indexed by bytecode offset, of the method currently
|
||||
* being parsed (only bytecode offsets for which a label is needed have a
|
||||
* non null associated Label object).
|
||||
*/
|
||||
Label[] labels;
|
||||
|
||||
/**
|
||||
* The target of the type annotation currently being parsed.
|
||||
*/
|
||||
int typeRef;
|
||||
|
||||
/**
|
||||
* The path of the type annotation currently being parsed.
|
||||
*/
|
||||
TypePath typePath;
|
||||
|
||||
/**
|
||||
* The offset of the latest stack map frame that has been parsed.
|
||||
*/
|
||||
int offset;
|
||||
|
||||
/**
|
||||
* The labels corresponding to the start of the local variable ranges in the
|
||||
* local variable type annotation currently being parsed.
|
||||
*/
|
||||
Label[] start;
|
||||
|
||||
/**
|
||||
* The labels corresponding to the end of the local variable ranges in the
|
||||
* local variable type annotation currently being parsed.
|
||||
*/
|
||||
Label[] end;
|
||||
|
||||
/**
|
||||
* The local variable indices for each local variable range in the local
|
||||
* variable type annotation currently being parsed.
|
||||
*/
|
||||
int[] index;
|
||||
|
||||
/**
|
||||
* The encoding of the latest stack map frame that has been parsed.
|
||||
*/
|
||||
|
||||
@@ -31,8 +31,8 @@ package org.springframework.asm;
|
||||
|
||||
/**
|
||||
* A visitor to visit a Java field. The methods of this class must be called in
|
||||
* the following order: ( <tt>visitAnnotation</tt> | <tt>visitAttribute</tt> )*
|
||||
* <tt>visitEnd</tt>.
|
||||
* the following order: ( <tt>visitAnnotation</tt> |
|
||||
* <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* <tt>visitEnd</tt>.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
@@ -40,7 +40,7 @@ public abstract class FieldVisitor {
|
||||
|
||||
/**
|
||||
* The ASM API version implemented by this visitor. The value of this field
|
||||
* must be one of {@link Opcodes#ASM4}.
|
||||
* must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
|
||||
*/
|
||||
protected final int api;
|
||||
|
||||
@@ -55,7 +55,7 @@ public abstract class FieldVisitor {
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4}.
|
||||
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
|
||||
*/
|
||||
public FieldVisitor(final int api) {
|
||||
this(api, null);
|
||||
@@ -66,13 +66,13 @@ public abstract class FieldVisitor {
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4}.
|
||||
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
|
||||
* @param fv
|
||||
* the field visitor to which this visitor must delegate method
|
||||
* calls. May be null.
|
||||
*/
|
||||
public FieldVisitor(final int api, final FieldVisitor fv) {
|
||||
if (api != Opcodes.ASM4) {
|
||||
if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.api = api;
|
||||
@@ -96,6 +96,35 @@ public abstract class FieldVisitor {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an annotation on the type of the field.
|
||||
*
|
||||
* @param typeRef
|
||||
* a reference to the annotated type. The sort of this type
|
||||
* reference must be {@link TypeReference#FIELD FIELD}. See
|
||||
* {@link TypeReference}.
|
||||
* @param typePath
|
||||
* the path to the annotated type argument, wildcard bound, array
|
||||
* element type, or static inner type within 'typeRef'. May be
|
||||
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||
* @param desc
|
||||
* the class descriptor of the annotation class.
|
||||
* @param visible
|
||||
* <tt>true</tt> if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
||||
* this visitor is not interested in visiting this annotation.
|
||||
*/
|
||||
public AnnotationVisitor visitTypeAnnotation(int typeRef,
|
||||
TypePath typePath, String desc, boolean visible) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
if (fv != null) {
|
||||
return fv.visitTypeAnnotation(typeRef, typePath, desc, visible);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a non standard attribute of the field.
|
||||
*
|
||||
|
||||
@@ -80,6 +80,17 @@ final class FieldWriter extends FieldVisitor {
|
||||
*/
|
||||
private AnnotationWriter ianns;
|
||||
|
||||
/**
|
||||
* The runtime visible type annotations of this field. May be <tt>null</tt>.
|
||||
*/
|
||||
private AnnotationWriter tanns;
|
||||
|
||||
/**
|
||||
* The runtime invisible type annotations of this field. May be
|
||||
* <tt>null</tt>.
|
||||
*/
|
||||
private AnnotationWriter itanns;
|
||||
|
||||
/**
|
||||
* The non standard attributes of this field. May be <tt>null</tt>.
|
||||
*/
|
||||
@@ -107,7 +118,7 @@ final class FieldWriter extends FieldVisitor {
|
||||
*/
|
||||
FieldWriter(final ClassWriter cw, final int access, final String name,
|
||||
final String desc, final String signature, final Object value) {
|
||||
super(Opcodes.ASM4);
|
||||
super(Opcodes.ASM5);
|
||||
if (cw.firstField == null) {
|
||||
cw.firstField = this;
|
||||
} else {
|
||||
@@ -150,6 +161,29 @@ final class FieldWriter extends FieldVisitor {
|
||||
return aw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitTypeAnnotation(final int typeRef,
|
||||
final TypePath typePath, final String desc, final boolean visible) {
|
||||
if (!ClassReader.ANNOTATIONS) {
|
||||
return null;
|
||||
}
|
||||
ByteVector bv = new ByteVector();
|
||||
// write target_type and target_info
|
||||
AnnotationWriter.putTarget(typeRef, typePath, bv);
|
||||
// write type, and reserve space for values count
|
||||
bv.putShort(cw.newUTF8(desc)).putShort(0);
|
||||
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
|
||||
bv.length - 2);
|
||||
if (visible) {
|
||||
aw.next = tanns;
|
||||
tanns = aw;
|
||||
} else {
|
||||
aw.next = itanns;
|
||||
itanns = aw;
|
||||
}
|
||||
return aw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAttribute(final Attribute attr) {
|
||||
attr.next = attrs;
|
||||
@@ -198,6 +232,14 @@ final class FieldWriter extends FieldVisitor {
|
||||
cw.newUTF8("RuntimeInvisibleAnnotations");
|
||||
size += 8 + ianns.getSize();
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && tanns != null) {
|
||||
cw.newUTF8("RuntimeVisibleTypeAnnotations");
|
||||
size += 8 + tanns.getSize();
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && itanns != null) {
|
||||
cw.newUTF8("RuntimeInvisibleTypeAnnotations");
|
||||
size += 8 + itanns.getSize();
|
||||
}
|
||||
if (attrs != null) {
|
||||
size += attrs.getSize(cw, null, 0, -1, -1);
|
||||
}
|
||||
@@ -237,6 +279,12 @@ final class FieldWriter extends FieldVisitor {
|
||||
if (ClassReader.ANNOTATIONS && ianns != null) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && tanns != null) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && itanns != null) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (attrs != null) {
|
||||
attributeCount += attrs.getCount();
|
||||
}
|
||||
@@ -266,6 +314,14 @@ final class FieldWriter extends FieldVisitor {
|
||||
out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
|
||||
ianns.put(out);
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && tanns != null) {
|
||||
out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
|
||||
tanns.put(out);
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && itanns != null) {
|
||||
out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
|
||||
itanns.put(out);
|
||||
}
|
||||
if (attrs != null) {
|
||||
attrs.put(cw, null, 0, -1, -1, out);
|
||||
}
|
||||
|
||||
@@ -70,8 +70,8 @@ final class Frame {
|
||||
* stack types. VALUE depends on KIND. For LOCAL types, it is an index in
|
||||
* the input local variable types. For STACK types, it is a position
|
||||
* relatively to the top of input frame stack. For BASE types, it is either
|
||||
* one of the constants defined in FrameVisitor, or for OBJECT and
|
||||
* UNINITIALIZED types, a tag and an index in the type table.
|
||||
* one of the constants defined below, or for OBJECT and UNINITIALIZED
|
||||
* types, a tag and an index in the type table.
|
||||
*
|
||||
* Output frames can contain types of any kind and with a positive or
|
||||
* negative dimension (and even unassigned types, represented by 0 - which
|
||||
@@ -585,7 +585,7 @@ final class Frame {
|
||||
}
|
||||
// pushes the type on the output stack
|
||||
outputStack[outputStackTop++] = type;
|
||||
// updates the maximum height reached by the output stack, if needed
|
||||
// updates the maximun height reached by the output stack, if needed
|
||||
int top = owner.inputStackTop + outputStackTop;
|
||||
if (top > owner.outputStackMax) {
|
||||
owner.outputStackMax = top;
|
||||
@@ -1417,6 +1417,7 @@ final class Frame {
|
||||
// if t is the NULL type, merge(u,t)=u, so there is no change
|
||||
return false;
|
||||
} else if ((t & (DIM | BASE_KIND)) == (u & (DIM | BASE_KIND))) {
|
||||
// if t and u have the same dimension and same base kind
|
||||
if ((u & BASE_KIND) == OBJECT) {
|
||||
// if t is also a reference type, and if u and t have the
|
||||
// same dimension merge(u,t) = dim(t) | common parent of the
|
||||
@@ -1429,9 +1430,13 @@ final class Frame {
|
||||
v = OBJECT | cw.addType("java/lang/Object");
|
||||
}
|
||||
} else if ((t & BASE_KIND) == OBJECT || (t & DIM) != 0) {
|
||||
// if t is any other reference or array type,
|
||||
// merge(u,t)=java/lang/Object
|
||||
v = OBJECT | cw.addType("java/lang/Object");
|
||||
// if t is any other reference or array type, the merged type
|
||||
// is Object, or min(dim(u), dim(t)) | java/lang/Object is u
|
||||
// and t have different array dimensions
|
||||
int tdim = t & DIM;
|
||||
int udim = u & DIM;
|
||||
v = (udim != tdim ? Math.min(tdim, udim) : 0) | OBJECT
|
||||
| cw.addType("java/lang/Object");
|
||||
} else {
|
||||
// if t is any other type, merge(u,t)=TOP
|
||||
v = TOP;
|
||||
|
||||
@@ -31,18 +31,24 @@ package org.springframework.asm;
|
||||
|
||||
/**
|
||||
* A visitor to visit a Java method. The methods of this class must be called in
|
||||
* the following order: [ <tt>visitAnnotationDefault</tt> ] (
|
||||
* <tt>visitAnnotation</tt> | <tt>visitParameterAnnotation</tt> |
|
||||
* <tt>visitAttribute</tt> )* [ <tt>visitCode</tt> ( <tt>visitFrame</tt> |
|
||||
* <tt>visit</tt><i>X</i>Insn</tt> | <tt>visitLabel</tt> |
|
||||
* <tt>visitTryCatchBlock</tt> | <tt>visitLocalVariable</tt> |
|
||||
* the following order: ( <tt>visitParameter</tt> )* [
|
||||
* <tt>visitAnnotationDefault</tt> ] ( <tt>visitAnnotation</tt> |
|
||||
* <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* [
|
||||
* <tt>visitCode</tt> ( <tt>visitFrame</tt> | <tt>visit<i>X</i>Insn</tt> |
|
||||
* <tt>visitLabel</tt> | <tt>visitInsnAnnotation</tt> |
|
||||
* <tt>visitTryCatchBlock</tt> | <tt>visitTryCatchBlockAnnotation</tt> |
|
||||
* <tt>visitLocalVariable</tt> | <tt>visitLocalVariableAnnotation</tt> |
|
||||
* <tt>visitLineNumber</tt> )* <tt>visitMaxs</tt> ] <tt>visitEnd</tt>. In
|
||||
* addition, the <tt>visit</tt><i>X</i>Insn</tt> and <tt>visitLabel</tt> methods
|
||||
* must be called in the sequential order of the bytecode instructions of the
|
||||
* visited code, <tt>visitTryCatchBlock</tt> must be called <i>before</i> the
|
||||
* labels passed as arguments have been visited, and the
|
||||
* <tt>visitLocalVariable</tt> and <tt>visitLineNumber</tt> methods must be
|
||||
* called <i>after</i> the labels passed as arguments have been visited.
|
||||
* addition, the <tt>visit<i>X</i>Insn</tt> and <tt>visitLabel</tt> methods must
|
||||
* be called in the sequential order of the bytecode instructions of the visited
|
||||
* code, <tt>visitInsnAnnotation</tt> must be called <i>after</i> the annotated
|
||||
* instruction, <tt>visitTryCatchBlock</tt> must be called <i>before</i> the
|
||||
* labels passed as arguments have been visited,
|
||||
* <tt>visitTryCatchBlockAnnotation</tt> must be called <i>after</i> the
|
||||
* corresponding try catch block has been visited, and the
|
||||
* <tt>visitLocalVariable</tt>, <tt>visitLocalVariableAnnotation</tt> and
|
||||
* <tt>visitLineNumber</tt> methods must be called <i>after</i> the labels
|
||||
* passed as arguments have been visited.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
@@ -50,7 +56,7 @@ public abstract class MethodVisitor {
|
||||
|
||||
/**
|
||||
* The ASM API version implemented by this visitor. The value of this field
|
||||
* must be one of {@link Opcodes#ASM4}.
|
||||
* must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
|
||||
*/
|
||||
protected final int api;
|
||||
|
||||
@@ -65,7 +71,7 @@ public abstract class MethodVisitor {
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4}.
|
||||
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
|
||||
*/
|
||||
public MethodVisitor(final int api) {
|
||||
this(api, null);
|
||||
@@ -76,13 +82,13 @@ public abstract class MethodVisitor {
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4}.
|
||||
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
|
||||
* @param mv
|
||||
* the method visitor to which this visitor must delegate method
|
||||
* calls. May be null.
|
||||
*/
|
||||
public MethodVisitor(final int api, final MethodVisitor mv) {
|
||||
if (api != Opcodes.ASM4) {
|
||||
if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.api = api;
|
||||
@@ -90,9 +96,28 @@ public abstract class MethodVisitor {
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Annotations and non standard attributes
|
||||
// Parameters, annotations and non standard attributes
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Visits a parameter of this method.
|
||||
*
|
||||
* @param name
|
||||
* parameter name or null if none is provided.
|
||||
* @param access
|
||||
* the parameter's access flags, only <tt>ACC_FINAL</tt>,
|
||||
* <tt>ACC_SYNTHETIC</tt> or/and <tt>ACC_MANDATED</tt> are
|
||||
* allowed (see {@link Opcodes}).
|
||||
*/
|
||||
public void visitParameter(String name, int access) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
if (mv != null) {
|
||||
mv.visitParameter(name, access);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits the default value of this annotation interface method.
|
||||
*
|
||||
@@ -127,6 +152,42 @@ public abstract class MethodVisitor {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an annotation on a type in the method signature.
|
||||
*
|
||||
* @param typeRef
|
||||
* a reference to the annotated type. The sort of this type
|
||||
* reference must be {@link TypeReference#METHOD_TYPE_PARAMETER
|
||||
* METHOD_TYPE_PARAMETER},
|
||||
* {@link TypeReference#METHOD_TYPE_PARAMETER_BOUND
|
||||
* METHOD_TYPE_PARAMETER_BOUND},
|
||||
* {@link TypeReference#METHOD_RETURN METHOD_RETURN},
|
||||
* {@link TypeReference#METHOD_RECEIVER METHOD_RECEIVER},
|
||||
* {@link TypeReference#METHOD_FORMAL_PARAMETER
|
||||
* METHOD_FORMAL_PARAMETER} or {@link TypeReference#THROWS
|
||||
* THROWS}. See {@link TypeReference}.
|
||||
* @param typePath
|
||||
* the path to the annotated type argument, wildcard bound, array
|
||||
* element type, or static inner type within 'typeRef'. May be
|
||||
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||
* @param desc
|
||||
* the class descriptor of the annotation class.
|
||||
* @param visible
|
||||
* <tt>true</tt> if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
||||
* this visitor is not interested in visiting this annotation.
|
||||
*/
|
||||
public AnnotationVisitor visitTypeAnnotation(int typeRef,
|
||||
TypePath typePath, String desc, boolean visible) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
if (mv != null) {
|
||||
return mv.visitTypeAnnotation(typeRef, typePath, desc, visible);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an annotation of a parameter this method.
|
||||
*
|
||||
@@ -201,9 +262,11 @@ public abstract class MethodVisitor {
|
||||
* <li>{@link Opcodes#F_CHOP} representing frame with current locals are the
|
||||
* same as the locals in the previous frame, except that the last 1-3 locals
|
||||
* are absent and with the empty stack (<code>nLocals</code> is 1, 2 or 3).</li>
|
||||
* <li>{@link Opcodes#F_FULL} representing complete frame data.</li></li>
|
||||
* <li>{@link Opcodes#F_FULL} representing complete frame data.</li>
|
||||
* </ul>
|
||||
* </ul> <br>
|
||||
* </li>
|
||||
* </ul>
|
||||
* <br>
|
||||
* In both cases the first frame, corresponding to the method's parameters
|
||||
* and access flags, is implicit and must not be visited. Also, it is
|
||||
* illegal to visit two or more frames for the same code location (i.e., at
|
||||
@@ -376,13 +439,52 @@ public abstract class MethodVisitor {
|
||||
* @param desc
|
||||
* the method's descriptor (see {@link Type Type}).
|
||||
*/
|
||||
@Deprecated
|
||||
public void visitMethodInsn(int opcode, String owner, String name,
|
||||
String desc) {
|
||||
if (api >= Opcodes.ASM5) {
|
||||
boolean itf = opcode == Opcodes.INVOKEINTERFACE;
|
||||
visitMethodInsn(opcode, owner, name, desc, itf);
|
||||
return;
|
||||
}
|
||||
if (mv != null) {
|
||||
mv.visitMethodInsn(opcode, owner, name, desc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a method instruction. A method instruction is an instruction that
|
||||
* invokes a method.
|
||||
*
|
||||
* @param opcode
|
||||
* the opcode of the type instruction to be visited. This opcode
|
||||
* is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
|
||||
* INVOKEINTERFACE.
|
||||
* @param owner
|
||||
* the internal name of the method's owner class (see
|
||||
* {@link Type#getInternalName() getInternalName}).
|
||||
* @param name
|
||||
* the method's name.
|
||||
* @param desc
|
||||
* the method's descriptor (see {@link Type Type}).
|
||||
* @param itf
|
||||
* if the method's owner class is an interface.
|
||||
*/
|
||||
public void visitMethodInsn(int opcode, String owner, String name,
|
||||
String desc, boolean itf) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
if (itf != (opcode == Opcodes.INVOKEINTERFACE)) {
|
||||
throw new IllegalArgumentException(
|
||||
"INVOKESPECIAL/STATIC on interfaces require ASM 5");
|
||||
}
|
||||
visitMethodInsn(opcode, owner, name, desc);
|
||||
return;
|
||||
}
|
||||
if (mv != null) {
|
||||
mv.visitMethodInsn(opcode, owner, name, desc, itf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an invokedynamic instruction.
|
||||
*
|
||||
@@ -449,7 +551,7 @@ public abstract class MethodVisitor {
|
||||
* constant types, implementations of this method should check for
|
||||
* unexpected constant types, like this:
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>
|
||||
* if (cst instanceof Integer) {
|
||||
* // ...
|
||||
* } else if (cst instanceof Float) {
|
||||
@@ -558,6 +660,48 @@ public abstract class MethodVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an annotation on an instruction. This method must be called just
|
||||
* <i>after</i> the annotated instruction. It can be called several times
|
||||
* for the same instruction.
|
||||
*
|
||||
* @param typeRef
|
||||
* a reference to the annotated type. The sort of this type
|
||||
* reference must be {@link TypeReference#INSTANCEOF INSTANCEOF},
|
||||
* {@link TypeReference#NEW NEW},
|
||||
* {@link TypeReference#CONSTRUCTOR_REFERENCE
|
||||
* CONSTRUCTOR_REFERENCE}, {@link TypeReference#METHOD_REFERENCE
|
||||
* METHOD_REFERENCE}, {@link TypeReference#CAST CAST},
|
||||
* {@link TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
|
||||
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
|
||||
* {@link TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT
|
||||
* METHOD_INVOCATION_TYPE_ARGUMENT},
|
||||
* {@link TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
|
||||
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
|
||||
* {@link TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT
|
||||
* METHOD_REFERENCE_TYPE_ARGUMENT}. See {@link TypeReference}.
|
||||
* @param typePath
|
||||
* the path to the annotated type argument, wildcard bound, array
|
||||
* element type, or static inner type within 'typeRef'. May be
|
||||
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||
* @param desc
|
||||
* the class descriptor of the annotation class.
|
||||
* @param visible
|
||||
* <tt>true</tt> if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
||||
* this visitor is not interested in visiting this annotation.
|
||||
*/
|
||||
public AnnotationVisitor visitInsnAnnotation(int typeRef,
|
||||
TypePath typePath, String desc, boolean visible) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
if (mv != null) {
|
||||
return mv.visitInsnAnnotation(typeRef, typePath, desc, visible);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Exceptions table entries, debug information, max stack and max locals
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -586,6 +730,38 @@ public abstract class MethodVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an annotation on an exception handler type. This method must be
|
||||
* called <i>after</i> the {@link #visitTryCatchBlock} for the annotated
|
||||
* exception handler. It can be called several times for the same exception
|
||||
* handler.
|
||||
*
|
||||
* @param typeRef
|
||||
* a reference to the annotated type. The sort of this type
|
||||
* reference must be {@link TypeReference#EXCEPTION_PARAMETER
|
||||
* EXCEPTION_PARAMETER}. See {@link TypeReference}.
|
||||
* @param typePath
|
||||
* the path to the annotated type argument, wildcard bound, array
|
||||
* element type, or static inner type within 'typeRef'. May be
|
||||
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||
* @param desc
|
||||
* the class descriptor of the annotation class.
|
||||
* @param visible
|
||||
* <tt>true</tt> if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
||||
* this visitor is not interested in visiting this annotation.
|
||||
*/
|
||||
public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
|
||||
TypePath typePath, String desc, boolean visible) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
if (mv != null) {
|
||||
return mv.visitTryCatchAnnotation(typeRef, typePath, desc, visible);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a local variable declaration.
|
||||
*
|
||||
@@ -616,6 +792,48 @@ public abstract class MethodVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an annotation on a local variable type.
|
||||
*
|
||||
* @param typeRef
|
||||
* a reference to the annotated type. The sort of this type
|
||||
* reference must be {@link TypeReference#LOCAL_VARIABLE
|
||||
* LOCAL_VARIABLE} or {@link TypeReference#RESOURCE_VARIABLE
|
||||
* RESOURCE_VARIABLE}. See {@link TypeReference}.
|
||||
* @param typePath
|
||||
* the path to the annotated type argument, wildcard bound, array
|
||||
* element type, or static inner type within 'typeRef'. May be
|
||||
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
|
||||
* @param start
|
||||
* the fist instructions corresponding to the continuous ranges
|
||||
* that make the scope of this local variable (inclusive).
|
||||
* @param end
|
||||
* the last instructions corresponding to the continuous ranges
|
||||
* that make the scope of this local variable (exclusive). This
|
||||
* array must have the same size as the 'start' array.
|
||||
* @param index
|
||||
* the local variable's index in each range. This array must have
|
||||
* the same size as the 'start' array.
|
||||
* @param desc
|
||||
* the class descriptor of the annotation class.
|
||||
* @param visible
|
||||
* <tt>true</tt> if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or <tt>null</tt> if
|
||||
* this visitor is not interested in visiting this annotation.
|
||||
*/
|
||||
public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
|
||||
TypePath typePath, Label[] start, Label[] end, int[] index,
|
||||
String desc, boolean visible) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
if (mv != null) {
|
||||
return mv.visitLocalVariableAnnotation(typeRef, typePath, start,
|
||||
end, index, desc, visible);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a line number declaration.
|
||||
*
|
||||
|
||||
@@ -191,6 +191,18 @@ class MethodWriter extends MethodVisitor {
|
||||
*/
|
||||
private AnnotationWriter ianns;
|
||||
|
||||
/**
|
||||
* The runtime visible type annotations of this method. May be <tt>null</tt>
|
||||
* .
|
||||
*/
|
||||
private AnnotationWriter tanns;
|
||||
|
||||
/**
|
||||
* The runtime invisible type annotations of this method. May be
|
||||
* <tt>null</tt>.
|
||||
*/
|
||||
private AnnotationWriter itanns;
|
||||
|
||||
/**
|
||||
* The runtime visible parameter annotations of this method. May be
|
||||
* <tt>null</tt>.
|
||||
@@ -282,6 +294,16 @@ class MethodWriter extends MethodVisitor {
|
||||
*/
|
||||
private Handler lastHandler;
|
||||
|
||||
/**
|
||||
* Number of entries in the MethodParameters attribute.
|
||||
*/
|
||||
private int methodParametersCount;
|
||||
|
||||
/**
|
||||
* The MethodParameters attribute.
|
||||
*/
|
||||
private ByteVector methodParameters;
|
||||
|
||||
/**
|
||||
* Number of entries in the LocalVariableTable attribute.
|
||||
*/
|
||||
@@ -312,6 +334,21 @@ class MethodWriter extends MethodVisitor {
|
||||
*/
|
||||
private ByteVector lineNumber;
|
||||
|
||||
/**
|
||||
* The start offset of the last visited instruction.
|
||||
*/
|
||||
private int lastCodeOffset;
|
||||
|
||||
/**
|
||||
* The runtime visible type annotations of the code. May be <tt>null</tt>.
|
||||
*/
|
||||
private AnnotationWriter ctanns;
|
||||
|
||||
/**
|
||||
* The runtime invisible type annotations of the code. May be <tt>null</tt>.
|
||||
*/
|
||||
private AnnotationWriter ictanns;
|
||||
|
||||
/**
|
||||
* The non standard attributes of the method's code.
|
||||
*/
|
||||
@@ -416,7 +453,7 @@ class MethodWriter extends MethodVisitor {
|
||||
final String desc, final String signature,
|
||||
final String[] exceptions, final boolean computeMaxs,
|
||||
final boolean computeFrames) {
|
||||
super(Opcodes.ASM4);
|
||||
super(Opcodes.ASM5);
|
||||
if (cw.firstMethod == null) {
|
||||
cw.firstMethod = this;
|
||||
} else {
|
||||
@@ -461,6 +498,16 @@ class MethodWriter extends MethodVisitor {
|
||||
// Implementation of the MethodVisitor abstract class
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void visitParameter(String name, int access) {
|
||||
if (methodParameters == null) {
|
||||
methodParameters = new ByteVector();
|
||||
}
|
||||
++methodParametersCount;
|
||||
methodParameters.putShort((name == null) ? 0 : cw.newUTF8(name))
|
||||
.putShort(access);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotationDefault() {
|
||||
if (!ClassReader.ANNOTATIONS) {
|
||||
@@ -490,6 +537,29 @@ class MethodWriter extends MethodVisitor {
|
||||
return aw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitTypeAnnotation(final int typeRef,
|
||||
final TypePath typePath, final String desc, final boolean visible) {
|
||||
if (!ClassReader.ANNOTATIONS) {
|
||||
return null;
|
||||
}
|
||||
ByteVector bv = new ByteVector();
|
||||
// write target_type and target_info
|
||||
AnnotationWriter.putTarget(typeRef, typePath, bv);
|
||||
// write type, and reserve space for values count
|
||||
bv.putShort(cw.newUTF8(desc)).putShort(0);
|
||||
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
|
||||
bv.length - 2);
|
||||
if (visible) {
|
||||
aw.next = tanns;
|
||||
tanns = aw;
|
||||
} else {
|
||||
aw.next = itanns;
|
||||
itanns = aw;
|
||||
}
|
||||
return aw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitParameterAnnotation(final int parameter,
|
||||
final String desc, final boolean visible) {
|
||||
@@ -642,6 +712,7 @@ class MethodWriter extends MethodVisitor {
|
||||
|
||||
@Override
|
||||
public void visitInsn(final int opcode) {
|
||||
lastCodeOffset = code.length;
|
||||
// adds the instruction to the bytecode of the method
|
||||
code.putByte(opcode);
|
||||
// update currentBlock
|
||||
@@ -667,6 +738,7 @@ class MethodWriter extends MethodVisitor {
|
||||
|
||||
@Override
|
||||
public void visitIntInsn(final int opcode, final int operand) {
|
||||
lastCodeOffset = code.length;
|
||||
// Label currentBlock = this.currentBlock;
|
||||
if (currentBlock != null) {
|
||||
if (compute == FRAMES) {
|
||||
@@ -691,6 +763,7 @@ class MethodWriter extends MethodVisitor {
|
||||
|
||||
@Override
|
||||
public void visitVarInsn(final int opcode, final int var) {
|
||||
lastCodeOffset = code.length;
|
||||
// Label currentBlock = this.currentBlock;
|
||||
if (currentBlock != null) {
|
||||
if (compute == FRAMES) {
|
||||
@@ -749,6 +822,7 @@ class MethodWriter extends MethodVisitor {
|
||||
|
||||
@Override
|
||||
public void visitTypeInsn(final int opcode, final String type) {
|
||||
lastCodeOffset = code.length;
|
||||
Item i = cw.newClassItem(type);
|
||||
// Label currentBlock = this.currentBlock;
|
||||
if (currentBlock != null) {
|
||||
@@ -771,6 +845,7 @@ class MethodWriter extends MethodVisitor {
|
||||
@Override
|
||||
public void visitFieldInsn(final int opcode, final String owner,
|
||||
final String name, final String desc) {
|
||||
lastCodeOffset = code.length;
|
||||
Item i = cw.newFieldItem(owner, name, desc);
|
||||
// Label currentBlock = this.currentBlock;
|
||||
if (currentBlock != null) {
|
||||
@@ -808,8 +883,8 @@ class MethodWriter extends MethodVisitor {
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(final int opcode, final String owner,
|
||||
final String name, final String desc) {
|
||||
boolean itf = opcode == Opcodes.INVOKEINTERFACE;
|
||||
final String name, final String desc, final boolean itf) {
|
||||
lastCodeOffset = code.length;
|
||||
Item i = cw.newMethodItem(owner, name, desc, itf);
|
||||
int argSize = i.intVal;
|
||||
// Label currentBlock = this.currentBlock;
|
||||
@@ -847,7 +922,7 @@ class MethodWriter extends MethodVisitor {
|
||||
}
|
||||
}
|
||||
// adds the instruction to the bytecode of the method
|
||||
if (itf) {
|
||||
if (opcode == Opcodes.INVOKEINTERFACE) {
|
||||
if (argSize == 0) {
|
||||
argSize = Type.getArgumentsAndReturnSizes(desc);
|
||||
i.intVal = argSize;
|
||||
@@ -861,6 +936,7 @@ class MethodWriter extends MethodVisitor {
|
||||
@Override
|
||||
public void visitInvokeDynamicInsn(final String name, final String desc,
|
||||
final Handle bsm, final Object... bsmArgs) {
|
||||
lastCodeOffset = code.length;
|
||||
Item i = cw.newInvokeDynamicItem(name, desc, bsm, bsmArgs);
|
||||
int argSize = i.intVal;
|
||||
// Label currentBlock = this.currentBlock;
|
||||
@@ -900,6 +976,7 @@ class MethodWriter extends MethodVisitor {
|
||||
|
||||
@Override
|
||||
public void visitJumpInsn(final int opcode, final Label label) {
|
||||
lastCodeOffset = code.length;
|
||||
Label nextInsn = null;
|
||||
// Label currentBlock = this.currentBlock;
|
||||
if (currentBlock != null) {
|
||||
@@ -1045,6 +1122,7 @@ class MethodWriter extends MethodVisitor {
|
||||
|
||||
@Override
|
||||
public void visitLdcInsn(final Object cst) {
|
||||
lastCodeOffset = code.length;
|
||||
Item i = cw.newConstItem(cst);
|
||||
// Label currentBlock = this.currentBlock;
|
||||
if (currentBlock != null) {
|
||||
@@ -1078,6 +1156,7 @@ class MethodWriter extends MethodVisitor {
|
||||
|
||||
@Override
|
||||
public void visitIincInsn(final int var, final int increment) {
|
||||
lastCodeOffset = code.length;
|
||||
if (currentBlock != null) {
|
||||
if (compute == FRAMES) {
|
||||
currentBlock.frame.execute(Opcodes.IINC, var, null, null);
|
||||
@@ -1102,6 +1181,7 @@ class MethodWriter extends MethodVisitor {
|
||||
@Override
|
||||
public void visitTableSwitchInsn(final int min, final int max,
|
||||
final Label dflt, final Label... labels) {
|
||||
lastCodeOffset = code.length;
|
||||
// adds the instruction to the bytecode of the method
|
||||
int source = code.length;
|
||||
code.putByte(Opcodes.TABLESWITCH);
|
||||
@@ -1118,6 +1198,7 @@ class MethodWriter extends MethodVisitor {
|
||||
@Override
|
||||
public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
|
||||
final Label[] labels) {
|
||||
lastCodeOffset = code.length;
|
||||
// adds the instruction to the bytecode of the method
|
||||
int source = code.length;
|
||||
code.putByte(Opcodes.LOOKUPSWITCH);
|
||||
@@ -1160,6 +1241,7 @@ class MethodWriter extends MethodVisitor {
|
||||
|
||||
@Override
|
||||
public void visitMultiANewArrayInsn(final String desc, final int dims) {
|
||||
lastCodeOffset = code.length;
|
||||
Item i = cw.newClassItem(desc);
|
||||
// Label currentBlock = this.currentBlock;
|
||||
if (currentBlock != null) {
|
||||
@@ -1175,6 +1257,30 @@ class MethodWriter extends MethodVisitor {
|
||||
code.put12(Opcodes.MULTIANEWARRAY, i.index).putByte(dims);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitInsnAnnotation(int typeRef,
|
||||
TypePath typePath, String desc, boolean visible) {
|
||||
if (!ClassReader.ANNOTATIONS) {
|
||||
return null;
|
||||
}
|
||||
ByteVector bv = new ByteVector();
|
||||
// write target_type and target_info
|
||||
typeRef = (typeRef & 0xFF0000FF) | (lastCodeOffset << 8);
|
||||
AnnotationWriter.putTarget(typeRef, typePath, bv);
|
||||
// write type, and reserve space for values count
|
||||
bv.putShort(cw.newUTF8(desc)).putShort(0);
|
||||
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
|
||||
bv.length - 2);
|
||||
if (visible) {
|
||||
aw.next = ctanns;
|
||||
ctanns = aw;
|
||||
} else {
|
||||
aw.next = ictanns;
|
||||
ictanns = aw;
|
||||
}
|
||||
return aw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTryCatchBlock(final Label start, final Label end,
|
||||
final Label handler, final String type) {
|
||||
@@ -1193,6 +1299,29 @@ class MethodWriter extends MethodVisitor {
|
||||
lastHandler = h;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
|
||||
TypePath typePath, String desc, boolean visible) {
|
||||
if (!ClassReader.ANNOTATIONS) {
|
||||
return null;
|
||||
}
|
||||
ByteVector bv = new ByteVector();
|
||||
// write target_type and target_info
|
||||
AnnotationWriter.putTarget(typeRef, typePath, bv);
|
||||
// write type, and reserve space for values count
|
||||
bv.putShort(cw.newUTF8(desc)).putShort(0);
|
||||
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
|
||||
bv.length - 2);
|
||||
if (visible) {
|
||||
aw.next = ctanns;
|
||||
ctanns = aw;
|
||||
} else {
|
||||
aw.next = ictanns;
|
||||
ictanns = aw;
|
||||
}
|
||||
return aw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(final String name, final String desc,
|
||||
final String signature, final Label start, final Label end,
|
||||
@@ -1225,6 +1354,41 @@ class MethodWriter extends MethodVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
|
||||
TypePath typePath, Label[] start, Label[] end, int[] index,
|
||||
String desc, boolean visible) {
|
||||
if (!ClassReader.ANNOTATIONS) {
|
||||
return null;
|
||||
}
|
||||
ByteVector bv = new ByteVector();
|
||||
// write target_type and target_info
|
||||
bv.putByte(typeRef >>> 24).putShort(start.length);
|
||||
for (int i = 0; i < start.length; ++i) {
|
||||
bv.putShort(start[i].position)
|
||||
.putShort(end[i].position - start[i].position)
|
||||
.putShort(index[i]);
|
||||
}
|
||||
if (typePath == null) {
|
||||
bv.putByte(0);
|
||||
} else {
|
||||
int length = typePath.b[typePath.offset] * 2 + 1;
|
||||
bv.putByteArray(typePath.b, typePath.offset, length);
|
||||
}
|
||||
// write type, and reserve space for values count
|
||||
bv.putShort(cw.newUTF8(desc)).putShort(0);
|
||||
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
|
||||
bv.length - 2);
|
||||
if (visible) {
|
||||
aw.next = ctanns;
|
||||
ctanns = aw;
|
||||
} else {
|
||||
aw.next = ictanns;
|
||||
ictanns = aw;
|
||||
}
|
||||
return aw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLineNumber(final int line, final Label start) {
|
||||
if (lineNumber == null) {
|
||||
@@ -1890,6 +2054,14 @@ class MethodWriter extends MethodVisitor {
|
||||
cw.newUTF8(zip ? "StackMapTable" : "StackMap");
|
||||
size += 8 + stackMap.length;
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && ctanns != null) {
|
||||
cw.newUTF8("RuntimeVisibleTypeAnnotations");
|
||||
size += 8 + ctanns.getSize();
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && ictanns != null) {
|
||||
cw.newUTF8("RuntimeInvisibleTypeAnnotations");
|
||||
size += 8 + ictanns.getSize();
|
||||
}
|
||||
if (cattrs != null) {
|
||||
size += cattrs.getSize(cw, code.data, code.length, maxStack,
|
||||
maxLocals);
|
||||
@@ -1915,6 +2087,10 @@ class MethodWriter extends MethodVisitor {
|
||||
cw.newUTF8(signature);
|
||||
size += 8;
|
||||
}
|
||||
if (methodParameters != null) {
|
||||
cw.newUTF8("MethodParameters");
|
||||
size += 7 + methodParameters.length;
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && annd != null) {
|
||||
cw.newUTF8("AnnotationDefault");
|
||||
size += 6 + annd.length;
|
||||
@@ -1927,6 +2103,14 @@ class MethodWriter extends MethodVisitor {
|
||||
cw.newUTF8("RuntimeInvisibleAnnotations");
|
||||
size += 8 + ianns.getSize();
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && tanns != null) {
|
||||
cw.newUTF8("RuntimeVisibleTypeAnnotations");
|
||||
size += 8 + tanns.getSize();
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && itanns != null) {
|
||||
cw.newUTF8("RuntimeInvisibleTypeAnnotations");
|
||||
size += 8 + itanns.getSize();
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && panns != null) {
|
||||
cw.newUTF8("RuntimeVisibleParameterAnnotations");
|
||||
size += 7 + 2 * (panns.length - synthetics);
|
||||
@@ -1983,6 +2167,9 @@ class MethodWriter extends MethodVisitor {
|
||||
if (ClassReader.SIGNATURES && signature != null) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (methodParameters != null) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && annd != null) {
|
||||
++attributeCount;
|
||||
}
|
||||
@@ -1992,6 +2179,12 @@ class MethodWriter extends MethodVisitor {
|
||||
if (ClassReader.ANNOTATIONS && ianns != null) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && tanns != null) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && itanns != null) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && panns != null) {
|
||||
++attributeCount;
|
||||
}
|
||||
@@ -2016,6 +2209,12 @@ class MethodWriter extends MethodVisitor {
|
||||
if (stackMap != null) {
|
||||
size += 8 + stackMap.length;
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && ctanns != null) {
|
||||
size += 8 + ctanns.getSize();
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && ictanns != null) {
|
||||
size += 8 + ictanns.getSize();
|
||||
}
|
||||
if (cattrs != null) {
|
||||
size += cattrs.getSize(cw, code.data, code.length, maxStack,
|
||||
maxLocals);
|
||||
@@ -2045,6 +2244,12 @@ class MethodWriter extends MethodVisitor {
|
||||
if (stackMap != null) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && ctanns != null) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && ictanns != null) {
|
||||
++attributeCount;
|
||||
}
|
||||
if (cattrs != null) {
|
||||
attributeCount += cattrs.getCount();
|
||||
}
|
||||
@@ -2070,6 +2275,14 @@ class MethodWriter extends MethodVisitor {
|
||||
out.putInt(stackMap.length + 2).putShort(frameCount);
|
||||
out.putByteArray(stackMap.data, 0, stackMap.length);
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && ctanns != null) {
|
||||
out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
|
||||
ctanns.put(out);
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && ictanns != null) {
|
||||
out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
|
||||
ictanns.put(out);
|
||||
}
|
||||
if (cattrs != null) {
|
||||
cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out);
|
||||
}
|
||||
@@ -2095,6 +2308,12 @@ class MethodWriter extends MethodVisitor {
|
||||
out.putShort(cw.newUTF8("Signature")).putInt(2)
|
||||
.putShort(cw.newUTF8(signature));
|
||||
}
|
||||
if (methodParameters != null) {
|
||||
out.putShort(cw.newUTF8("MethodParameters"));
|
||||
out.putInt(methodParameters.length + 1).putByte(
|
||||
methodParametersCount);
|
||||
out.putByteArray(methodParameters.data, 0, methodParameters.length);
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && annd != null) {
|
||||
out.putShort(cw.newUTF8("AnnotationDefault"));
|
||||
out.putInt(annd.length);
|
||||
@@ -2108,6 +2327,14 @@ class MethodWriter extends MethodVisitor {
|
||||
out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
|
||||
ianns.put(out);
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && tanns != null) {
|
||||
out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
|
||||
tanns.put(out);
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && itanns != null) {
|
||||
out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
|
||||
itanns.put(out);
|
||||
}
|
||||
if (ClassReader.ANNOTATIONS && panns != null) {
|
||||
out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations"));
|
||||
AnnotationWriter.put(panns, synthetics, out);
|
||||
|
||||
@@ -46,6 +46,7 @@ public interface Opcodes {
|
||||
// ASM API versions
|
||||
|
||||
int ASM4 = 4 << 16 | 0 << 8 | 0;
|
||||
int ASM5 = 5 << 16 | 0 << 8 | 0;
|
||||
|
||||
// versions
|
||||
|
||||
@@ -56,6 +57,7 @@ public interface Opcodes {
|
||||
int V1_5 = 0 << 16 | 49;
|
||||
int V1_6 = 0 << 16 | 50;
|
||||
int V1_7 = 0 << 16 | 51;
|
||||
int V1_8 = 0 << 16 | 52;
|
||||
|
||||
// access flags
|
||||
|
||||
@@ -63,7 +65,7 @@ public interface Opcodes {
|
||||
int ACC_PRIVATE = 0x0002; // class, field, method
|
||||
int ACC_PROTECTED = 0x0004; // class, field, method
|
||||
int ACC_STATIC = 0x0008; // field, method
|
||||
int ACC_FINAL = 0x0010; // class, field, method
|
||||
int ACC_FINAL = 0x0010; // class, field, method, parameter
|
||||
int ACC_SUPER = 0x0020; // class
|
||||
int ACC_SYNCHRONIZED = 0x0020; // method
|
||||
int ACC_VOLATILE = 0x0040; // field
|
||||
@@ -74,9 +76,10 @@ public interface Opcodes {
|
||||
int ACC_INTERFACE = 0x0200; // class
|
||||
int ACC_ABSTRACT = 0x0400; // class, method
|
||||
int ACC_STRICT = 0x0800; // method
|
||||
int ACC_SYNTHETIC = 0x1000; // class, field, method
|
||||
int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter
|
||||
int ACC_ANNOTATION = 0x2000; // class
|
||||
int ACC_ENUM = 0x4000; // class(?) field inner
|
||||
int ACC_MANDATED = 0x8000; // parameter
|
||||
|
||||
// ASM specific pseudo access flags
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,9 +18,9 @@ package org.springframework.asm;
|
||||
|
||||
/**
|
||||
* Utility class exposing constants related to Spring's internal repackaging
|
||||
* of the ASM bytecode manipulation library.
|
||||
* of the ASM bytecode manipulation library (currently based on version 5.0).
|
||||
*
|
||||
* <p>See <a href="package-summary.html">package-level javadoc</a> for more
|
||||
* <p>See <a href="package-summary.html">package-level javadocs</a> for more
|
||||
* information on {@code org.springframework.asm}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
@@ -30,9 +30,9 @@ public final class SpringAsmInfo {
|
||||
|
||||
/**
|
||||
* The ASM compatibility version for Spring's ASM visitor implementations:
|
||||
* as of Spring 3.2, it's ASM4. To be updated once we upgrade to ASM 5.0.
|
||||
* @see Opcodes#ASM4
|
||||
* as of Spring 4.0.3, it's ASM5.
|
||||
* @see Opcodes#ASM5
|
||||
*/
|
||||
public static final int ASM_VERSION = Opcodes.ASM4;
|
||||
public static final int ASM_VERSION = Opcodes.ASM5;
|
||||
|
||||
}
|
||||
|
||||
193
spring-core/src/main/java/org/springframework/asm/TypePath.java
Normal file
193
spring-core/src/main/java/org/springframework/asm/TypePath.java
Normal file
@@ -0,0 +1,193 @@
|
||||
/***
|
||||
* 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.springframework.asm;
|
||||
|
||||
/**
|
||||
* The path to a type argument, wildcard bound, array element type, or static
|
||||
* inner type within an enclosing type.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class TypePath {
|
||||
|
||||
/**
|
||||
* A type path step that steps into the element type of an array type. See
|
||||
* {@link #getStep getStep}.
|
||||
*/
|
||||
public final static int ARRAY_ELEMENT = 0;
|
||||
|
||||
/**
|
||||
* A type path step that steps into the nested type of a class type. See
|
||||
* {@link #getStep getStep}.
|
||||
*/
|
||||
public final static int INNER_TYPE = 1;
|
||||
|
||||
/**
|
||||
* A type path step that steps into the bound of a wildcard type. See
|
||||
* {@link #getStep getStep}.
|
||||
*/
|
||||
public final static int WILDCARD_BOUND = 2;
|
||||
|
||||
/**
|
||||
* A type path step that steps into a type argument of a generic type. See
|
||||
* {@link #getStep getStep}.
|
||||
*/
|
||||
public final static int TYPE_ARGUMENT = 3;
|
||||
|
||||
/**
|
||||
* The byte array where the path is stored, in Java class file format.
|
||||
*/
|
||||
byte[] b;
|
||||
|
||||
/**
|
||||
* The offset of the first byte of the type path in 'b'.
|
||||
*/
|
||||
int offset;
|
||||
|
||||
/**
|
||||
* Creates a new type path.
|
||||
*
|
||||
* @param b
|
||||
* the byte array containing the type path in Java class file
|
||||
* format.
|
||||
* @param offset
|
||||
* the offset of the first byte of the type path in 'b'.
|
||||
*/
|
||||
TypePath(byte[] b, int offset) {
|
||||
this.b = b;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of this path.
|
||||
*
|
||||
* @return the length of this path.
|
||||
*/
|
||||
public int getLength() {
|
||||
return b[offset];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the given step of this path.
|
||||
*
|
||||
* @param index
|
||||
* an index between 0 and {@link #getLength()}, exclusive.
|
||||
* @return {@link #ARRAY_ELEMENT ARRAY_ELEMENT}, {@link #INNER_TYPE
|
||||
* INNER_TYPE}, {@link #WILDCARD_BOUND WILDCARD_BOUND}, or
|
||||
* {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
|
||||
*/
|
||||
public int getStep(int index) {
|
||||
return b[offset + 2 * index + 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the type argument that the given step is stepping
|
||||
* into. This method should only be used for steps whose value is
|
||||
* {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
|
||||
*
|
||||
* @param index
|
||||
* an index between 0 and {@link #getLength()}, exclusive.
|
||||
* @return the index of the type argument that the given step is stepping
|
||||
* into.
|
||||
*/
|
||||
public int getStepArgument(int index) {
|
||||
return b[offset + 2 * index + 2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a type path in string form, in the format used by
|
||||
* {@link #toString()}, into a TypePath object.
|
||||
*
|
||||
* @param typePath
|
||||
* a type path in string form, in the format used by
|
||||
* {@link #toString()}. May be null or empty.
|
||||
* @return the corresponding TypePath object, or null if the path is empty.
|
||||
*/
|
||||
public static TypePath fromString(final String typePath) {
|
||||
if (typePath == null || typePath.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
int n = typePath.length();
|
||||
ByteVector out = new ByteVector(n);
|
||||
out.putByte(0);
|
||||
for (int i = 0; i < n;) {
|
||||
char c = typePath.charAt(i++);
|
||||
if (c == '[') {
|
||||
out.put11(ARRAY_ELEMENT, 0);
|
||||
} else if (c == '.') {
|
||||
out.put11(INNER_TYPE, 0);
|
||||
} else if (c == '*') {
|
||||
out.put11(WILDCARD_BOUND, 0);
|
||||
} else if (c >= '0' && c <= '9') {
|
||||
int typeArg = c - '0';
|
||||
while (i < n && (c = typePath.charAt(i)) >= '0' && c <= '9') {
|
||||
typeArg = typeArg * 10 + c - '0';
|
||||
i += 1;
|
||||
}
|
||||
out.put11(TYPE_ARGUMENT, typeArg);
|
||||
}
|
||||
}
|
||||
out.data[0] = (byte) (out.length / 2);
|
||||
return new TypePath(out.data, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this type path. {@link #ARRAY_ELEMENT
|
||||
* ARRAY_ELEMENT} steps are represented with '[', {@link #INNER_TYPE
|
||||
* INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND WILDCARD_BOUND} steps
|
||||
* with '*' and {@link #TYPE_ARGUMENT TYPE_ARGUMENT} steps with their type
|
||||
* argument index in decimal form.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
int length = getLength();
|
||||
StringBuilder result = new StringBuilder(length * 2);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
switch (getStep(i)) {
|
||||
case ARRAY_ELEMENT:
|
||||
result.append('[');
|
||||
break;
|
||||
case INNER_TYPE:
|
||||
result.append('.');
|
||||
break;
|
||||
case WILDCARD_BOUND:
|
||||
result.append('*');
|
||||
break;
|
||||
case TYPE_ARGUMENT:
|
||||
result.append(getStepArgument(i));
|
||||
break;
|
||||
default:
|
||||
result.append('_');
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,452 @@
|
||||
/***
|
||||
* 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.springframework.asm;
|
||||
|
||||
/**
|
||||
* A reference to a type appearing in a class, field or method declaration, or
|
||||
* on an instruction. Such a reference designates the part of the class where
|
||||
* the referenced type is appearing (e.g. an 'extends', 'implements' or 'throws'
|
||||
* clause, a 'new' instruction, a 'catch' clause, a type cast, a local variable
|
||||
* declaration, etc).
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class TypeReference {
|
||||
|
||||
/**
|
||||
* The sort of type references that target a type parameter of a generic
|
||||
* class. See {@link #getSort getSort}.
|
||||
*/
|
||||
public final static int CLASS_TYPE_PARAMETER = 0x00;
|
||||
|
||||
/**
|
||||
* The sort of type references that target a type parameter of a generic
|
||||
* method. See {@link #getSort getSort}.
|
||||
*/
|
||||
public final static int METHOD_TYPE_PARAMETER = 0x01;
|
||||
|
||||
/**
|
||||
* The sort of type references that target the super class of a class or one
|
||||
* of the interfaces it implements. See {@link #getSort getSort}.
|
||||
*/
|
||||
public final static int CLASS_EXTENDS = 0x10;
|
||||
|
||||
/**
|
||||
* The sort of type references that target a bound of a type parameter of a
|
||||
* generic class. See {@link #getSort getSort}.
|
||||
*/
|
||||
public final static int CLASS_TYPE_PARAMETER_BOUND = 0x11;
|
||||
|
||||
/**
|
||||
* The sort of type references that target a bound of a type parameter of a
|
||||
* generic method. See {@link #getSort getSort}.
|
||||
*/
|
||||
public final static int METHOD_TYPE_PARAMETER_BOUND = 0x12;
|
||||
|
||||
/**
|
||||
* The sort of type references that target the type of a field. See
|
||||
* {@link #getSort getSort}.
|
||||
*/
|
||||
public final static int FIELD = 0x13;
|
||||
|
||||
/**
|
||||
* The sort of type references that target the return type of a method. See
|
||||
* {@link #getSort getSort}.
|
||||
*/
|
||||
public final static int METHOD_RETURN = 0x14;
|
||||
|
||||
/**
|
||||
* The sort of type references that target the receiver type of a method.
|
||||
* See {@link #getSort getSort}.
|
||||
*/
|
||||
public final static int METHOD_RECEIVER = 0x15;
|
||||
|
||||
/**
|
||||
* The sort of type references that target the type of a formal parameter of
|
||||
* a method. See {@link #getSort getSort}.
|
||||
*/
|
||||
public final static int METHOD_FORMAL_PARAMETER = 0x16;
|
||||
|
||||
/**
|
||||
* The sort of type references that target the type of an exception declared
|
||||
* in the throws clause of a method. See {@link #getSort getSort}.
|
||||
*/
|
||||
public final static int THROWS = 0x17;
|
||||
|
||||
/**
|
||||
* The sort of type references that target the type of a local variable in a
|
||||
* method. See {@link #getSort getSort}.
|
||||
*/
|
||||
public final static int LOCAL_VARIABLE = 0x40;
|
||||
|
||||
/**
|
||||
* The sort of type references that target the type of a resource variable
|
||||
* in a method. See {@link #getSort getSort}.
|
||||
*/
|
||||
public final static int RESOURCE_VARIABLE = 0x41;
|
||||
|
||||
/**
|
||||
* The sort of type references that target the type of the exception of a
|
||||
* 'catch' clause in a method. See {@link #getSort getSort}.
|
||||
*/
|
||||
public final static int EXCEPTION_PARAMETER = 0x42;
|
||||
|
||||
/**
|
||||
* The sort of type references that target the type declared in an
|
||||
* 'instanceof' instruction. See {@link #getSort getSort}.
|
||||
*/
|
||||
public final static int INSTANCEOF = 0x43;
|
||||
|
||||
/**
|
||||
* The sort of type references that target the type of the object created by
|
||||
* a 'new' instruction. See {@link #getSort getSort}.
|
||||
*/
|
||||
public final static int NEW = 0x44;
|
||||
|
||||
/**
|
||||
* The sort of type references that target the receiver type of a
|
||||
* constructor reference. See {@link #getSort getSort}.
|
||||
*/
|
||||
public final static int CONSTRUCTOR_REFERENCE = 0x45;
|
||||
|
||||
/**
|
||||
* The sort of type references that target the receiver type of a method
|
||||
* reference. See {@link #getSort getSort}.
|
||||
*/
|
||||
public final static int METHOD_REFERENCE = 0x46;
|
||||
|
||||
/**
|
||||
* The sort of type references that target the type declared in an explicit
|
||||
* or implicit cast instruction. See {@link #getSort getSort}.
|
||||
*/
|
||||
public final static int CAST = 0x47;
|
||||
|
||||
/**
|
||||
* The sort of type references that target a type parameter of a generic
|
||||
* constructor in a constructor call. See {@link #getSort getSort}.
|
||||
*/
|
||||
public final static int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48;
|
||||
|
||||
/**
|
||||
* The sort of type references that target a type parameter of a generic
|
||||
* method in a method call. See {@link #getSort getSort}.
|
||||
*/
|
||||
public final static int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49;
|
||||
|
||||
/**
|
||||
* The sort of type references that target a type parameter of a generic
|
||||
* constructor in a constructor reference. See {@link #getSort getSort}.
|
||||
*/
|
||||
public final static int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A;
|
||||
|
||||
/**
|
||||
* The sort of type references that target a type parameter of a generic
|
||||
* method in a method reference. See {@link #getSort getSort}.
|
||||
*/
|
||||
public final static int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B;
|
||||
|
||||
/**
|
||||
* The type reference value in Java class file format.
|
||||
*/
|
||||
private int value;
|
||||
|
||||
/**
|
||||
* Creates a new TypeReference.
|
||||
*
|
||||
* @param typeRef
|
||||
* the int encoded value of the type reference, as received in a
|
||||
* visit method related to type annotations, like
|
||||
* visitTypeAnnotation.
|
||||
*/
|
||||
public TypeReference(int typeRef) {
|
||||
this.value = typeRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a type reference of the given sort.
|
||||
*
|
||||
* @param sort
|
||||
* {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN},
|
||||
* {@link #METHOD_RECEIVER METHOD_RECEIVER},
|
||||
* {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
|
||||
* {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE},
|
||||
* {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW},
|
||||
* {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, or
|
||||
* {@link #METHOD_REFERENCE METHOD_REFERENCE}.
|
||||
* @return a type reference of the given sort.
|
||||
*/
|
||||
public static TypeReference newTypeReference(int sort) {
|
||||
return new TypeReference(sort << 24);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to a type parameter of a generic class or method.
|
||||
*
|
||||
* @param sort
|
||||
* {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or
|
||||
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}.
|
||||
* @param paramIndex
|
||||
* the type parameter index.
|
||||
* @return a reference to the given generic class or method type parameter.
|
||||
*/
|
||||
public static TypeReference newTypeParameterReference(int sort,
|
||||
int paramIndex) {
|
||||
return new TypeReference((sort << 24) | (paramIndex << 16));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to a type parameter bound of a generic class or
|
||||
* method.
|
||||
*
|
||||
* @param sort
|
||||
* {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or
|
||||
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}.
|
||||
* @param paramIndex
|
||||
* the type parameter index.
|
||||
* @param boundIndex
|
||||
* the type bound index within the above type parameters.
|
||||
* @return a reference to the given generic class or method type parameter
|
||||
* bound.
|
||||
*/
|
||||
public static TypeReference newTypeParameterBoundReference(int sort,
|
||||
int paramIndex, int boundIndex) {
|
||||
return new TypeReference((sort << 24) | (paramIndex << 16)
|
||||
| (boundIndex << 8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the super class or to an interface of the
|
||||
* 'implements' clause of a class.
|
||||
*
|
||||
* @param itfIndex
|
||||
* the index of an interface in the 'implements' clause of a
|
||||
* class, or -1 to reference the super class of the class.
|
||||
* @return a reference to the given super type of a class.
|
||||
*/
|
||||
public static TypeReference newSuperTypeReference(int itfIndex) {
|
||||
itfIndex &= 0xFFFF;
|
||||
return new TypeReference((CLASS_EXTENDS << 24) | (itfIndex << 8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the type of a formal parameter of a method.
|
||||
*
|
||||
* @param paramIndex
|
||||
* the formal parameter index.
|
||||
*
|
||||
* @return a reference to the type of the given method formal parameter.
|
||||
*/
|
||||
public static TypeReference newFormalParameterReference(int paramIndex) {
|
||||
return new TypeReference((METHOD_FORMAL_PARAMETER << 24)
|
||||
| (paramIndex << 16));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the type of an exception, in a 'throws' clause of
|
||||
* a method.
|
||||
*
|
||||
* @param exceptionIndex
|
||||
* the index of an exception in a 'throws' clause of a method.
|
||||
*
|
||||
* @return a reference to the type of the given exception.
|
||||
*/
|
||||
public static TypeReference newExceptionReference(int exceptionIndex) {
|
||||
return new TypeReference((THROWS << 24) | (exceptionIndex << 8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the type of the exception declared in a 'catch'
|
||||
* clause of a method.
|
||||
*
|
||||
* @param tryCatchBlockIndex
|
||||
* the index of a try catch block (using the order in which they
|
||||
* are visited with visitTryCatchBlock).
|
||||
*
|
||||
* @return a reference to the type of the given exception.
|
||||
*/
|
||||
public static TypeReference newTryCatchReference(int tryCatchBlockIndex) {
|
||||
return new TypeReference((EXCEPTION_PARAMETER << 24)
|
||||
| (tryCatchBlockIndex << 8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the type of a type argument in a constructor or
|
||||
* method call or reference.
|
||||
*
|
||||
* @param sort
|
||||
* {@link #CAST CAST},
|
||||
* {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
|
||||
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
|
||||
* {@link #METHOD_INVOCATION_TYPE_ARGUMENT
|
||||
* METHOD_INVOCATION_TYPE_ARGUMENT},
|
||||
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
|
||||
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
|
||||
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT
|
||||
* METHOD_REFERENCE_TYPE_ARGUMENT}.
|
||||
* @param argIndex
|
||||
* the type argument index.
|
||||
*
|
||||
* @return a reference to the type of the given type argument.
|
||||
*/
|
||||
public static TypeReference newTypeArgumentReference(int sort, int argIndex) {
|
||||
return new TypeReference((sort << 24) | argIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sort of this type reference.
|
||||
*
|
||||
* @return {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
|
||||
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
|
||||
* {@link #CLASS_EXTENDS CLASS_EXTENDS},
|
||||
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND},
|
||||
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND},
|
||||
* {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN},
|
||||
* {@link #METHOD_RECEIVER METHOD_RECEIVER},
|
||||
* {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER},
|
||||
* {@link #THROWS THROWS}, {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
|
||||
* {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE},
|
||||
* {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER},
|
||||
* {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW},
|
||||
* {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE},
|
||||
* {@link #METHOD_REFERENCE METHOD_REFERENCE}, {@link #CAST CAST},
|
||||
* {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
|
||||
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
|
||||
* {@link #METHOD_INVOCATION_TYPE_ARGUMENT
|
||||
* METHOD_INVOCATION_TYPE_ARGUMENT},
|
||||
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
|
||||
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
|
||||
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT
|
||||
* METHOD_REFERENCE_TYPE_ARGUMENT}.
|
||||
*/
|
||||
public int getSort() {
|
||||
return value >>> 24;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the type parameter referenced by this type
|
||||
* reference. This method must only be used for type references whose sort
|
||||
* is {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
|
||||
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
|
||||
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
|
||||
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
|
||||
*
|
||||
* @return a type parameter index.
|
||||
*/
|
||||
public int getTypeParameterIndex() {
|
||||
return (value & 0x00FF0000) >> 16;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the type parameter bound, within the type parameter
|
||||
* {@link #getTypeParameterIndex}, referenced by this type reference. This
|
||||
* method must only be used for type references whose sort is
|
||||
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
|
||||
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
|
||||
*
|
||||
* @return a type parameter bound index.
|
||||
*/
|
||||
public int getTypeParameterBoundIndex() {
|
||||
return (value & 0x0000FF00) >> 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the "super type" of a class that is referenced by
|
||||
* this type reference. This method must only be used for type references
|
||||
* whose sort is {@link #CLASS_EXTENDS CLASS_EXTENDS}.
|
||||
*
|
||||
* @return the index of an interface in the 'implements' clause of a class,
|
||||
* or -1 if this type reference references the type of the super
|
||||
* class.
|
||||
*/
|
||||
public int getSuperTypeIndex() {
|
||||
return (short) ((value & 0x00FFFF00) >> 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the formal parameter whose type is referenced by
|
||||
* this type reference. This method must only be used for type references
|
||||
* whose sort is {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}.
|
||||
*
|
||||
* @return a formal parameter index.
|
||||
*/
|
||||
public int getFormalParameterIndex() {
|
||||
return (value & 0x00FF0000) >> 16;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the exception, in a 'throws' clause of a method,
|
||||
* whose type is referenced by this type reference. This method must only be
|
||||
* used for type references whose sort is {@link #THROWS THROWS}.
|
||||
*
|
||||
* @return the index of an exception in the 'throws' clause of a method.
|
||||
*/
|
||||
public int getExceptionIndex() {
|
||||
return (value & 0x00FFFF00) >> 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the try catch block (using the order in which they
|
||||
* are visited with visitTryCatchBlock), whose 'catch' type is referenced by
|
||||
* this type reference. This method must only be used for type references
|
||||
* whose sort is {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER} .
|
||||
*
|
||||
* @return the index of an exception in the 'throws' clause of a method.
|
||||
*/
|
||||
public int getTryCatchBlockIndex() {
|
||||
return (value & 0x00FFFF00) >> 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the type argument referenced by this type reference.
|
||||
* This method must only be used for type references whose sort is
|
||||
* {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
|
||||
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
|
||||
* {@link #METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT},
|
||||
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
|
||||
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
|
||||
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}.
|
||||
*
|
||||
* @return a type parameter index.
|
||||
*/
|
||||
public int getTypeArgumentIndex() {
|
||||
return value & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the int encoded value of this type reference, suitable for use in
|
||||
* visit methods related to type annotations, like visitTypeAnnotation.
|
||||
*
|
||||
* @return the int encoded value of this type reference.
|
||||
*/
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,16 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Spring's repackaging of <a href="http://asm.ow2.org">org.objectweb.asm 4</a> (for
|
||||
* internal use only).
|
||||
* Spring's repackaging of
|
||||
* <a href="http://asm.ow2.org">org.objectweb.asm 5.0</a>
|
||||
* (for internal use only).
|
||||
*
|
||||
* <p>This repackaging technique avoids any potential conflicts with
|
||||
* dependencies on ASM at the application level or from other third-party
|
||||
* dependencies on ASM at the application level or from third-party
|
||||
* libraries and frameworks.
|
||||
* <p>As this repackaging happens at the classfile level, sources and Javadoc
|
||||
* are not available here. See the original ObjectWeb
|
||||
* <a href="http://asm.ow2.org/asm40/javadoc/user">ASM 4 Javadoc</a>
|
||||
*
|
||||
* <p>As this repackaging happens at the class file level, sources
|
||||
* and javadocs are not available here. See the original ObjectWeb
|
||||
* <a href="http://asm.ow2.org/asm50/javadoc/user">ASM 5.0 javadocs</a>
|
||||
* for details when working with these classes.
|
||||
*
|
||||
* @since 3.2
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.asm.util;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.SpringAsmInfo;
|
||||
|
||||
/**
|
||||
* Dummy implementation of missing TraceClassVisitor from cglib-nodep's internally
|
||||
* repackaged ASM library, added to avoid NoClassDefFoundErrors.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.2
|
||||
*/
|
||||
public class TraceClassVisitor extends ClassVisitor {
|
||||
|
||||
public TraceClassVisitor(Object object, PrintWriter pw) {
|
||||
super(SpringAsmInfo.ASM_VERSION);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Dummy implementations of asm-util classes (for internal use only).
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
package org.springframework.asm.util;
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,10 +17,10 @@
|
||||
package org.springframework.cglib;
|
||||
|
||||
/**
|
||||
* Empty class used to ensure that the {@code org.springframework.cglib} package is
|
||||
* processed during Javadoc generation.
|
||||
* Empty class used to ensure that the {@code org.springframework.cglib}
|
||||
* package is processed during javadoc generation.
|
||||
*
|
||||
* <p>See <a href="package-summary.html">package-level Javadoc</a> for more
|
||||
* <p>See <a href="package-summary.html">package-level javadocs</a> for more
|
||||
* information on {@code org.springframework.cglib}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
|
||||
@@ -1,28 +1,16 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Spring's repackaging of <a href="http://cglib.sourceforge.net">net.sf.cglib 3</a> (for
|
||||
* internal use only).
|
||||
* Spring's repackaging of
|
||||
* <a href="http://cglib.sourceforge.net">net.sf.cglib 3.1</a>
|
||||
* (for internal use only).
|
||||
*
|
||||
* <p>This repackaging technique avoids any potential conflicts with
|
||||
* dependencies on CGLIB at the application level or from other third-party
|
||||
* dependencies on CGLIB at the application level or from third-party
|
||||
* libraries and frameworks.
|
||||
* <p>As this repackaging happens at the classfile level, sources and Javadoc
|
||||
* are not available here. See the original
|
||||
* <a href="http://cglib.sourceforge.net/apidocs">CGLIB 3 Javadoc</a>
|
||||
*
|
||||
* <p>As this repackaging happens at the class file level, sources
|
||||
* and javadocs are not available here. See the original
|
||||
* <a href="http://cglib.sourceforge.net/apidocs">CGLIB 3.1 javadocs</a>
|
||||
* for details when working with these classes.
|
||||
*
|
||||
* @since 3.2
|
||||
|
||||
Reference in New Issue
Block a user