Upgraded embedded ASM version to 5.0

Issue: SPR-11239
This commit is contained in:
Juergen Hoeller
2014-03-20 01:06:22 +01:00
parent 99cd2f6098
commit ad09f1b5ec
22 changed files with 1835 additions and 242 deletions

View File

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

View File

@@ -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);
}
}
}

View File

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

View File

@@ -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) {

View File

@@ -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.
*

View File

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

View File

@@ -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.
*/

View File

@@ -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.
*

View File

@@ -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);
}

View File

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

View File

@@ -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.
*

View File

@@ -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);

View File

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

View File

@@ -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;
}

View 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();
}
}

View File

@@ -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;
}
}

View File

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

View File

@@ -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);
}
}

View File

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

View File

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

View File

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