Переглянути джерело

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 роки тому
джерело
коміт
5a4853ee87

+ 5
- 0
src/main/javassist/CtBehavior.java Переглянути файл

* or a static constructor (class initializer). * or a static constructor (class initializer).
* It is the abstract super class of * It is the abstract super class of
* <code>CtMethod</code> and <code>CtConstructor</code>. * <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 { public abstract class CtBehavior extends CtMember {
protected MethodInfo methodInfo; protected MethodInfo methodInfo;

+ 2
- 0
src/main/javassist/bytecode/AttributeInfo.java Переглянути файл

if (nameStr.charAt(0) < 'L') { if (nameStr.charAt(0) < 'L') {
if (nameStr.equals(AnnotationDefaultAttribute.tag)) if (nameStr.equals(AnnotationDefaultAttribute.tag))
return new AnnotationDefaultAttribute(cp, name, in); return new AnnotationDefaultAttribute(cp, name, in);
else if (nameStr.equals(BootstrapMethodsAttribute.tag))
return new BootstrapMethodsAttribute(cp, name, in);
else if (nameStr.equals(CodeAttribute.tag)) else if (nameStr.equals(CodeAttribute.tag))
return new CodeAttribute(cp, name, in); return new CodeAttribute(cp, name, in);
else if (nameStr.equals(ConstantAttribute.tag)) else if (nameStr.equals(ConstantAttribute.tag))

+ 123
- 0
src/main/javassist/bytecode/BootstrapMethodsAttribute.java Переглянути файл

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 Переглянути файл

public void addInvokevirtual(int clazz, String name, String desc) { public void addInvokevirtual(int clazz, String name, String desc) {
add(INVOKEVIRTUAL); add(INVOKEVIRTUAL);
addIndex(constPool.addMethodrefInfo(clazz, name, desc)); addIndex(constPool.addMethodrefInfo(clazz, name, desc));
growStack(Descriptor.dataSize(desc) - 1);
growStack(Descriptor.dataSize(desc)); // assume CosntPool#REF_invokeStatic
} }


/** /**
growStack(Descriptor.dataSize(desc) - 1); 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> * Appends LDC or LDC_W. The pushed item is a <code>String</code>
* object. * object.

+ 4
- 0
src/main/javassist/bytecode/CodeAnalyzer.java Переглянути файл

ci.u16bitAt(index + 1)); ci.u16bitAt(index + 1));
stack += Descriptor.dataSize(desc) - 1; stack += Descriptor.dataSize(desc) - 1;
break; break;
case INVOKEDYNAMIC :
desc = constPool.getInvokeDynamicType(ci.u16bitAt(index + 1));
stack += Descriptor.dataSize(desc); // assume CosntPool#REF_invokeStatic
break;
case ATHROW : case ATHROW :
stack = 1; // the stack becomes empty (1 means no values). stack = 1; // the stack becomes empty (1 means no values).
break; break;

+ 7
- 0
src/main/javassist/bytecode/CodeAttribute.java Переглянути файл

* use <code>CodeIterator</code>. * use <code>CodeIterator</code>.
* *
* @see CodeIterator * @see CodeIterator
* @see #iterator()
*/ */
public class CodeAttribute extends AttributeInfo implements Opcode { public class CodeAttribute extends AttributeInfo implements Opcode {
/** /**
newcode[i + 3] = code[i + 3]; newcode[i + 3] = code[i + 3];
newcode[i + 4] = code[i + 4]; newcode[i + 4] = code[i + 4];
break; break;
case INVOKEDYNAMIC :
copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp,
classnameMap);
newcode[i + 3] = 0;
newcode[i + 4] = 0;
break;
case MULTIANEWARRAY : case MULTIANEWARRAY :
copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp, copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp,
classnameMap); classnameMap);

+ 15
- 4
src/main/javassist/bytecode/CodeIterator.java Переглянути файл

/** /**
* An iterator for editing a code attribute. * 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 * <p>If there are multiple <code>CodeIterator</code>s referring to the
* same <code>Code_attribute</code>, then inserting a gap by one * same <code>Code_attribute</code>, then inserting a gap by one
* <code>CodeIterator</code> will break the other * <code>CodeIterator</code> will break the other
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, 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, 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, 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 5, 5
}; };
// 0 .. UNUSED (186), LOOKUPSWITCH, TABLESWITCH, WIDE
// 0 .. LOOKUPSWITCH, TABLESWITCH, WIDE


/** /**
* Calculates the index of the next opcode. * Calculates the index of the next opcode.
int padding = 3 - (pos & 3); int padding = 3 - (pos & 3);
int nops = gap - padding; int nops = gap - padding;
int bytecodeSize = 5 + (3 - (orgPos & 3)) + tableSize(); int bytecodeSize = 5 + (3 - (orgPos & 3)) + tableSize();
adjustOffsets(bytecodeSize, nops);
if (nops > 0)
adjustOffsets(bytecodeSize, nops);

newcode[dest++] = code[src]; newcode[dest++] = code[src];
while (padding-- > 0) while (padding-- > 0)
newcode[dest++] = 0; newcode[dest++] = 0;

+ 356
- 0
src/main/javassist/bytecode/ConstPool.java Переглянути файл

*/ */
public static final int CONST_Utf8 = Utf8Info.tag; 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. * Represents the class using this constant pool table.
*/ */
public static final CtClass THIS = null; 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. * Constructs a constant pool table.
* *
return utf.string; 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> * Determines whether <code>CONSTANT_Methodref_info</code>
* structure at the given index represents the constructor * structure at the given index represents the constructor
return addItem(new Utf8Info(utf8, numOfItems)); 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. * Get all the class names.
* *
case NameAndTypeInfo.tag : // 12 case NameAndTypeInfo.tag : // 12
info = new NameAndTypeInfo(in, numOfItems); info = new NameAndTypeInfo(in, numOfItems);
break; 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 : default :
throw new IOException("invalid constant type: " + tag + " at " + numOfItems); throw new IOException("invalid constant type: " + tag + " at " + numOfItems);
} }
out.println("\""); 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 Переглянути файл

return opstring + " " + methodInfo(pool, iter.u16bitAt(pos + 1)); return opstring + " " + methodInfo(pool, iter.u16bitAt(pos + 1));
case INVOKEINTERFACE: case INVOKEINTERFACE:
return opstring + " " + interfaceMethodInfo(pool, iter.u16bitAt(pos + 1)); 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: case NEW:
return opstring + " " + classInfo(pool, iter.u16bitAt(pos + 1)); return opstring + " " + classInfo(pool, iter.u16bitAt(pos + 1));
case NEWARRAY: case NEWARRAY:

+ 6
- 0
src/main/javassist/bytecode/MethodInfo.java Переглянути файл



/** /**
* <code>method_info</code> structure. * <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.CtMethod#getMethodInfo()
* @see javassist.CtConstructor#getMethodInfo() * @see javassist.CtConstructor#getMethodInfo()
*/ */
* @param cf rebuild if this class file is for Java 6 or later. * @param cf rebuild if this class file is for Java 6 or later.
* @see #rebuildStackMap(ClassPool) * @see #rebuildStackMap(ClassPool)
* @see #rebuildStackMapForME(ClassPool) * @see #rebuildStackMapForME(ClassPool)
* @see #doPreverify
* @since 3.6 * @since 3.6
*/ */
public void rebuildStackMapIf6(ClassPool pool, ClassFile cf) public void rebuildStackMapIf6(ClassPool pool, ClassFile cf)

+ 1
- 4
src/main/javassist/bytecode/Mnemonic.java Переглянути файл

/** /**
* The instruction names (mnemonics) sorted by the opcode. * The instruction names (mnemonics) sorted by the opcode.
* The length of this array is 202 (jsr_w=201). * 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 = { String[] OPCODE = {
"nop", /* 0*/ "nop", /* 0*/
"invokespecial", /* 183*/ "invokespecial", /* 183*/
"invokestatic", /* 184*/ "invokestatic", /* 184*/
"invokeinterface", /* 185*/ "invokeinterface", /* 185*/
null,
"invokedynamic", /* 186 */
"new", /* 187*/ "new", /* 187*/
"newarray", /* 188*/ "newarray", /* 188*/
"anewarray", /* 189*/ "anewarray", /* 189*/

+ 2
- 1
src/main/javassist/bytecode/Opcode.java Переглянути файл

int IMUL = 104; int IMUL = 104;
int INEG = 116; int INEG = 116;
int INSTANCEOF = 193; int INSTANCEOF = 193;
int INVOKEDYNAMIC = 186;
int INVOKEINTERFACE = 185; int INVOKEINTERFACE = 185;
int INVOKESPECIAL = 183; int INVOKESPECIAL = 183;
int INVOKESTATIC = 184; int INVOKESTATIC = 184;
0, // invokespecial, 183 depends on the type 0, // invokespecial, 183 depends on the type
0, // invokestatic, 184 depends on the type 0, // invokestatic, 184 depends on the type
0, // invokeinterface, 185 depends on the type 0, // invokeinterface, 185 depends on the type
0, // undefined, 186
0, // invokedynaimc, 186 depends on the type
1, // new, 187 1, // new, 187
0, // newarray, 188 0, // newarray, 188
0, // anewarray, 189 0, // anewarray, 189

+ 4
- 0
src/main/javassist/bytecode/StackMapTable.java Переглянути файл

newDelta = offsetDelta - gap; newDelta = offsetDelta - gap;
else if (where == oldPos) else if (where == oldPos)
newDelta = offsetDelta + gap; newDelta = offsetDelta + gap;
// else if (gap > 0 && oldPos < where && where < position) // chiba
// throw new RuntimeException("old:" + oldPos + " where:" + where + " pos:" + position);
else else
return; return;


newDelta = offsetDelta - gap; newDelta = offsetDelta - gap;
else if (where == oldPos) else if (where == oldPos)
newDelta = offsetDelta + gap; newDelta = offsetDelta + gap;
// else if (gap > 0 && oldPos < where && where < position) // chiba
// throw new RuntimeException("old:" + oldPos + " where:" + where + " pos:" + position);
else else
return; return;



+ 17
- 2
src/main/javassist/bytecode/analysis/Executor.java Переглянути файл

case INVOKEINTERFACE: case INVOKEINTERFACE:
evalInvokeIntfMethod(opcode, iter.u16bitAt(pos + 1), frame); evalInvokeIntfMethod(opcode, iter.u16bitAt(pos + 1), frame);
break; break;
case 186:
throw new RuntimeException("Bad opcode 186");
case INVOKEDYNAMIC:
evalInvokeDynamic(opcode, iter.u16bitAt(pos + 1), frame);
break;
case NEW: case NEW:
frame.push(resolveClassInfo(constPool.getClassInfo(iter.u16bitAt(pos + 1)))); frame.push(resolveClassInfo(constPool.getClassInfo(iter.u16bitAt(pos + 1))));
break; break;
simplePush(zeroExtend(returnType), frame); 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 { private void evalLDC(int index, Frame frame) throws BadBytecode {
int tag = constPool.getTag(index); int tag = constPool.getTag(index);

+ 17
- 2
src/main/javassist/bytecode/stackmap/Tracer.java Переглянути файл

return doInvokeMethod(pos, code, false); return doInvokeMethod(pos, code, false);
case Opcode.INVOKEINTERFACE : case Opcode.INVOKEINTERFACE :
return doInvokeIntfMethod(pos, code); return doInvokeIntfMethod(pos, code);
case 186 :
throw new RuntimeException("bad opcode 186");
case Opcode.INVOKEDYNAMIC :
return doInvokeDynamic(pos, code);
case Opcode.NEW : { case Opcode.NEW : {
int i = ByteArray.readU16bit(code, pos + 1); int i = ByteArray.readU16bit(code, pos + 1);
stackTypes[stackTop++] stackTypes[stackTop++]
return 5; 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) { private void pushMemberType(String descriptor) {
int top = 0; int top = 0;
if (descriptor.charAt(0) == '(') { if (descriptor.charAt(0) == '(') {

+ 10
- 1
src/test/javassist/JvstTest4.java Переглянути файл

} }


public void testJIRA150b() throws Exception { public void testJIRA150b() throws Exception {
int origSize = javassist.compiler.MemberResolver.getInvalidMapSize();
int N = 100; int N = 100;
for (int k = 0; k < N; k++) { for (int k = 0; k < N; k++) {
ClassPool pool = new ClassPool(true); ClassPool pool = new ClassPool(true);
" int n5 = java.lang.Integer#valueOf(5); " + " int n5 = java.lang.Integer#valueOf(5); " +
" return n1+n2+n3+n4+n5; }"); " 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();
System.gc(); System.gc();
int size = javassist.compiler.MemberResolver.getInvalidMapSize(); int size = javassist.compiler.MemberResolver.getInvalidMapSize();
System.out.println("JIRA150b " + size); 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 { public void testJIRA152() throws Exception {

+ 46
- 0
src/test/javassist/bytecode/BytecodeTest.java Переглянути файл

assertEquals("[Ltest.Bar2;", cp.getClassInfo(n8)); 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) { public static void main(String[] args) {
// junit.textui.TestRunner.run(suite()); // junit.textui.TestRunner.run(suite());
junit.awtui.TestRunner.main(new String[] { junit.awtui.TestRunner.main(new String[] {

+ 165
- 0
src/test/javassist/bytecode/StackMapTest.java Переглянути файл

} }
} }


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 { public void tstCtClassType() throws Exception {
ClassPool cp = ClassPool.getDefault(); ClassPool cp = ClassPool.getDefault();
CtClass cc = cp.get("javassist.CtClassType"); CtClass cc = cp.get("javassist.CtClassType");

+ 14
- 0
src/test/test4/InvokeDyn.java Переглянути файл

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

Завантаження…
Відмінити
Зберегти