From 24f91de8b90ff7beae305dd4df4c9a5f0c8879e1 Mon Sep 17 00:00:00 2001 From: chiba Date: Sun, 8 Nov 2009 14:53:47 +0000 Subject: [PATCH] for JIRA JASSIST-95 git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@502 30ef5769-5b8d-40dd-aea6-55b5d6557bb3 --- src/main/javassist/CtBehavior.java | 4 + .../javassist/bytecode/ClassFileWriter.java | 2 +- .../javassist/bytecode/CodeAttribute.java | 7 +- src/main/javassist/bytecode/CodeIterator.java | 9 + src/main/javassist/bytecode/StackMap.java | 426 +++++++++++++++--- .../javassist/bytecode/StackMapTable.java | 10 +- .../javassist/bytecode/stackmap/MapMaker.java | 11 +- 7 files changed, 399 insertions(+), 70 deletions(-) diff --git a/src/main/javassist/CtBehavior.java b/src/main/javassist/CtBehavior.java index 7c26d093..1414d05d 100644 --- a/src/main/javassist/CtBehavior.java +++ b/src/main/javassist/CtBehavior.java @@ -627,6 +627,10 @@ public abstract class CtBehavior extends CtMember { StackMapTable smt = (StackMapTable)ca.getAttribute(StackMapTable.tag); if (smt != null) smt.insertLocal(where, StackMapTable.typeTagOf(typeDesc), classInfo); + + StackMap sm = (StackMap)ca.getAttribute(StackMap.tag); + if (sm != null) + sm.insertLocal(where, StackMapTable.typeTagOf(typeDesc), classInfo); } } diff --git a/src/main/javassist/bytecode/ClassFileWriter.java b/src/main/javassist/bytecode/ClassFileWriter.java index 2dcbfc1c..e1d835bd 100644 --- a/src/main/javassist/bytecode/ClassFileWriter.java +++ b/src/main/javassist/bytecode/ClassFileWriter.java @@ -115,7 +115,7 @@ public class ClassFileWriter { } else if (ai instanceof StackMap) { out.println(""); - StackMap.Printer.print((StackMap)ai, out); + ((StackMap)ai).print(out); out.println(""); } else if (ai instanceof SignatureAttribute) { diff --git a/src/main/javassist/bytecode/CodeAttribute.java b/src/main/javassist/bytecode/CodeAttribute.java index 45da15cb..59948e2a 100644 --- a/src/main/javassist/bytecode/CodeAttribute.java +++ b/src/main/javassist/bytecode/CodeAttribute.java @@ -452,15 +452,16 @@ public class CodeAttribute extends AttributeInfo implements Opcode { /** * Changes the index numbers of the local variables * to append a new parameter. - * This method does not update LocalVariableAttribute - * or StackMapTable. These attributes must be - * explicitly updated. + * This method does not update LocalVariableAttribute, + * StackMapTable, or StackMap. + * These attributes must be explicitly updated. * * @param where the index of the new parameter. * @param size the type size of the new parameter (1 or 2). * * @see LocalVariableAttribute#shiftIndex(int, int) * @see StackMapTable#insertLocal(int, int, int) + * @see StackMap#insertLocal(int, int, int) */ public void insertLocalVar(int where, int size) throws BadBytecode { CodeIterator ci = iterator(); diff --git a/src/main/javassist/bytecode/CodeIterator.java b/src/main/javassist/bytecode/CodeIterator.java index 80507fc0..14db6055 100644 --- a/src/main/javassist/bytecode/CodeIterator.java +++ b/src/main/javassist/bytecode/CodeIterator.java @@ -843,6 +843,10 @@ public class CodeIterator implements Opcode { if (smt != null) smt.shiftPc(where, gapLength, exclusive); + StackMap sm = (StackMap)ca.getAttribute(StackMap.tag); + if (sm != null) + sm.shiftPc(where, gapLength, exclusive); + return newcode; } @@ -993,6 +997,7 @@ public class CodeIterator implements Opcode { LineNumberAttribute line; LocalVariableAttribute vars, types; StackMapTable stack; + StackMap stack2; Pointers(int cur, int m, int m0, ExceptionTable et, CodeAttribute ca) { cursor = cur; @@ -1003,6 +1008,7 @@ public class CodeIterator implements Opcode { vars = (LocalVariableAttribute)ca.getAttribute(LocalVariableAttribute.tag); types = (LocalVariableAttribute)ca.getAttribute(LocalVariableAttribute.typeTag); stack = (StackMapTable)ca.getAttribute(StackMapTable.tag); + stack2 = (StackMap)ca.getAttribute(StackMap.tag); } void shiftPc(int where, int gapLength, boolean exclusive) throws BadBytecode { @@ -1027,6 +1033,9 @@ public class CodeIterator implements Opcode { if (stack != null) stack.shiftPc(where, gapLength, exclusive); + + if (stack2 != null) + stack2.shiftPc(where, gapLength, exclusive); } } diff --git a/src/main/javassist/bytecode/StackMap.java b/src/main/javassist/bytecode/StackMap.java index 06b637ee..ead1dffb 100644 --- a/src/main/javassist/bytecode/StackMap.java +++ b/src/main/javassist/bytecode/StackMap.java @@ -20,6 +20,11 @@ import java.io.DataInputStream; import java.io.IOException; import java.util.Map; +import javassist.CannotCompileException; +import javassist.bytecode.StackMapTable.InsertLocal; +import javassist.bytecode.StackMapTable.NewRemover; +import javassist.bytecode.StackMapTable.Shifter; + /** * Another stack_map attribute defined in CLDC 1.1 for J2ME. * @@ -31,6 +36,7 @@ import java.util.Map; * is more than 64K. However, for the J2ME CLDC technology, they are always 16bit. * The implementation of the StackMap class assumes they are 16bit. * + * @see MethodInfo#doPreverify * @see StackMapTable * @since 3.12 */ @@ -110,99 +116,384 @@ public class StackMap extends AttributeInfo { * Makes a copy. */ public AttributeInfo copy(ConstPool newCp, Map classnames) { - ConstPool cp = getConstPool(); - byte[] srcInfo = info; - byte[] newInfo = new byte[srcInfo.length]; - int num = numOfEntries(); - ByteArray.write16bit(num, newInfo, 0); - int pos = 2; - for (int i = 0; i < num; i++) { - int offset = ByteArray.readU16bit(srcInfo, pos); - ByteArray.write16bit(offset, newInfo, pos); - pos += 2; - int numLoc = ByteArray.readU16bit(srcInfo, pos); - ByteArray.write16bit(numLoc, newInfo, pos); - pos = copyFrames(srcInfo, newInfo, pos + 2, numLoc, cp, newCp, - classnames); - int numStack = ByteArray.readU16bit(srcInfo, pos); - ByteArray.write16bit(numStack, newInfo, pos); - pos = copyFrames(srcInfo, newInfo, pos + 2, numStack, cp, newCp, - classnames); - } - - return new StackMap(newCp, newInfo); - } - - private static int copyFrames(byte[] srcInfo, byte[] newInfo, int pos, - int numFrames, ConstPool cp, ConstPool newCp, Map classnames) { - for (int k = 0; k < numFrames; k++) { - byte tag = srcInfo[pos]; - newInfo[pos] = tag; + Copier copier = new Copier(this, newCp, classnames); + copier.visit(); + return copier.getStackMap(); + } + + /** + * A code walker for a StackMap attribute. + */ + public static class Walker { + byte[] info; + + /** + * Constructs a walker. + */ + public Walker(StackMap sm) { + info = sm.get(); + } + + /** + * Visits each entry of the stack map frames. + */ + public void visit() { + int num = ByteArray.readU16bit(info, 0); + int pos = 2; + for (int i = 0; i < num; i++) { + int offset = ByteArray.readU16bit(info, pos); + int numLoc = ByteArray.readU16bit(info, pos + 2); + pos = locals(pos + 4, offset, numLoc); + int numStack = ByteArray.readU16bit(info, pos); + pos = stack(pos + 2, offset, numStack); + } + } + + /** + * Invoked when locals of stack_map_frame + * is visited. + */ + public int locals(int pos, int offset, int num) { + return typeInfoArray(pos, offset, num, true); + } + + /** + * Invoked when stack of stack_map_frame + * is visited. + */ + public int stack(int pos, int offset, int num) { + return typeInfoArray(pos, offset, num, false); + } + + /** + * Invoked when an array of verification_type_info is + * visited. + * + * @param num the number of elements. + * @param isLocals true if this array is for locals. + * false if it is for stack. + * @return + */ + public int typeInfoArray(int pos, int offset, int num, boolean isLocals) { + for (int k = 0; k < num; k++) + pos = typeInfoArray2(k, pos); + + return pos; + } + + int typeInfoArray2(int k, int pos) { + byte tag = info[pos]; if (tag == OBJECT) { - int clazz = ByteArray.readU16bit(srcInfo, pos + 1); - clazz = cp.copy(clazz, newCp, classnames); - ByteArray.write16bit(clazz, newInfo, pos + 1); + int clazz = ByteArray.readU16bit(info, pos + 1); + objectVariable(pos, clazz); pos += 3; } else if (tag == UNINIT) { - ByteArray.write16bit(ByteArray.readU16bit(srcInfo, pos + 1), - newInfo, pos + 1); + int offsetOfNew = ByteArray.readU16bit(info, pos + 1); + uninitialized(pos, offsetOfNew); pos += 3; } - else + else { + typeInfo(pos, tag); pos++; + } + + return pos; } - return pos; + /** + * Invoked when an element of verification_type_info + * (except Object_variable_info and + * Uninitialized_variable_info) is visited. + */ + public void typeInfo(int pos, byte tag) {} + + /** + * Invoked when an element of type Object_variable_info + * is visited. + */ + public void objectVariable(int pos, int clazz) {} + + /** + * Invoked when an element of type Uninitialized_variable_info + * is visited. + */ + public void uninitialized(int pos, int offset) {} + } + + static class Copier extends Walker { + byte[] dest; + ConstPool srcCp, destCp; + Map classnames; + + Copier(StackMap map, ConstPool newCp, Map classnames) { + super(map); + srcCp = map.getConstPool(); + dest = new byte[info.length]; + destCp = newCp; + this.classnames = classnames; + } + + public void visit() { + int num = ByteArray.readU16bit(info, 0); + ByteArray.write16bit(num, dest, 0); + super.visit(); + } + + public int locals(int pos, int offset, int num) { + ByteArray.write16bit(offset, dest, pos - 4); + return super.locals(pos, offset, num); + } + + public int typeInfoArray(int pos, int offset, int num, boolean isLocals) { + ByteArray.write16bit(num, dest, pos - 2); + return super.typeInfoArray(pos, offset, num, isLocals); + } + + public void typeInfo(int pos, byte tag) { + dest[pos] = tag; + } + + public void objectVariable(int pos, int clazz) { + dest[pos] = OBJECT; + int newClazz = srcCp.copy(clazz, destCp, classnames); + ByteArray.write16bit(newClazz, dest, pos + 1); + } + + public void uninitialized(int pos, int offset) { + dest[pos] = UNINIT; + ByteArray.write16bit(offset, dest, pos + 1); + } + + public StackMap getStackMap() { + return new StackMap(destCp, dest); + } } /** - * Printer + * Updates this stack map table when a new local variable is inserted + * for a new parameter. + * + * @param index the index of the added local variable. + * @param tag the type tag of that local variable. + * It is available by StackMapTable.typeTagOf(char). + * @param classInfo the index of the CONSTANT_Class_info structure + * in a constant pool table. This should be zero unless the tag + * is ITEM_Object. + * + * @see javassist.CtBehavior#addParameter(javassist.CtClass) + * @see StackMapTable#typeTagOf(char) + * @see ConstPool */ - public static class Printer { - /** - * Prints a StackMap attribute. - * - * @param sm the StackMap attribute. - * @param cp the ConstPool of the class file - * containing the StackMap attribute. - */ - public static void print(StackMap sm, java.io.PrintWriter out) { - int num = sm.numOfEntries(); - out.println(num + " entries"); - byte[] srcInfo = sm.get(); - int pos = 2; - for (int i = 0; i < num; i++) { - int offset = ByteArray.readU16bit(srcInfo, pos); - out.println(" * offset " + offset); - pos += 2; - int numLoc = ByteArray.readU16bit(srcInfo, pos); - pos = printFrames(srcInfo, pos + 2, numLoc); - int numStack = ByteArray.readU16bit(srcInfo, pos); - pos = printFrames(srcInfo, pos + 2, numStack); + public void insertLocal(int index, int tag, int classInfo) + throws BadBytecode + { + byte[] data = new InsertLocal(this, index, tag, classInfo).doit(); + this.set(data); + } + + static class SimpleCopy extends Walker { + Writer writer; + + SimpleCopy(StackMap map) { + super(map); + writer = new Writer(); + } + + byte[] doit() { + visit(); + return writer.toByteArray(); + } + + public void visit() { + int num = ByteArray.readU16bit(info, 0); + writer.write16bit(num); + super.visit(); + } + + public int locals(int pos, int offset, int num) { + writer.write16bit(offset); + return super.locals(pos, offset, num); + } + + public int typeInfoArray(int pos, int offset, int num, boolean isLocals) { + writer.write16bit(num); + return super.typeInfoArray(pos, offset, num, isLocals); + } + + public void typeInfo(int pos, byte tag) { + writer.writeVerifyTypeInfo(tag, 0); + } + + public void objectVariable(int pos, int clazz) { + writer.writeVerifyTypeInfo(OBJECT, clazz); + } + + public void uninitialized(int pos, int offset) { + writer.writeVerifyTypeInfo(UNINIT, offset); + } + } + + static class InsertLocal extends SimpleCopy { + private int varIndex; + private int varTag, varData; + + InsertLocal(StackMap map, int varIndex, int varTag, int varData) { + super(map); + this.varIndex = varIndex; + this.varTag = varTag; + this.varData = varData; + } + + public int typeInfoArray(int pos, int offset, int num, boolean isLocals) { + if (!isLocals || num < varIndex) + return super.typeInfoArray(pos, offset, num, isLocals); + + writer.write16bit(num + 1); + for (int k = 0; k < num; k++) { + if (k == varIndex) + writeVarTypeInfo(); + + pos = typeInfoArray2(k, pos); } + + if (num == varIndex) + writeVarTypeInfo(); + + return pos; + } + + private void writeVarTypeInfo() { + if (varTag == OBJECT) + writer.writeVerifyTypeInfo(OBJECT, varData); + else if (varTag == UNINIT) + writer.writeVerifyTypeInfo(UNINIT, varData); + else + writer.writeVerifyTypeInfo(varTag, 0); + } + } + + void shiftPc(int where, int gapSize, boolean exclusive) + throws BadBytecode + { + new Shifter(this, where, gapSize, exclusive).visit(); + } + + static class Shifter extends Walker { + private int where, gap; + private boolean exclusive; + + public Shifter(StackMap smt, int where, int gap, boolean exclusive) { + super(smt); + this.where = where; + this.gap = gap; + this.exclusive = exclusive; } - private static int printFrames(byte[] srcInfo, int pos, - int numFrames) { - for (int k = 0; k < numFrames; k++) { - byte tag = srcInfo[pos]; + public int locals(int pos, int offset, int num) { + if (exclusive ? where <= offset : where < offset) + ByteArray.write16bit(offset + gap, info, pos - 4); + + return super.locals(pos, offset, num); + } + } + + /** + * Undocumented method. Do not use; internal-use only. + * + *

This method is for javassist.convert.TransformNew. + * It is called to update the stack map when + * the NEW opcode (and the following DUP) is removed. + * + * @param where the position of the removed NEW opcode. + */ + public void removeNew(int where) throws CannotCompileException { + byte[] data = new NewRemover(this, where).doit(); + this.set(data); + } + + static class NewRemover extends SimpleCopy { + int posOfNew; + + NewRemover(StackMap map, int where) { + super(map); + posOfNew = where; + } + + public int stack(int pos, int offset, int num) { + return stackTypeInfoArray(pos, offset, num); + } + + private int stackTypeInfoArray(int pos, int offset, int num) { + int p = pos; + int count = 0; + for (int k = 0; k < num; k++) { + byte tag = info[p]; + if (tag == OBJECT) + p += 3; + else if (tag == UNINIT) { + int offsetOfNew = ByteArray.readU16bit(info, p + 1); + if (offsetOfNew == posOfNew) + count++; + + p += 3; + } + else + p++; + } + + writer.write16bit(num - count); + for (int k = 0; k < num; k++) { + byte tag = info[pos]; if (tag == OBJECT) { - ByteArray.readU16bit(srcInfo, pos + 1); + int clazz = ByteArray.readU16bit(info, pos + 1); + objectVariable(pos, clazz); pos += 3; } else if (tag == UNINIT) { - ByteArray.readU16bit(srcInfo, pos + 1); + int offsetOfNew = ByteArray.readU16bit(info, pos + 1); + if (offsetOfNew != posOfNew) + uninitialized(pos, offsetOfNew); + pos += 3; } - else + else { + typeInfo(pos, tag); pos++; + } } return pos; } } + /** + * Prints this stack map. + */ + public void print(java.io.PrintWriter out) { + new Printer(this, out).print(); + } + + static class Printer extends Walker { + private java.io.PrintWriter writer; + + public Printer(StackMap map, java.io.PrintWriter out) { + super(map); + writer = out; + } + + public void print() { + int num = ByteArray.readU16bit(info, 0); + writer.println(num + " entries"); + visit(); + } + + public int locals(int pos, int offset, int num) { + writer.println(" * offset " + offset); + return super.locals(pos, offset, num); + } + } + /** * Internal use only. */ @@ -218,6 +509,13 @@ public class StackMap extends AttributeInfo { output = new ByteArrayOutputStream(); } + /** + * Converts the written data into a byte array. + */ + public byte[] toByteArray() { + return output.toByteArray(); + } + /** * Converts to a StackMap attribute. */ diff --git a/src/main/javassist/bytecode/StackMapTable.java b/src/main/javassist/bytecode/StackMapTable.java index 2ca8bd72..f3cea6fa 100644 --- a/src/main/javassist/bytecode/StackMapTable.java +++ b/src/main/javassist/bytecode/StackMapTable.java @@ -30,6 +30,7 @@ import javassist.CannotCompileException; * It was introduced by J2SE 6 for the process of verification by * typechecking. * + * @see StackMap * @since 3.4 */ public class StackMapTable extends AttributeInfo { @@ -425,7 +426,8 @@ public class StackMapTable extends AttributeInfo { } /** - * Updates this stack map table when a new local variable is added. + * Updates this stack map table when a new local variable is inserted + * for a new parameter. * * @param index the index of the added local variable. * @param tag the type tag of that local variable. @@ -433,6 +435,7 @@ public class StackMapTable extends AttributeInfo { * in a constant pool table. This should be zero unless the tag * is ITEM_Object. * + * @see javassist.CtBehavior#addParameter(javassist.CtClass) * @see #typeTagOf(char) * @see ConstPool */ @@ -469,6 +472,11 @@ public class StackMapTable extends AttributeInfo { } } + /* This implementation assumes that a local variable initially + * holding a parameter value is never changed to be a different + * type. + * + */ static class InsertLocal extends SimpleCopy { private int varIndex; private int varTag, varData; diff --git a/src/main/javassist/bytecode/stackmap/MapMaker.java b/src/main/javassist/bytecode/stackmap/MapMaker.java index 6d2bf685..92cd37c6 100644 --- a/src/main/javassist/bytecode/stackmap/MapMaker.java +++ b/src/main/javassist/bytecode/stackmap/MapMaker.java @@ -502,7 +502,16 @@ public class MapMaker extends Tracer { } private void writeVerifyTypeInfo(StackMap.Writer writer, ConstPool cp, TypeData[] types, int num) { - writer.write16bit(num); + int numDWord = 0; + for (int i = 0; i < num; i++) { + TypeData td = types[i]; + if (td != null && td.is2WordType()) { + numDWord++; + i++; + } + } + + writer.write16bit(num - numDWord); for (int i = 0; i < num; i++) { TypeData td = types[i]; if (td == TOP) -- 2.39.5