summaryrefslogtreecommitdiffstats
path: root/src/main
diff options
context:
space:
mode:
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>2012-10-04 07:37:39 +0000
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>2012-10-04 07:37:39 +0000
commit5a4853ee87743b72a5a0c1486f3af4ce04ae8774 (patch)
treeb90b93aa0e098efc2fd3a0df4a2c1cd6ee07e8f5 /src/main
parentc3329e418ee0a8eea563ace2fd483630527a1080 (diff)
downloadjavassist-5a4853ee87743b72a5a0c1486f3af4ce04ae8774.tar.gz
javassist-5a4853ee87743b72a5a0c1486f3af4ce04ae8774.zip
fixed JASSIST-174
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@669 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
Diffstat (limited to 'src/main')
-rw-r--r--src/main/javassist/CtBehavior.java5
-rw-r--r--src/main/javassist/bytecode/AttributeInfo.java2
-rw-r--r--src/main/javassist/bytecode/BootstrapMethodsAttribute.java123
-rw-r--r--src/main/javassist/bytecode/Bytecode.java21
-rw-r--r--src/main/javassist/bytecode/CodeAnalyzer.java4
-rw-r--r--src/main/javassist/bytecode/CodeAttribute.java7
-rw-r--r--src/main/javassist/bytecode/CodeIterator.java19
-rw-r--r--src/main/javassist/bytecode/ConstPool.java356
-rw-r--r--src/main/javassist/bytecode/InstructionPrinter.java4
-rw-r--r--src/main/javassist/bytecode/MethodInfo.java6
-rw-r--r--src/main/javassist/bytecode/Mnemonic.java5
-rw-r--r--src/main/javassist/bytecode/Opcode.java3
-rw-r--r--src/main/javassist/bytecode/StackMapTable.java4
-rw-r--r--src/main/javassist/bytecode/analysis/Executor.java19
-rw-r--r--src/main/javassist/bytecode/stackmap/Tracer.java19
15 files changed, 581 insertions, 16 deletions
diff --git a/src/main/javassist/CtBehavior.java b/src/main/javassist/CtBehavior.java
index 06873e2c..1ca8408b 100644
--- a/src/main/javassist/CtBehavior.java
+++ b/src/main/javassist/CtBehavior.java
@@ -26,6 +26,11 @@ import javassist.expr.ExprEditor;
* or a static constructor (class initializer).
* It is the abstract super class of
* <code>CtMethod</code> and <code>CtConstructor</code>.
+ *
+ * <p>To directly read or modify bytecode, obtain <code>MethodInfo</code>
+ * objects.
+ *
+ * @see #getMethodInfo()
*/
public abstract class CtBehavior extends CtMember {
protected MethodInfo methodInfo;
diff --git a/src/main/javassist/bytecode/AttributeInfo.java b/src/main/javassist/bytecode/AttributeInfo.java
index a6cbc09b..2cf878eb 100644
--- a/src/main/javassist/bytecode/AttributeInfo.java
+++ b/src/main/javassist/bytecode/AttributeInfo.java
@@ -77,6 +77,8 @@ public class AttributeInfo {
if (nameStr.charAt(0) < 'L') {
if (nameStr.equals(AnnotationDefaultAttribute.tag))
return new AnnotationDefaultAttribute(cp, name, in);
+ else if (nameStr.equals(BootstrapMethodsAttribute.tag))
+ return new BootstrapMethodsAttribute(cp, name, in);
else if (nameStr.equals(CodeAttribute.tag))
return new CodeAttribute(cp, name, in);
else if (nameStr.equals(ConstantAttribute.tag))
diff --git a/src/main/javassist/bytecode/BootstrapMethodsAttribute.java b/src/main/javassist/bytecode/BootstrapMethodsAttribute.java
new file mode 100644
index 00000000..98268b87
--- /dev/null
+++ b/src/main/javassist/bytecode/BootstrapMethodsAttribute.java
@@ -0,0 +1,123 @@
+package javassist.bytecode;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.Map;
+
+public class BootstrapMethodsAttribute extends AttributeInfo {
+ /**
+ * The name of this attribute <code>"BootstrapMethods"</code>.
+ */
+ public static final String tag = "BootstrapMethods";
+
+ /**
+ * An element of <code>bootstrap_methods</code>.
+ */
+ public static class BootstrapMethod {
+ /**
+ * Constructs an element of <code>bootstrap_methods</code>.
+ *
+ * @param method <code>bootstrap_method_ref</code>.
+ * @param args <code>bootstrap_arguments</code>.
+ */
+ public BootstrapMethod(int method, int[] args) {
+ methodRef = method;
+ arguments = args;
+ }
+
+ /**
+ * <code>bootstrap_method_ref</code>.
+ * The value at this index must be a <code>CONSTANT_MethodHandle_info</code>.
+ */
+ public int methodRef;
+
+ /**
+ * <code>bootstrap_arguments</code>.
+ */
+ public int[] arguments;
+ }
+
+ BootstrapMethodsAttribute(ConstPool cp, int n, DataInputStream in)
+ throws IOException
+ {
+ super(cp, n, in);
+ }
+
+ /**
+ * Constructs a BootstrapMethods attribute.
+ *
+ * @param cp a constant pool table.
+ * @param methods the contents.
+ */
+ public BootstrapMethodsAttribute(ConstPool cp, BootstrapMethod[] methods) {
+ super(cp, tag);
+ int size = 2;
+ for (int i = 0; i < methods.length; i++)
+ size += 4 + methods[i].arguments.length * 2;
+
+ byte[] data = new byte[size];
+ ByteArray.write16bit(methods.length, data, 0); // num_bootstrap_methods
+ int pos = 2;
+ for (int i = 0; i < methods.length; i++) {
+ ByteArray.write16bit(methods[i].methodRef, data, pos);
+ ByteArray.write16bit(methods[i].arguments.length, data, pos + 2);
+ int[] args = methods[i].arguments;
+ pos += 4;
+ for (int k = 0; k < args.length; k++) {
+ ByteArray.write16bit(args[k], data, pos);
+ pos += 2;
+ }
+ }
+
+ set(data);
+ }
+
+ /**
+ * Obtains <code>bootstrap_methods</code> in this attribute.
+ *
+ * @return an array of <code>BootstrapMethod</code>. Since it
+ * is a fresh copy, modifying the returned array does not
+ * affect the original contents of this attribute.
+ */
+ public BootstrapMethod[] getMethods() {
+ byte[] data = this.get();
+ int num = ByteArray.readU16bit(data, 0);
+ BootstrapMethod[] methods = new BootstrapMethod[num];
+ int pos = 2;
+ for (int i = 0; i < num; i++) {
+ int ref = ByteArray.readU16bit(data, pos);
+ int len = ByteArray.readU16bit(data, pos + 2);
+ int[] args = new int[len];
+ pos += 4;
+ for (int k = 0; k < len; k++) {
+ args[k] = ByteArray.readU16bit(data, pos);
+ pos += 2;
+ }
+
+ methods[i] = new BootstrapMethod(ref, args);
+ }
+
+ return methods;
+ }
+
+ /**
+ * Makes a copy. Class names are replaced according to the
+ * given <code>Map</code> object.
+ *
+ * @param newCp the constant pool table used by the new copy.
+ * @param classnames pairs of replaced and substituted
+ * class names.
+ */
+ public AttributeInfo copy(ConstPool newCp, Map classnames) {
+ BootstrapMethod[] methods = getMethods();
+ ConstPool thisCp = getConstPool();
+ for (int i = 0; i < methods.length; i++) {
+ BootstrapMethod m = methods[i];
+ m.methodRef = thisCp.copy(m.methodRef, newCp, classnames);
+ for (int k = 0; k < m.arguments.length; k++)
+ m.arguments[k] = thisCp.copy(m.arguments[k], newCp, classnames);
+ }
+
+ return new BootstrapMethodsAttribute(newCp, methods);
+ }
+}
diff --git a/src/main/javassist/bytecode/Bytecode.java b/src/main/javassist/bytecode/Bytecode.java
index 9991a332..bea7b6fa 100644
--- a/src/main/javassist/bytecode/Bytecode.java
+++ b/src/main/javassist/bytecode/Bytecode.java
@@ -1083,7 +1083,7 @@ public class Bytecode extends ByteVector implements Cloneable, Opcode {
public void addInvokevirtual(int clazz, String name, String desc) {
add(INVOKEVIRTUAL);
addIndex(constPool.addMethodrefInfo(clazz, name, desc));
- growStack(Descriptor.dataSize(desc) - 1);
+ growStack(Descriptor.dataSize(desc)); // assume CosntPool#REF_invokeStatic
}
/**
@@ -1155,6 +1155,25 @@ public class Bytecode extends ByteVector implements Cloneable, Opcode {
}
/**
+ * Appends INVOKEDYNAMIC.
+ *
+ * @param bootstrap an index into the <code>bootstrap_methods</code> array
+ * of the bootstrap method table.
+ * @param name the method name.
+ * @param desc the method descriptor.
+ * @see Descriptor#ofMethod(CtClass,CtClass[])
+ * @since 3.17
+ */
+ public void addInvokedynamic(int bootstrap, String name, String desc) {
+ int nt = constPool.addNameAndTypeInfo(name, desc);
+ int dyn = constPool.addInvokeDynamicInfo(bootstrap, nt);
+ add(INVOKEDYNAMIC);
+ addIndex(dyn);
+ add(0, 0);
+ growStack(Descriptor.dataSize(desc) - 1);
+ }
+
+ /**
* Appends LDC or LDC_W. The pushed item is a <code>String</code>
* object.
*
diff --git a/src/main/javassist/bytecode/CodeAnalyzer.java b/src/main/javassist/bytecode/CodeAnalyzer.java
index f8766764..d02fb19e 100644
--- a/src/main/javassist/bytecode/CodeAnalyzer.java
+++ b/src/main/javassist/bytecode/CodeAnalyzer.java
@@ -240,6 +240,10 @@ class CodeAnalyzer implements Opcode {
ci.u16bitAt(index + 1));
stack += Descriptor.dataSize(desc) - 1;
break;
+ case INVOKEDYNAMIC :
+ desc = constPool.getInvokeDynamicType(ci.u16bitAt(index + 1));
+ stack += Descriptor.dataSize(desc); // assume CosntPool#REF_invokeStatic
+ break;
case ATHROW :
stack = 1; // the stack becomes empty (1 means no values).
break;
diff --git a/src/main/javassist/bytecode/CodeAttribute.java b/src/main/javassist/bytecode/CodeAttribute.java
index fc4b1d1e..dbf714e7 100644
--- a/src/main/javassist/bytecode/CodeAttribute.java
+++ b/src/main/javassist/bytecode/CodeAttribute.java
@@ -32,6 +32,7 @@ import java.util.Map;
* use <code>CodeIterator</code>.
*
* @see CodeIterator
+ * @see #iterator()
*/
public class CodeAttribute extends AttributeInfo implements Opcode {
/**
@@ -400,6 +401,12 @@ public class CodeAttribute extends AttributeInfo implements Opcode {
newcode[i + 3] = code[i + 3];
newcode[i + 4] = code[i + 4];
break;
+ case INVOKEDYNAMIC :
+ copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp,
+ classnameMap);
+ newcode[i + 3] = 0;
+ newcode[i + 4] = 0;
+ break;
case MULTIANEWARRAY :
copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp,
classnameMap);
diff --git a/src/main/javassist/bytecode/CodeIterator.java b/src/main/javassist/bytecode/CodeIterator.java
index 68abd55a..0c5db6ff 100644
--- a/src/main/javassist/bytecode/CodeIterator.java
+++ b/src/main/javassist/bytecode/CodeIterator.java
@@ -21,6 +21,16 @@ import java.util.ArrayList;
/**
* An iterator for editing a code attribute.
*
+ * <p>To directly read or edit a bytecode sequence, call {@link #byteAt(int)}, {@link #s16bitAt(int)},
+ * {@link #writeByte(int, int)}, {@link #write16bit(int, int)}, and other methods.
+ * For example, if <code>method</code> refers to a <code>CtMethod</code> object,
+ * the following code substitutes the <code>NOP</code> instruction for the first
+ * instruction of the method:
+ *
+ * <pre>CodeAttribute ca = method.getMethodInfo().getCodeAttribute();
+ * CodeIterator ci = ca.iterator();
+ * ci.writeByte(Opcode.NOP, 0);</pre>
+ *
* <p>If there are multiple <code>CodeIterator</code>s referring to the
* same <code>Code_attribute</code>, then inserting a gap by one
* <code>CodeIterator</code> will break the other
@@ -725,11 +735,10 @@ public class CodeIterator implements Opcode {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3,
- // 3, 3, 3, 3, 3, 5, 5, 3, 2, 3, 1, 1, 3, 3, 1, 1, 0, 4, 3, 3,
- 3, 3, 3, 3, 3, 5, 0, 3, 2, 3, 1, 1, 3, 3, 1, 1, 0, 4, 3, 3,
+ 3, 3, 3, 3, 3, 5, 5, 3, 2, 3, 1, 1, 3, 3, 1, 1, 0, 4, 3, 3,
5, 5
};
- // 0 .. UNUSED (186), LOOKUPSWITCH, TABLESWITCH, WIDE
+ // 0 .. LOOKUPSWITCH, TABLESWITCH, WIDE
/**
* Calculates the index of the next opcode.
@@ -1496,7 +1505,9 @@ public class CodeIterator implements Opcode {
int padding = 3 - (pos & 3);
int nops = gap - padding;
int bytecodeSize = 5 + (3 - (orgPos & 3)) + tableSize();
- adjustOffsets(bytecodeSize, nops);
+ if (nops > 0)
+ adjustOffsets(bytecodeSize, nops);
+
newcode[dest++] = code[src];
while (padding-- > 0)
newcode[dest++] = 0;
diff --git a/src/main/javassist/bytecode/ConstPool.java b/src/main/javassist/bytecode/ConstPool.java
index 27124ac1..f1024216 100644
--- a/src/main/javassist/bytecode/ConstPool.java
+++ b/src/main/javassist/bytecode/ConstPool.java
@@ -94,11 +94,61 @@ public final class ConstPool {
public static final int CONST_Utf8 = Utf8Info.tag;
/**
+ * <code>Cosnt_MethodHandle</code>
+ */
+ public static final int CONST_MethodHandle = MethodHandleInfo.tag;
+
+ /**
* Represents the class using this constant pool table.
*/
public static final CtClass THIS = null;
/**
+ * <code>reference_kind</code> of <code>CONSTANT_MethodHandle_info</code>.
+ */
+ public static final int REF_getField = 1;
+
+ /**
+ * <code>reference_kind</code> of <code>CONSTANT_MethodHandle_info</code>.
+ */
+ public static final int REF_getStatic = 2;
+
+ /**
+ * <code>reference_kind</code> of <code>CONSTANT_MethodHandle_info</code>.
+ */
+ public static final int REF_putField = 3;
+
+ /**
+ * <code>reference_kind</code> of <code>CONSTANT_MethodHandle_info</code>.
+ */
+ public static final int REF_putStatic = 4;
+
+ /**
+ * <code>reference_kind</code> of <code>CONSTANT_MethodHandle_info</code>.
+ */
+ public static final int REF_invokeVirtual = 5;
+
+ /**
+ * <code>reference_kind</code> of <code>CONSTANT_MethodHandle_info</code>.
+ */
+ public static final int REF_invokeStatic = 6;
+
+ /**
+ * <code>reference_kind</code> of <code>CONSTANT_MethodHandle_info</code>.
+ */
+ public static final int REF_invokeSpecial = 7;
+
+ /**
+ * <code>reference_kind</code> of <code>CONSTANT_MethodHandle_info</code>.
+ */
+ public static final int REF_newInvokeSpecial = 8;
+
+ /**
+ * <code>reference_kind</code> of <code>CONSTANT_MethodHandle_info</code>.
+ */
+ public static final int REF_invokeInterface = 9;
+
+ /**
* Constructs a constant pool table.
*
* @param thisclass the name of the class using this constant
@@ -589,6 +639,97 @@ public final class ConstPool {
}
/**
+ * Reads the <code>reference_kind</code> field of the
+ * <code>CONSTANT_MethodHandle_info</code> structure
+ * at the given index.
+ *
+ * @see #REF_getField
+ * @see #REF_getStatic
+ * @see #REF_invokeInterface
+ * @see #REF_invokeSpecial
+ * @see #REF_invokeStatic
+ * @see #REF_invokeVirtual
+ * @see #REF_newInvokeSpecial
+ * @see #REF_putField
+ * @see #REF_putStatic
+ * @since 3.17
+ */
+ public int getMethodHandleKind(int index) {
+ MethodHandleInfo mhinfo = (MethodHandleInfo)getItem(index);
+ return mhinfo.refKind;
+ }
+
+ /**
+ * Reads the <code>reference_index</code> field of the
+ * <code>CONSTANT_MethodHandle_info</code> structure
+ * at the given index.
+ *
+ * @since 3.17
+ */
+ public int getMethodHandleIndex(int index) {
+ MethodHandleInfo mhinfo = (MethodHandleInfo)getItem(index);
+ return mhinfo.refIndex;
+ }
+
+ /**
+ * Reads the <code>descriptor_index</code> field of the
+ * <code>CONSTANT_MethodType_info</code> structure
+ * at the given index.
+ *
+ * @since 3.17
+ */
+ public int getMethodTypeInfo(int index) {
+ MethodTypeInfo mtinfo = (MethodTypeInfo)getItem(index);
+ return mtinfo.descriptor;
+ }
+
+ /**
+ * Reads the <code>bootstrap_method_attr_index</code> field of the
+ * <code>CONSTANT_InvokeDynamic_info</code> structure
+ * at the given index.
+ *
+ * @since 3.17
+ */
+ public int getInvokeDynamicBootstrap(int index) {
+ InvokeDynamicInfo iv = (InvokeDynamicInfo)getItem(index);
+ return iv.bootstrap;
+ }
+
+ /**
+ * Reads the <code>name_and_type_index</code> field of the
+ * <code>CONSTANT_InvokeDynamic_info</code> structure
+ * at the given index.
+ *
+ * @since 3.17
+ */
+ public int getInvokeDynamicNameAndType(int index) {
+ InvokeDynamicInfo iv = (InvokeDynamicInfo)getItem(index);
+ return iv.nameAndType;
+ }
+
+ /**
+ * Reads the <code>descriptor_index</code> field of the
+ * <code>CONSTANT_NameAndType_info</code> structure
+ * indirectly specified by the given index.
+ *
+ * @param index an index to a <code>CONSTANT_InvokeDynamic_info</code>.
+ * @return the descriptor of the method.
+ * @since 3.17
+ */
+ public String getInvokeDynamicType(int index) {
+ InvokeDynamicInfo iv = (InvokeDynamicInfo)getItem(index);
+ if (iv == null)
+ return null;
+ else {
+ NameAndTypeInfo n = (NameAndTypeInfo)getItem(iv.nameAndType);
+ if(n == null)
+ return null;
+ else
+ return getUtf8Info(n.typeDescriptor);
+ }
+ }
+
+ /**
* Determines whether <code>CONSTANT_Methodref_info</code>
* structure at the given index represents the constructor
* of the given class.
@@ -927,6 +1068,48 @@ public final class ConstPool {
}
/**
+ * Adds a new <code>CONSTANT_MethodHandle_info</code>
+ * structure.
+ *
+ * @param kind <code>reference_kind</code>
+ * such as {@link #REF_invokeStatic <code>REF_invokeStatic</code>}.
+ * @param index <code>reference_index</code>.
+ * @return the index of the added entry.
+ *
+ * @since 3.17
+ */
+ public int addMethodHandleInfo(int kind, int index) {
+ return addItem(new MethodHandleInfo(kind, index, numOfItems));
+ }
+
+ /**
+ * Adds a new <code>CONSTANT_MethodType_info</code>
+ * structure.
+ *
+ * @param desc <code>descriptor_index</code>.
+ * @return the index of the added entry.
+ *
+ * @since 3.17
+ */
+ public int addMethodTypeInfo(int desc) {
+ return addItem(new MethodTypeInfo(desc, numOfItems));
+ }
+
+ /**
+ * Adds a new <code>CONSTANT_InvokeDynamic_info</code>
+ * structure.
+ *
+ * @param bootstrap <code>bootstrap_method_attr_index</code>.
+ * @param nameAndType <code>name_and_type_index</code>.
+ * @return the index of the added entry.
+ *
+ * @since 3.17
+ */
+ public int addInvokeDynamicInfo(int bootstrap, int nameAndType) {
+ return addItem(new InvokeDynamicInfo(bootstrap, nameAndType, numOfItems));
+ }
+
+ /**
* Get all the class names.
*
* @return a set of class names (<code>String</code> objects).
@@ -1040,6 +1223,15 @@ public final class ConstPool {
case NameAndTypeInfo.tag : // 12
info = new NameAndTypeInfo(in, numOfItems);
break;
+ case MethodHandleInfo.tag : // 15
+ info = new MethodHandleInfo(in, numOfItems);
+ break;
+ case MethodTypeInfo.tag : // 16
+ info = new MethodTypeInfo(in, numOfItems);
+ break;
+ case InvokeDynamicInfo.tag : // 18
+ info = new InvokeDynamicInfo(in, numOfItems);
+ break;
default :
throw new IOException("invalid constant type: " + tag + " at " + numOfItems);
}
@@ -1632,3 +1824,167 @@ class Utf8Info extends ConstInfo {
out.println("\"");
}
}
+
+class MethodHandleInfo extends ConstInfo {
+ static final int tag = 15;
+ int refKind, refIndex;
+
+ public MethodHandleInfo(int kind, int referenceIndex, int index) {
+ super(index);
+ refKind = kind;
+ refIndex = referenceIndex;
+ }
+
+ public MethodHandleInfo(DataInputStream in, int index) throws IOException {
+ super(index);
+ refKind = in.readUnsignedByte();
+ refIndex = in.readUnsignedShort();
+ }
+
+ public int hashCode() { return (refKind << 16) ^ refIndex; }
+
+ public boolean equals(Object obj) {
+ if (obj instanceof MethodHandleInfo) {
+ MethodHandleInfo mh = (MethodHandleInfo)obj;
+ return mh.refKind == refKind && mh.refIndex == refIndex;
+ }
+ else
+ return false;
+ }
+
+ public int getTag() { return tag; }
+
+ public int copy(ConstPool src, ConstPool dest, Map map) {
+ return dest.addMethodHandleInfo(refKind,
+ src.getItem(refIndex).copy(src, dest, map));
+ }
+
+ public void write(DataOutputStream out) throws IOException {
+ out.writeByte(tag);
+ out.writeByte(refKind);
+ out.writeShort(refIndex);
+ }
+
+ public void print(PrintWriter out) {
+ out.print("MethodHandle #");
+ out.print(refKind);
+ out.print(", index #");
+ out.println(refIndex);
+ }
+}
+
+class MethodTypeInfo extends ConstInfo {
+ static final int tag = 16;
+ int descriptor;
+
+ public MethodTypeInfo(int desc, int index) {
+ super(index);
+ descriptor = desc;
+ }
+
+ public MethodTypeInfo(DataInputStream in, int index) throws IOException {
+ super(index);
+ descriptor = in.readUnsignedShort();
+ }
+
+ public int hashCode() { return descriptor; }
+
+ public boolean equals(Object obj) {
+ if (obj instanceof MethodTypeInfo)
+ return ((MethodTypeInfo)obj).descriptor == descriptor;
+ else
+ return false;
+ }
+
+ public int getTag() { return tag; }
+
+ public void renameClass(ConstPool cp, String oldName, String newName, HashMap cache) {
+ String desc = cp.getUtf8Info(descriptor);
+ String desc2 = Descriptor.rename(desc, oldName, newName);
+ if (desc != desc2)
+ if (cache == null)
+ descriptor = cp.addUtf8Info(desc2);
+ else {
+ cache.remove(this);
+ descriptor = cp.addUtf8Info(desc2);
+ cache.put(this, this);
+ }
+ }
+
+ public void renameClass(ConstPool cp, Map map, HashMap cache) {
+ String desc = cp.getUtf8Info(descriptor);
+ String desc2 = Descriptor.rename(desc, map);
+ if (desc != desc2)
+ if (cache == null)
+ descriptor = cp.addUtf8Info(desc2);
+ else {
+ cache.remove(this);
+ descriptor = cp.addUtf8Info(desc2);
+ cache.put(this, this);
+ }
+ }
+
+ public int copy(ConstPool src, ConstPool dest, Map map) {
+ String desc = src.getUtf8Info(descriptor);
+ desc = Descriptor.rename(desc, map);
+ return dest.addMethodTypeInfo(dest.addUtf8Info(desc));
+ }
+
+ public void write(DataOutputStream out) throws IOException {
+ out.writeByte(tag);
+ out.writeShort(descriptor);
+ }
+
+ public void print(PrintWriter out) {
+ out.print("MethodType #");
+ out.println(descriptor);
+ }
+}
+
+class InvokeDynamicInfo extends ConstInfo {
+ static final int tag = 18;
+ int bootstrap, nameAndType;
+
+ public InvokeDynamicInfo(int bootstrapMethod, int ntIndex, int index) {
+ super(index);
+ bootstrap = bootstrapMethod;
+ nameAndType = ntIndex;
+ }
+
+ public InvokeDynamicInfo(DataInputStream in, int index) throws IOException {
+ super(index);
+ bootstrap = in.readUnsignedShort();
+ nameAndType = in.readUnsignedShort();
+ }
+
+ public int hashCode() { return (bootstrap << 16) ^ nameAndType; }
+
+ public boolean equals(Object obj) {
+ if (obj instanceof InvokeDynamicInfo) {
+ InvokeDynamicInfo iv = (InvokeDynamicInfo)obj;
+ return iv.bootstrap == bootstrap && iv.nameAndType == nameAndType;
+ }
+ else
+ return false;
+ }
+
+ public int getTag() { return tag; }
+
+ public int copy(ConstPool src, ConstPool dest, Map map) {
+ return dest.addInvokeDynamicInfo(bootstrap,
+ src.getItem(nameAndType).copy(src, dest, map));
+ }
+
+ public void write(DataOutputStream out) throws IOException {
+ out.writeByte(tag);
+ out.writeShort(bootstrap);
+ out.writeShort(nameAndType);
+ }
+
+ public void print(PrintWriter out) {
+ out.print("InvokeDynamic #");
+ out.print(bootstrap);
+ out.print(", name&type #");
+ out.println(nameAndType);
+ }
+}
diff --git a/src/main/javassist/bytecode/InstructionPrinter.java b/src/main/javassist/bytecode/InstructionPrinter.java
index c02767d9..12f74d5b 100644
--- a/src/main/javassist/bytecode/InstructionPrinter.java
+++ b/src/main/javassist/bytecode/InstructionPrinter.java
@@ -137,8 +137,8 @@ public class InstructionPrinter implements Opcode {
return opstring + " " + methodInfo(pool, iter.u16bitAt(pos + 1));
case INVOKEINTERFACE:
return opstring + " " + interfaceMethodInfo(pool, iter.u16bitAt(pos + 1));
- case 186:
- throw new RuntimeException("Bad opcode 186");
+ case INVOKEDYNAMIC:
+ return opstring + " " + iter.u16bitAt(pos + 1);
case NEW:
return opstring + " " + classInfo(pool, iter.u16bitAt(pos + 1));
case NEWARRAY:
diff --git a/src/main/javassist/bytecode/MethodInfo.java b/src/main/javassist/bytecode/MethodInfo.java
index 411e5549..4ca4e90d 100644
--- a/src/main/javassist/bytecode/MethodInfo.java
+++ b/src/main/javassist/bytecode/MethodInfo.java
@@ -27,7 +27,12 @@ import javassist.bytecode.stackmap.MapMaker;
/**
* <code>method_info</code> structure.
+ *
+ * <p>The bytecode sequence of the method is represented
+ * by a <code>CodeAttribute</code> object.
*
+ * @see #getCodeAttribute()
+ * @see CodeAttribute
* @see javassist.CtMethod#getMethodInfo()
* @see javassist.CtConstructor#getMethodInfo()
*/
@@ -390,6 +395,7 @@ public class MethodInfo {
* @param cf rebuild if this class file is for Java 6 or later.
* @see #rebuildStackMap(ClassPool)
* @see #rebuildStackMapForME(ClassPool)
+ * @see #doPreverify
* @since 3.6
*/
public void rebuildStackMapIf6(ClassPool pool, ClassFile cf)
diff --git a/src/main/javassist/bytecode/Mnemonic.java b/src/main/javassist/bytecode/Mnemonic.java
index 7846ea9b..0872655b 100644
--- a/src/main/javassist/bytecode/Mnemonic.java
+++ b/src/main/javassist/bytecode/Mnemonic.java
@@ -31,9 +31,6 @@ public interface Mnemonic {
/**
* The instruction names (mnemonics) sorted by the opcode.
* The length of this array is 202 (jsr_w=201).
- *
- * <p>The value at index 186 is null since no instruction is
- * assigned to 186.
*/
String[] OPCODE = {
"nop", /* 0*/
@@ -222,7 +219,7 @@ public interface Mnemonic {
"invokespecial", /* 183*/
"invokestatic", /* 184*/
"invokeinterface", /* 185*/
- null,
+ "invokedynamic", /* 186 */
"new", /* 187*/
"newarray", /* 188*/
"anewarray", /* 189*/
diff --git a/src/main/javassist/bytecode/Opcode.java b/src/main/javassist/bytecode/Opcode.java
index 363dbe23..54555bd1 100644
--- a/src/main/javassist/bytecode/Opcode.java
+++ b/src/main/javassist/bytecode/Opcode.java
@@ -156,6 +156,7 @@ public interface Opcode {
int IMUL = 104;
int INEG = 116;
int INSTANCEOF = 193;
+ int INVOKEDYNAMIC = 186;
int INVOKEINTERFACE = 185;
int INVOKESPECIAL = 183;
int INVOKESTATIC = 184;
@@ -428,7 +429,7 @@ public interface Opcode {
0, // invokespecial, 183 depends on the type
0, // invokestatic, 184 depends on the type
0, // invokeinterface, 185 depends on the type
- 0, // undefined, 186
+ 0, // invokedynaimc, 186 depends on the type
1, // new, 187
0, // newarray, 188
0, // anewarray, 189
diff --git a/src/main/javassist/bytecode/StackMapTable.java b/src/main/javassist/bytecode/StackMapTable.java
index 4518ef36..0ea3e089 100644
--- a/src/main/javassist/bytecode/StackMapTable.java
+++ b/src/main/javassist/bytecode/StackMapTable.java
@@ -909,6 +909,8 @@ public class StackMapTable extends AttributeInfo {
newDelta = offsetDelta - gap;
else if (where == oldPos)
newDelta = offsetDelta + gap;
+ // else if (gap > 0 && oldPos < where && where < position) // chiba
+ // throw new RuntimeException("old:" + oldPos + " where:" + where + " pos:" + position);
else
return;
@@ -949,6 +951,8 @@ public class StackMapTable extends AttributeInfo {
newDelta = offsetDelta - gap;
else if (where == oldPos)
newDelta = offsetDelta + gap;
+ // else if (gap > 0 && oldPos < where && where < position) // chiba
+ // throw new RuntimeException("old:" + oldPos + " where:" + where + " pos:" + position);
else
return;
diff --git a/src/main/javassist/bytecode/analysis/Executor.java b/src/main/javassist/bytecode/analysis/Executor.java
index f53e98bf..63c4c7c7 100644
--- a/src/main/javassist/bytecode/analysis/Executor.java
+++ b/src/main/javassist/bytecode/analysis/Executor.java
@@ -573,8 +573,9 @@ public class Executor implements Opcode {
case INVOKEINTERFACE:
evalInvokeIntfMethod(opcode, iter.u16bitAt(pos + 1), frame);
break;
- case 186:
- throw new RuntimeException("Bad opcode 186");
+ case INVOKEDYNAMIC:
+ evalInvokeDynamic(opcode, iter.u16bitAt(pos + 1), frame);
+ break;
case NEW:
frame.push(resolveClassInfo(constPool.getClassInfo(iter.u16bitAt(pos + 1))));
break;
@@ -748,6 +749,20 @@ public class Executor implements Opcode {
simplePush(zeroExtend(returnType), frame);
}
+ private void evalInvokeDynamic(int opcode, int index, Frame frame) throws BadBytecode {
+ String desc = constPool.getInvokeDynamicType(index);
+ Type[] types = paramTypesFromDesc(desc);
+ int i = types.length;
+
+ while (i > 0)
+ verifyAssignable(zeroExtend(types[--i]), simplePop(frame));
+
+ // simplePop(frame); // assume CosntPool#REF_invokeStatic
+
+ Type returnType = returnTypeFromDesc(desc);
+ if (returnType != Type.VOID)
+ simplePush(zeroExtend(returnType), frame);
+ }
private void evalLDC(int index, Frame frame) throws BadBytecode {
int tag = constPool.getTag(index);
diff --git a/src/main/javassist/bytecode/stackmap/Tracer.java b/src/main/javassist/bytecode/stackmap/Tracer.java
index 8a5aa97d..1bacd09c 100644
--- a/src/main/javassist/bytecode/stackmap/Tracer.java
+++ b/src/main/javassist/bytecode/stackmap/Tracer.java
@@ -597,8 +597,8 @@ public abstract class Tracer implements TypeTag {
return doInvokeMethod(pos, code, false);
case Opcode.INVOKEINTERFACE :
return doInvokeIntfMethod(pos, code);
- case 186 :
- throw new RuntimeException("bad opcode 186");
+ case Opcode.INVOKEDYNAMIC :
+ return doInvokeDynamic(pos, code);
case Opcode.NEW : {
int i = ByteArray.readU16bit(code, pos + 1);
stackTypes[stackTop++]
@@ -835,6 +835,21 @@ public abstract class Tracer implements TypeTag {
return 5;
}
+ private int doInvokeDynamic(int pos, byte[] code) throws BadBytecode {
+ int i = ByteArray.readU16bit(code, pos + 1);
+ String desc = cpool.getInvokeDynamicType(i);
+ checkParamTypes(desc, 1);
+
+ // assume CosntPool#REF_invokeStatic
+ /* TypeData target = stackTypes[--stackTop];
+ if (target instanceof TypeData.UninitTypeVar && target.isUninit())
+ constructorCalled((TypeData.UninitTypeVar)target);
+ */
+
+ pushMemberType(desc);
+ return 5;
+ }
+
private void pushMemberType(String descriptor) {
int top = 0;
if (descriptor.charAt(0) == '(') {