提交 a0014334 编写于 作者: K ksrini

8027227: [asm] generate CONSTANT_InterfaceMethodref for invoke{special/static)...

8027227: [asm] generate CONSTANT_InterfaceMethodref for invoke{special/static) of non-abstract methods on ifaces
Reviewed-by: ksrini, lagergren
Contributed-by: ebruneton@free.fr, forax@univ-mlv.fr, john.r.rose@oracle.com, paul.sandoz@oracle.com
上级 600daf2e
...@@ -233,11 +233,14 @@ public class ByteVector { ...@@ -233,11 +233,14 @@ public class ByteVector {
* automatically enlarged if necessary. * automatically enlarged if necessary.
* *
* @param s * @param s
* a String. * a String whose UTF8 encoded length must be less than 65536.
* @return this byte vector. * @return this byte vector.
*/ */
public ByteVector putUTF8(final String s) { public ByteVector putUTF8(final String s) {
int charLength = s.length(); int charLength = s.length();
if (charLength > 65535) {
throw new IllegalArgumentException();
}
int len = length; int len = length;
if (len + 2 + charLength > data.length) { if (len + 2 + charLength > data.length) {
enlarge(2 + charLength); enlarge(2 + charLength);
...@@ -267,6 +270,9 @@ public class ByteVector { ...@@ -267,6 +270,9 @@ public class ByteVector {
byteLength += 2; byteLength += 2;
} }
} }
if (byteLength > 65535) {
throw new IllegalArgumentException();
}
data[length] = (byte) (byteLength >>> 8); data[length] = (byte) (byteLength >>> 8);
data[length + 1] = (byte) byteLength; data[length + 1] = (byte) byteLength;
if (length + 2 + byteLength > data.length) { if (length + 2 + byteLength > data.length) {
......
...@@ -1266,7 +1266,7 @@ public class ClassReader { ...@@ -1266,7 +1266,7 @@ public class ClassReader {
u += 2; u += 2;
// generates the first (implicit) stack map frame // generates the first (implicit) stack map frame
if (FRAMES && (stackMap != 0 || unzip)) { if (FRAMES && stackMap != 0) {
/* /*
* for the first explicit frame the offset is not offset_delta + 1 * for the first explicit frame the offset is not offset_delta + 1
* but only offset_delta; setting the implicit frame offset to -1 * but only offset_delta; setting the implicit frame offset to -1
...@@ -1283,8 +1283,6 @@ public class ClassReader { ...@@ -1283,8 +1283,6 @@ public class ClassReader {
if (unzip) { if (unzip) {
getImplicitFrame(context); getImplicitFrame(context);
} }
}
if (FRAMES && stackMap != 0) {
/* /*
* Finds labels for UNINITIALIZED frame types. Instead of decoding * Finds labels for UNINITIALIZED frame types. Instead of decoding
* each element of the stack map table, we look for 3 consecutive * each element of the stack map table, we look for 3 consecutive
...@@ -1322,18 +1320,20 @@ public class ClassReader { ...@@ -1322,18 +1320,20 @@ public class ClassReader {
} }
} }
// visits the frame(s) for this offset, if any // visits the frame for this offset, if any
while (FRAMES && frame != null while (FRAMES && frame != null
&& (frame.offset == offset || frame.offset == -1)) { && (frame.offset == offset || frame.offset == -1)) {
// if there is a frame for this offset, makes the visitor visit // if there is a frame for this offset, makes the visitor visit
// it, and reads the next frame if there is one. // it, and reads the next frame if there is one.
if (frame.offset != -1) {
if (!zip || unzip) { if (!zip || unzip) {
mv.visitFrame(Opcodes.F_NEW, frame.localCount, frame.local, mv.visitFrame(Opcodes.F_NEW, frame.localCount,
frame.stackCount, frame.stack); frame.local, frame.stackCount, frame.stack);
} else if (frame.offset != -1) { } else {
mv.visitFrame(frame.mode, frame.localDiff, frame.local, mv.visitFrame(frame.mode, frame.localDiff, frame.local,
frame.stackCount, frame.stack); frame.stackCount, frame.stack);
} }
}
if (frameCount > 0) { if (frameCount > 0) {
stackMap = readFrame(stackMap, zip, unzip, frame); stackMap = readFrame(stackMap, zip, unzip, frame);
--frameCount; --frameCount;
...@@ -1434,6 +1434,7 @@ public class ClassReader { ...@@ -1434,6 +1434,7 @@ public class ClassReader {
case ClassWriter.FIELDORMETH_INSN: case ClassWriter.FIELDORMETH_INSN:
case ClassWriter.ITFMETH_INSN: { case ClassWriter.ITFMETH_INSN: {
int cpIndex = items[readUnsignedShort(u + 1)]; int cpIndex = items[readUnsignedShort(u + 1)];
boolean itf = b[cpIndex - 1] == ClassWriter.IMETH;
String iowner = readClass(cpIndex, c); String iowner = readClass(cpIndex, c);
cpIndex = items[readUnsignedShort(cpIndex + 2)]; cpIndex = items[readUnsignedShort(cpIndex + 2)];
String iname = readUTF8(cpIndex, c); String iname = readUTF8(cpIndex, c);
...@@ -1441,7 +1442,7 @@ public class ClassReader { ...@@ -1441,7 +1442,7 @@ public class ClassReader {
if (opcode < Opcodes.INVOKEVIRTUAL) { if (opcode < Opcodes.INVOKEVIRTUAL) {
mv.visitFieldInsn(opcode, iowner, iname, idesc); mv.visitFieldInsn(opcode, iowner, iname, idesc);
} else { } else {
mv.visitMethodInsn(opcode, iowner, iname, idesc); mv.visitMethodInsn(opcode, iowner, iname, idesc, itf);
} }
if (opcode == Opcodes.INVOKEINTERFACE) { if (opcode == Opcodes.INVOKEINTERFACE) {
u += 5; u += 5;
......
...@@ -516,12 +516,12 @@ public class ClassWriter extends ClassVisitor { ...@@ -516,12 +516,12 @@ public class ClassWriter extends ClassVisitor {
* <tt>true</tt> if the maximum stack size and number of local variables * <tt>true</tt> if the maximum stack size and number of local variables
* must be automatically computed. * must be automatically computed.
*/ */
private final boolean computeMaxs; private boolean computeMaxs;
/** /**
* <tt>true</tt> if the stack map frames must be recomputed from scratch. * <tt>true</tt> if the stack map frames must be recomputed from scratch.
*/ */
private final boolean computeFrames; private boolean computeFrames;
/** /**
* <tt>true</tt> if the stack map tables of this class are invalid. The * <tt>true</tt> if the stack map tables of this class are invalid. The
...@@ -988,9 +988,22 @@ public class ClassWriter extends ClassVisitor { ...@@ -988,9 +988,22 @@ public class ClassWriter extends ClassVisitor {
attrs.put(this, null, 0, -1, -1, out); attrs.put(this, null, 0, -1, -1, out);
} }
if (invalidFrames) { if (invalidFrames) {
ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); anns = null;
new ClassReader(out.data).accept(cw, ClassReader.SKIP_FRAMES); ianns = null;
return cw.toByteArray(); attrs = null;
innerClassesCount = 0;
innerClasses = null;
bootstrapMethodsCount = 0;
bootstrapMethods = null;
firstField = null;
lastField = null;
firstMethod = null;
lastMethod = null;
computeMaxs = false;
computeFrames = true;
invalidFrames = false;
new ClassReader(out.data).accept(this, ClassReader.SKIP_FRAMES);
return toByteArray();
} }
return out.data; return out.data;
} }
......
...@@ -78,7 +78,8 @@ public final class Handle { ...@@ -78,7 +78,8 @@ public final class Handle {
final int tag; final int tag;
/** /**
* The internal name of the field or method designed by this handle. * The internal name of the class that owns the field or method designated
* by this handle.
*/ */
final String owner; final String owner;
...@@ -105,8 +106,8 @@ public final class Handle { ...@@ -105,8 +106,8 @@ public final class Handle {
* {@link Opcodes#H_NEWINVOKESPECIAL} or * {@link Opcodes#H_NEWINVOKESPECIAL} or
* {@link Opcodes#H_INVOKEINTERFACE}. * {@link Opcodes#H_INVOKEINTERFACE}.
* @param owner * @param owner
* the internal name of the field or method designed by this * the internal name of the class that owns the field or method
* handle. * designated by this handle.
* @param name * @param name
* the name of the field or method designated by this handle. * the name of the field or method designated by this handle.
* @param desc * @param desc
...@@ -135,9 +136,11 @@ public final class Handle { ...@@ -135,9 +136,11 @@ public final class Handle {
} }
/** /**
* Returns the internal name of the field or method designed by this handle. * Returns the internal name of the class that owns the field or method
* designated by this handle.
* *
* @return the internal name of the field or method designed by this handle. * @return the internal name of the class that owns the field or method
* designated by this handle.
*/ */
public String getOwner() { public String getOwner() {
return owner; return owner;
......
...@@ -68,11 +68,11 @@ package jdk.internal.org.objectweb.asm; ...@@ -68,11 +68,11 @@ package jdk.internal.org.objectweb.asm;
* <tt>visitTryCatchBlock</tt> | <tt>visitTryCatchBlockAnnotation</tt> | * <tt>visitTryCatchBlock</tt> | <tt>visitTryCatchBlockAnnotation</tt> |
* <tt>visitLocalVariable</tt> | <tt>visitLocalVariableAnnotation</tt> | * <tt>visitLocalVariable</tt> | <tt>visitLocalVariableAnnotation</tt> |
* <tt>visitLineNumber</tt> )* <tt>visitMaxs</tt> ] <tt>visitEnd</tt>. In * <tt>visitLineNumber</tt> )* <tt>visitMaxs</tt> ] <tt>visitEnd</tt>. In
* addition, the <tt>visit<i>X</i>Insn</tt> and <tt>visitLabel</tt> * addition, the <tt>visit<i>X</i>Insn</tt> and <tt>visitLabel</tt> methods must
* methods must be called in the sequential order of the bytecode instructions * be called in the sequential order of the bytecode instructions of the visited
* of the visited code, <tt>visitInsnAnnotation</tt> must be called <i>after</i> * code, <tt>visitInsnAnnotation</tt> must be called <i>after</i> the annotated
* the annotated instruction, <tt>visitTryCatchBlock</tt> must be called * instruction, <tt>visitTryCatchBlock</tt> must be called <i>before</i> the
* <i>before</i> the labels passed as arguments have been visited, * labels passed as arguments have been visited,
* <tt>visitTryCatchBlockAnnotation</tt> must be called <i>after</i> the * <tt>visitTryCatchBlockAnnotation</tt> must be called <i>after</i> the
* corresponding try catch block has been visited, and the * corresponding try catch block has been visited, and the
* <tt>visitLocalVariable</tt>, <tt>visitLocalVariableAnnotation</tt> and * <tt>visitLocalVariable</tt>, <tt>visitLocalVariableAnnotation</tt> and
...@@ -274,13 +274,9 @@ public abstract class MethodVisitor { ...@@ -274,13 +274,9 @@ public abstract class MethodVisitor {
* compressed form (all frames must use the same format, i.e. you must not * compressed form (all frames must use the same format, i.e. you must not
* mix expanded and compressed frames within a single method): * mix expanded and compressed frames within a single method):
* <ul> * <ul>
* <li>In expanded form, all frames must have the F_NEW type, and a first * <li>In expanded form, all frames must have the F_NEW type.</li>
* frame corresponding to the method signature must be explicitly visited
* before the first instruction.</li>
* <li>In compressed form, frames are basically "deltas" from the state of * <li>In compressed form, frames are basically "deltas" from the state of
* the previous frame (the first frame, corresponding to the method's * the previous frame:
* parameters and access flags, is implicit in this form, and must not be
* visited):
* <ul> * <ul>
* <li>{@link Opcodes#F_SAME} representing frame with exactly the same * <li>{@link Opcodes#F_SAME} representing frame with exactly the same
* locals as the previous frame and with the empty stack.</li> * locals as the previous frame and with the empty stack.</li>
...@@ -296,8 +292,14 @@ public abstract class MethodVisitor { ...@@ -296,8 +292,14 @@ public abstract class MethodVisitor {
* same as the locals in the previous frame, except that the last 1-3 locals * 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> * 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>{@link Opcodes#F_FULL} representing complete frame data.</li>
* </ul></li>
* </ul> * </ul>
* </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
* least one instruction must be visited between two calls to visitFrame).
* *
* @param type * @param type
* the type of this stack map frame. Must be * the type of this stack map frame. Must be
...@@ -466,13 +468,52 @@ public abstract class MethodVisitor { ...@@ -466,13 +468,52 @@ public abstract class MethodVisitor {
* @param desc * @param desc
* the method's descriptor (see {@link Type Type}). * the method's descriptor (see {@link Type Type}).
*/ */
@Deprecated
public void visitMethodInsn(int opcode, String owner, String name, public void visitMethodInsn(int opcode, String owner, String name,
String desc) { String desc) {
if (api >= Opcodes.ASM5) {
boolean itf = opcode == Opcodes.INVOKEINTERFACE;
visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
if (mv != null) { if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc); 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. * Visits an invokedynamic instruction.
* *
......
...@@ -71,7 +71,7 @@ class MethodWriter extends MethodVisitor { ...@@ -71,7 +71,7 @@ class MethodWriter extends MethodVisitor {
/** /**
* Pseudo access flag used to denote constructors. * Pseudo access flag used to denote constructors.
*/ */
static final int ACC_CONSTRUCTOR = 262144; static final int ACC_CONSTRUCTOR = 0x80000;
/** /**
* Frame has exactly the same locals as the previous stack map frame and * Frame has exactly the same locals as the previous stack map frame and
...@@ -297,11 +297,6 @@ class MethodWriter extends MethodVisitor { ...@@ -297,11 +297,6 @@ class MethodWriter extends MethodVisitor {
*/ */
private int[] previousFrame; private int[] previousFrame;
/**
* Index of the next element to be added in {@link #frame}.
*/
private int frameIndex;
/** /**
* The current stack map frame. The first element contains the offset of the * The current stack map frame. The first element contains the offset of the
* instruction to which the frame corresponds, the second element is the * instruction to which the frame corresponds, the second element is the
...@@ -496,6 +491,9 @@ class MethodWriter extends MethodVisitor { ...@@ -496,6 +491,9 @@ class MethodWriter extends MethodVisitor {
cw.lastMethod = this; cw.lastMethod = this;
this.cw = cw; this.cw = cw;
this.access = access; this.access = access;
if ("<init>".equals(name)) {
this.access |= ACC_CONSTRUCTOR;
}
this.name = cw.newUTF8(name); this.name = cw.newUTF8(name);
this.desc = cw.newUTF8(desc); this.desc = cw.newUTF8(desc);
this.descriptor = desc; this.descriptor = desc;
...@@ -511,9 +509,6 @@ class MethodWriter extends MethodVisitor { ...@@ -511,9 +509,6 @@ class MethodWriter extends MethodVisitor {
} }
this.compute = computeFrames ? FRAMES : (computeMaxs ? MAXS : NOTHING); this.compute = computeFrames ? FRAMES : (computeMaxs ? MAXS : NOTHING);
if (computeMaxs || computeFrames) { if (computeMaxs || computeFrames) {
if (computeFrames && "<init>".equals(name)) {
this.access |= ACC_CONSTRUCTOR;
}
// updates maxLocals // updates maxLocals
int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2; int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
if ((access & Opcodes.ACC_STATIC) != 0) { if ((access & Opcodes.ACC_STATIC) != 0) {
...@@ -649,8 +644,11 @@ class MethodWriter extends MethodVisitor { ...@@ -649,8 +644,11 @@ class MethodWriter extends MethodVisitor {
} }
if (type == Opcodes.F_NEW) { if (type == Opcodes.F_NEW) {
if (previousFrame == null) {
visitImplicitFirstFrame();
}
currentLocals = nLocal; currentLocals = nLocal;
startFrame(code.length, nLocal, nStack); int frameIndex = startFrame(code.length, nLocal, nStack);
for (int i = 0; i < nLocal; ++i) { for (int i = 0; i < nLocal; ++i) {
if (local[i] instanceof String) { if (local[i] instanceof String) {
frame[frameIndex++] = Frame.OBJECT frame[frameIndex++] = Frame.OBJECT
...@@ -914,9 +912,8 @@ class MethodWriter extends MethodVisitor { ...@@ -914,9 +912,8 @@ class MethodWriter extends MethodVisitor {
@Override @Override
public void visitMethodInsn(final int opcode, final String owner, public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc) { final String name, final String desc, final boolean itf) {
lastCodeOffset = code.length; lastCodeOffset = code.length;
boolean itf = opcode == Opcodes.INVOKEINTERFACE;
Item i = cw.newMethodItem(owner, name, desc, itf); Item i = cw.newMethodItem(owner, name, desc, itf);
int argSize = i.intVal; int argSize = i.intVal;
// Label currentBlock = this.currentBlock; // Label currentBlock = this.currentBlock;
...@@ -954,7 +951,7 @@ class MethodWriter extends MethodVisitor { ...@@ -954,7 +951,7 @@ class MethodWriter extends MethodVisitor {
} }
} }
// adds the instruction to the bytecode of the method // adds the instruction to the bytecode of the method
if (itf) { if (opcode == Opcodes.INVOKEINTERFACE) {
if (argSize == 0) { if (argSize == 0) {
argSize = Type.getArgumentsAndReturnSizes(desc); argSize = Type.getArgumentsAndReturnSizes(desc);
i.intVal = argSize; i.intVal = argSize;
...@@ -1528,8 +1525,8 @@ class MethodWriter extends MethodVisitor { ...@@ -1528,8 +1525,8 @@ class MethodWriter extends MethodVisitor {
} }
code.data[end] = (byte) Opcodes.ATHROW; code.data[end] = (byte) Opcodes.ATHROW;
// emits a frame for this unreachable block // emits a frame for this unreachable block
startFrame(start, 0, 1); int frameIndex = startFrame(start, 0, 1);
frame[frameIndex++] = Frame.OBJECT frame[frameIndex] = Frame.OBJECT
| cw.addType("java/lang/Throwable"); | cw.addType("java/lang/Throwable");
endFrame(); endFrame();
// removes the start-end range from the exception // removes the start-end range from the exception
...@@ -1756,7 +1753,7 @@ class MethodWriter extends MethodVisitor { ...@@ -1756,7 +1753,7 @@ class MethodWriter extends MethodVisitor {
} }
} }
// visits the frame and its content // visits the frame and its content
startFrame(f.owner.position, nLocal, nStack); int frameIndex = startFrame(f.owner.position, nLocal, nStack);
for (i = 0; nLocal > 0; ++i, --nLocal) { for (i = 0; nLocal > 0; ++i, --nLocal) {
t = locals[i]; t = locals[i];
frame[frameIndex++] = t; frame[frameIndex++] = t;
...@@ -1774,6 +1771,67 @@ class MethodWriter extends MethodVisitor { ...@@ -1774,6 +1771,67 @@ class MethodWriter extends MethodVisitor {
endFrame(); endFrame();
} }
/**
* Visit the implicit first frame of this method.
*/
private void visitImplicitFirstFrame() {
// There can be at most descriptor.length() + 1 locals
int frameIndex = startFrame(0, descriptor.length() + 1, 0);
if ((access & Opcodes.ACC_STATIC) == 0) {
if ((access & ACC_CONSTRUCTOR) == 0) {
frame[frameIndex++] = Frame.OBJECT | cw.addType(cw.thisName);
} else {
frame[frameIndex++] = 6; // Opcodes.UNINITIALIZED_THIS;
}
}
int i = 1;
loop: while (true) {
int j = i;
switch (descriptor.charAt(i++)) {
case 'Z':
case 'C':
case 'B':
case 'S':
case 'I':
frame[frameIndex++] = 1; // Opcodes.INTEGER;
break;
case 'F':
frame[frameIndex++] = 2; // Opcodes.FLOAT;
break;
case 'J':
frame[frameIndex++] = 4; // Opcodes.LONG;
break;
case 'D':
frame[frameIndex++] = 3; // Opcodes.DOUBLE;
break;
case '[':
while (descriptor.charAt(i) == '[') {
++i;
}
if (descriptor.charAt(i) == 'L') {
++i;
while (descriptor.charAt(i) != ';') {
++i;
}
}
frame[frameIndex++] = Frame.OBJECT
| cw.addType(descriptor.substring(j, ++i));
break;
case 'L':
while (descriptor.charAt(i) != ';') {
++i;
}
frame[frameIndex++] = Frame.OBJECT
| cw.addType(descriptor.substring(j + 1, i++));
break;
default:
break loop;
}
}
frame[1] = frameIndex - 3;
endFrame();
}
/** /**
* Starts the visit of a stack map frame. * Starts the visit of a stack map frame.
* *
...@@ -1783,8 +1841,9 @@ class MethodWriter extends MethodVisitor { ...@@ -1783,8 +1841,9 @@ class MethodWriter extends MethodVisitor {
* the number of local variables in the frame. * the number of local variables in the frame.
* @param nStack * @param nStack
* the number of stack elements in the frame. * the number of stack elements in the frame.
* @return the index of the next element to be written in this frame.
*/ */
private void startFrame(final int offset, final int nLocal, final int nStack) { private int startFrame(final int offset, final int nLocal, final int nStack) {
int n = 3 + nLocal + nStack; int n = 3 + nLocal + nStack;
if (frame == null || frame.length < n) { if (frame == null || frame.length < n) {
frame = new int[n]; frame = new int[n];
...@@ -1792,7 +1851,7 @@ class MethodWriter extends MethodVisitor { ...@@ -1792,7 +1851,7 @@ class MethodWriter extends MethodVisitor {
frame[0] = offset; frame[0] = offset;
frame[1] = nLocal; frame[1] = nLocal;
frame[2] = nStack; frame[2] = nStack;
frameIndex = 3; return 3;
} }
/** /**
...@@ -2110,7 +2169,8 @@ class MethodWriter extends MethodVisitor { ...@@ -2110,7 +2169,8 @@ class MethodWriter extends MethodVisitor {
*/ */
final void put(final ByteVector out) { final void put(final ByteVector out) {
final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC; final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC;
int mask = Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE int mask = ACC_CONSTRUCTOR | Opcodes.ACC_DEPRECATED
| ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
| ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR); | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR);
out.putShort(access & ~mask).putShort(name).putShort(desc); out.putShort(access & ~mask).putShort(name).putShort(desc);
if (classReaderOffset != 0) { if (classReaderOffset != 0) {
......
...@@ -442,10 +442,31 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes ...@@ -442,10 +442,31 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
} }
} }
@Deprecated
@Override @Override
public void visitMethodInsn(final int opcode, final String owner, public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc) { final String name, final String desc) {
mv.visitMethodInsn(opcode, owner, name, desc); if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc);
return;
}
doVisitMethodInsn(opcode, owner, name, desc,
opcode == Opcodes.INVOKEINTERFACE);
}
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc, final boolean itf) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
doVisitMethodInsn(opcode, owner, name, desc, itf);
}
private void doVisitMethodInsn(int opcode, final String owner,
final String name, final String desc, final boolean itf) {
mv.visitMethodInsn(opcode, owner, name, desc, itf);
if (constructor) { if (constructor) {
Type[] types = Type.getArgumentTypes(desc); Type[] types = Type.getArgumentTypes(desc);
for (int i = 0; i < types.length; i++) { for (int i = 0; i < types.length; i++) {
......
...@@ -165,10 +165,15 @@ public class AnalyzerAdapter extends MethodVisitor { ...@@ -165,10 +165,15 @@ public class AnalyzerAdapter extends MethodVisitor {
* @param mv * @param mv
* the method visitor to which this adapter delegates calls. May * the method visitor to which this adapter delegates calls. May
* be <tt>null</tt>. * be <tt>null</tt>.
* @throws IllegalStateException
* If a subclass calls this constructor.
*/ */
public AnalyzerAdapter(final String owner, final int access, public AnalyzerAdapter(final String owner, final int access,
final String name, final String desc, final MethodVisitor mv) { final String name, final String desc, final MethodVisitor mv) {
this(Opcodes.ASM5, owner, access, name, desc, mv); this(Opcodes.ASM5, owner, access, name, desc, mv);
if (getClass() != AnalyzerAdapter.class) {
throw new IllegalStateException();
}
} }
/** /**
...@@ -331,11 +336,32 @@ public class AnalyzerAdapter extends MethodVisitor { ...@@ -331,11 +336,32 @@ public class AnalyzerAdapter extends MethodVisitor {
execute(opcode, 0, desc); execute(opcode, 0, desc);
} }
@Deprecated
@Override @Override
public void visitMethodInsn(final int opcode, final String owner, public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc) { final String name, final String desc) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc);
return;
}
doVisitMethodInsn(opcode, owner, name, desc,
opcode == Opcodes.INVOKEINTERFACE);
}
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc, final boolean itf) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
doVisitMethodInsn(opcode, owner, name, desc, itf);
}
private void doVisitMethodInsn(int opcode, final String owner,
final String name, final String desc, final boolean itf) {
if (mv != null) { if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc); mv.visitMethodInsn(opcode, owner, name, desc, itf);
} }
if (this.locals == null) { if (this.locals == null) {
labels = null; labels = null;
......
...@@ -149,9 +149,30 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes { ...@@ -149,9 +149,30 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
} }
} }
@Deprecated
@Override @Override
public void visitMethodInsn(final int opcode, final String owner, public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc) { final String name, final String desc) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc);
return;
}
doVisitMethodInsn(opcode, owner, name, desc,
opcode == Opcodes.INVOKEINTERFACE);
}
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc, final boolean itf) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
doVisitMethodInsn(opcode, owner, name, desc, itf);
}
private void doVisitMethodInsn(int opcode, final String owner,
final String name, final String desc, final boolean itf) {
if (opcode == INVOKEINTERFACE) { if (opcode == INVOKEINTERFACE) {
minSize += 5; minSize += 5;
maxSize += 5; maxSize += 5;
...@@ -160,7 +181,7 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes { ...@@ -160,7 +181,7 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
maxSize += 3; maxSize += 3;
} }
if (mv != null) { if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc); mv.visitMethodInsn(opcode, owner, name, desc, itf);
} }
} }
......
...@@ -284,10 +284,15 @@ public class GeneratorAdapter extends LocalVariablesSorter { ...@@ -284,10 +284,15 @@ public class GeneratorAdapter extends LocalVariablesSorter {
* the method's name. * the method's name.
* @param desc * @param desc
* the method's descriptor (see {@link Type Type}). * the method's descriptor (see {@link Type Type}).
* @throws IllegalStateException
* If a subclass calls this constructor.
*/ */
public GeneratorAdapter(final MethodVisitor mv, final int access, public GeneratorAdapter(final MethodVisitor mv, final int access,
final String name, final String desc) { final String name, final String desc) {
this(Opcodes.ASM5, mv, access, name, desc); this(Opcodes.ASM5, mv, access, name, desc);
if (getClass() != GeneratorAdapter.class) {
throw new IllegalStateException();
}
} }
/** /**
...@@ -1400,11 +1405,11 @@ public class GeneratorAdapter extends LocalVariablesSorter { ...@@ -1400,11 +1405,11 @@ public class GeneratorAdapter extends LocalVariablesSorter {
* the method to be invoked. * the method to be invoked.
*/ */
private void invokeInsn(final int opcode, final Type type, private void invokeInsn(final int opcode, final Type type,
final Method method) { final Method method, final boolean itf) {
String owner = type.getSort() == Type.ARRAY ? type.getDescriptor() String owner = type.getSort() == Type.ARRAY ? type.getDescriptor()
: type.getInternalName(); : type.getInternalName();
mv.visitMethodInsn(opcode, owner, method.getName(), mv.visitMethodInsn(opcode, owner, method.getName(),
method.getDescriptor()); method.getDescriptor(), itf);
} }
/** /**
...@@ -1416,7 +1421,7 @@ public class GeneratorAdapter extends LocalVariablesSorter { ...@@ -1416,7 +1421,7 @@ public class GeneratorAdapter extends LocalVariablesSorter {
* the method to be invoked. * the method to be invoked.
*/ */
public void invokeVirtual(final Type owner, final Method method) { public void invokeVirtual(final Type owner, final Method method) {
invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method); invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method, false);
} }
/** /**
...@@ -1428,7 +1433,7 @@ public class GeneratorAdapter extends LocalVariablesSorter { ...@@ -1428,7 +1433,7 @@ public class GeneratorAdapter extends LocalVariablesSorter {
* the constructor to be invoked. * the constructor to be invoked.
*/ */
public void invokeConstructor(final Type type, final Method method) { public void invokeConstructor(final Type type, final Method method) {
invokeInsn(Opcodes.INVOKESPECIAL, type, method); invokeInsn(Opcodes.INVOKESPECIAL, type, method, false);
} }
/** /**
...@@ -1440,7 +1445,7 @@ public class GeneratorAdapter extends LocalVariablesSorter { ...@@ -1440,7 +1445,7 @@ public class GeneratorAdapter extends LocalVariablesSorter {
* the method to be invoked. * the method to be invoked.
*/ */
public void invokeStatic(final Type owner, final Method method) { public void invokeStatic(final Type owner, final Method method) {
invokeInsn(Opcodes.INVOKESTATIC, owner, method); invokeInsn(Opcodes.INVOKESTATIC, owner, method, false);
} }
/** /**
...@@ -1452,7 +1457,7 @@ public class GeneratorAdapter extends LocalVariablesSorter { ...@@ -1452,7 +1457,7 @@ public class GeneratorAdapter extends LocalVariablesSorter {
* the method to be invoked. * the method to be invoked.
*/ */
public void invokeInterface(final Type owner, final Method method) { public void invokeInterface(final Type owner, final Method method) {
invokeInsn(Opcodes.INVOKEINTERFACE, owner, method); invokeInsn(Opcodes.INVOKEINTERFACE, owner, method, true);
} }
/** /**
......
...@@ -82,9 +82,14 @@ public class InstructionAdapter extends MethodVisitor { ...@@ -82,9 +82,14 @@ public class InstructionAdapter extends MethodVisitor {
* *
* @param mv * @param mv
* the method visitor to which this adapter delegates calls. * the method visitor to which this adapter delegates calls.
* @throws IllegalStateException
* If a subclass calls this constructor.
*/ */
public InstructionAdapter(final MethodVisitor mv) { public InstructionAdapter(final MethodVisitor mv) {
this(Opcodes.ASM5, mv); this(Opcodes.ASM5, mv);
if (getClass() != InstructionAdapter.class) {
throw new IllegalStateException();
}
} }
/** /**
...@@ -536,18 +541,39 @@ public class InstructionAdapter extends MethodVisitor { ...@@ -536,18 +541,39 @@ public class InstructionAdapter extends MethodVisitor {
} }
} }
@Deprecated
@Override @Override
public void visitMethodInsn(final int opcode, final String owner, public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc) { final String name, final String desc) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc);
return;
}
doVisitMethodInsn(opcode, owner, name, desc,
opcode == Opcodes.INVOKEINTERFACE);
}
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc, final boolean itf) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
doVisitMethodInsn(opcode, owner, name, desc, itf);
}
private void doVisitMethodInsn(int opcode, final String owner,
final String name, final String desc, final boolean itf) {
switch (opcode) { switch (opcode) {
case Opcodes.INVOKESPECIAL: case Opcodes.INVOKESPECIAL:
invokespecial(owner, name, desc); invokespecial(owner, name, desc, itf);
break; break;
case Opcodes.INVOKEVIRTUAL: case Opcodes.INVOKEVIRTUAL:
invokevirtual(owner, name, desc); invokevirtual(owner, name, desc, itf);
break; break;
case Opcodes.INVOKESTATIC: case Opcodes.INVOKESTATIC:
invokestatic(owner, name, desc); invokestatic(owner, name, desc, itf);
break; break;
case Opcodes.INVOKEINTERFACE: case Opcodes.INVOKEINTERFACE:
invokeinterface(owner, name, desc); invokeinterface(owner, name, desc);
...@@ -1014,24 +1040,78 @@ public class InstructionAdapter extends MethodVisitor { ...@@ -1014,24 +1040,78 @@ public class InstructionAdapter extends MethodVisitor {
mv.visitFieldInsn(Opcodes.PUTFIELD, owner, name, desc); mv.visitFieldInsn(Opcodes.PUTFIELD, owner, name, desc);
} }
@Deprecated
public void invokevirtual(final String owner, final String name, public void invokevirtual(final String owner, final String name,
final String desc) { final String desc) {
if (api >= Opcodes.ASM5) {
invokevirtual(owner, name, desc, false);
return;
}
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc);
} }
public void invokevirtual(final String owner, final String name,
final String desc, final boolean itf) {
if (api < Opcodes.ASM5) {
if (itf) {
throw new IllegalArgumentException(
"INVOKEVIRTUAL on interfaces require ASM 5");
}
invokevirtual(owner, name, desc);
return;
}
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, itf);
}
@Deprecated
public void invokespecial(final String owner, final String name, public void invokespecial(final String owner, final String name,
final String desc) { final String desc) {
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc); if (api >= Opcodes.ASM5) {
invokespecial(owner, name, desc, false);
return;
}
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, false);
}
public void invokespecial(final String owner, final String name,
final String desc, final boolean itf) {
if (api < Opcodes.ASM5) {
if (itf) {
throw new IllegalArgumentException(
"INVOKESPECIAL on interfaces require ASM 5");
}
invokespecial(owner, name, desc);
return;
}
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, itf);
} }
@Deprecated
public void invokestatic(final String owner, final String name, public void invokestatic(final String owner, final String name,
final String desc) { final String desc) {
mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc); if (api < Opcodes.ASM5) {
invokestatic(owner, name, desc, false);
return;
}
mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, false);
}
public void invokestatic(final String owner, final String name,
final String desc, final boolean itf) {
if (api < Opcodes.ASM5) {
if (itf) {
throw new IllegalArgumentException(
"INVOKESTATIC on interfaces require ASM 5");
}
invokestatic(owner, name, desc);
return;
}
mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, itf);
} }
public void invokeinterface(final String owner, final String name, public void invokeinterface(final String owner, final String name,
final String desc) { final String desc) {
mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, desc); mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, desc, true);
} }
public void invokedynamic(String name, String desc, Handle bsm, public void invokedynamic(String name, String desc, Handle bsm,
......
...@@ -136,11 +136,16 @@ public class JSRInlinerAdapter extends MethodNode implements Opcodes { ...@@ -136,11 +136,16 @@ public class JSRInlinerAdapter extends MethodNode implements Opcodes {
* the internal names of the method's exception classes (see * the internal names of the method's exception classes (see
* {@link Type#getInternalName() getInternalName}). May be * {@link Type#getInternalName() getInternalName}). May be
* <tt>null</tt>. * <tt>null</tt>.
* @throws IllegalStateException
* If a subclass calls this constructor.
*/ */
public JSRInlinerAdapter(final MethodVisitor mv, final int access, public JSRInlinerAdapter(final MethodVisitor mv, final int access,
final String name, final String desc, final String signature, final String name, final String desc, final String signature,
final String[] exceptions) { final String[] exceptions) {
this(Opcodes.ASM5, mv, access, name, desc, signature, exceptions); this(Opcodes.ASM5, mv, access, name, desc, signature, exceptions);
if (getClass() != JSRInlinerAdapter.class) {
throw new IllegalStateException();
}
} }
/** /**
...@@ -381,6 +386,17 @@ public class JSRInlinerAdapter extends MethodNode implements Opcodes { ...@@ -381,6 +386,17 @@ public class JSRInlinerAdapter extends MethodNode implements Opcodes {
// Use tail recursion here in the form of an outer while loop to // Use tail recursion here in the form of an outer while loop to
// avoid our stack growing needlessly: // avoid our stack growing needlessly:
index++; index++;
// We implicitly assumed above that execution can always fall
// through to the next instruction after a JSR. But a subroutine may
// never return, in which case the code after the JSR is unreachable
// and can be anything. In particular, it can seem to fall off the
// end of the method, so we must handle this case here (we could
// instead detect whether execution can return or not from a JSR,
// but this is more complicated).
if (index >= instructions.size()) {
return;
}
} }
} }
......
...@@ -120,10 +120,15 @@ public class LocalVariablesSorter extends MethodVisitor { ...@@ -120,10 +120,15 @@ public class LocalVariablesSorter extends MethodVisitor {
* the method's descriptor (see {@link Type Type}). * the method's descriptor (see {@link Type Type}).
* @param mv * @param mv
* the method visitor to which this adapter delegates calls. * the method visitor to which this adapter delegates calls.
* @throws IllegalStateException
* If a subclass calls this constructor.
*/ */
public LocalVariablesSorter(final int access, final String desc, public LocalVariablesSorter(final int access, final String desc,
final MethodVisitor mv) { final MethodVisitor mv) {
this(Opcodes.ASM5, access, desc, mv); this(Opcodes.ASM5, access, desc, mv);
if (getClass() != LocalVariablesSorter.class) {
throw new IllegalStateException();
}
} }
/** /**
...@@ -323,6 +328,7 @@ public class LocalVariablesSorter extends MethodVisitor { ...@@ -323,6 +328,7 @@ public class LocalVariablesSorter extends MethodVisitor {
int local = newLocalMapping(type); int local = newLocalMapping(type);
setLocalType(local, type); setLocalType(local, type);
setFrameLocal(local, t); setFrameLocal(local, t);
changed = true;
return local; return local;
} }
......
...@@ -148,12 +148,41 @@ public class RemappingMethodAdapter extends LocalVariablesSorter { ...@@ -148,12 +148,41 @@ public class RemappingMethodAdapter extends LocalVariablesSorter {
remapper.mapDesc(desc)); remapper.mapDesc(desc));
} }
@Deprecated
@Override @Override
public void visitMethodInsn(int opcode, String owner, String name, public void visitMethodInsn(final int opcode, final String owner,
String desc) { final String name, final String desc) {
super.visitMethodInsn(opcode, remapper.mapType(owner), if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc);
return;
}
doVisitMethodInsn(opcode, owner, name, desc,
opcode == Opcodes.INVOKEINTERFACE);
}
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc, final boolean itf) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
doVisitMethodInsn(opcode, owner, name, desc, itf);
}
private void doVisitMethodInsn(int opcode, String owner, String name,
String desc, boolean itf) {
// Calling super.visitMethodInsn requires to call the correct version
// depending on this.api (otherwise infinite loops can occur). To
// simplify and to make it easier to automatically remove the backward
// compatibility code, we inline the code of the overridden method here.
// IMPORTANT: THIS ASSUMES THAT visitMethodInsn IS NOT OVERRIDDEN IN
// LocalVariableSorter.
if (mv != null) {
mv.visitMethodInsn(opcode, remapper.mapType(owner),
remapper.mapMethodName(owner, name, desc), remapper.mapMethodName(owner, name, desc),
remapper.mapMethodDesc(desc)); remapper.mapMethodDesc(desc), itf);
}
} }
@Override @Override
......
...@@ -95,10 +95,12 @@ public class RemappingSignatureAdapter extends SignatureVisitor { ...@@ -95,10 +95,12 @@ public class RemappingSignatureAdapter extends SignatureVisitor {
@Override @Override
public void visitInnerClassType(String name) { public void visitInnerClassType(String name) {
String remappedOuter = remapper.mapType(className) + '$';
className = className + '$' + name; className = className + '$' + name;
String remappedName = remapper.mapType(className); String remappedName = remapper.mapType(className);
v.visitInnerClassType(remappedName.substring(remappedName int index = remappedName.startsWith(remappedOuter) ? remappedOuter
.lastIndexOf('$') + 1)); .length() : remappedName.lastIndexOf('$') + 1;
v.visitInnerClassType(remappedName.substring(index));
} }
@Override @Override
......
...@@ -195,9 +195,14 @@ public class SerialVersionUIDAdder extends ClassVisitor { ...@@ -195,9 +195,14 @@ public class SerialVersionUIDAdder extends ClassVisitor {
* @param cv * @param cv
* a {@link ClassVisitor} to which this visitor will delegate * a {@link ClassVisitor} to which this visitor will delegate
* calls. * calls.
* @throws IllegalStateException
* If a subclass calls this constructor.
*/ */
public SerialVersionUIDAdder(final ClassVisitor cv) { public SerialVersionUIDAdder(final ClassVisitor cv) {
this(Opcodes.ASM5, cv); this(Opcodes.ASM5, cv);
if (getClass() != SerialVersionUIDAdder.class) {
throw new IllegalStateException();
}
} }
/** /**
...@@ -218,7 +223,7 @@ public class SerialVersionUIDAdder extends ClassVisitor { ...@@ -218,7 +223,7 @@ public class SerialVersionUIDAdder extends ClassVisitor {
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Overriden methods // Overridden methods
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/* /*
...@@ -234,7 +239,7 @@ public class SerialVersionUIDAdder extends ClassVisitor { ...@@ -234,7 +239,7 @@ public class SerialVersionUIDAdder extends ClassVisitor {
if (computeSVUID) { if (computeSVUID) {
this.name = name; this.name = name;
this.access = access; this.access = access;
this.interfaces = interfaces; this.interfaces = Arrays.copyOf(interfaces, interfaces.length);
} }
super.visit(version, access, name, signature, superName, interfaces); super.visit(version, access, name, signature, superName, interfaces);
......
...@@ -107,7 +107,8 @@ public class StaticInitMerger extends ClassVisitor { ...@@ -107,7 +107,8 @@ public class StaticInitMerger extends ClassVisitor {
if (clinit == null) { if (clinit == null) {
clinit = cv.visitMethod(a, name, desc, null, null); clinit = cv.visitMethod(a, name, desc, null, null);
} }
clinit.visitMethodInsn(Opcodes.INVOKESTATIC, this.name, n, desc); clinit.visitMethodInsn(Opcodes.INVOKESTATIC, this.name, n, desc,
false);
} else { } else {
mv = cv.visitMethod(access, name, desc, signature, exceptions); mv = cv.visitMethod(access, name, desc, signature, exceptions);
} }
......
...@@ -66,7 +66,6 @@ import jdk.internal.org.objectweb.asm.MethodVisitor; ...@@ -66,7 +66,6 @@ import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.tree.MethodNode; import jdk.internal.org.objectweb.asm.tree.MethodNode;
import jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode; import jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode;
import jdk.internal.org.objectweb.asm.tree.TypeAnnotationNode;
/** /**
* A {@link MethodVisitor} adapter to sort the exception handlers. The handlers * A {@link MethodVisitor} adapter to sort the exception handlers. The handlers
......
...@@ -96,9 +96,14 @@ public class AnnotationNode extends AnnotationVisitor { ...@@ -96,9 +96,14 @@ public class AnnotationNode extends AnnotationVisitor {
* *
* @param desc * @param desc
* the class descriptor of the annotation class. * the class descriptor of the annotation class.
* @throws IllegalStateException
* If a subclass calls this constructor.
*/ */
public AnnotationNode(final String desc) { public AnnotationNode(final String desc) {
this(Opcodes.ASM5, desc); this(Opcodes.ASM5, desc);
if (getClass() != AnnotationNode.class) {
throw new IllegalStateException();
}
} }
/** /**
......
...@@ -216,9 +216,15 @@ public class ClassNode extends ClassVisitor { ...@@ -216,9 +216,15 @@ public class ClassNode extends ClassVisitor {
* Constructs a new {@link ClassNode}. <i>Subclasses must not use this * Constructs a new {@link ClassNode}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the {@link #ClassNode(int)} * constructor</i>. Instead, they must use the {@link #ClassNode(int)}
* version. * version.
*
* @throws IllegalStateException
* If a subclass calls this constructor.
*/ */
public ClassNode() { public ClassNode() {
this(Opcodes.ASM5); this(Opcodes.ASM5);
if (getClass() != ClassNode.class) {
throw new IllegalStateException();
}
} }
/** /**
......
...@@ -168,16 +168,20 @@ public class FieldNode extends FieldVisitor { ...@@ -168,16 +168,20 @@ public class FieldNode extends FieldVisitor {
* <tt>null</tt> if the field does not have an initial value, * <tt>null</tt> if the field does not have an initial value,
* must be an {@link Integer}, a {@link Float}, a {@link Long}, a * must be an {@link Integer}, a {@link Float}, a {@link Long}, a
* {@link Double} or a {@link String}. * {@link Double} or a {@link String}.
* @throws IllegalStateException
* If a subclass calls this constructor.
*/ */
public FieldNode(final int access, final String name, final String desc, public FieldNode(final int access, final String name, final String desc,
final String signature, final Object value) { final String signature, final Object value) {
this(Opcodes.ASM5, access, name, desc, signature, value); this(Opcodes.ASM5, access, name, desc, signature, value);
if (getClass() != FieldNode.class) {
throw new IllegalStateException();
}
} }
/** /**
* Constructs a new {@link FieldNode}. <i>Subclasses must not use this * Constructs a new {@link FieldNode}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the * constructor</i>.
* {@link #FieldNode(int, int, String, String, String, Object)} version.
* *
* @param api * @param api
* the ASM API version implemented by this visitor. Must be one * the ASM API version implemented by this visitor. Must be one
......
...@@ -61,6 +61,7 @@ package jdk.internal.org.objectweb.asm.tree; ...@@ -61,6 +61,7 @@ package jdk.internal.org.objectweb.asm.tree;
import java.util.Map; import java.util.Map;
import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
/** /**
* A node that represents a method instruction. A method instruction is an * A node that represents a method instruction. A method instruction is an
...@@ -86,6 +87,11 @@ public class MethodInsnNode extends AbstractInsnNode { ...@@ -86,6 +87,11 @@ public class MethodInsnNode extends AbstractInsnNode {
*/ */
public String desc; public String desc;
/**
* If the method's owner class if an interface.
*/
public boolean itf;
/** /**
* Constructs a new {@link MethodInsnNode}. * Constructs a new {@link MethodInsnNode}.
* *
...@@ -102,12 +108,37 @@ public class MethodInsnNode extends AbstractInsnNode { ...@@ -102,12 +108,37 @@ public class MethodInsnNode extends AbstractInsnNode {
* @param desc * @param desc
* the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}). * the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}).
*/ */
@Deprecated
public MethodInsnNode(final int opcode, final String owner, public MethodInsnNode(final int opcode, final String owner,
final String name, final String desc) { final String name, final String desc) {
this(opcode, owner, name, desc, opcode == Opcodes.INVOKEINTERFACE);
}
/**
* Constructs a new {@link MethodInsnNode}.
*
* @param opcode
* the opcode of the type instruction to be constructed. This
* opcode must be INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
* INVOKEINTERFACE.
* @param owner
* the internal name of the method's owner class (see
* {@link jdk.internal.org.objectweb.asm.Type#getInternalName()
* getInternalName}).
* @param name
* the method's name.
* @param desc
* the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}).
* @param itf
* if the method's owner class is an interface.
*/
public MethodInsnNode(final int opcode, final String owner,
final String name, final String desc, final boolean itf) {
super(opcode); super(opcode);
this.owner = owner; this.owner = owner;
this.name = name; this.name = name;
this.desc = desc; this.desc = desc;
this.itf = itf;
} }
/** /**
...@@ -128,11 +159,11 @@ public class MethodInsnNode extends AbstractInsnNode { ...@@ -128,11 +159,11 @@ public class MethodInsnNode extends AbstractInsnNode {
@Override @Override
public void accept(final MethodVisitor mv) { public void accept(final MethodVisitor mv) {
mv.visitMethodInsn(opcode, owner, name, desc); mv.visitMethodInsn(opcode, owner, name, desc, itf);
} }
@Override @Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) { public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new MethodInsnNode(opcode, owner, name, desc); return new MethodInsnNode(opcode, owner, name, desc, itf);
} }
} }
...@@ -71,7 +71,6 @@ import jdk.internal.org.objectweb.asm.MethodVisitor; ...@@ -71,7 +71,6 @@ import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type; import jdk.internal.org.objectweb.asm.Type;
import jdk.internal.org.objectweb.asm.TypePath; import jdk.internal.org.objectweb.asm.TypePath;
import jdk.internal.org.objectweb.asm.TypeReference;
/** /**
* A node that represents a method. * A node that represents a method.
...@@ -245,9 +244,15 @@ public class MethodNode extends MethodVisitor { ...@@ -245,9 +244,15 @@ public class MethodNode extends MethodVisitor {
* Constructs an uninitialized {@link MethodNode}. <i>Subclasses must not * Constructs an uninitialized {@link MethodNode}. <i>Subclasses must not
* use this constructor</i>. Instead, they must use the * use this constructor</i>. Instead, they must use the
* {@link #MethodNode(int)} version. * {@link #MethodNode(int)} version.
*
* @throws IllegalStateException
* If a subclass calls this constructor.
*/ */
public MethodNode() { public MethodNode() {
this(Opcodes.ASM5); this(Opcodes.ASM5);
if (getClass() != MethodNode.class) {
throw new IllegalStateException();
}
} }
/** /**
...@@ -281,10 +286,15 @@ public class MethodNode extends MethodVisitor { ...@@ -281,10 +286,15 @@ public class MethodNode extends MethodVisitor {
* the internal names of the method's exception classes (see * the internal names of the method's exception classes (see
* {@link Type#getInternalName() getInternalName}). May be * {@link Type#getInternalName() getInternalName}). May be
* <tt>null</tt>. * <tt>null</tt>.
* @throws IllegalStateException
* If a subclass calls this constructor.
*/ */
public MethodNode(final int access, final String name, final String desc, public MethodNode(final int access, final String name, final String desc,
final String signature, final String[] exceptions) { final String signature, final String[] exceptions) {
this(Opcodes.ASM5, access, name, desc, signature, exceptions); this(Opcodes.ASM5, access, name, desc, signature, exceptions);
if (getClass() != MethodNode.class) {
throw new IllegalStateException();
}
} }
/** /**
...@@ -461,12 +471,27 @@ public class MethodNode extends MethodVisitor { ...@@ -461,12 +471,27 @@ public class MethodNode extends MethodVisitor {
instructions.add(new FieldInsnNode(opcode, owner, name, desc)); instructions.add(new FieldInsnNode(opcode, owner, name, desc));
} }
@Deprecated
@Override @Override
public void visitMethodInsn(final int opcode, final String owner, public void visitMethodInsn(int opcode, String owner, String name,
final String name, final String desc) { String desc) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc);
return;
}
instructions.add(new MethodInsnNode(opcode, owner, name, desc)); instructions.add(new MethodInsnNode(opcode, owner, name, desc));
} }
@Override
public void visitMethodInsn(int opcode, String owner, String name,
String desc, boolean itf) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
instructions.add(new MethodInsnNode(opcode, owner, name, desc, itf));
}
@Override @Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
Object... bsmArgs) { Object... bsmArgs) {
...@@ -696,6 +721,12 @@ public class MethodNode extends MethodVisitor { ...@@ -696,6 +721,12 @@ public class MethodNode extends MethodVisitor {
&& insn.invisibleTypeAnnotations.size() > 0) { && insn.invisibleTypeAnnotations.size() > 0) {
throw new RuntimeException(); throw new RuntimeException();
} }
if (insn instanceof MethodInsnNode) {
boolean itf = ((MethodInsnNode) insn).itf;
if (itf != (insn.opcode == Opcodes.INVOKEINTERFACE)) {
throw new RuntimeException();
}
}
} }
if (visibleLocalVariableAnnotations != null if (visibleLocalVariableAnnotations != null
&& visibleLocalVariableAnnotations.size() > 0) { && visibleLocalVariableAnnotations.size() > 0) {
...@@ -705,7 +736,6 @@ public class MethodNode extends MethodVisitor { ...@@ -705,7 +736,6 @@ public class MethodNode extends MethodVisitor {
&& invisibleLocalVariableAnnotations.size() > 0) { && invisibleLocalVariableAnnotations.size() > 0) {
throw new RuntimeException(); throw new RuntimeException();
} }
} }
} }
......
...@@ -94,10 +94,15 @@ public class TypeAnnotationNode extends AnnotationNode { ...@@ -94,10 +94,15 @@ public class TypeAnnotationNode extends AnnotationNode {
* <tt>null</tt> if the annotation targets 'typeRef' as a whole. * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* @param desc * @param desc
* the class descriptor of the annotation class. * the class descriptor of the annotation class.
* @throws IllegalStateException
* If a subclass calls this constructor.
*/ */
public TypeAnnotationNode(final int typeRef, final TypePath typePath, public TypeAnnotationNode(final int typeRef, final TypePath typePath,
final String desc) { final String desc) {
this(Opcodes.ASM5, typeRef, typePath, desc); this(Opcodes.ASM5, typeRef, typePath, desc);
if (getClass() != TypeAnnotationNode.class) {
throw new IllegalStateException();
}
} }
/** /**
......
...@@ -162,6 +162,15 @@ public class Frame<V extends Value> { ...@@ -162,6 +162,15 @@ public class Frame<V extends Value> {
return locals; return locals;
} }
/**
* Returns the maximum stack size of this frame.
*
* @return the maximum stack size of this frame.
*/
public int getMaxStackSize() {
return values.length - locals;
}
/** /**
* Returns the value of the given local variable. * Returns the value of the given local variable.
* *
......
...@@ -113,9 +113,15 @@ public class ASMifier extends Printer { ...@@ -113,9 +113,15 @@ public class ASMifier extends Printer {
* Constructs a new {@link ASMifier}. <i>Subclasses must not use this * Constructs a new {@link ASMifier}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the * constructor</i>. Instead, they must use the
* {@link #ASMifier(int, String, int)} version. * {@link #ASMifier(int, String, int)} version.
*
* @throws IllegalStateException
* If a subclass calls this constructor.
*/ */
public ASMifier() { public ASMifier() {
this(Opcodes.ASM5, "cw", 0); this(Opcodes.ASM5, "cw", 0);
if (getClass() != ASMifier.class) {
throw new IllegalStateException();
}
} }
/** /**
...@@ -483,8 +489,9 @@ public class ASMifier extends Printer { ...@@ -483,8 +489,9 @@ public class ASMifier extends Printer {
@Override @Override
public void visitParameter(String parameterName, int access) { public void visitParameter(String parameterName, int access) {
buf.setLength(0); buf.setLength(0);
buf.append(name).append(".visitParameter(").append(parameterName) buf.append(name).append(".visitParameter(");
.append(", "); appendString(buf, parameterName);
buf.append(", ");
appendAccess(access); appendAccess(access);
text.add(buf.append(");\n").toString()); text.add(buf.append(");\n").toString());
} }
...@@ -639,9 +646,30 @@ public class ASMifier extends Printer { ...@@ -639,9 +646,30 @@ public class ASMifier extends Printer {
text.add(buf.toString()); text.add(buf.toString());
} }
@Deprecated
@Override @Override
public void visitMethodInsn(final int opcode, final String owner, public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc) { final String name, final String desc) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc);
return;
}
doVisitMethodInsn(opcode, owner, name, desc,
opcode == Opcodes.INVOKEINTERFACE);
}
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc, final boolean itf) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
doVisitMethodInsn(opcode, owner, name, desc, itf);
}
private void doVisitMethodInsn(final int opcode, final String owner,
final String name, final String desc, final boolean itf) {
buf.setLength(0); buf.setLength(0);
buf.append(this.name).append(".visitMethodInsn(") buf.append(this.name).append(".visitMethodInsn(")
.append(OPCODES[opcode]).append(", "); .append(OPCODES[opcode]).append(", ");
...@@ -650,6 +678,8 @@ public class ASMifier extends Printer { ...@@ -650,6 +678,8 @@ public class ASMifier extends Printer {
appendConstant(name); appendConstant(name);
buf.append(", "); buf.append(", ");
appendConstant(desc); appendConstant(desc);
buf.append(", ");
buf.append(itf ? "true" : "false");
buf.append(");\n"); buf.append(");\n");
text.add(buf.toString()); text.add(buf.toString());
} }
...@@ -1076,6 +1106,13 @@ public class ASMifier extends Printer { ...@@ -1076,6 +1106,13 @@ public class ASMifier extends Printer {
buf.append("ACC_DEPRECATED"); buf.append("ACC_DEPRECATED");
first = false; first = false;
} }
if ((access & Opcodes.ACC_MANDATED) != 0) {
if (!first) {
buf.append(" + ");
}
buf.append("ACC_MANDATED");
first = false;
}
if (first) { if (first) {
buf.append('0'); buf.append('0');
} }
......
...@@ -246,7 +246,7 @@ public class CheckClassAdapter extends ClassVisitor { ...@@ -246,7 +246,7 @@ public class CheckClassAdapter extends ClassVisitor {
List<Type> interfaces = new ArrayList<Type>(); List<Type> interfaces = new ArrayList<Type>();
for (Iterator<String> i = cn.interfaces.iterator(); i.hasNext();) { for (Iterator<String> i = cn.interfaces.iterator(); i.hasNext();) {
interfaces.add(Type.getObjectType(i.next().toString())); interfaces.add(Type.getObjectType(i.next()));
} }
for (int i = 0; i < methods.size(); ++i) { for (int i = 0; i < methods.size(); ++i) {
...@@ -359,9 +359,14 @@ public class CheckClassAdapter extends ClassVisitor { ...@@ -359,9 +359,14 @@ public class CheckClassAdapter extends ClassVisitor {
* <tt>false</tt> to not perform any data flow check (see * <tt>false</tt> to not perform any data flow check (see
* {@link CheckMethodAdapter}). This option requires valid * {@link CheckMethodAdapter}). This option requires valid
* maxLocals and maxStack values. * maxLocals and maxStack values.
* @throws IllegalStateException
* If a subclass calls this constructor.
*/ */
public CheckClassAdapter(final ClassVisitor cv, final boolean checkDataFlow) { public CheckClassAdapter(final ClassVisitor cv, final boolean checkDataFlow) {
this(Opcodes.ASM5, cv, checkDataFlow); this(Opcodes.ASM5, cv, checkDataFlow);
if (getClass() != CheckClassAdapter.class) {
throw new IllegalStateException();
}
} }
/** /**
...@@ -471,7 +476,15 @@ public class CheckClassAdapter extends ClassVisitor { ...@@ -471,7 +476,15 @@ public class CheckClassAdapter extends ClassVisitor {
CheckMethodAdapter.checkInternalName(outerName, "outer class name"); CheckMethodAdapter.checkInternalName(outerName, "outer class name");
} }
if (innerName != null) { if (innerName != null) {
CheckMethodAdapter.checkIdentifier(innerName, "inner class name"); int start = 0;
while (start < innerName.length()
&& Character.isDigit(innerName.charAt(start))) {
start++;
}
if (start == 0 || start < innerName.length()) {
CheckMethodAdapter.checkIdentifier(innerName, start, -1,
"inner class name");
}
} }
checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE
+ Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
......
...@@ -79,9 +79,14 @@ public class CheckFieldAdapter extends FieldVisitor { ...@@ -79,9 +79,14 @@ public class CheckFieldAdapter extends FieldVisitor {
* *
* @param fv * @param fv
* the field visitor to which this adapter must delegate calls. * the field visitor to which this adapter must delegate calls.
* @throws IllegalStateException
* If a subclass calls this constructor.
*/ */
public CheckFieldAdapter(final FieldVisitor fv) { public CheckFieldAdapter(final FieldVisitor fv) {
this(Opcodes.ASM5, fv); this(Opcodes.ASM5, fv);
if (getClass() != CheckFieldAdapter.class) {
throw new IllegalStateException();
}
} }
/** /**
......
...@@ -142,11 +142,6 @@ public class CheckMethodAdapter extends MethodVisitor { ...@@ -142,11 +142,6 @@ public class CheckMethodAdapter extends MethodVisitor {
*/ */
private Set<Label> usedLabels; private Set<Label> usedLabels;
/**
* If an explicit first frame has been visited before the first instruction.
*/
private boolean hasExplicitFirstFrame;
/** /**
* Number of visited frames in expanded form. * Number of visited frames in expanded form.
*/ */
...@@ -157,6 +152,11 @@ public class CheckMethodAdapter extends MethodVisitor { ...@@ -157,6 +152,11 @@ public class CheckMethodAdapter extends MethodVisitor {
*/ */
private int compressedFrames; private int compressedFrames;
/**
* Number of instructions before the last visited frame.
*/
private int lastFrame = -1;
/** /**
* The exception handler ranges. Each pair of list element contains the * The exception handler ranges. Each pair of list element contains the
* start and end labels of an exception handler block. * start and end labels of an exception handler block.
...@@ -421,10 +421,15 @@ public class CheckMethodAdapter extends MethodVisitor { ...@@ -421,10 +421,15 @@ public class CheckMethodAdapter extends MethodVisitor {
* the method visitor to which this adapter must delegate calls. * the method visitor to which this adapter must delegate calls.
* @param labels * @param labels
* a map of already visited labels (in other methods). * a map of already visited labels (in other methods).
* @throws IllegalStateException
* If a subclass calls this constructor.
*/ */
public CheckMethodAdapter(final MethodVisitor mv, public CheckMethodAdapter(final MethodVisitor mv,
final Map<Label, Integer> labels) { final Map<Label, Integer> labels) {
this(Opcodes.ASM5, mv, labels); this(Opcodes.ASM5, mv, labels);
if (getClass() != CheckMethodAdapter.class) {
throw new IllegalStateException();
}
} }
/** /**
...@@ -465,7 +470,7 @@ public class CheckMethodAdapter extends MethodVisitor { ...@@ -465,7 +470,7 @@ public class CheckMethodAdapter extends MethodVisitor {
public CheckMethodAdapter(final int access, final String name, public CheckMethodAdapter(final int access, final String name,
final String desc, final MethodVisitor cmv, final String desc, final MethodVisitor cmv,
final Map<Label, Integer> labels) { final Map<Label, Integer> labels) {
this(new MethodNode(access, name, desc, null, null) { this(new MethodNode(Opcodes.ASM5, access, name, desc, null, null) {
@Override @Override
public void visitEnd() { public void visitEnd() {
Analyzer<BasicValue> a = new Analyzer<BasicValue>( Analyzer<BasicValue> a = new Analyzer<BasicValue>(
...@@ -499,6 +504,7 @@ public class CheckMethodAdapter extends MethodVisitor { ...@@ -499,6 +504,7 @@ public class CheckMethodAdapter extends MethodVisitor {
} }
CheckClassAdapter.checkAccess(access, Opcodes.ACC_FINAL CheckClassAdapter.checkAccess(access, Opcodes.ACC_FINAL
+ Opcodes.ACC_MANDATED + Opcodes.ACC_SYNTHETIC); + Opcodes.ACC_MANDATED + Opcodes.ACC_SYNTHETIC);
super.visitParameter(name, access);
} }
@Override @Override
...@@ -566,6 +572,11 @@ public class CheckMethodAdapter extends MethodVisitor { ...@@ -566,6 +572,11 @@ public class CheckMethodAdapter extends MethodVisitor {
@Override @Override
public void visitFrame(final int type, final int nLocal, public void visitFrame(final int type, final int nLocal,
final Object[] local, final int nStack, final Object[] stack) { final Object[] local, final int nStack, final Object[] stack) {
if (insnCount == lastFrame) {
throw new IllegalStateException(
"At most one frame can be visited at a given code location.");
}
lastFrame = insnCount;
int mLocal; int mLocal;
int mStack; int mStack;
switch (type) { switch (type) {
...@@ -621,13 +632,6 @@ public class CheckMethodAdapter extends MethodVisitor { ...@@ -621,13 +632,6 @@ public class CheckMethodAdapter extends MethodVisitor {
checkFrameValue(stack[i]); checkFrameValue(stack[i]);
} }
if (type == Opcodes.F_NEW) { if (type == Opcodes.F_NEW) {
if (insnCount == 0) {
hasExplicitFirstFrame = true;
} else if (!hasExplicitFirstFrame) {
throw new RuntimeException(
"In expanded form, a first frame must be explicitly "
+ "visited before the first instruction.");
}
++expandedFrames; ++expandedFrames;
} else { } else {
++compressedFrames; ++compressedFrames;
...@@ -709,9 +713,30 @@ public class CheckMethodAdapter extends MethodVisitor { ...@@ -709,9 +713,30 @@ public class CheckMethodAdapter extends MethodVisitor {
++insnCount; ++insnCount;
} }
@Deprecated
@Override @Override
public void visitMethodInsn(final int opcode, final String owner, public void visitMethodInsn(int opcode, String owner, String name,
final String name, final String desc) { String desc) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc);
return;
}
doVisitMethodInsn(opcode, owner, name, desc,
opcode == Opcodes.INVOKEINTERFACE);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name,
String desc, boolean itf) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
doVisitMethodInsn(opcode, owner, name, desc, itf);
}
private void doVisitMethodInsn(int opcode, final String owner,
final String name, final String desc, final boolean itf) {
checkStartCode(); checkStartCode();
checkEndCode(); checkEndCode();
checkOpcode(opcode, 5); checkOpcode(opcode, 5);
...@@ -720,7 +745,21 @@ public class CheckMethodAdapter extends MethodVisitor { ...@@ -720,7 +745,21 @@ public class CheckMethodAdapter extends MethodVisitor {
} }
checkInternalName(owner, "owner"); checkInternalName(owner, "owner");
checkMethodDesc(desc); checkMethodDesc(desc);
super.visitMethodInsn(opcode, owner, name, desc); if (opcode == Opcodes.INVOKEVIRTUAL && itf) {
throw new IllegalArgumentException(
"INVOKEVIRTUAL can't be used with interfaces");
}
if (opcode == Opcodes.INVOKEINTERFACE && !itf) {
throw new IllegalArgumentException(
"INVOKEINTERFACE can't be used with classes");
}
// Calling super.visitMethodInsn requires to call the correct version
// depending on this.api (otherwise infinite loops can occur). To
// simplify and to make it easier to automatically remove the backward
// compatibility code, we inline the code of the overridden method here.
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc, itf);
}
++insnCount; ++insnCount;
} }
......
...@@ -401,8 +401,33 @@ public abstract class Printer { ...@@ -401,8 +401,33 @@ public abstract class Printer {
* Method instruction. See * Method instruction. See
* {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMethodInsn}. * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMethodInsn}.
*/ */
public abstract void visitMethodInsn(final int opcode, final String owner, @Deprecated
final String name, final String desc); public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc) {
if (api >= Opcodes.ASM5) {
boolean itf = opcode == Opcodes.INVOKEINTERFACE;
visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
throw new RuntimeException("Must be overriden");
}
/**
* Method instruction. See
* {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMethodInsn}.
*/
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc, final 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;
}
throw new RuntimeException("Must be overriden");
}
/** /**
* Method instruction. See * Method instruction. See
......
...@@ -172,9 +172,15 @@ public class Textifier extends Printer { ...@@ -172,9 +172,15 @@ public class Textifier extends Printer {
* Constructs a new {@link Textifier}. <i>Subclasses must not use this * Constructs a new {@link Textifier}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the {@link #Textifier(int)} * constructor</i>. Instead, they must use the {@link #Textifier(int)}
* version. * version.
*
* @throws IllegalStateException
* If a subclass calls this constructor.
*/ */
public Textifier() { public Textifier() {
this(Opcodes.ASM5); this(Opcodes.ASM5);
if (getClass() != Textifier.class) {
throw new IllegalStateException();
}
} }
/** /**
...@@ -821,14 +827,36 @@ public class Textifier extends Printer { ...@@ -821,14 +827,36 @@ public class Textifier extends Printer {
text.add(buf.toString()); text.add(buf.toString());
} }
@Deprecated
@Override @Override
public void visitMethodInsn(final int opcode, final String owner, public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc) { final String name, final String desc) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc);
return;
}
doVisitMethodInsn(opcode, owner, name, desc,
opcode == Opcodes.INVOKEINTERFACE);
}
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc, final boolean itf) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
doVisitMethodInsn(opcode, owner, name, desc, itf);
}
private void doVisitMethodInsn(final int opcode, final String owner,
final String name, final String desc, final boolean itf) {
buf.setLength(0); buf.setLength(0);
buf.append(tab2).append(OPCODES[opcode]).append(' '); buf.append(tab2).append(OPCODES[opcode]).append(' ');
appendDescriptor(INTERNAL_NAME, owner); appendDescriptor(INTERNAL_NAME, owner);
buf.append('.').append(name).append(' '); buf.append('.').append(name).append(' ');
appendDescriptor(METHOD_DESCRIPTOR, desc); appendDescriptor(METHOD_DESCRIPTOR, desc);
buf.append(' ').append(itf ? "itf" : "");
buf.append('\n'); buf.append('\n');
text.add(buf.toString()); text.add(buf.toString());
} }
......
...@@ -176,11 +176,31 @@ public final class TraceMethodVisitor extends MethodVisitor { ...@@ -176,11 +176,31 @@ public final class TraceMethodVisitor extends MethodVisitor {
super.visitFieldInsn(opcode, owner, name, desc); super.visitFieldInsn(opcode, owner, name, desc);
} }
@Deprecated
@Override @Override
public void visitMethodInsn(final int opcode, final String owner, public void visitMethodInsn(int opcode, String owner, String name,
final String name, final String desc) { String desc) {
p.visitMethodInsn(opcode, owner, name, desc); if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc); super.visitMethodInsn(opcode, owner, name, desc);
return;
}
p.visitMethodInsn(opcode, owner, name, desc);
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc);
}
}
@Override
public void visitMethodInsn(int opcode, String owner, String name,
String desc, boolean itf) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
p.visitMethodInsn(opcode, owner, name, desc, itf);
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc, itf);
}
} }
@Override @Override
......
Path: . Path: .
Working Copy Root Path: /w/lthudson/hudson-data/jobs/objectweb-cr-pull/workspace/ASM_5_FUTURE Working Copy Root Path: /hudson/jobs/objectweb-pull/workspace/ASM_5_0_BETA
URL: svn://svn.forge.objectweb.org/svnroot/asm/branches/ASM_5_FUTURE URL: svn://svn.forge.objectweb.org/svnroot/asm/trunk/asm
Repository Root: svn://svn.forge.objectweb.org/svnroot/asm Repository Root: svn://svn.forge.objectweb.org/svnroot/asm
Repository UUID: 271bd773-ee82-43a6-9b2b-1890ed8ce7f9 Repository UUID: 271bd773-ee82-43a6-9b2b-1890ed8ce7f9
Revision: 1681 Revision: 1700
Node Kind: directory Node Kind: directory
Schedule: normal Schedule: normal
Last Changed Author: forax Last Changed Author: ebruneton
Last Changed Rev: 1681 Last Changed Rev: 1700
Last Changed Date: 2013-04-01 11:28:58 -0700 (Mon, 01 Apr 2013) Last Changed Date: 2013-10-29 20:22:52 +0100 (Tue, 29 Oct 2013)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册