提交 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 {
* automatically enlarged if necessary.
*
* @param s
* a String.
* a String whose UTF8 encoded length must be less than 65536.
* @return this byte vector.
*/
public ByteVector putUTF8(final String s) {
int charLength = s.length();
if (charLength > 65535) {
throw new IllegalArgumentException();
}
int len = length;
if (len + 2 + charLength > data.length) {
enlarge(2 + charLength);
......@@ -267,6 +270,9 @@ public class ByteVector {
byteLength += 2;
}
}
if (byteLength > 65535) {
throw new IllegalArgumentException();
}
data[length] = (byte) (byteLength >>> 8);
data[length + 1] = (byte) byteLength;
if (length + 2 + byteLength > data.length) {
......
......@@ -1266,7 +1266,7 @@ public class ClassReader {
u += 2;
// 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
* but only offset_delta; setting the implicit frame offset to -1
......@@ -1283,8 +1283,6 @@ public class ClassReader {
if (unzip) {
getImplicitFrame(context);
}
}
if (FRAMES && stackMap != 0) {
/*
* Finds labels for UNINITIALIZED frame types. Instead of decoding
* each element of the stack map table, we look for 3 consecutive
......@@ -1322,17 +1320,19 @@ public class ClassReader {
}
}
// visits the frame(s) for this offset, if any
// visits the frame for this offset, if any
while (FRAMES && frame != null
&& (frame.offset == offset || frame.offset == -1)) {
// if there is a frame for this offset, makes the visitor visit
// it, and reads the next frame if there is one.
if (!zip || unzip) {
mv.visitFrame(Opcodes.F_NEW, frame.localCount, frame.local,
frame.stackCount, frame.stack);
} else if (frame.offset != -1) {
mv.visitFrame(frame.mode, frame.localDiff, frame.local,
frame.stackCount, frame.stack);
if (frame.offset != -1) {
if (!zip || unzip) {
mv.visitFrame(Opcodes.F_NEW, frame.localCount,
frame.local, frame.stackCount, frame.stack);
} else {
mv.visitFrame(frame.mode, frame.localDiff, frame.local,
frame.stackCount, frame.stack);
}
}
if (frameCount > 0) {
stackMap = readFrame(stackMap, zip, unzip, frame);
......@@ -1434,6 +1434,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);
......@@ -1441,7 +1442,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;
......
......@@ -516,12 +516,12 @@ public class ClassWriter extends ClassVisitor {
* <tt>true</tt> if the maximum stack size and number of local variables
* must be automatically computed.
*/
private final boolean computeMaxs;
private boolean computeMaxs;
/**
* <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
......@@ -988,9 +988,22 @@ public class ClassWriter extends ClassVisitor {
attrs.put(this, null, 0, -1, -1, out);
}
if (invalidFrames) {
ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
new ClassReader(out.data).accept(cw, ClassReader.SKIP_FRAMES);
return cw.toByteArray();
anns = null;
ianns = null;
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;
}
......
......@@ -78,7 +78,8 @@ public final class Handle {
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;
......@@ -105,8 +106,8 @@ public final class Handle {
* {@link Opcodes#H_NEWINVOKESPECIAL} or
* {@link Opcodes#H_INVOKEINTERFACE}.
* @param owner
* 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.
* @param name
* the name of the field or method designated by this handle.
* @param desc
......@@ -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() {
return owner;
......
......@@ -68,11 +68,11 @@ package jdk.internal.org.objectweb.asm;
* <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<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,
* 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
......@@ -274,13 +274,9 @@ public abstract class MethodVisitor {
* compressed form (all frames must use the same format, i.e. you must not
* mix expanded and compressed frames within a single method):
* <ul>
* <li>In expanded form, all frames must have the F_NEW type, and a first
* frame corresponding to the method signature must be explicitly visited
* before the first instruction.</li>
* <li>In expanded form, all frames must have the F_NEW type.</li>
* <li>In compressed form, frames are basically "deltas" from the state of
* the previous frame (the first frame, corresponding to the method's
* parameters and access flags, is implicit in this form, and must not be
* visited):
* the previous frame:
* <ul>
* <li>{@link Opcodes#F_SAME} representing frame with exactly the same
* locals as the previous frame and with the empty stack.</li>
......@@ -296,8 +292,14 @@ public abstract class MethodVisitor {
* 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>
* </ul></li>
* </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
* the type of this stack map frame. Must be
......@@ -466,13 +468,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.
*
......
......@@ -71,7 +71,7 @@ class MethodWriter extends MethodVisitor {
/**
* 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
......@@ -297,11 +297,6 @@ class MethodWriter extends MethodVisitor {
*/
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
* instruction to which the frame corresponds, the second element is the
......@@ -496,6 +491,9 @@ class MethodWriter extends MethodVisitor {
cw.lastMethod = this;
this.cw = cw;
this.access = access;
if ("<init>".equals(name)) {
this.access |= ACC_CONSTRUCTOR;
}
this.name = cw.newUTF8(name);
this.desc = cw.newUTF8(desc);
this.descriptor = desc;
......@@ -511,9 +509,6 @@ class MethodWriter extends MethodVisitor {
}
this.compute = computeFrames ? FRAMES : (computeMaxs ? MAXS : NOTHING);
if (computeMaxs || computeFrames) {
if (computeFrames && "<init>".equals(name)) {
this.access |= ACC_CONSTRUCTOR;
}
// updates maxLocals
int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
if ((access & Opcodes.ACC_STATIC) != 0) {
......@@ -649,8 +644,11 @@ class MethodWriter extends MethodVisitor {
}
if (type == Opcodes.F_NEW) {
if (previousFrame == null) {
visitImplicitFirstFrame();
}
currentLocals = nLocal;
startFrame(code.length, nLocal, nStack);
int frameIndex = startFrame(code.length, nLocal, nStack);
for (int i = 0; i < nLocal; ++i) {
if (local[i] instanceof String) {
frame[frameIndex++] = Frame.OBJECT
......@@ -914,9 +912,8 @@ class MethodWriter extends MethodVisitor {
@Override
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;
boolean itf = opcode == Opcodes.INVOKEINTERFACE;
Item i = cw.newMethodItem(owner, name, desc, itf);
int argSize = i.intVal;
// Label currentBlock = this.currentBlock;
......@@ -954,7 +951,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;
......@@ -1528,8 +1525,8 @@ class MethodWriter extends MethodVisitor {
}
code.data[end] = (byte) Opcodes.ATHROW;
// emits a frame for this unreachable block
startFrame(start, 0, 1);
frame[frameIndex++] = Frame.OBJECT
int frameIndex = startFrame(start, 0, 1);
frame[frameIndex] = Frame.OBJECT
| cw.addType("java/lang/Throwable");
endFrame();
// removes the start-end range from the exception
......@@ -1756,7 +1753,7 @@ class MethodWriter extends MethodVisitor {
}
}
// 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) {
t = locals[i];
frame[frameIndex++] = t;
......@@ -1774,6 +1771,67 @@ class MethodWriter extends MethodVisitor {
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.
*
......@@ -1783,8 +1841,9 @@ class MethodWriter extends MethodVisitor {
* the number of local variables in the frame.
* @param nStack
* 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;
if (frame == null || frame.length < n) {
frame = new int[n];
......@@ -1792,7 +1851,7 @@ class MethodWriter extends MethodVisitor {
frame[0] = offset;
frame[1] = nLocal;
frame[2] = nStack;
frameIndex = 3;
return 3;
}
/**
......@@ -2110,7 +2169,8 @@ class MethodWriter extends MethodVisitor {
*/
final void put(final ByteVector out) {
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);
out.putShort(access & ~mask).putShort(name).putShort(desc);
if (classReaderOffset != 0) {
......
......@@ -442,10 +442,31 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
}
}
@Deprecated
@Override
public void visitMethodInsn(final int opcode, final String owner,
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) {
Type[] types = Type.getArgumentTypes(desc);
for (int i = 0; i < types.length; i++) {
......
......@@ -165,10 +165,15 @@ public class AnalyzerAdapter extends MethodVisitor {
* @param mv
* the method visitor to which this adapter delegates calls. May
* be <tt>null</tt>.
* @throws IllegalStateException
* If a subclass calls this constructor.
*/
public AnalyzerAdapter(final String owner, final int access,
final String name, final String desc, final MethodVisitor 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 {
execute(opcode, 0, desc);
}
@Deprecated
@Override
public void visitMethodInsn(final int opcode, final String owner,
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) {
mv.visitMethodInsn(opcode, owner, name, desc);
mv.visitMethodInsn(opcode, owner, name, desc, itf);
}
if (this.locals == null) {
labels = null;
......
......@@ -149,9 +149,30 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
}
}
@Deprecated
@Override
public void visitMethodInsn(final int opcode, final String owner,
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) {
minSize += 5;
maxSize += 5;
......@@ -160,7 +181,7 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
maxSize += 3;
}
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 {
* the method's name.
* @param desc
* the method's descriptor (see {@link Type Type}).
* @throws IllegalStateException
* If a subclass calls this constructor.
*/
public GeneratorAdapter(final MethodVisitor mv, final int access,
final String name, final String desc) {
this(Opcodes.ASM5, mv, access, name, desc);
if (getClass() != GeneratorAdapter.class) {
throw new IllegalStateException();
}
}
/**
......@@ -1400,11 +1405,11 @@ public class GeneratorAdapter extends LocalVariablesSorter {
* the method to be invoked.
*/
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()
: type.getInternalName();
mv.visitMethodInsn(opcode, owner, method.getName(),
method.getDescriptor());
method.getDescriptor(), itf);
}
/**
......@@ -1416,7 +1421,7 @@ public class GeneratorAdapter extends LocalVariablesSorter {
* the method to be invoked.
*/
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 {
* the constructor to be invoked.
*/
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 {
* the method to be invoked.
*/
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 {
* the method to be invoked.
*/
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 {
*
* @param mv
* the method visitor to which this adapter delegates calls.
* @throws IllegalStateException
* If a subclass calls this constructor.
*/
public InstructionAdapter(final MethodVisitor mv) {
this(Opcodes.ASM5, mv);
if (getClass() != InstructionAdapter.class) {
throw new IllegalStateException();
}
}
/**
......@@ -536,18 +541,39 @@ public class InstructionAdapter extends MethodVisitor {
}
}
@Deprecated
@Override
public void visitMethodInsn(final int opcode, final String owner,
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) {
case Opcodes.INVOKESPECIAL:
invokespecial(owner, name, desc);
invokespecial(owner, name, desc, itf);
break;
case Opcodes.INVOKEVIRTUAL:
invokevirtual(owner, name, desc);
invokevirtual(owner, name, desc, itf);
break;
case Opcodes.INVOKESTATIC:
invokestatic(owner, name, desc);
invokestatic(owner, name, desc, itf);
break;
case Opcodes.INVOKEINTERFACE:
invokeinterface(owner, name, desc);
......@@ -1014,24 +1040,78 @@ public class InstructionAdapter extends MethodVisitor {
mv.visitFieldInsn(Opcodes.PUTFIELD, owner, name, desc);
}
@Deprecated
public void invokevirtual(final String owner, final String name,
final String desc) {
if (api >= Opcodes.ASM5) {
invokevirtual(owner, name, desc, false);
return;
}
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,
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,
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,
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,
......
......@@ -136,11 +136,16 @@ public class JSRInlinerAdapter extends MethodNode implements Opcodes {
* the internal names of the method's exception classes (see
* {@link Type#getInternalName() getInternalName}). May be
* <tt>null</tt>.
* @throws IllegalStateException
* If a subclass calls this constructor.
*/
public JSRInlinerAdapter(final MethodVisitor mv, final int access,
final String name, final String desc, final String signature,
final String[] 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 {
// Use tail recursion here in the form of an outer while loop to
// avoid our stack growing needlessly:
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 {
* the method's descriptor (see {@link Type Type}).
* @param mv
* 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,
final MethodVisitor mv) {
this(Opcodes.ASM5, access, desc, mv);
if (getClass() != LocalVariablesSorter.class) {
throw new IllegalStateException();
}
}
/**
......@@ -323,6 +328,7 @@ public class LocalVariablesSorter extends MethodVisitor {
int local = newLocalMapping(type);
setLocalType(local, type);
setFrameLocal(local, t);
changed = true;
return local;
}
......
......@@ -148,12 +148,41 @@ public class RemappingMethodAdapter extends LocalVariablesSorter {
remapper.mapDesc(desc));
}
@Deprecated
@Override
public void visitMethodInsn(int opcode, String owner, String name,
String desc) {
super.visitMethodInsn(opcode, remapper.mapType(owner),
remapper.mapMethodName(owner, name, desc),
remapper.mapMethodDesc(desc));
public void visitMethodInsn(final int opcode, final String owner,
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, 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.mapMethodDesc(desc), itf);
}
}
@Override
......
......@@ -95,10 +95,12 @@ public class RemappingSignatureAdapter extends SignatureVisitor {
@Override
public void visitInnerClassType(String name) {
String remappedOuter = remapper.mapType(className) + '$';
className = className + '$' + name;
String remappedName = remapper.mapType(className);
v.visitInnerClassType(remappedName.substring(remappedName
.lastIndexOf('$') + 1));
int index = remappedName.startsWith(remappedOuter) ? remappedOuter
.length() : remappedName.lastIndexOf('$') + 1;
v.visitInnerClassType(remappedName.substring(index));
}
@Override
......
......@@ -195,9 +195,14 @@ public class SerialVersionUIDAdder extends ClassVisitor {
* @param cv
* a {@link ClassVisitor} to which this visitor will delegate
* calls.
* @throws IllegalStateException
* If a subclass calls this constructor.
*/
public SerialVersionUIDAdder(final ClassVisitor cv) {
this(Opcodes.ASM5, cv);
if (getClass() != SerialVersionUIDAdder.class) {
throw new IllegalStateException();
}
}
/**
......@@ -218,7 +223,7 @@ public class SerialVersionUIDAdder extends ClassVisitor {
}
// ------------------------------------------------------------------------
// Overriden methods
// Overridden methods
// ------------------------------------------------------------------------
/*
......@@ -234,7 +239,7 @@ public class SerialVersionUIDAdder extends ClassVisitor {
if (computeSVUID) {
this.name = name;
this.access = access;
this.interfaces = interfaces;
this.interfaces = Arrays.copyOf(interfaces, interfaces.length);
}
super.visit(version, access, name, signature, superName, interfaces);
......
......@@ -107,7 +107,8 @@ public class StaticInitMerger extends ClassVisitor {
if (clinit == 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 {
mv = cv.visitMethod(access, name, desc, signature, exceptions);
}
......
......@@ -66,7 +66,6 @@ import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.tree.MethodNode;
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
......
......@@ -96,9 +96,14 @@ public class AnnotationNode extends AnnotationVisitor {
*
* @param desc
* the class descriptor of the annotation class.
* @throws IllegalStateException
* If a subclass calls this constructor.
*/
public AnnotationNode(final String desc) {
this(Opcodes.ASM5, desc);
if (getClass() != AnnotationNode.class) {
throw new IllegalStateException();
}
}
/**
......
......@@ -216,9 +216,15 @@ public class ClassNode extends ClassVisitor {
* Constructs a new {@link ClassNode}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the {@link #ClassNode(int)}
* version.
*
* @throws IllegalStateException
* If a subclass calls this constructor.
*/
public ClassNode() {
this(Opcodes.ASM5);
if (getClass() != ClassNode.class) {
throw new IllegalStateException();
}
}
/**
......
......@@ -168,16 +168,20 @@ public class FieldNode extends FieldVisitor {
* <tt>null</tt> if the field does not have an initial value,
* must be an {@link Integer}, a {@link Float}, a {@link Long}, a
* {@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,
final String signature, final Object 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
* constructor</i>. Instead, they must use the
* {@link #FieldNode(int, int, String, String, String, Object)} version.
* constructor</i>.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
......
......@@ -61,6 +61,7 @@ package jdk.internal.org.objectweb.asm.tree;
import java.util.Map;
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
......@@ -86,6 +87,11 @@ public class MethodInsnNode extends AbstractInsnNode {
*/
public String desc;
/**
* If the method's owner class if an interface.
*/
public boolean itf;
/**
* Constructs a new {@link MethodInsnNode}.
*
......@@ -102,12 +108,37 @@ public class MethodInsnNode extends AbstractInsnNode {
* @param desc
* the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}).
*/
@Deprecated
public MethodInsnNode(final int opcode, final String owner,
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);
this.owner = owner;
this.name = name;
this.desc = desc;
this.itf = itf;
}
/**
......@@ -128,11 +159,11 @@ public class MethodInsnNode extends AbstractInsnNode {
@Override
public void accept(final MethodVisitor mv) {
mv.visitMethodInsn(opcode, owner, name, desc);
mv.visitMethodInsn(opcode, owner, name, desc, itf);
}
@Override
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;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type;
import jdk.internal.org.objectweb.asm.TypePath;
import jdk.internal.org.objectweb.asm.TypeReference;
/**
* A node that represents a method.
......@@ -245,9 +244,15 @@ public class MethodNode extends MethodVisitor {
* Constructs an uninitialized {@link MethodNode}. <i>Subclasses must not
* use this constructor</i>. Instead, they must use the
* {@link #MethodNode(int)} version.
*
* @throws IllegalStateException
* If a subclass calls this constructor.
*/
public MethodNode() {
this(Opcodes.ASM5);
if (getClass() != MethodNode.class) {
throw new IllegalStateException();
}
}
/**
......@@ -281,10 +286,15 @@ public class MethodNode extends MethodVisitor {
* the internal names of the method's exception classes (see
* {@link Type#getInternalName() getInternalName}). May be
* <tt>null</tt>.
* @throws IllegalStateException
* If a subclass calls this constructor.
*/
public MethodNode(final int access, final String name, final String desc,
final String signature, final String[] 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 {
instructions.add(new FieldInsnNode(opcode, owner, name, desc));
}
@Deprecated
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc) {
public void visitMethodInsn(int opcode, String owner, String name,
String desc) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc);
return;
}
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
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
Object... bsmArgs) {
......@@ -696,6 +721,12 @@ public class MethodNode extends MethodVisitor {
&& insn.invisibleTypeAnnotations.size() > 0) {
throw new RuntimeException();
}
if (insn instanceof MethodInsnNode) {
boolean itf = ((MethodInsnNode) insn).itf;
if (itf != (insn.opcode == Opcodes.INVOKEINTERFACE)) {
throw new RuntimeException();
}
}
}
if (visibleLocalVariableAnnotations != null
&& visibleLocalVariableAnnotations.size() > 0) {
......@@ -705,7 +736,6 @@ public class MethodNode extends MethodVisitor {
&& invisibleLocalVariableAnnotations.size() > 0) {
throw new RuntimeException();
}
}
}
......
......@@ -94,10 +94,15 @@ public class TypeAnnotationNode extends AnnotationNode {
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* @param desc
* the class descriptor of the annotation class.
* @throws IllegalStateException
* If a subclass calls this constructor.
*/
public TypeAnnotationNode(final int typeRef, final TypePath typePath,
final String desc) {
this(Opcodes.ASM5, typeRef, typePath, desc);
if (getClass() != TypeAnnotationNode.class) {
throw new IllegalStateException();
}
}
/**
......
......@@ -162,6 +162,15 @@ public class Frame<V extends Value> {
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.
*
......
......@@ -113,9 +113,15 @@ public class ASMifier extends Printer {
* Constructs a new {@link ASMifier}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the
* {@link #ASMifier(int, String, int)} version.
*
* @throws IllegalStateException
* If a subclass calls this constructor.
*/
public ASMifier() {
this(Opcodes.ASM5, "cw", 0);
if (getClass() != ASMifier.class) {
throw new IllegalStateException();
}
}
/**
......@@ -483,8 +489,9 @@ public class ASMifier extends Printer {
@Override
public void visitParameter(String parameterName, int access) {
buf.setLength(0);
buf.append(name).append(".visitParameter(").append(parameterName)
.append(", ");
buf.append(name).append(".visitParameter(");
appendString(buf, parameterName);
buf.append(", ");
appendAccess(access);
text.add(buf.append(");\n").toString());
}
......@@ -639,9 +646,30 @@ public class ASMifier extends Printer {
text.add(buf.toString());
}
@Deprecated
@Override
public void visitMethodInsn(final int opcode, final String owner,
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.append(this.name).append(".visitMethodInsn(")
.append(OPCODES[opcode]).append(", ");
......@@ -650,6 +678,8 @@ public class ASMifier extends Printer {
appendConstant(name);
buf.append(", ");
appendConstant(desc);
buf.append(", ");
buf.append(itf ? "true" : "false");
buf.append(");\n");
text.add(buf.toString());
}
......@@ -1076,6 +1106,13 @@ public class ASMifier extends Printer {
buf.append("ACC_DEPRECATED");
first = false;
}
if ((access & Opcodes.ACC_MANDATED) != 0) {
if (!first) {
buf.append(" + ");
}
buf.append("ACC_MANDATED");
first = false;
}
if (first) {
buf.append('0');
}
......
......@@ -246,7 +246,7 @@ public class CheckClassAdapter extends ClassVisitor {
List<Type> interfaces = new ArrayList<Type>();
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) {
......@@ -359,9 +359,14 @@ public class CheckClassAdapter extends ClassVisitor {
* <tt>false</tt> to not perform any data flow check (see
* {@link CheckMethodAdapter}). This option requires valid
* maxLocals and maxStack values.
* @throws IllegalStateException
* If a subclass calls this constructor.
*/
public CheckClassAdapter(final ClassVisitor cv, final boolean checkDataFlow) {
this(Opcodes.ASM5, cv, checkDataFlow);
if (getClass() != CheckClassAdapter.class) {
throw new IllegalStateException();
}
}
/**
......@@ -471,7 +476,15 @@ public class CheckClassAdapter extends ClassVisitor {
CheckMethodAdapter.checkInternalName(outerName, "outer class name");
}
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
+ Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
......
......@@ -79,9 +79,14 @@ public class CheckFieldAdapter extends FieldVisitor {
*
* @param fv
* the field visitor to which this adapter must delegate calls.
* @throws IllegalStateException
* If a subclass calls this constructor.
*/
public CheckFieldAdapter(final FieldVisitor fv) {
this(Opcodes.ASM5, fv);
if (getClass() != CheckFieldAdapter.class) {
throw new IllegalStateException();
}
}
/**
......
......@@ -142,11 +142,6 @@ public class CheckMethodAdapter extends MethodVisitor {
*/
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.
*/
......@@ -157,6 +152,11 @@ public class CheckMethodAdapter extends MethodVisitor {
*/
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
* start and end labels of an exception handler block.
......@@ -421,10 +421,15 @@ public class CheckMethodAdapter extends MethodVisitor {
* the method visitor to which this adapter must delegate calls.
* @param labels
* a map of already visited labels (in other methods).
* @throws IllegalStateException
* If a subclass calls this constructor.
*/
public CheckMethodAdapter(final MethodVisitor mv,
final Map<Label, Integer> labels) {
this(Opcodes.ASM5, mv, labels);
if (getClass() != CheckMethodAdapter.class) {
throw new IllegalStateException();
}
}
/**
......@@ -465,7 +470,7 @@ public class CheckMethodAdapter extends MethodVisitor {
public CheckMethodAdapter(final int access, final String name,
final String desc, final MethodVisitor cmv,
final Map<Label, Integer> labels) {
this(new MethodNode(access, name, desc, null, null) {
this(new MethodNode(Opcodes.ASM5, access, name, desc, null, null) {
@Override
public void visitEnd() {
Analyzer<BasicValue> a = new Analyzer<BasicValue>(
......@@ -499,6 +504,7 @@ public class CheckMethodAdapter extends MethodVisitor {
}
CheckClassAdapter.checkAccess(access, Opcodes.ACC_FINAL
+ Opcodes.ACC_MANDATED + Opcodes.ACC_SYNTHETIC);
super.visitParameter(name, access);
}
@Override
......@@ -566,6 +572,11 @@ public class CheckMethodAdapter extends MethodVisitor {
@Override
public void visitFrame(final int type, final int nLocal,
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 mStack;
switch (type) {
......@@ -621,13 +632,6 @@ public class CheckMethodAdapter extends MethodVisitor {
checkFrameValue(stack[i]);
}
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;
} else {
++compressedFrames;
......@@ -709,9 +713,30 @@ public class CheckMethodAdapter extends MethodVisitor {
++insnCount;
}
@Deprecated
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc) {
public void visitMethodInsn(int opcode, String owner, String name,
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();
checkEndCode();
checkOpcode(opcode, 5);
......@@ -720,7 +745,21 @@ public class CheckMethodAdapter extends MethodVisitor {
}
checkInternalName(owner, "owner");
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;
}
......
......@@ -401,8 +401,33 @@ public abstract class Printer {
* Method instruction. See
* {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMethodInsn}.
*/
public abstract void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc);
@Deprecated
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
......
......@@ -172,9 +172,15 @@ public class Textifier extends Printer {
* Constructs a new {@link Textifier}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the {@link #Textifier(int)}
* version.
*
* @throws IllegalStateException
* If a subclass calls this constructor.
*/
public Textifier() {
this(Opcodes.ASM5);
if (getClass() != Textifier.class) {
throw new IllegalStateException();
}
}
/**
......@@ -821,14 +827,36 @@ public class Textifier extends Printer {
text.add(buf.toString());
}
@Deprecated
@Override
public void visitMethodInsn(final int opcode, final String owner,
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.append(tab2).append(OPCODES[opcode]).append(' ');
appendDescriptor(INTERNAL_NAME, owner);
buf.append('.').append(name).append(' ');
appendDescriptor(METHOD_DESCRIPTOR, desc);
buf.append(' ').append(itf ? "itf" : "");
buf.append('\n');
text.add(buf.toString());
}
......
......@@ -176,11 +176,31 @@ public final class TraceMethodVisitor extends MethodVisitor {
super.visitFieldInsn(opcode, owner, name, desc);
}
@Deprecated
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc) {
public void visitMethodInsn(int opcode, String owner, String name,
String desc) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc);
return;
}
p.visitMethodInsn(opcode, owner, name, desc);
super.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
......
Path: .
Working Copy Root Path: /w/lthudson/hudson-data/jobs/objectweb-cr-pull/workspace/ASM_5_FUTURE
URL: svn://svn.forge.objectweb.org/svnroot/asm/branches/ASM_5_FUTURE
Working Copy Root Path: /hudson/jobs/objectweb-pull/workspace/ASM_5_0_BETA
URL: svn://svn.forge.objectweb.org/svnroot/asm/trunk/asm
Repository Root: svn://svn.forge.objectweb.org/svnroot/asm
Repository UUID: 271bd773-ee82-43a6-9b2b-1890ed8ce7f9
Revision: 1681
Revision: 1700
Node Kind: directory
Schedule: normal
Last Changed Author: forax
Last Changed Rev: 1681
Last Changed Date: 2013-04-01 11:28:58 -0700 (Mon, 01 Apr 2013)
Last Changed Author: ebruneton
Last Changed Rev: 1700
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.
先完成此消息的编辑!
想要评论请 注册