Browse Source

fixed JASSIST-174

git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@669 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
tags/rel_3_17_1_ga
chiba 11 years ago
parent
commit
5a4853ee87

+ 5
- 0
src/main/javassist/CtBehavior.java View File

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

+ 2
- 0
src/main/javassist/bytecode/AttributeInfo.java View File

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

+ 123
- 0
src/main/javassist/bytecode/BootstrapMethodsAttribute.java View File

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

+ 20
- 1
src/main/javassist/bytecode/Bytecode.java View File

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

/**
@@ -1154,6 +1154,25 @@ public class Bytecode extends ByteVector implements Cloneable, Opcode {
growStack(Descriptor.dataSize(desc) - 1);
}

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

+ 4
- 0
src/main/javassist/bytecode/CodeAnalyzer.java View File

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

+ 7
- 0
src/main/javassist/bytecode/CodeAttribute.java View File

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

+ 15
- 4
src/main/javassist/bytecode/CodeIterator.java View File

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

+ 356
- 0
src/main/javassist/bytecode/ConstPool.java View File

@@ -93,11 +93,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.
*
@@ -588,6 +638,97 @@ public final class ConstPool {
return utf.string;
}

/**
* 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
@@ -926,6 +1067,48 @@ public final class ConstPool {
return addItem(new Utf8Info(utf8, numOfItems));
}

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

+ 2
- 2
src/main/javassist/bytecode/InstructionPrinter.java View File

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

+ 6
- 0
src/main/javassist/bytecode/MethodInfo.java View File

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

+ 1
- 4
src/main/javassist/bytecode/Mnemonic.java View File

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

+ 2
- 1
src/main/javassist/bytecode/Opcode.java View File

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

+ 4
- 0
src/main/javassist/bytecode/StackMapTable.java View File

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


+ 17
- 2
src/main/javassist/bytecode/analysis/Executor.java View File

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

+ 17
- 2
src/main/javassist/bytecode/stackmap/Tracer.java View File

@@ -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) == '(') {

+ 10
- 1
src/test/javassist/JvstTest4.java View File

@@ -662,6 +662,7 @@ public class JvstTest4 extends JvstTestRoot {
}

public void testJIRA150b() throws Exception {
int origSize = javassist.compiler.MemberResolver.getInvalidMapSize();
int N = 100;
for (int k = 0; k < N; k++) {
ClassPool pool = new ClassPool(true);
@@ -681,12 +682,20 @@ public class JvstTest4 extends JvstTestRoot {
" int n5 = java.lang.Integer#valueOf(5); " +
" return n1+n2+n3+n4+n5; }");
}
pool = null;
}

// try to run garbage collection.
int[] large;
for (int i = 0; i < 100; i++) {
large = new int[1000000];
large[large.length - 2] = 9;
}
System.gc();
System.gc();
int size = javassist.compiler.MemberResolver.getInvalidMapSize();
System.out.println("JIRA150b " + size);
assertTrue("JIRA150b size: " + size, size < N - 10);
assertTrue("JIRA150b size: " + origSize + " " + size, size < origSize + N);
}

public void testJIRA152() throws Exception {

+ 46
- 0
src/test/javassist/bytecode/BytecodeTest.java View File

@@ -779,6 +779,52 @@ public class BytecodeTest extends TestCase {
assertEquals("[Ltest.Bar2;", cp.getClassInfo(n8));
}

public void testInvokeDynamic() throws Exception {
CtClass cc = loader.get("test4.InvokeDyn");
ClassFile cf = cc.getClassFile();
ConstPool cp = cf.getConstPool();

Bytecode code = new Bytecode(cp, 0, 1);
code.addAload(0);
code.addIconst(9);
code.addLdc("nine");
code.addInvokedynamic(0, "call", "(ILjava/lang/String;)I");
code.addOpcode(Opcode.SWAP);
code.addOpcode(Opcode.POP);
code.addOpcode(Opcode.IRETURN);

MethodInfo minfo = new MethodInfo(cp, "test", "()I");
minfo.setCodeAttribute(code.toCodeAttribute());
minfo.setAccessFlags(AccessFlag.PUBLIC);
minfo.rebuildStackMapIf6(loader, cf);
cf.addMethod(minfo);

cf.addMethod(new MethodInfo(cp, "test2", minfo, null));
int mtIndex = cp.addMethodTypeInfo(cp.addUtf8Info("(I)V"));

String desc
= "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)" +
"Ljava/lang/invoke/CallSite;";
int mri = cp.addMethodrefInfo(cp.addClassInfo(cc.getName()), "boot", desc);
int mhi = cp.addMethodHandleInfo(ConstPool.REF_invokeStatic, mri);
int[] args = new int[0];
BootstrapMethodsAttribute.BootstrapMethod[] bms
= new BootstrapMethodsAttribute.BootstrapMethod[1];
bms[0] = new BootstrapMethodsAttribute.BootstrapMethod(mhi, args);

cf.addAttribute(new BootstrapMethodsAttribute(cp, bms));
cc.writeFile();
Object obj = make(cc.getName());
assertEquals(9, invoke(obj, "test"));

ClassPool cp2 = new ClassPool();
cp2.appendClassPath(".");
CtClass cc2 = cp2.get(cc.getName());
assertEquals("test4.InvokeDyn", cc2.getClassFile().getName());
ConstPool cPool2 = cc2.getClassFile().getConstPool();
assertEquals("(I)V", cPool2.getUtf8Info(cPool2.getMethodTypeInfo(mtIndex)));
}

public static void main(String[] args) {
// junit.textui.TestRunner.run(suite());
junit.awtui.TestRunner.main(new String[] {

+ 165
- 0
src/test/javassist/bytecode/StackMapTest.java View File

@@ -423,6 +423,171 @@ public class StackMapTest extends TestCase {
}
}

public void testSwitchCase3() throws Exception {
CtClass cc = loader.get("javassist.bytecode.StackMapTest$T7c");
StringBuffer sbuf = new StringBuffer("String s;");
for (int i = 0; i < 130; i++)
sbuf.append("s =\"" + i + "\";");

cc.getDeclaredMethod("foo").insertBefore(sbuf.toString());
cc.getDeclaredMethod("test2").setBody(loader.get("javassist.bytecode.StackMapTest$T8c").getDeclaredMethod("test2"), null);

cc.writeFile();
Object t1 = make(cc.getName());
assertEquals(100, invoke(t1, "test"));
}

public static class T7c {
int value = 1;
T7b t7;
public static T7b make2() { return null; }
public static void print(String s) {}
public int foo() { return 1; }
public int test() { return test2(10); }
public int test2(int k) { return 0; }
}

public static class T8c {
public int test2(int k) {
int jj = 50;
if (k > 0)
k += "fooo".length();

int j = 50;
loop: for (int i = 0; i < 10; i++) {
int jjj = 1;
switch (i) {
case 0:
k++;
{ int poi = 0; }
break;
case 9:
break loop;
case 7:
k += jjj;
break;
}
}
return j + jj;
}
}

public void testSwitchCase4() throws Exception {
CtClass cc = loader.get("javassist.bytecode.StackMapTest$T8e");
StringBuffer sbuf = new StringBuffer("String s;");
for (int i = 0; i < 130; i++)
sbuf.append("s =\"" + i + "\";");

cc.getDeclaredMethod("foo").insertBefore(sbuf.toString());
CtClass orig = loader.get("javassist.bytecode.StackMapTest$T8d");
CtMethod origM = orig.getDeclaredMethod("test2");
writeLdcw(origM);
cc.getDeclaredMethod("test2").setBody(origM, null);

orig.writeFile();
cc.writeFile();
Object t1 = make(cc.getName());
assertEquals(100, invoke(t1, "test"));
}

private void writeLdcw(CtMethod method) {
CodeAttribute ca = method.getMethodInfo().getCodeAttribute();
int index = ca.getConstPool().addStringInfo("ldcw");
CodeIterator ci = ca.iterator();
ci.writeByte(Opcode.LDC_W, 14);
ci.write16bit(index, 15);
ci.writeByte(Opcode.LDC_W, 43);
ci.write16bit(index, 44);
}

public static class T8e {
static T8dd helper() { return new T8dd(); }
int integer() { return 9; }
boolean integer2(String s) { return true; }
static void print(String s) {}
private void print2(String s) {}
private Object func(String s) { return null; }
I8d func2(String s) { return null; }
static String ldcw() { return "k"; }
static boolean debug = false;
void log(String p1,String p2,String p3,Long p4, Object p5, Object p6) {}

public int foo() { return 1; }
public int test() {
try {
return test2("", 10) ? 1 : 0;
} catch (Exception e) {}
return 100;
}
public boolean test2(String s, int k) throws Exception { return false; }
}

public static interface I8d {
String foo(String s, int i);
}

public static class T8dd {
java.util.List foo(String s) { return new java.util.ArrayList(); }
}
public static class T8d {
static T8dd helper() { return new T8dd(); }
int integer() { return 9; }
boolean integer2(String s) { return true; }
static void print(String s) {}
private void print2(String s) {}
private Object func(String s) { return null; }
I8d func2(String s) { return null; }
static String ldcw() { return "k"; }
static boolean debug = false;
void log(String p1,String p2,String p3,Long p4, Object p5, Object p6) {}

public boolean test2(String s, int i) throws Exception {
String k = null;
Object k2 = null;
boolean v5 = true;
if (!debug)
print(ldcw());

Object k3 = this.func(s);
if (k3 == null)
throw new Exception(new StringBuilder().append(ldcw()).append(s).append(",").toString());

String v7 = k3.toString();
k2 = this.func2(v7);
if (k2 != null) { // 82:
if (k2 instanceof I8d) {
I8d k5 = (I8d)k2;
k = k5.foo(s, i);
}
}

java.util.List list = helper().foo(v7); // local 8
for (int v9 = 0; v9 < list.size(); v9++) {
boolean v10 = true;
T8d v11 = (T8d)list.get(v9);
switch (v11.integer()) {
case 1:
break;
case 2:
v10 = this.integer2(s);
v5 &= v10;
break;
default :
throw new Exception(new StringBuilder().append("ldc 189").append(v11.integer()).append("ldc 169").toString());
}
}

if (v5) // 246:
this.print2(s);
if (v5)
this.log(ldcw(), v7, s, Long.valueOf(new Integer(i).longValue()), k, null);
else // 290:
this.log(ldcw(), v7, s, Long.valueOf(new Integer(i).longValue()), k, null);

return v5;
}
}

public void tstCtClassType() throws Exception {
ClassPool cp = ClassPool.getDefault();
CtClass cc = cp.get("javassist.CtClassType");

+ 14
- 0
src/test/test4/InvokeDyn.java View File

@@ -0,0 +1,14 @@
package test4;

import java.lang.invoke.*;

public class InvokeDyn {
public static int test9(int i, String s) { return 9; }

public static CallSite boot(MethodHandles.Lookup caller, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
MethodHandles.Lookup lookup = MethodHandles.lookup();
Class thisClass = lookup.lookupClass();
MethodHandle method = lookup.findStatic(thisClass, "test9", MethodType.methodType(int.class, int.class, String.class));
return new ConstantCallSite(method);
}
}

Loading…
Cancel
Save