aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/javassist
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/javassist')
-rw-r--r--src/main/javassist/CtBehavior.java4
-rw-r--r--src/main/javassist/bytecode/ClassFileWriter.java2
-rw-r--r--src/main/javassist/bytecode/CodeAttribute.java7
-rw-r--r--src/main/javassist/bytecode/CodeIterator.java9
-rw-r--r--src/main/javassist/bytecode/StackMap.java426
-rw-r--r--src/main/javassist/bytecode/StackMapTable.java10
-rw-r--r--src/main/javassist/bytecode/stackmap/MapMaker.java11
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("<stack map begin>");
- StackMap.Printer.print((StackMap)ai, out);
+ ((StackMap)ai).print(out);
out.println("<stack map end>");
}
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 <code>LocalVariableAttribute</code>
- * or <code>StackMapTable</code>. These attributes must be
- * explicitly updated.
+ * This method does not update <code>LocalVariableAttribute</code>,
+ * <code>StackMapTable</code>, or <code>StackMap</code>.
+ * 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 <code>stack_map</code> 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,93 +116,351 @@ 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 <code>locals</code> of <code>stack_map_frame</code>
+ * is visited.
+ */
+ public int locals(int pos, int offset, int num) {
+ return typeInfoArray(pos, offset, num, true);
+ }
+
+ /**
+ * Invoked when <code>stack</code> of <code>stack_map_frame</code>
+ * is visited.
+ */
+ public int stack(int pos, int offset, int num) {
+ return typeInfoArray(pos, offset, num, false);
+ }
+
+ /**
+ * Invoked when an array of <code>verification_type_info</code> is
+ * visited.
+ *
+ * @param num the number of elements.
+ * @param isLocals true if this array is for <code>locals</code>.
+ * false if it is for <code>stack</code>.
+ * @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 <code>verification_type_info</code>
+ * (except <code>Object_variable_info</code> and
+ * <code>Uninitialized_variable_info</code>) is visited.
+ */
+ public void typeInfo(int pos, byte tag) {}
+
+ /**
+ * Invoked when an element of type <code>Object_variable_info</code>
+ * is visited.
+ */
+ public void objectVariable(int pos, int clazz) {}
+
+ /**
+ * Invoked when an element of type <code>Uninitialized_variable_info</code>
+ * 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 <code>StackMapTable.typeTagOf(char)</code>.
+ * @param classInfo the index of the <code>CONSTANT_Class_info</code> structure
+ * in a constant pool table. This should be zero unless the tag
+ * is <code>ITEM_Object</code>.
+ *
+ * @see javassist.CtBehavior#addParameter(javassist.CtClass)
+ * @see StackMapTable#typeTagOf(char)
+ * @see ConstPool
*/
- public static class Printer {
- /**
- * Prints a <code>StackMap</code> attribute.
- *
- * @param sm the <code>StackMap</code> attribute.
- * @param cp the <code>ConstPool</code> of the class file
- * containing the <code>StackMap</code> 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.
+ *
+ * <p>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;
@@ -204,6 +468,33 @@ public class StackMap extends AttributeInfo {
}
/**
+ * 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.
*/
public static class Writer {
@@ -219,6 +510,13 @@ public class StackMap extends AttributeInfo {
}
/**
+ * Converts the written data into a byte array.
+ */
+ public byte[] toByteArray() {
+ return output.toByteArray();
+ }
+
+ /**
* Converts to a <code>StackMap</code> attribute.
*/
public StackMap toStackMap(ConstPool cp) {
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 <code>ITEM_Object</code>.
*
+ * @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)