aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>2007-02-09 18:05:21 +0000
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>2007-02-09 18:05:21 +0000
commitfa1ebd7549d3f17ce49e7942703bc598f9142081 (patch)
tree442d970dbe49c0e02f8bf5b7a04549ce65f6d66b
parent0940370343d08e42be624650d0a9077dc838b4f9 (diff)
downloadjavassist-fa1ebd7549d3f17ce49e7942703bc598f9142081.tar.gz
javassist-fa1ebd7549d3f17ce49e7942703bc598f9142081.zip
modified javassist.convert.* to support the stack map table of Java 6.
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@351 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
-rw-r--r--.classpath5
-rw-r--r--.project12
-rw-r--r--build.xml2
-rw-r--r--src/main/javassist/bytecode/ClassFileWriter.java2
-rw-r--r--src/main/javassist/bytecode/CodeIterator.java4
-rw-r--r--src/main/javassist/bytecode/StackMapTable.java267
-rw-r--r--src/main/javassist/bytecode/stackmap/BasicBlock.java4
-rw-r--r--src/main/javassist/bytecode/stackmap/StackAnalyzer.java840
-rw-r--r--src/main/javassist/bytecode/stackmap/StackAnalyzerCore.java846
-rw-r--r--src/main/javassist/convert/TransformAccessArrayField.java146
-rw-r--r--src/main/javassist/convert/TransformNew.java5
-rw-r--r--src/test/test/Test.java14
12 files changed, 1181 insertions, 966 deletions
diff --git a/.classpath b/.classpath
index deae2f47..21f8fe5a 100644
--- a/.classpath
+++ b/.classpath
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
- <classpathentry excluding="javassist/util/HotSwapper.java" kind="src" path="src/main"/>
- <classpathentry kind="src" path="src/test"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="src" path="src/main"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.launching.macosx.MacOSXType/JVM 1.4.2"/>
<classpathentry kind="output" path="build/classes"/>
</classpath>
diff --git a/.project b/.project
index 20b52261..4d88bda1 100644
--- a/.project
+++ b/.project
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
- <name>javassist</name>
+ <name>jvst</name>
<comment></comment>
<projects>
</projects>
@@ -10,16 +10,6 @@
<arguments>
</arguments>
</buildCommand>
- <buildCommand>
- <name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
- <triggers>full,incremental,</triggers>
- <arguments>
- <dictionary>
- <key>LaunchConfigHandle</key>
- <value>&lt;project&gt;/.externalToolBuilders/Ant.launch</value>
- </dictionary>
- </arguments>
- </buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
diff --git a/build.xml b/build.xml
index a3dcadaf..214259f0 100644
--- a/build.xml
+++ b/build.xml
@@ -109,7 +109,7 @@ to ${build.classes.dir}.</echo>
<javadoc
Locale="en_US"
packagenames="javassist.*"
- excludepackagenames="javassist.compiler.*,javassist.convert.*,javassist.scopedpool.*"
+ excludepackagenames="javassist.compiler.*,javassist.convert.*,javassist.scopedpool.*,javassist.bytecode.stackmap.*"
sourcepath="src/main"
defaultexcludes="yes"
destdir="html"
diff --git a/src/main/javassist/bytecode/ClassFileWriter.java b/src/main/javassist/bytecode/ClassFileWriter.java
index 528d98af..2d667a86 100644
--- a/src/main/javassist/bytecode/ClassFileWriter.java
+++ b/src/main/javassist/bytecode/ClassFileWriter.java
@@ -109,7 +109,7 @@ public class ClassFileWriter {
}
else if (ai instanceof StackMapTable) {
out.println("<stack map table begin>");
- StackMapTable.Writer.print((StackMapTable)ai, out);
+ StackMapTable.Printer.print((StackMapTable)ai, out);
out.println("<stack map table end>");
}
else if (ai instanceof SignatureAttribute) {
diff --git a/src/main/javassist/bytecode/CodeIterator.java b/src/main/javassist/bytecode/CodeIterator.java
index 13948c91..fbad5ee5 100644
--- a/src/main/javassist/bytecode/CodeIterator.java
+++ b/src/main/javassist/bytecode/CodeIterator.java
@@ -671,6 +671,10 @@ public class CodeIterator implements Opcode {
if (vta != null)
vta.shiftPc(where, gapLength, exclusive);
+ StackMapTable smt = (StackMapTable)ca.getAttribute(StackMapTable.tag);
+ if (smt != null)
+ smt.shiftPc(where, gapLength, exclusive);
+
return newcode;
}
diff --git a/src/main/javassist/bytecode/StackMapTable.java b/src/main/javassist/bytecode/StackMapTable.java
index a2fecaef..cb59efa2 100644
--- a/src/main/javassist/bytecode/StackMapTable.java
+++ b/src/main/javassist/bytecode/StackMapTable.java
@@ -21,6 +21,7 @@ import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.io.IOException;
import java.util.Map;
+import javassist.CannotCompileException;
/**
* <code>stack_map</code> attribute.
@@ -54,8 +55,8 @@ public class StackMapTable extends AttributeInfo {
* Makes a copy.
*
* @exception RuntimeCopyException if a <code>BadBytecode</code>
- * exception is thrown, it is
- * converted into
+ * exception is thrown while copying,
+ * it is converted into
* <code>RuntimeCopyException</code>.
*
*/
@@ -136,17 +137,26 @@ public class StackMapTable extends AttributeInfo {
/**
* A code walker for a StackMapTable attribute.
*/
- static class Walker {
+ public static class Walker {
byte[] info;
int numOfEntries;
/**
* Constructs a walker.
+ */
+ public Walker(StackMapTable smt) {
+ this(smt.get());
+ }
+
+ /**
+ * Constructs a walker.
*
* @param data the <code>info</code> field of the
* <code>attribute_info</code> structure.
+ * It can be obtained by <code>get()</code>
+ * in the <code>AttributeInfo</code> class.
*/
- public Walker(byte[] data) {
+ Walker(byte[] data) {
info = data;
numOfEntries = ByteArray.readU16bit(data, 0);
}
@@ -159,7 +169,7 @@ public class StackMapTable extends AttributeInfo {
/**
* Visits each entry of the stack map frames.
*/
- public final void parse() throws BadBytecode {
+ public void parse() throws BadBytecode {
int n = numOfEntries;
int pos = 2;
for (int i = 0; i < n; i++)
@@ -213,9 +223,9 @@ public class StackMapTable extends AttributeInfo {
* field of <code>attribute_info</code> structure.
* @param offsetDelta
*/
- public void sameFrame(int pos, int offsetDelta) {}
+ public void sameFrame(int pos, int offsetDelta) throws BadBytecode {}
- private int sameLocals(int pos, int type) {
+ private int sameLocals(int pos, int type) throws BadBytecode {
int offset;
if (type < 128)
offset = type - 64;
@@ -247,7 +257,8 @@ public class StackMapTable extends AttributeInfo {
* or <code>stack[0].offset</code>
* if the tag is <code>UNINIT</code>.
*/
- public void sameLocals(int pos, int offsetDelta, int stackTag, int stackData) {}
+ public void sameLocals(int pos, int offsetDelta, int stackTag, int stackData)
+ throws BadBytecode {}
/**
* Invoked if the visited frame is a <code>chop_frame</code>.
@@ -256,9 +267,9 @@ public class StackMapTable extends AttributeInfo {
* @param offsetDelta
* @param k the <cod>k</code> last locals are absent.
*/
- public void chopFrame(int pos, int offsetDelta, int k) {}
+ public void chopFrame(int pos, int offsetDelta, int k) throws BadBytecode {}
- private int appendFrame(int pos, int type) {
+ private int appendFrame(int pos, int type) throws BadBytecode {
int k = type - 251;
int offset = ByteArray.readU16bit(info, pos + 1);
int[] tags = new int[k];
@@ -290,9 +301,10 @@ public class StackMapTable extends AttributeInfo {
* @param data <code>locals[i].cpool_index</code>
* or <cod>locals[i].offset</code>.
*/
- public void appendFrame(int pos, int offsetDelta, int[] tags, int[] data) {}
+ public void appendFrame(int pos, int offsetDelta, int[] tags, int[] data)
+ throws BadBytecode {}
- private int fullFrame(int pos) {
+ private int fullFrame(int pos) throws BadBytecode {
int offset = ByteArray.readU16bit(info, pos + 1);
int numOfLocals = ByteArray.readU16bit(info, pos + 3);
int[] localsTags = new int[numOfLocals];
@@ -319,7 +331,8 @@ public class StackMapTable extends AttributeInfo {
* or <code>stack[i].offset</code>
*/
public void fullFrame(int pos, int offsetDelta, int[] localTags, int[] localData,
- int[] stackTags, int[] stackData) {}
+ int[] stackTags, int[] stackData)
+ throws BadBytecode {}
private int verifyTypeInfo(int pos, int n, int[] tags, int[] data) {
for (int i = 0; i < n; i++) {
@@ -335,15 +348,12 @@ public class StackMapTable extends AttributeInfo {
}
}
- static class Copier extends Walker {
+ static class SimpleCopy extends Walker {
private Writer writer;
- private ConstPool srcPool, destPool;
- public Copier(ConstPool src, byte[] data, ConstPool dest) {
+ public SimpleCopy(byte[] data) {
super(data);
writer = new Writer(data.length);
- srcPool = src;
- destPool = dest;
}
public byte[] doit() throws BadBytecode {
@@ -356,10 +366,7 @@ public class StackMapTable extends AttributeInfo {
}
public void sameLocals(int pos, int offsetDelta, int stackTag, int stackData) {
- if (stackTag == OBJECT)
- stackData = srcPool.copy(stackData, destPool, null);
-
- writer.sameLocals(offsetDelta, stackTag, stackData);
+ writer.sameLocals(offsetDelta, stackTag, copyData(stackTag, stackData));
}
public void chopFrame(int pos, int offsetDelta, int k) {
@@ -376,7 +383,32 @@ public class StackMapTable extends AttributeInfo {
stackTags, copyData(stackTags, stackData));
}
- private int[] copyData(int[] tags, int[] data) {
+ protected int copyData(int tag, int data) {
+ return data;
+ }
+
+ protected int[] copyData(int[] tags, int[] data) {
+ return data;
+ }
+ }
+
+ static class Copier extends SimpleCopy {
+ private ConstPool srcPool, destPool;
+
+ public Copier(ConstPool src, byte[] data, ConstPool dest) {
+ super(data);
+ srcPool = src;
+ destPool = dest;
+ }
+
+ protected int copyData(int tag, int data) {
+ if (tag == OBJECT)
+ return srcPool.copy(data, destPool, null);
+ else
+ return data;
+ }
+
+ protected int[] copyData(int[] tags, int[] data) {
int[] newData = new int[data.length];
for (int i = 0; i < data.length; i++)
if (tags[i] == OBJECT)
@@ -391,23 +423,11 @@ public class StackMapTable extends AttributeInfo {
/**
* A writer of stack map tables.
*/
- static class Writer {
+ public static class Writer {
ByteArrayOutputStream output;
int numOfEntries;
/**
- * Prints the stack table map.
- */
- public static void print(StackMapTable smt, PrintWriter writer) {
- try {
- new Printer(smt.get(), writer).parse();
- }
- catch (BadBytecode e) {
- writer.println(e.getMessage());
- }
- }
-
- /**
* Constructs a writer.
* @param size the initial buffer size.
*/
@@ -522,6 +542,7 @@ public class StackMapTable extends AttributeInfo {
writeTypeInfo(localTags[i], localData[i]);
n = stackTags.length;
+ write16(n);
for (int i = 0; i < n; i++)
writeTypeInfo(stackTags[i], stackData[i]);
}
@@ -541,6 +562,18 @@ public class StackMapTable extends AttributeInfo {
static class Printer extends Walker {
private PrintWriter writer;
+ /**
+ * Prints the stack table map.
+ */
+ public static void print(StackMapTable smt, PrintWriter writer) {
+ try {
+ new Printer(smt.get(), writer).parse();
+ }
+ catch (BadBytecode e) {
+ writer.println(e.getMessage());
+ }
+ }
+
Printer(byte[] data, PrintWriter pw) {
super(data);
writer = pw;
@@ -612,4 +645,166 @@ public class StackMapTable extends AttributeInfo {
writer.println(msg);
}
}
+
+ void shiftPc(int where, int gapSize, boolean exclusive)
+ throws BadBytecode
+ {
+ new Shifter(this, where, gapSize, exclusive).doit();
+ }
+
+ static class Shifter extends Walker {
+ private StackMapTable stackMap;
+ private int where, gap;
+ private int position;
+ private byte[] updatedInfo;
+ private boolean exclusive;
+
+ public Shifter(StackMapTable smt, int where, int gap, boolean exclusive) {
+ super(smt);
+ stackMap = smt;
+ this.where = where;
+ this.gap = gap;
+ this.position = 0;
+ this.updatedInfo = null;
+ this.exclusive = exclusive;
+ }
+
+ public void doit() throws BadBytecode {
+ parse();
+ if (updatedInfo != null)
+ stackMap.set(updatedInfo);
+ }
+
+ public void sameFrame(int pos, int offsetDelta) {
+ update(pos, offsetDelta, 0, 251);
+ }
+
+ public void sameLocals(int pos, int offsetDelta, int stackTag, int stackData) {
+ update(pos, offsetDelta, 64, 247);
+ }
+
+ private void update(int pos, int offsetDelta, int base, int entry) {
+ int oldPos = position;
+ position = oldPos + offsetDelta + (oldPos == 0 ? 0 : 1);
+ boolean match;
+ if (exclusive)
+ match = oldPos < where && where <= position;
+ else
+ match = oldPos <= where && where < position;
+
+ if (match) {
+ int newDelta = offsetDelta + gap;
+ position += gap;
+ if (newDelta < 64)
+ info[pos] = (byte)(newDelta + base);
+ else if (offsetDelta < 64) {
+ byte[] newinfo = insertGap(info, pos, 2);
+ newinfo[pos] = (byte)entry;
+ ByteArray.write16bit(newDelta, info, pos + 1);
+ updatedInfo = newinfo;
+ }
+ else
+ ByteArray.write16bit(newDelta, info, pos + 1);
+ }
+ }
+
+ private static byte[] insertGap(byte[] info, int where, int gap) {
+ int len = info.length;
+ byte[] newinfo = new byte[len + gap];
+ for (int i = 0; i < len; i++)
+ newinfo[i + (i < where ? 0 : gap)] = info[i];
+
+ return newinfo;
+ }
+
+ public void chopFrame(int pos, int offsetDelta, int k) {
+ update(pos, offsetDelta);
+ }
+
+ public void appendFrame(int pos, int offsetDelta, int[] tags, int[] data) {
+ update(pos, offsetDelta);
+ }
+
+ public void fullFrame(int pos, int offsetDelta, int[] localTags, int[] localData,
+ int[] stackTags, int[] stackData) {
+ update(pos, offsetDelta);
+ }
+
+ private void update(int pos, int offsetDelta) {
+ int oldPos = position;
+ position = oldPos + offsetDelta + (oldPos == 0 ? 0 : 1);
+ boolean match;
+ if (exclusive)
+ match = oldPos < where && where <= position;
+ else
+ match = oldPos <= where && where < position;
+
+ if (match) {
+ int newDelta = offsetDelta + gap;
+ ByteArray.write16bit(newDelta, info, pos + 1);
+ position += gap;
+ }
+ }
+ }
+
+ /**
+ * Undocumented method. Do not use; internal-use only.
+ *
+ * <p>This method is for javassist.convert.TransformNew.
+ * It is called to update the stack map table 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 {
+ try {
+ byte[] data = new NewRemover(this.get(), where).doit();
+ this.set(data);
+ }
+ catch (BadBytecode e) {
+ throw new CannotCompileException("bad stack map table", e);
+ }
+ }
+
+ static class NewRemover extends SimpleCopy {
+ int posOfNew;
+
+ public NewRemover(byte[] data, int pos) {
+ super(data);
+ posOfNew = pos;
+ }
+
+ public void sameLocals(int pos, int offsetDelta, int stackTag, int stackData) {
+ if (stackTag == UNINIT && stackData == posOfNew)
+ super.sameFrame(pos, offsetDelta);
+ else
+ super.sameLocals(pos, offsetDelta, stackTag, stackData);
+ }
+
+ public void fullFrame(int pos, int offsetDelta, int[] localTags, int[] localData,
+ int[] stackTags, int[] stackData) {
+ int n = stackTags.length - 1;
+ for (int i = 0; i < n; i++)
+ if (stackTags[i] == UNINIT && stackData[i] == posOfNew
+ && stackTags[i + 1] == UNINIT && stackData[i + 1] == posOfNew) {
+ n++;
+ int[] stackTags2 = new int[n - 2];
+ int[] stackData2 = new int[n - 2];
+ int k = 0;
+ for (int j = 0; j < n; j++)
+ if (j == i)
+ j++;
+ else {
+ stackTags2[k] = stackTags[j];
+ stackData2[k++] = stackData[j];
+ }
+
+ stackTags = stackTags2;
+ stackData = stackData2;
+ break;
+ }
+
+ super.fullFrame(pos, offsetDelta, localTags, localData, stackTags, stackData);
+ }
+ }
}
diff --git a/src/main/javassist/bytecode/stackmap/BasicBlock.java b/src/main/javassist/bytecode/stackmap/BasicBlock.java
index d7076152..4f0111bf 100644
--- a/src/main/javassist/bytecode/stackmap/BasicBlock.java
+++ b/src/main/javassist/bytecode/stackmap/BasicBlock.java
@@ -29,10 +29,10 @@ public class BasicBlock {
int n = ltypes.length;
for (int i = 0; i < n; i++)
if (ltypes[i] != localsTypes[i]) {
- localsTypes[i] = StackAnalyzer.EMPTY;
+ localsTypes[i] = StackAnalyzerCore.EMPTY;
localsData[i] = null;
}
- else if (ltypes[i] == StackAnalyzer.OBJECT
+ else if (ltypes[i] == StackAnalyzerCore.OBJECT
&& !ldata[i].equals(localsData[i]))
; // localsData[i] = ??;
}
diff --git a/src/main/javassist/bytecode/stackmap/StackAnalyzer.java b/src/main/javassist/bytecode/stackmap/StackAnalyzer.java
index 12b4892d..264ffe86 100644
--- a/src/main/javassist/bytecode/stackmap/StackAnalyzer.java
+++ b/src/main/javassist/bytecode/stackmap/StackAnalyzer.java
@@ -1,846 +1,10 @@
package javassist.bytecode.stackmap;
-import javassist.bytecode.StackMapTable;
-import javassist.bytecode.ByteArray;
-import javassist.bytecode.Opcode;
import javassist.bytecode.ConstPool;
-import javassist.bytecode.Descriptor;
-import javassist.bytecode.BadBytecode;
-public class StackAnalyzer {
- private ConstPool cpool;
- private int stackTop;
- private int[] stackTypes;
- private Object[] stackData; // String or Integer
-
- private int[] localsTypes;
- private boolean[] localsUpdated;
- private Object[] localsData; // String or Integer
-
- static final int EMPTY = -1;
- static final int TOP = StackMapTable.TOP;
- static final int INTEGER = StackMapTable.INTEGER;
- static final int FLOAT = StackMapTable.FLOAT;
- static final int DOUBLE = StackMapTable.DOUBLE;
- static final int LONG = StackMapTable.LONG;
- static final int NULL = StackMapTable.NULL;
- static final int THIS = StackMapTable.THIS;
- static final int OBJECT = StackMapTable.OBJECT;
- static final int UNINIT = StackMapTable.UNINIT;
+public class StackAnalyzer extends StackAnalyzerCore {
public StackAnalyzer(ConstPool cp, int maxStack, int maxLocals) {
- cpool = cp;
- stackTop = 0;
- stackTypes = null;
- localsTypes = null;
- growStack(maxStack);
- growLocals(maxLocals);
- }
-
- public void clearUpdatedFlags() {
- boolean[] updated = localsUpdated;
- for (int i = 0; i < updated.length; i++)
- updated[i] = false;
- }
-
- public void growStack(int size) {
- int oldSize;
- int[] types = new int[size];
- Object[] data = new Object[size];
- if (stackTypes == null)
- oldSize = 0;
- else {
- oldSize = stackTypes.length;
- System.arraycopy(stackTypes, 0, types, 0, oldSize);
- System.arraycopy(stackData, 0, data, 0, oldSize);
- }
-
- stackTypes = types;
- stackData = data;
- for (int i = oldSize; i < size; i++)
- stackTypes[i] = EMPTY;
- }
-
- public void growLocals(int size) {
- int oldSize;
- int[] types = new int[size];
- boolean[] updated = new boolean[size];
- Object[] data = new Object[size];
- if (localsTypes == null)
- oldSize = 0;
- else {
- oldSize = localsTypes.length;
- System.arraycopy(localsTypes, 0, types, 0, oldSize);
- System.arraycopy(localsUpdated, 0, updated, 0, oldSize);
- System.arraycopy(localsData, 0, data, 0, oldSize);
- }
-
- localsTypes = types;
- localsUpdated = updated;
- localsData = data;
- for (int i = oldSize; i < size; i++)
- localsTypes[i] = EMPTY;
- }
-
- public void pushType(int type, Object data) {
- stackTypes[stackTop] = type;
- stackData[stackTop++] = data;
- }
-
- /**
- * @return the size of the instruction at POS.
- */
- protected int doOpcode(int pos, byte[] code) throws BadBytecode {
- int op = code[pos] & 0xff;
- if (op < 96)
- if (op < 54)
- return doOpcode0_53(pos, code, op);
- else
- return doOpcode54_95(pos, code, op);
- else
- if (op < 148)
- return doOpcode96_147(pos, code, op);
- else
- return doOpcode148_201(pos, code, op);
- }
-
- protected void visitBranch(int pos, byte[] code, int offset) {}
- protected void visitGoto(int pos, byte[] code, int offset) {}
- protected void visitTableSwitch(int pos, byte[] code, int n, int offsetPos, int defaultByte) {}
- protected void visitLookupSwitch(int pos, byte[] code, int n, int pairsPos, int defaultByte) {}
- protected void visitReturn(int pos, byte[] code) {}
- protected void visitThrow(int pos, byte[] code) {}
-
- /**
- * Invoked when the visited instruction is jsr.
- */
- protected void visitJSR(int pos, byte[] code) throws BadBytecode {
- throwBadBytecode(pos, "jsr");
- }
-
- /**
- * Invoked when the visited instruction is ret.
- */
- protected void visitRET(int pos, byte[] code) throws BadBytecode {
- throwBadBytecode(pos, "ret");
- }
-
- private void throwBadBytecode(int pos, String name) throws BadBytecode {
- throw new BadBytecode(name + " at " + pos);
- }
-
- private int doOpcode0_53(int pos, byte[] code, int op) throws BadBytecode {
- int[] stackTypes = this.stackTypes;
- switch (op) {
- case Opcode.NOP :
- break;
- case Opcode.ACONST_NULL :
- stackTypes[stackTop++] = NULL;
- break;
- case Opcode.ICONST_M1 :
- case Opcode.ICONST_0 :
- case Opcode.ICONST_1 :
- case Opcode.ICONST_2 :
- case Opcode.ICONST_3 :
- case Opcode.ICONST_4 :
- case Opcode.ICONST_5 :
- stackTypes[stackTop++] = INTEGER;
- break;
- case Opcode.LCONST_0 :
- case Opcode.LCONST_1 :
- stackTypes[stackTop++] = LONG;
- stackTypes[stackTop++] = TOP;
- break;
- case Opcode.FCONST_0 :
- case Opcode.FCONST_1 :
- case Opcode.FCONST_2 :
- stackTypes[stackTop++] = FLOAT;
- break;
- case Opcode.DCONST_0 :
- case Opcode.DCONST_1 :
- stackTypes[stackTop++] = DOUBLE;
- stackTypes[stackTop++] = TOP;
- break;
- case Opcode.BIPUSH :
- case Opcode.SIPUSH :
- stackTypes[stackTop++] = INTEGER;
- return op == Opcode.SIPUSH ? 3 : 2;
- case Opcode.LDC :
- doLDC(code[pos + 1] & 0xff);
- return 2;
- case Opcode.LDC_W :
- case Opcode.LDC2_W :
- doLDC(ByteArray.readU16bit(code, pos + 1));
- return 3;
- case Opcode.ILOAD :
- return doXLOAD(INTEGER);
- case Opcode.LLOAD :
- return doXLOAD(LONG);
- case Opcode.FLOAD :
- return doXLOAD(FLOAT);
- case Opcode.DLOAD :
- return doXLOAD(DOUBLE);
- case Opcode.ALOAD :
- stackTypes[stackTop] = OBJECT;
- stackData[stackTop++] = localsData[code[pos + 1] & 0xff];
- return 2;
- case Opcode.ILOAD_0 :
- case Opcode.ILOAD_1 :
- case Opcode.ILOAD_2 :
- case Opcode.ILOAD_3 :
- stackTypes[stackTop++] = INTEGER;
- break;
- case Opcode.LLOAD_0 :
- case Opcode.LLOAD_1 :
- case Opcode.LLOAD_2 :
- case Opcode.LLOAD_3 :
- stackTypes[stackTop++] = LONG;
- stackTypes[stackTop++] = TOP;
- break;
- case Opcode.FLOAD_0 :
- case Opcode.FLOAD_1 :
- case Opcode.FLOAD_2 :
- case Opcode.FLOAD_3 :
- stackTypes[stackTop++] = FLOAT;
- break;
- case Opcode.DLOAD_0 :
- case Opcode.DLOAD_1 :
- case Opcode.DLOAD_2 :
- case Opcode.DLOAD_3 :
- stackTypes[stackTop++] = DOUBLE;
- stackTypes[stackTop++] = TOP;
- break;
- case Opcode.ALOAD_0 :
- case Opcode.ALOAD_1 :
- case Opcode.ALOAD_2 :
- case Opcode.ALOAD_3 :
- stackTypes[stackTop] = OBJECT;
- stackData[stackTop++] = localsData[op - Opcode.ALOAD_0];
- break;
- case Opcode.IALOAD :
- stackTypes[--stackTop - 1] = INTEGER;
- break;
- case Opcode.LALOAD :
- stackTypes[stackTop - 2] = LONG;
- stackTypes[stackTop - 1] = TOP;
- break;
- case Opcode.FALOAD :
- stackTypes[--stackTop - 1] = FLOAT;
- break;
- case Opcode.DALOAD :
- stackTypes[stackTop - 2] = DOUBLE;
- stackTypes[stackTop - 1] = TOP;
- break;
- case Opcode.AALOAD : {
- int s = --stackTop - 1;
- stackTypes[s] = OBJECT;
- Object data = stackData[s];
- if (data != null && data instanceof String)
- stackData[s] = getDerefType((String)data);
- else
- throw new BadBytecode("bad AALOAD");
-
- break; }
- case Opcode.BALOAD :
- case Opcode.CALOAD :
- case Opcode.SALOAD :
- stackTypes[--stackTop - 1] = INTEGER;
- break;
- default :
- throw new RuntimeException("fatal");
- }
-
- return 1;
- }
-
- private void doLDC(int index) {
- int[] stackTypes = this.stackTypes;
- int tag = cpool.getTag(index);
- if (tag == ConstPool.CONST_String) {
- stackTypes[stackTop] = OBJECT;
- stackData[stackTop++] = "java/lang/String";
- }
- else if (tag == ConstPool.CONST_Integer)
- stackTypes[stackTop++] = INTEGER;
- else if (tag == ConstPool.CONST_Float)
- stackTypes[stackTop++] = FLOAT;
- else if (tag == ConstPool.CONST_Long) {
- stackTypes[stackTop++] = LONG;
- stackTypes[stackTop++] = TOP;
- }
- else if (tag == ConstPool.CONST_Double) {
- stackTypes[stackTop++] = DOUBLE;
- stackTypes[stackTop++] = TOP;
- }
- else if (tag == ConstPool.CONST_Class) {
- stackTypes[stackTop] = OBJECT;
- stackData[stackTop++] = "java/lang/Class";
- }
- else
- throw new RuntimeException("bad LDC: " + tag);
- }
-
- private int doXLOAD(int type) {
- int[] stackTypes = this.stackTypes;
- stackTypes[stackTop++] = type;
- if (type == LONG || type == DOUBLE)
- stackTypes[stackTop++] = TOP;
-
- return 2;
- }
-
- private String getDerefType(String type) throws BadBytecode {
- if (type.charAt(0) == '[') {
- String type2 = type.substring(1);
- if (type2.length() > 0) {
- char c = type2.charAt(0);
- if (c == '[')
- return type2;
- else if (c == 'L')
- return type2.substring(1, type.length() - 2);
- else
- return type2;
- }
- }
-
- throw new BadBytecode("bad array type for AALOAD: " + type);
- }
-
- private int doOpcode54_95(int pos, byte[] code, int op) {
- int[] localsTypes = this.localsTypes;
- int[] stackTypes = this.stackTypes;
- switch (op) {
- case Opcode.ISTORE :
- return doXSTORE(pos, code, INTEGER);
- case Opcode.LSTORE :
- return doXSTORE(pos, code, LONG);
- case Opcode.FSTORE :
- return doXSTORE(pos, code, FLOAT);
- case Opcode.DSTORE :
- return doXSTORE(pos, code, DOUBLE);
- case Opcode.ASTORE :
- return doXSTORE(pos, code, OBJECT);
- case Opcode.ISTORE_0 :
- case Opcode.ISTORE_1 :
- case Opcode.ISTORE_2 :
- case Opcode.ISTORE_3 :
- { int var = op - Opcode.ISTORE_0;
- localsTypes[var] = INTEGER;
- localsUpdated[var] = true; }
- stackTop--;
- break;
- case Opcode.LSTORE_0 :
- case Opcode.LSTORE_1 :
- case Opcode.LSTORE_2 :
- case Opcode.LSTORE_3 :
- { int var = op - Opcode.LSTORE_0;
- localsTypes[var] = LONG;
- localsTypes[var + 1] = TOP;
- localsUpdated[var] = true; }
- stackTop -= 2;
- break;
- case Opcode.FSTORE_0 :
- case Opcode.FSTORE_1 :
- case Opcode.FSTORE_2 :
- case Opcode.FSTORE_3 :
- { int var = op - Opcode.FSTORE_0;
- localsTypes[var] = FLOAT;
- localsUpdated[var] = true; }
- stackTop--;
- break;
- case Opcode.DSTORE_0 :
- case Opcode.DSTORE_1 :
- case Opcode.DSTORE_2 :
- case Opcode.DSTORE_3 :
- { int var = op - Opcode.DSTORE_0;
- localsTypes[var] = DOUBLE;
- localsTypes[var + 1] = TOP;
- localsUpdated[var] = true; }
- stackTop -= 2;
- break;
- case Opcode.ASTORE_0 :
- case Opcode.ASTORE_1 :
- case Opcode.ASTORE_2 :
- case Opcode.ASTORE_3 :
- { int var = op - Opcode.ASTORE_0;
- localsTypes[var] = OBJECT;
- localsUpdated[var] = true;
- localsData[var] = stackData[--stackTop]; }
- break;
- case Opcode.IASTORE :
- case Opcode.LASTORE :
- case Opcode.FASTORE :
- case Opcode.DASTORE :
- case Opcode.AASTORE :
- case Opcode.BASTORE :
- case Opcode.CASTORE :
- case Opcode.SASTORE :
- stackTop -= (op == Opcode.LASTORE || op == Opcode.DASTORE) ? 4 : 3;
- break;
- case Opcode.POP :
- stackTop--;
- break;
- case Opcode.POP2 :
- stackTop -= 2;
- break;
- case Opcode.DUP : {
- int sp = stackTop;
- stackTypes[sp] = stackTypes[sp - 1];
- stackData[sp] = stackData[sp - 1];
- stackTop = sp + 1;
- break; }
- case Opcode.DUP_X1 :
- case Opcode.DUP_X2 : {
- int len = op - Opcode.DUP_X1 + 2;
- doDUP_XX(1, len);
- int sp = stackTop;
- stackTypes[sp - len] = stackTypes[sp];
- stackData[sp - len] = stackData[sp];
- stackTop = sp + 1;
- break; }
- case Opcode.DUP2 :
- doDUP_XX(2, 2);
- stackTop += 2;
- break;
- case Opcode.DUP2_X1 :
- case Opcode.DUP2_X2 : {
- int len = op - Opcode.DUP2_X1 + 3;
- doDUP_XX(2, len);
- Object[] stackData = this.stackData;
- int sp = stackTop;
- stackTypes[sp - len] = stackTypes[sp];
- stackData[sp - len] = stackData[sp];
- stackTypes[sp - len + 1] = stackTypes[sp + 1];
- stackData[sp - len + 1] = stackData[sp + 1];
- stackTop = sp + 2;
- break; }
- case Opcode.SWAP : {
- Object[] stackData = this.stackData;
- int sp = stackTop - 1;
- int t = stackTypes[sp];
- Object d = stackData[sp];
- stackTypes[sp] = stackTypes[sp - 1];
- stackData[sp] = stackData[sp - 1];
- stackTypes[sp - 1] = t;
- stackData[sp - 1] = d;
- break; }
- default :
- throw new RuntimeException("fatal");
- }
-
- return 1;
- }
-
- private int doXSTORE(int pos, byte[] code, int type) {
- int index = code[pos + 1] & 0xff;
- return doXSTORE(index, type);
- }
-
- private int doXSTORE(int index, int type) {
- stackTop--;
- localsTypes[index] = type;
- localsUpdated[index] = true;
- if (type == LONG || type == DOUBLE) {
- stackTop--;
- localsTypes[index + 1] = TOP;
- }
- else if (type == OBJECT)
- localsData[index] = stackData[stackTop];
-
- return 2;
- }
-
- private void doDUP_XX(int delta, int len) {
- int types[] = stackTypes;
- Object data[] = stackData;
- int sp = stackTop;
- int end = sp - len;
- while (sp > end) {
- types[sp + delta] = types[sp];
- data[sp + delta] = data[sp];
- sp--;
- }
- }
-
- private int doOpcode96_147(int pos, byte[] code, int op) {
- if (op <= Opcode.LXOR) { // IADD...LXOR
- stackTop -= Opcode.STACK_GROW[op];
- return 1;
- }
-
- switch (op) {
- case Opcode.IINC :
- return 3;
- case Opcode.I2L :
- stackTypes[stackTop] = LONG;
- stackTypes[stackTop - 1] = TOP;
- stackTop++;
- break;
- case Opcode.I2F :
- stackTypes[stackTop - 1] = FLOAT;
- break;
- case Opcode.I2D :
- stackTypes[stackTop] = DOUBLE;
- stackTypes[stackTop - 1] = TOP;
- stackTop++;
- break;
- case Opcode.L2I :
- stackTypes[--stackTop - 1] = INTEGER;
- break;
- case Opcode.L2F :
- stackTypes[--stackTop - 1] = FLOAT;
- break;
- case Opcode.L2D :
- stackTypes[stackTop - 1] = DOUBLE;
- break;
- case Opcode.F2I :
- stackTypes[stackTop - 1] = INTEGER;
- break;
- case Opcode.F2L :
- stackTypes[stackTop - 1] = TOP;
- stackTypes[stackTop++] = LONG;
- break;
- case Opcode.F2D :
- stackTypes[stackTop - 1] = TOP;
- stackTypes[stackTop++] = DOUBLE;
- break;
- case Opcode.D2I :
- stackTypes[--stackTop - 1] = INTEGER;
- break;
- case Opcode.D2L :
- stackTypes[stackTop - 1] = LONG;
- break;
- case Opcode.D2F :
- stackTypes[--stackTop - 1] = FLOAT;
- break;
- case Opcode.I2B :
- case Opcode.I2C :
- case Opcode.I2S :
- break;
- default :
- throw new RuntimeException("fatal");
- }
-
- return 1;
- }
-
- private int doOpcode148_201(int pos, byte[] code, int op) throws BadBytecode {
- switch (op) {
- case Opcode.LCMP :
- stackTypes[stackTop - 4] = INTEGER;
- stackTop -= 3;
- break;
- case Opcode.FCMPL :
- case Opcode.FCMPG :
- stackTypes[--stackTop - 1] = INTEGER;
- break;
- case Opcode.DCMPL :
- case Opcode.DCMPG :
- stackTypes[stackTop - 4] = INTEGER;
- stackTop -= 3;
- break;
- case Opcode.IFEQ :
- case Opcode.IFNE :
- case Opcode.IFLT :
- case Opcode.IFGE :
- case Opcode.IFGT :
- case Opcode.IFLE :
- stackTop--; // branch
- visitBranch(pos, code, ByteArray.readS16bit(code, pos + 1));
- return 3;
- case Opcode.IF_ICMPEQ :
- case Opcode.IF_ICMPNE :
- case Opcode.IF_ICMPLT :
- case Opcode.IF_ICMPGE :
- case Opcode.IF_ICMPGT :
- case Opcode.IF_ICMPLE :
- case Opcode.IF_ACMPEQ :
- case Opcode.IF_ACMPNE :
- stackTop -= 2; // branch
- visitBranch(pos, code, ByteArray.readS16bit(code, pos + 1));
- return 3;
- case Opcode.GOTO :
- visitGoto(pos, code, ByteArray.readS16bit(code, pos + 1));
- return 3; // branch
- case Opcode.JSR :
- stackTypes[stackTop++] = TOP; // not allowed?
- visitJSR(pos, code);
- return 3; // branch
- case Opcode.RET :
- visitRET(pos, code);
- return 2; // not allowed?
- case Opcode.TABLESWITCH : {
- stackTop--; // branch
- int pos2 = (pos & ~3) + 8;
- int low = ByteArray.read32bit(code, pos2);
- int high = ByteArray.read32bit(code, pos2 + 4);
- int n = high - low + 1;
- visitTableSwitch(pos, code, n, pos2 + 8, ByteArray.read32bit(code, pos2 - 4));
- return n * 4 + 16 - (pos & 3); }
- case Opcode.LOOKUPSWITCH : {
- stackTop--; // branch
- int pos2 = (pos & ~3) + 8;
- int n = ByteArray.read32bit(code, pos2);
- visitLookupSwitch(pos, code, n, pos2 + 4, ByteArray.read32bit(code, pos2 - 4));
- return n * 8 + 12 - (pos & 3); }
- case Opcode.IRETURN :
- stackTop--;
- visitReturn(pos, code);
- break;
- case Opcode.LRETURN :
- stackTop -= 2;
- visitReturn(pos, code);
- break;
- case Opcode.FRETURN :
- stackTop--;
- visitReturn(pos, code);
- break;
- case Opcode.DRETURN :
- stackTop -= 2;
- visitReturn(pos, code);
- break;
- case Opcode.ARETURN :
- stackTop--;
- visitReturn(pos, code);
- break;
- case Opcode.RETURN :
- visitReturn(pos, code);
- break;
- case Opcode.GETSTATIC :
- return doFieldAccess(pos, code, true);
- case Opcode.PUTSTATIC :
- return doFieldAccess(pos, code, false);
- case Opcode.GETFIELD :
- stackTop--;
- return doFieldAccess(pos, code, true);
- case Opcode.PUTFIELD :
- stackTop--;
- return doFieldAccess(pos, code, false);
- case Opcode.INVOKEVIRTUAL :
- case Opcode.INVOKESPECIAL :
- return doInvokeMethod(pos, code, 1);
- case Opcode.INVOKESTATIC :
- return doInvokeMethod(pos, code, 0);
- case Opcode.INVOKEINTERFACE :
- return doInvokeIntfMethod(pos, code, 1);
- case 186 :
- throw new RuntimeException("bad opcode 186");
- case Opcode.NEW : {
- int i = ByteArray.readU16bit(code, pos + 1);
- stackTypes[stackTop - 1] = UNINIT;
- stackData[stackTop - 1] = new Integer(pos);
- return 3; }
- case Opcode.NEWARRAY :
- return doNEWARRAY(pos, code);
- case Opcode.ANEWARRAY : {
- int i = ByteArray.readU16bit(code, pos + 1);
- stackTypes[stackTop - 1] = OBJECT;
- stackData[stackTop - 1]
- = "[L" + cpool.getClassInfo(i).replace('.', '/') + ";";
- return 3; }
- case Opcode.ARRAYLENGTH :
- stackTypes[stackTop - 1] = INTEGER;
- break;
- case Opcode.ATHROW :
- stackTop--; // branch?
- visitThrow(pos, code);
- break;
- case Opcode.CHECKCAST : {
- int i = ByteArray.readU16bit(code, pos + 1);
- stackData[stackTop - 1] = cpool.getClassInfo(i);
- return 3; }
- case Opcode.INSTANCEOF :
- stackTypes[stackTop - 1] = INTEGER;
- return 3;
- case Opcode.MONITORENTER :
- case Opcode.MONITOREXIT :
- stackTop--;
- break;
- case Opcode.WIDE :
- return doWIDE(pos, code);
- case Opcode.MULTIANEWARRAY :
- return doMultiANewArray(pos, code);
- case Opcode.IFNULL :
- case Opcode.IFNONNULL :
- stackTop--; // branch
- visitBranch(pos, code, ByteArray.readS16bit(code, pos + 1));
- return 3;
- case Opcode.GOTO_W :
- visitGoto(pos, code, ByteArray.read32bit(code, pos + 1));
- return 5; // branch
- case Opcode.JSR_W :
- stackTypes[stackTop++] = TOP; // not allowed?
- visitJSR(pos, code);
- return 5;
- }
- return 1;
- }
-
- private int doWIDE(int pos, byte[] code) {
- int op = code[pos + 1] & 0xff;
- switch (op) {
- case Opcode.ILOAD :
- doXLOAD(INTEGER);
- break;
- case Opcode.LLOAD :
- doXLOAD(LONG);
- break;
- case Opcode.FLOAD :
- doXLOAD(FLOAT);
- break;
- case Opcode.DLOAD :
- doXLOAD(DOUBLE);
- break;
- case Opcode.ALOAD :
- stackTypes[stackTop] = OBJECT;
- stackData[stackTop++] = localsData[ByteArray.readU16bit(code, pos)];
- break;
- case Opcode.ISTORE :
- return doWIDE_STORE(pos, code, INTEGER);
- case Opcode.LSTORE :
- return doWIDE_STORE(pos, code, LONG);
- case Opcode.FSTORE :
- return doWIDE_STORE(pos, code, FLOAT);
- case Opcode.DSTORE :
- return doWIDE_STORE(pos, code, DOUBLE);
- case Opcode.ASTORE :
- return doWIDE_STORE(pos, code, OBJECT);
- case Opcode.IINC :
- return 6;
- case Opcode.RET :
- break;
- default :
- throw new RuntimeException("bad WIDE instruction: " + op);
- }
-
- return 4;
- }
-
- private int doWIDE_STORE(int pos, byte[] code, int type) {
- int index = ByteArray.readU16bit(code, pos);
- return doXSTORE(index, type);
- }
-
- private int doFieldAccess(int pos, byte[] code, boolean isGet) {
- int index = ByteArray.readU16bit(code, pos + 1);
- String desc = cpool.getFieldrefType(index);
- if (isGet)
- pushMemberType(desc);
- else
- stackTop -= Descriptor.dataSize(desc);
-
- return 3;
- }
-
- private int doNEWARRAY(int pos, byte[] code) {
- int s = stackTop - 1;
- stackTypes[s] = OBJECT;
- String type;
- switch (code[pos + 1] & 0xff) {
- case Opcode.T_BOOLEAN :
- type = "[Z";
- break;
- case Opcode.T_CHAR :
- type = "[C";
- break;
- case Opcode.T_FLOAT :
- type = "[F";
- break;
- case Opcode.T_DOUBLE :
- type = "[D";
- break;
- case Opcode.T_BYTE :
- type = "[B";
- break;
- case Opcode.T_SHORT :
- type = "[S";
- break;
- case Opcode.T_INT :
- type = "[I";
- break;
- case Opcode.T_LONG :
- type = "[J";
- break;
- default :
- throw new RuntimeException("bad newarray");
- }
-
- stackData[s] = type;
- return 2;
- }
-
- private int doMultiANewArray(int pos, byte[] code) {
- int i = ByteArray.readU16bit(code, pos + 1);
- int dim = code[pos + 3] & 0xff;
- stackTop -= dim - 1;
- String type = cpool.getClassInfo(i);
- StringBuffer sbuf = new StringBuffer();
- while (dim-- > 0)
- sbuf.append('[');
-
- sbuf.append('L').append(type.replace('.', '/')).append(';');
- stackTypes[stackTop - 1] = OBJECT;
- stackData[stackTop - 1] = sbuf.toString();
- return 4;
- }
-
- private int doInvokeMethod(int pos, byte[] code, int targetSize) {
- int i = ByteArray.readU16bit(code, pos + 1);
- String desc = cpool.getMethodrefType(i);
- stackTop -= Descriptor.paramSize(desc) + targetSize;
- pushMemberType(desc);
- return 3;
- }
-
- private int doInvokeIntfMethod(int pos, byte[] code, int targetSize) {
- int i = ByteArray.readU16bit(code, pos + 1);
- String desc = cpool.getInterfaceMethodrefType(i);
- stackTop -= Descriptor.paramSize(desc) + targetSize;
- pushMemberType(desc);
- return 5;
- }
-
- private void pushMemberType(String descriptor) {
- int top = 0;
- if (descriptor.charAt(0) == '(') {
- top = descriptor.indexOf(')') + 1;
- if (top < 1)
- throw new IndexOutOfBoundsException("bad descriptor: "
- + descriptor);
- }
-
- int[] types = stackTypes;
- int index = stackTop;
- switch (descriptor.charAt(top)) {
- case '[' :
- types[index] = OBJECT;
- stackData[index] = descriptor.substring(top);
- break;
- case 'L' :
- types[index] = OBJECT;
- stackData[index] = descriptor.substring(top + 1,
- descriptor.indexOf(';', top));
- break;
- case 'J' :
- types[index] = LONG;
- types[index + 1] = TOP;
- stackTop += 2;
- return;
- case 'F' :
- types[index] = FLOAT;
- break;
- case 'D' :
- types[index] = DOUBLE;
- types[index + 1] = TOP;
- stackTop += 2;
- return;
- case 'V' :
- return;
- default : // C, B, S, I, Z
- types[index] = INTEGER;
- break;
- }
-
- stackTop++;
+ super(cp, maxStack, maxLocals);
}
}
diff --git a/src/main/javassist/bytecode/stackmap/StackAnalyzerCore.java b/src/main/javassist/bytecode/stackmap/StackAnalyzerCore.java
new file mode 100644
index 00000000..c3c79c86
--- /dev/null
+++ b/src/main/javassist/bytecode/stackmap/StackAnalyzerCore.java
@@ -0,0 +1,846 @@
+package javassist.bytecode.stackmap;
+
+import javassist.bytecode.StackMapTable;
+import javassist.bytecode.ByteArray;
+import javassist.bytecode.Opcode;
+import javassist.bytecode.ConstPool;
+import javassist.bytecode.Descriptor;
+import javassist.bytecode.BadBytecode;
+
+public class StackAnalyzerCore {
+ private ConstPool cpool;
+ private int stackTop;
+ private int[] stackTypes;
+ private Object[] stackData; // String or Integer
+
+ private int[] localsTypes;
+ private boolean[] localsUpdated;
+ private Object[] localsData; // String or Integer
+
+ static final int EMPTY = -1;
+ static final int TOP = StackMapTable.TOP;
+ static final int INTEGER = StackMapTable.INTEGER;
+ static final int FLOAT = StackMapTable.FLOAT;
+ static final int DOUBLE = StackMapTable.DOUBLE;
+ static final int LONG = StackMapTable.LONG;
+ static final int NULL = StackMapTable.NULL;
+ static final int THIS = StackMapTable.THIS;
+ static final int OBJECT = StackMapTable.OBJECT;
+ static final int UNINIT = StackMapTable.UNINIT;
+
+ public StackAnalyzerCore(ConstPool cp, int maxStack, int maxLocals) {
+ cpool = cp;
+ stackTop = 0;
+ stackTypes = null;
+ localsTypes = null;
+ growStack(maxStack);
+ growLocals(maxLocals);
+ }
+
+ public void clearUpdatedFlags() {
+ boolean[] updated = localsUpdated;
+ for (int i = 0; i < updated.length; i++)
+ updated[i] = false;
+ }
+
+ public void growStack(int size) {
+ int oldSize;
+ int[] types = new int[size];
+ Object[] data = new Object[size];
+ if (stackTypes == null)
+ oldSize = 0;
+ else {
+ oldSize = stackTypes.length;
+ System.arraycopy(stackTypes, 0, types, 0, oldSize);
+ System.arraycopy(stackData, 0, data, 0, oldSize);
+ }
+
+ stackTypes = types;
+ stackData = data;
+ for (int i = oldSize; i < size; i++)
+ stackTypes[i] = EMPTY;
+ }
+
+ public void growLocals(int size) {
+ int oldSize;
+ int[] types = new int[size];
+ boolean[] updated = new boolean[size];
+ Object[] data = new Object[size];
+ if (localsTypes == null)
+ oldSize = 0;
+ else {
+ oldSize = localsTypes.length;
+ System.arraycopy(localsTypes, 0, types, 0, oldSize);
+ System.arraycopy(localsUpdated, 0, updated, 0, oldSize);
+ System.arraycopy(localsData, 0, data, 0, oldSize);
+ }
+
+ localsTypes = types;
+ localsUpdated = updated;
+ localsData = data;
+ for (int i = oldSize; i < size; i++)
+ localsTypes[i] = EMPTY;
+ }
+
+ public void pushType(int type, Object data) {
+ stackTypes[stackTop] = type;
+ stackData[stackTop++] = data;
+ }
+
+ /**
+ * @return the size of the instruction at POS.
+ */
+ protected int doOpcode(int pos, byte[] code) throws BadBytecode {
+ int op = code[pos] & 0xff;
+ if (op < 96)
+ if (op < 54)
+ return doOpcode0_53(pos, code, op);
+ else
+ return doOpcode54_95(pos, code, op);
+ else
+ if (op < 148)
+ return doOpcode96_147(pos, code, op);
+ else
+ return doOpcode148_201(pos, code, op);
+ }
+
+ protected void visitBranch(int pos, byte[] code, int offset) {}
+ protected void visitGoto(int pos, byte[] code, int offset) {}
+ protected void visitTableSwitch(int pos, byte[] code, int n, int offsetPos, int defaultByte) {}
+ protected void visitLookupSwitch(int pos, byte[] code, int n, int pairsPos, int defaultByte) {}
+ protected void visitReturn(int pos, byte[] code) {}
+ protected void visitThrow(int pos, byte[] code) {}
+
+ /**
+ * Invoked when the visited instruction is jsr.
+ */
+ protected void visitJSR(int pos, byte[] code) throws BadBytecode {
+ throwBadBytecode(pos, "jsr");
+ }
+
+ /**
+ * Invoked when the visited instruction is ret.
+ */
+ protected void visitRET(int pos, byte[] code) throws BadBytecode {
+ throwBadBytecode(pos, "ret");
+ }
+
+ private void throwBadBytecode(int pos, String name) throws BadBytecode {
+ throw new BadBytecode(name + " at " + pos);
+ }
+
+ private int doOpcode0_53(int pos, byte[] code, int op) throws BadBytecode {
+ int[] stackTypes = this.stackTypes;
+ switch (op) {
+ case Opcode.NOP :
+ break;
+ case Opcode.ACONST_NULL :
+ stackTypes[stackTop++] = NULL;
+ break;
+ case Opcode.ICONST_M1 :
+ case Opcode.ICONST_0 :
+ case Opcode.ICONST_1 :
+ case Opcode.ICONST_2 :
+ case Opcode.ICONST_3 :
+ case Opcode.ICONST_4 :
+ case Opcode.ICONST_5 :
+ stackTypes[stackTop++] = INTEGER;
+ break;
+ case Opcode.LCONST_0 :
+ case Opcode.LCONST_1 :
+ stackTypes[stackTop++] = LONG;
+ stackTypes[stackTop++] = TOP;
+ break;
+ case Opcode.FCONST_0 :
+ case Opcode.FCONST_1 :
+ case Opcode.FCONST_2 :
+ stackTypes[stackTop++] = FLOAT;
+ break;
+ case Opcode.DCONST_0 :
+ case Opcode.DCONST_1 :
+ stackTypes[stackTop++] = DOUBLE;
+ stackTypes[stackTop++] = TOP;
+ break;
+ case Opcode.BIPUSH :
+ case Opcode.SIPUSH :
+ stackTypes[stackTop++] = INTEGER;
+ return op == Opcode.SIPUSH ? 3 : 2;
+ case Opcode.LDC :
+ doLDC(code[pos + 1] & 0xff);
+ return 2;
+ case Opcode.LDC_W :
+ case Opcode.LDC2_W :
+ doLDC(ByteArray.readU16bit(code, pos + 1));
+ return 3;
+ case Opcode.ILOAD :
+ return doXLOAD(INTEGER);
+ case Opcode.LLOAD :
+ return doXLOAD(LONG);
+ case Opcode.FLOAD :
+ return doXLOAD(FLOAT);
+ case Opcode.DLOAD :
+ return doXLOAD(DOUBLE);
+ case Opcode.ALOAD :
+ stackTypes[stackTop] = OBJECT;
+ stackData[stackTop++] = localsData[code[pos + 1] & 0xff];
+ return 2;
+ case Opcode.ILOAD_0 :
+ case Opcode.ILOAD_1 :
+ case Opcode.ILOAD_2 :
+ case Opcode.ILOAD_3 :
+ stackTypes[stackTop++] = INTEGER;
+ break;
+ case Opcode.LLOAD_0 :
+ case Opcode.LLOAD_1 :
+ case Opcode.LLOAD_2 :
+ case Opcode.LLOAD_3 :
+ stackTypes[stackTop++] = LONG;
+ stackTypes[stackTop++] = TOP;
+ break;
+ case Opcode.FLOAD_0 :
+ case Opcode.FLOAD_1 :
+ case Opcode.FLOAD_2 :
+ case Opcode.FLOAD_3 :
+ stackTypes[stackTop++] = FLOAT;
+ break;
+ case Opcode.DLOAD_0 :
+ case Opcode.DLOAD_1 :
+ case Opcode.DLOAD_2 :
+ case Opcode.DLOAD_3 :
+ stackTypes[stackTop++] = DOUBLE;
+ stackTypes[stackTop++] = TOP;
+ break;
+ case Opcode.ALOAD_0 :
+ case Opcode.ALOAD_1 :
+ case Opcode.ALOAD_2 :
+ case Opcode.ALOAD_3 :
+ stackTypes[stackTop] = OBJECT;
+ stackData[stackTop++] = localsData[op - Opcode.ALOAD_0];
+ break;
+ case Opcode.IALOAD :
+ stackTypes[--stackTop - 1] = INTEGER;
+ break;
+ case Opcode.LALOAD :
+ stackTypes[stackTop - 2] = LONG;
+ stackTypes[stackTop - 1] = TOP;
+ break;
+ case Opcode.FALOAD :
+ stackTypes[--stackTop - 1] = FLOAT;
+ break;
+ case Opcode.DALOAD :
+ stackTypes[stackTop - 2] = DOUBLE;
+ stackTypes[stackTop - 1] = TOP;
+ break;
+ case Opcode.AALOAD : {
+ int s = --stackTop - 1;
+ stackTypes[s] = OBJECT;
+ Object data = stackData[s];
+ if (data != null && data instanceof String)
+ stackData[s] = getDerefType((String)data);
+ else
+ throw new BadBytecode("bad AALOAD");
+
+ break; }
+ case Opcode.BALOAD :
+ case Opcode.CALOAD :
+ case Opcode.SALOAD :
+ stackTypes[--stackTop - 1] = INTEGER;
+ break;
+ default :
+ throw new RuntimeException("fatal");
+ }
+
+ return 1;
+ }
+
+ private void doLDC(int index) {
+ int[] stackTypes = this.stackTypes;
+ int tag = cpool.getTag(index);
+ if (tag == ConstPool.CONST_String) {
+ stackTypes[stackTop] = OBJECT;
+ stackData[stackTop++] = "java/lang/String";
+ }
+ else if (tag == ConstPool.CONST_Integer)
+ stackTypes[stackTop++] = INTEGER;
+ else if (tag == ConstPool.CONST_Float)
+ stackTypes[stackTop++] = FLOAT;
+ else if (tag == ConstPool.CONST_Long) {
+ stackTypes[stackTop++] = LONG;
+ stackTypes[stackTop++] = TOP;
+ }
+ else if (tag == ConstPool.CONST_Double) {
+ stackTypes[stackTop++] = DOUBLE;
+ stackTypes[stackTop++] = TOP;
+ }
+ else if (tag == ConstPool.CONST_Class) {
+ stackTypes[stackTop] = OBJECT;
+ stackData[stackTop++] = "java/lang/Class";
+ }
+ else
+ throw new RuntimeException("bad LDC: " + tag);
+ }
+
+ private int doXLOAD(int type) {
+ int[] stackTypes = this.stackTypes;
+ stackTypes[stackTop++] = type;
+ if (type == LONG || type == DOUBLE)
+ stackTypes[stackTop++] = TOP;
+
+ return 2;
+ }
+
+ private String getDerefType(String type) throws BadBytecode {
+ if (type.charAt(0) == '[') {
+ String type2 = type.substring(1);
+ if (type2.length() > 0) {
+ char c = type2.charAt(0);
+ if (c == '[')
+ return type2;
+ else if (c == 'L')
+ return type2.substring(1, type.length() - 2);
+ else
+ return type2;
+ }
+ }
+
+ throw new BadBytecode("bad array type for AALOAD: " + type);
+ }
+
+ private int doOpcode54_95(int pos, byte[] code, int op) {
+ int[] localsTypes = this.localsTypes;
+ int[] stackTypes = this.stackTypes;
+ switch (op) {
+ case Opcode.ISTORE :
+ return doXSTORE(pos, code, INTEGER);
+ case Opcode.LSTORE :
+ return doXSTORE(pos, code, LONG);
+ case Opcode.FSTORE :
+ return doXSTORE(pos, code, FLOAT);
+ case Opcode.DSTORE :
+ return doXSTORE(pos, code, DOUBLE);
+ case Opcode.ASTORE :
+ return doXSTORE(pos, code, OBJECT);
+ case Opcode.ISTORE_0 :
+ case Opcode.ISTORE_1 :
+ case Opcode.ISTORE_2 :
+ case Opcode.ISTORE_3 :
+ { int var = op - Opcode.ISTORE_0;
+ localsTypes[var] = INTEGER;
+ localsUpdated[var] = true; }
+ stackTop--;
+ break;
+ case Opcode.LSTORE_0 :
+ case Opcode.LSTORE_1 :
+ case Opcode.LSTORE_2 :
+ case Opcode.LSTORE_3 :
+ { int var = op - Opcode.LSTORE_0;
+ localsTypes[var] = LONG;
+ localsTypes[var + 1] = TOP;
+ localsUpdated[var] = true; }
+ stackTop -= 2;
+ break;
+ case Opcode.FSTORE_0 :
+ case Opcode.FSTORE_1 :
+ case Opcode.FSTORE_2 :
+ case Opcode.FSTORE_3 :
+ { int var = op - Opcode.FSTORE_0;
+ localsTypes[var] = FLOAT;
+ localsUpdated[var] = true; }
+ stackTop--;
+ break;
+ case Opcode.DSTORE_0 :
+ case Opcode.DSTORE_1 :
+ case Opcode.DSTORE_2 :
+ case Opcode.DSTORE_3 :
+ { int var = op - Opcode.DSTORE_0;
+ localsTypes[var] = DOUBLE;
+ localsTypes[var + 1] = TOP;
+ localsUpdated[var] = true; }
+ stackTop -= 2;
+ break;
+ case Opcode.ASTORE_0 :
+ case Opcode.ASTORE_1 :
+ case Opcode.ASTORE_2 :
+ case Opcode.ASTORE_3 :
+ { int var = op - Opcode.ASTORE_0;
+ localsTypes[var] = OBJECT;
+ localsUpdated[var] = true;
+ localsData[var] = stackData[--stackTop]; }
+ break;
+ case Opcode.IASTORE :
+ case Opcode.LASTORE :
+ case Opcode.FASTORE :
+ case Opcode.DASTORE :
+ case Opcode.AASTORE :
+ case Opcode.BASTORE :
+ case Opcode.CASTORE :
+ case Opcode.SASTORE :
+ stackTop -= (op == Opcode.LASTORE || op == Opcode.DASTORE) ? 4 : 3;
+ break;
+ case Opcode.POP :
+ stackTop--;
+ break;
+ case Opcode.POP2 :
+ stackTop -= 2;
+ break;
+ case Opcode.DUP : {
+ int sp = stackTop;
+ stackTypes[sp] = stackTypes[sp - 1];
+ stackData[sp] = stackData[sp - 1];
+ stackTop = sp + 1;
+ break; }
+ case Opcode.DUP_X1 :
+ case Opcode.DUP_X2 : {
+ int len = op - Opcode.DUP_X1 + 2;
+ doDUP_XX(1, len);
+ int sp = stackTop;
+ stackTypes[sp - len] = stackTypes[sp];
+ stackData[sp - len] = stackData[sp];
+ stackTop = sp + 1;
+ break; }
+ case Opcode.DUP2 :
+ doDUP_XX(2, 2);
+ stackTop += 2;
+ break;
+ case Opcode.DUP2_X1 :
+ case Opcode.DUP2_X2 : {
+ int len = op - Opcode.DUP2_X1 + 3;
+ doDUP_XX(2, len);
+ Object[] stackData = this.stackData;
+ int sp = stackTop;
+ stackTypes[sp - len] = stackTypes[sp];
+ stackData[sp - len] = stackData[sp];
+ stackTypes[sp - len + 1] = stackTypes[sp + 1];
+ stackData[sp - len + 1] = stackData[sp + 1];
+ stackTop = sp + 2;
+ break; }
+ case Opcode.SWAP : {
+ Object[] stackData = this.stackData;
+ int sp = stackTop - 1;
+ int t = stackTypes[sp];
+ Object d = stackData[sp];
+ stackTypes[sp] = stackTypes[sp - 1];
+ stackData[sp] = stackData[sp - 1];
+ stackTypes[sp - 1] = t;
+ stackData[sp - 1] = d;
+ break; }
+ default :
+ throw new RuntimeException("fatal");
+ }
+
+ return 1;
+ }
+
+ private int doXSTORE(int pos, byte[] code, int type) {
+ int index = code[pos + 1] & 0xff;
+ return doXSTORE(index, type);
+ }
+
+ private int doXSTORE(int index, int type) {
+ stackTop--;
+ localsTypes[index] = type;
+ localsUpdated[index] = true;
+ if (type == LONG || type == DOUBLE) {
+ stackTop--;
+ localsTypes[index + 1] = TOP;
+ }
+ else if (type == OBJECT)
+ localsData[index] = stackData[stackTop];
+
+ return 2;
+ }
+
+ private void doDUP_XX(int delta, int len) {
+ int types[] = stackTypes;
+ Object data[] = stackData;
+ int sp = stackTop;
+ int end = sp - len;
+ while (sp > end) {
+ types[sp + delta] = types[sp];
+ data[sp + delta] = data[sp];
+ sp--;
+ }
+ }
+
+ private int doOpcode96_147(int pos, byte[] code, int op) {
+ if (op <= Opcode.LXOR) { // IADD...LXOR
+ stackTop -= Opcode.STACK_GROW[op];
+ return 1;
+ }
+
+ switch (op) {
+ case Opcode.IINC :
+ return 3;
+ case Opcode.I2L :
+ stackTypes[stackTop] = LONG;
+ stackTypes[stackTop - 1] = TOP;
+ stackTop++;
+ break;
+ case Opcode.I2F :
+ stackTypes[stackTop - 1] = FLOAT;
+ break;
+ case Opcode.I2D :
+ stackTypes[stackTop] = DOUBLE;
+ stackTypes[stackTop - 1] = TOP;
+ stackTop++;
+ break;
+ case Opcode.L2I :
+ stackTypes[--stackTop - 1] = INTEGER;
+ break;
+ case Opcode.L2F :
+ stackTypes[--stackTop - 1] = FLOAT;
+ break;
+ case Opcode.L2D :
+ stackTypes[stackTop - 1] = DOUBLE;
+ break;
+ case Opcode.F2I :
+ stackTypes[stackTop - 1] = INTEGER;
+ break;
+ case Opcode.F2L :
+ stackTypes[stackTop - 1] = TOP;
+ stackTypes[stackTop++] = LONG;
+ break;
+ case Opcode.F2D :
+ stackTypes[stackTop - 1] = TOP;
+ stackTypes[stackTop++] = DOUBLE;
+ break;
+ case Opcode.D2I :
+ stackTypes[--stackTop - 1] = INTEGER;
+ break;
+ case Opcode.D2L :
+ stackTypes[stackTop - 1] = LONG;
+ break;
+ case Opcode.D2F :
+ stackTypes[--stackTop - 1] = FLOAT;
+ break;
+ case Opcode.I2B :
+ case Opcode.I2C :
+ case Opcode.I2S :
+ break;
+ default :
+ throw new RuntimeException("fatal");
+ }
+
+ return 1;
+ }
+
+ private int doOpcode148_201(int pos, byte[] code, int op) throws BadBytecode {
+ switch (op) {
+ case Opcode.LCMP :
+ stackTypes[stackTop - 4] = INTEGER;
+ stackTop -= 3;
+ break;
+ case Opcode.FCMPL :
+ case Opcode.FCMPG :
+ stackTypes[--stackTop - 1] = INTEGER;
+ break;
+ case Opcode.DCMPL :
+ case Opcode.DCMPG :
+ stackTypes[stackTop - 4] = INTEGER;
+ stackTop -= 3;
+ break;
+ case Opcode.IFEQ :
+ case Opcode.IFNE :
+ case Opcode.IFLT :
+ case Opcode.IFGE :
+ case Opcode.IFGT :
+ case Opcode.IFLE :
+ stackTop--; // branch
+ visitBranch(pos, code, ByteArray.readS16bit(code, pos + 1));
+ return 3;
+ case Opcode.IF_ICMPEQ :
+ case Opcode.IF_ICMPNE :
+ case Opcode.IF_ICMPLT :
+ case Opcode.IF_ICMPGE :
+ case Opcode.IF_ICMPGT :
+ case Opcode.IF_ICMPLE :
+ case Opcode.IF_ACMPEQ :
+ case Opcode.IF_ACMPNE :
+ stackTop -= 2; // branch
+ visitBranch(pos, code, ByteArray.readS16bit(code, pos + 1));
+ return 3;
+ case Opcode.GOTO :
+ visitGoto(pos, code, ByteArray.readS16bit(code, pos + 1));
+ return 3; // branch
+ case Opcode.JSR :
+ stackTypes[stackTop++] = TOP; // not allowed?
+ visitJSR(pos, code);
+ return 3; // branch
+ case Opcode.RET :
+ visitRET(pos, code);
+ return 2; // not allowed?
+ case Opcode.TABLESWITCH : {
+ stackTop--; // branch
+ int pos2 = (pos & ~3) + 8;
+ int low = ByteArray.read32bit(code, pos2);
+ int high = ByteArray.read32bit(code, pos2 + 4);
+ int n = high - low + 1;
+ visitTableSwitch(pos, code, n, pos2 + 8, ByteArray.read32bit(code, pos2 - 4));
+ return n * 4 + 16 - (pos & 3); }
+ case Opcode.LOOKUPSWITCH : {
+ stackTop--; // branch
+ int pos2 = (pos & ~3) + 8;
+ int n = ByteArray.read32bit(code, pos2);
+ visitLookupSwitch(pos, code, n, pos2 + 4, ByteArray.read32bit(code, pos2 - 4));
+ return n * 8 + 12 - (pos & 3); }
+ case Opcode.IRETURN :
+ stackTop--;
+ visitReturn(pos, code);
+ break;
+ case Opcode.LRETURN :
+ stackTop -= 2;
+ visitReturn(pos, code);
+ break;
+ case Opcode.FRETURN :
+ stackTop--;
+ visitReturn(pos, code);
+ break;
+ case Opcode.DRETURN :
+ stackTop -= 2;
+ visitReturn(pos, code);
+ break;
+ case Opcode.ARETURN :
+ stackTop--;
+ visitReturn(pos, code);
+ break;
+ case Opcode.RETURN :
+ visitReturn(pos, code);
+ break;
+ case Opcode.GETSTATIC :
+ return doFieldAccess(pos, code, true);
+ case Opcode.PUTSTATIC :
+ return doFieldAccess(pos, code, false);
+ case Opcode.GETFIELD :
+ stackTop--;
+ return doFieldAccess(pos, code, true);
+ case Opcode.PUTFIELD :
+ stackTop--;
+ return doFieldAccess(pos, code, false);
+ case Opcode.INVOKEVIRTUAL :
+ case Opcode.INVOKESPECIAL :
+ return doInvokeMethod(pos, code, 1);
+ case Opcode.INVOKESTATIC :
+ return doInvokeMethod(pos, code, 0);
+ case Opcode.INVOKEINTERFACE :
+ return doInvokeIntfMethod(pos, code, 1);
+ case 186 :
+ throw new RuntimeException("bad opcode 186");
+ case Opcode.NEW : {
+ int i = ByteArray.readU16bit(code, pos + 1);
+ stackTypes[stackTop - 1] = UNINIT;
+ stackData[stackTop - 1] = new Integer(pos);
+ return 3; }
+ case Opcode.NEWARRAY :
+ return doNEWARRAY(pos, code);
+ case Opcode.ANEWARRAY : {
+ int i = ByteArray.readU16bit(code, pos + 1);
+ stackTypes[stackTop - 1] = OBJECT;
+ stackData[stackTop - 1]
+ = "[L" + cpool.getClassInfo(i).replace('.', '/') + ";";
+ return 3; }
+ case Opcode.ARRAYLENGTH :
+ stackTypes[stackTop - 1] = INTEGER;
+ break;
+ case Opcode.ATHROW :
+ stackTop--; // branch?
+ visitThrow(pos, code);
+ break;
+ case Opcode.CHECKCAST : {
+ int i = ByteArray.readU16bit(code, pos + 1);
+ stackData[stackTop - 1] = cpool.getClassInfo(i);
+ return 3; }
+ case Opcode.INSTANCEOF :
+ stackTypes[stackTop - 1] = INTEGER;
+ return 3;
+ case Opcode.MONITORENTER :
+ case Opcode.MONITOREXIT :
+ stackTop--;
+ break;
+ case Opcode.WIDE :
+ return doWIDE(pos, code);
+ case Opcode.MULTIANEWARRAY :
+ return doMultiANewArray(pos, code);
+ case Opcode.IFNULL :
+ case Opcode.IFNONNULL :
+ stackTop--; // branch
+ visitBranch(pos, code, ByteArray.readS16bit(code, pos + 1));
+ return 3;
+ case Opcode.GOTO_W :
+ visitGoto(pos, code, ByteArray.read32bit(code, pos + 1));
+ return 5; // branch
+ case Opcode.JSR_W :
+ stackTypes[stackTop++] = TOP; // not allowed?
+ visitJSR(pos, code);
+ return 5;
+ }
+ return 1;
+ }
+
+ private int doWIDE(int pos, byte[] code) {
+ int op = code[pos + 1] & 0xff;
+ switch (op) {
+ case Opcode.ILOAD :
+ doXLOAD(INTEGER);
+ break;
+ case Opcode.LLOAD :
+ doXLOAD(LONG);
+ break;
+ case Opcode.FLOAD :
+ doXLOAD(FLOAT);
+ break;
+ case Opcode.DLOAD :
+ doXLOAD(DOUBLE);
+ break;
+ case Opcode.ALOAD :
+ stackTypes[stackTop] = OBJECT;
+ stackData[stackTop++] = localsData[ByteArray.readU16bit(code, pos)];
+ break;
+ case Opcode.ISTORE :
+ return doWIDE_STORE(pos, code, INTEGER);
+ case Opcode.LSTORE :
+ return doWIDE_STORE(pos, code, LONG);
+ case Opcode.FSTORE :
+ return doWIDE_STORE(pos, code, FLOAT);
+ case Opcode.DSTORE :
+ return doWIDE_STORE(pos, code, DOUBLE);
+ case Opcode.ASTORE :
+ return doWIDE_STORE(pos, code, OBJECT);
+ case Opcode.IINC :
+ return 6;
+ case Opcode.RET :
+ break;
+ default :
+ throw new RuntimeException("bad WIDE instruction: " + op);
+ }
+
+ return 4;
+ }
+
+ private int doWIDE_STORE(int pos, byte[] code, int type) {
+ int index = ByteArray.readU16bit(code, pos);
+ return doXSTORE(index, type);
+ }
+
+ private int doFieldAccess(int pos, byte[] code, boolean isGet) {
+ int index = ByteArray.readU16bit(code, pos + 1);
+ String desc = cpool.getFieldrefType(index);
+ if (isGet)
+ pushMemberType(desc);
+ else
+ stackTop -= Descriptor.dataSize(desc);
+
+ return 3;
+ }
+
+ private int doNEWARRAY(int pos, byte[] code) {
+ int s = stackTop - 1;
+ stackTypes[s] = OBJECT;
+ String type;
+ switch (code[pos + 1] & 0xff) {
+ case Opcode.T_BOOLEAN :
+ type = "[Z";
+ break;
+ case Opcode.T_CHAR :
+ type = "[C";
+ break;
+ case Opcode.T_FLOAT :
+ type = "[F";
+ break;
+ case Opcode.T_DOUBLE :
+ type = "[D";
+ break;
+ case Opcode.T_BYTE :
+ type = "[B";
+ break;
+ case Opcode.T_SHORT :
+ type = "[S";
+ break;
+ case Opcode.T_INT :
+ type = "[I";
+ break;
+ case Opcode.T_LONG :
+ type = "[J";
+ break;
+ default :
+ throw new RuntimeException("bad newarray");
+ }
+
+ stackData[s] = type;
+ return 2;
+ }
+
+ private int doMultiANewArray(int pos, byte[] code) {
+ int i = ByteArray.readU16bit(code, pos + 1);
+ int dim = code[pos + 3] & 0xff;
+ stackTop -= dim - 1;
+ String type = cpool.getClassInfo(i);
+ StringBuffer sbuf = new StringBuffer();
+ while (dim-- > 0)
+ sbuf.append('[');
+
+ sbuf.append('L').append(type.replace('.', '/')).append(';');
+ stackTypes[stackTop - 1] = OBJECT;
+ stackData[stackTop - 1] = sbuf.toString();
+ return 4;
+ }
+
+ private int doInvokeMethod(int pos, byte[] code, int targetSize) {
+ int i = ByteArray.readU16bit(code, pos + 1);
+ String desc = cpool.getMethodrefType(i);
+ stackTop -= Descriptor.paramSize(desc) + targetSize;
+ pushMemberType(desc);
+ return 3;
+ }
+
+ private int doInvokeIntfMethod(int pos, byte[] code, int targetSize) {
+ int i = ByteArray.readU16bit(code, pos + 1);
+ String desc = cpool.getInterfaceMethodrefType(i);
+ stackTop -= Descriptor.paramSize(desc) + targetSize;
+ pushMemberType(desc);
+ return 5;
+ }
+
+ private void pushMemberType(String descriptor) {
+ int top = 0;
+ if (descriptor.charAt(0) == '(') {
+ top = descriptor.indexOf(')') + 1;
+ if (top < 1)
+ throw new IndexOutOfBoundsException("bad descriptor: "
+ + descriptor);
+ }
+
+ int[] types = stackTypes;
+ int index = stackTop;
+ switch (descriptor.charAt(top)) {
+ case '[' :
+ types[index] = OBJECT;
+ stackData[index] = descriptor.substring(top);
+ break;
+ case 'L' :
+ types[index] = OBJECT;
+ stackData[index] = descriptor.substring(top + 1,
+ descriptor.indexOf(';', top));
+ break;
+ case 'J' :
+ types[index] = LONG;
+ types[index + 1] = TOP;
+ stackTop += 2;
+ return;
+ case 'F' :
+ types[index] = FLOAT;
+ break;
+ case 'D' :
+ types[index] = DOUBLE;
+ types[index + 1] = TOP;
+ stackTop += 2;
+ return;
+ case 'V' :
+ return;
+ default : // C, B, S, I, Z
+ types[index] = INTEGER;
+ break;
+ }
+
+ stackTop++;
+ }
+}
diff --git a/src/main/javassist/convert/TransformAccessArrayField.java b/src/main/javassist/convert/TransformAccessArrayField.java
index 9b08a128..afa944b6 100644
--- a/src/main/javassist/convert/TransformAccessArrayField.java
+++ b/src/main/javassist/convert/TransformAccessArrayField.java
@@ -14,7 +14,6 @@
*/
package javassist.convert;
-
import javassist.CtClass;
import javassist.NotFoundException;
import javassist.CodeConverter.ArrayAccessReplacementMethodNames;
@@ -25,43 +24,44 @@ import javassist.bytecode.ConstPool;
/**
*
* @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
- * @version $Revision: 1.2 $
+ * @version $Revision: 1.3 $
*/
-public class TransformAccessArrayField extends Transformer
-{
-// CtClass componentType;
+public class TransformAccessArrayField extends Transformer {
+// CtClass componentType;
String methodClassname;
ArrayAccessReplacementMethodNames names;
- public TransformAccessArrayField(Transformer next, String methodClassname, ArrayAccessReplacementMethodNames names) throws NotFoundException
+ public TransformAccessArrayField(Transformer next, String methodClassname,
+ ArrayAccessReplacementMethodNames names)
+ throws NotFoundException
{
super(next);
this.methodClassname = methodClassname;
this.names = names;
}
- public int transform(CtClass tclazz, int pos, CodeIterator iterator, ConstPool cp) throws BadBytecode
+ public int transform(CtClass tclazz, int pos, CodeIterator iterator,
+ ConstPool cp) throws BadBytecode
{
int c = iterator.byteAt(pos);
- if (c == AALOAD || c == BALOAD || c == CALOAD || c == DALOAD || c == FALOAD || c == IALOAD || c == LALOAD || c == SALOAD)
- {
+ if (c == AALOAD || c == BALOAD || c == CALOAD || c == DALOAD
+ || c == FALOAD || c == IALOAD || c == LALOAD || c == SALOAD)
replace(cp, iterator, pos, c, getLoadReplacementSignature(c));
- }
- else if (c == AASTORE || c == BASTORE || c == CASTORE || c == DASTORE || c == FASTORE || c == IASTORE || c == LASTORE || c == SASTORE)
- {
+ else if (c == AASTORE || c == BASTORE || c == CASTORE || c == DASTORE
+ || c == FASTORE || c == IASTORE || c == LASTORE || c == SASTORE)
replace(cp, iterator, pos, c, getStoreReplacementSignature(c));
- }
return pos;
}
- private void replace(ConstPool cp, CodeIterator iterator, int pos, int opcode, String signature) throws BadBytecode
+ private void replace(ConstPool cp, CodeIterator iterator,
+ int pos, int opcode, String signature)
+ throws BadBytecode
{
String methodName = getMethodName(opcode);
- if (methodName != null)
- {
+ if (methodName != null) {
iterator.insertGap(2);
int mi = cp.addClassInfo(methodClassname);
int methodref = cp.addMethodrefInfo(mi, methodName, signature);
@@ -70,114 +70,112 @@ public class TransformAccessArrayField extends Transformer
}
}
- private String getMethodName(int opcode)
- {
- String methodName = null;
- switch(opcode)
- {
- case AALOAD:
+ private String getMethodName(int opcode) {
+ String methodName = null;
+ switch (opcode) {
+ case AALOAD:
methodName = names.objectRead();
break;
- case BALOAD:
+ case BALOAD:
methodName = names.byteOrBooleanRead();
break;
- case CALOAD:
+ case CALOAD:
methodName = names.charRead();
break;
- case DALOAD:
+ case DALOAD:
methodName = names.doubleRead();
break;
- case FALOAD:
+ case FALOAD:
methodName = names.floatRead();
break;
- case IALOAD:
+ case IALOAD:
methodName = names.intRead();
break;
- case SALOAD:
+ case SALOAD:
methodName = names.shortRead();
break;
- case LALOAD:
+ case LALOAD:
methodName = names.longRead();
break;
- case AASTORE:
+ case AASTORE:
methodName = names.objectWrite();
break;
- case BASTORE:
+ case BASTORE:
methodName = names.byteOrBooleanWrite();
break;
- case CASTORE:
+ case CASTORE:
methodName = names.charWrite();
break;
- case DASTORE:
+ case DASTORE:
methodName = names.doubleWrite();
break;
- case FASTORE:
+ case FASTORE:
methodName = names.floatWrite();
break;
- case IASTORE:
+ case IASTORE:
methodName = names.intWrite();
break;
- case SASTORE:
+ case SASTORE:
methodName = names.shortWrite();
break;
- case LASTORE:
+ case LASTORE:
methodName = names.longWrite();
break;
- }
-
- if (methodName.equals(""))
- {
- methodName = null;
- }
- return methodName;
- }
+ }
- private String getLoadReplacementSignature(int opcode) throws BadBytecode
+ if (methodName.equals(""))
+ methodName = null;
+
+ return methodName;
+ }
+
+ private String getLoadReplacementSignature(int opcode)
+ throws BadBytecode
{
- switch(opcode)
- {
- case AALOAD:
+ switch (opcode) {
+ case AALOAD:
return "(Ljava/lang/Object;I)Ljava/lang/Object;";
- case BALOAD:
+ case BALOAD:
return "(Ljava/lang/Object;I)B";
- case CALOAD:
+ case CALOAD:
return "(Ljava/lang/Object;I)C";
- case DALOAD:
+ case DALOAD:
return "(Ljava/lang/Object;I)D";
- case FALOAD:
+ case FALOAD:
return "(Ljava/lang/Object;I)F";
- case IALOAD:
+ case IALOAD:
return "(Ljava/lang/Object;I)I";
- case SALOAD:
+ case SALOAD:
return "(Ljava/lang/Object;I)S";
- case LALOAD:
+ case LALOAD:
return "(Ljava/lang/Object;I)J";
- }
-
- throw new BadBytecode(opcode);
- }
+ }
+
+ throw new BadBytecode(opcode);
+ }
- private String getStoreReplacementSignature(int opcode) throws BadBytecode
+ private String getStoreReplacementSignature(int opcode)
+ throws BadBytecode
{
- switch(opcode)
- {
- case AASTORE:
+ switch (opcode) {
+ case AASTORE:
return "(Ljava/lang/Object;ILjava/lang/Object;)V";
- case BASTORE:
+ case BASTORE:
return "(Ljava/lang/Object;IB)V";
- case CASTORE:
+ case CASTORE:
return "(Ljava/lang/Object;IC)V";
- case DASTORE:
+ case DASTORE:
return "(Ljava/lang/Object;ID)V";
- case FASTORE:
+ case FASTORE:
return "(Ljava/lang/Object;IF)V";
- case IASTORE:
+ case IASTORE:
return "(Ljava/lang/Object;II)V";
- case SASTORE:
+ case SASTORE:
return "(Ljava/lang/Object;IS)V";
- case LASTORE:
+ case LASTORE:
return "(Ljava/lang/Object;IJ)V";
- }
- throw new BadBytecode(opcode);
- }
+ }
+
+ throw new BadBytecode(opcode);
+ }
}
diff --git a/src/main/javassist/convert/TransformNew.java b/src/main/javassist/convert/TransformNew.java
index c4347b7c..a853d2d5 100644
--- a/src/main/javassist/convert/TransformNew.java
+++ b/src/main/javassist/convert/TransformNew.java
@@ -64,6 +64,11 @@ final public class TransformNew extends Transformer {
iterator.writeByte(NOP, pos + 2);
iterator.writeByte(NOP, pos + 3);
++nested;
+
+ StackMapTable smt
+ = (StackMapTable)iterator.get().getAttribute(StackMapTable.tag);
+ if (smt != null)
+ smt.removeNew(pos);
}
}
else if (c == INVOKESPECIAL) {
diff --git a/src/test/test/Test.java b/src/test/test/Test.java
new file mode 100644
index 00000000..29a08a69
--- /dev/null
+++ b/src/test/test/Test.java
@@ -0,0 +1,14 @@
+package test;
+
+import javassist.bytecode.*;
+
+public class Test {
+ public static void main(String[] args) {
+ String[] names = Mnemonic.OPCODE;
+ for (int i = 0; i < names.length; i++)
+ if (names[i] == null)
+ System.out.println(" case " + i + " :");
+ else
+ System.out.println(" case Opcode." + names[i].toUpperCase() + " :");
+ }
+}