aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>2004-09-03 14:00:20 +0000
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>2004-09-03 14:00:20 +0000
commit0e6ebb79d3872415b7cb3d41f9aa8f83aba623ba (patch)
treeb51eb0c0a03c3f4c93035b066e3f226d51f3ea07
parent9b3b5570519634919030492e4dd9562cdd64d9a4 (diff)
downloadjavassist-0e6ebb79d3872415b7cb3d41f9aa8f83aba623ba.tar.gz
javassist-0e6ebb79d3872415b7cb3d41f9aa8f83aba623ba.zip
Now the compiler supports a switch statement.
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@131 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
-rw-r--r--Readme.html1
-rw-r--r--src/main/javassist/bytecode/Bytecode.java53
-rw-r--r--src/main/javassist/compiler/CodeGen.java80
-rw-r--r--src/main/javassist/compiler/TypeChecker.java4
-rw-r--r--tutorial/tutorial2.html3
5 files changed, 133 insertions, 8 deletions
diff --git a/Readme.html b/Readme.html
index 035bd6bd..9b90986c 100644
--- a/Readme.html
+++ b/Readme.html
@@ -265,6 +265,7 @@ see javassist.Dump.
<li><code>.class</code> notation has been supported. The modified class
file needs javassist.runtime.DotClass at runtime.
<li>a bug in <code>CtClass.getMethods()</code> has been fixed.
+ <li>The compiler supports a switch statement.
</ul>
<p>- version 3.0 beta in May 18th, 2004.
diff --git a/src/main/javassist/bytecode/Bytecode.java b/src/main/javassist/bytecode/Bytecode.java
index b606359e..d634ad26 100644
--- a/src/main/javassist/bytecode/Bytecode.java
+++ b/src/main/javassist/bytecode/Bytecode.java
@@ -299,6 +299,16 @@ public class Bytecode implements Opcode {
}
/**
+ * Reads a signed 32bit value at the offset from the beginning of the
+ * bytecode sequence.
+ */
+ public int read32bit(int offset) {
+ int v1 = read16bit(offset);
+ int v2 = read16bit(offset + 2);
+ return (v1 << 16) + (v2 & 0xffff);
+ }
+
+ /**
* Writes an 8bit value at the offset from the beginning of the
* bytecode sequence.
*
@@ -321,11 +331,20 @@ public class Bytecode implements Opcode {
* bytecode sequence.
*/
public void write16bit(int offset, int value) {
- write(offset, value >>> 8);
+ write(offset, value >> 8);
write(offset + 1, value);
}
/**
+ * Writes an 32bit value at the offset from the beginning of the
+ * bytecode sequence.
+ */
+ public void write32bit(int offset, int value) {
+ write16bit(offset, value >> 16);
+ write16bit(offset + 2, value);
+ }
+
+ /**
* Appends an 8bit value to the end of the bytecode sequence.
*/
public void add(int code) {
@@ -340,6 +359,38 @@ public class Bytecode implements Opcode {
}
/**
+ * Appends a 32bit value to the end of the bytecode sequence.
+ */
+ public void add32bit(int value) {
+ add(value >> 24);
+ add(value >> 16);
+ add(value >> 8);
+ add(value);
+ }
+
+ /**
+ * Appends the length-byte gap to the end of the bytecode sequence.
+ *
+ * @param length the gap length in byte.
+ */
+ public void addGap(int length) {
+ if (num < bufsize) {
+ num += length;
+ if (num <= bufsize)
+ return;
+ else {
+ length = num - bufsize;
+ num = bufsize;
+ }
+ }
+
+ if (next == null)
+ next = new Bytecode();
+
+ next.addGap(length);
+ }
+
+ /**
* Appends an 8bit opcode to the end of the bytecode sequence.
* The current stack depth is updated.
* <code>max_stack</code> is updated if the current stack depth
diff --git a/src/main/javassist/compiler/CodeGen.java b/src/main/javassist/compiler/CodeGen.java
index bf6c97ef..221cbfcd 100644
--- a/src/main/javassist/compiler/CodeGen.java
+++ b/src/main/javassist/compiler/CodeGen.java
@@ -16,6 +16,7 @@
package javassist.compiler;
import java.util.ArrayList;
+import java.util.Arrays;
import javassist.compiler.ast.*;
import javassist.bytecode.*;
@@ -338,14 +339,12 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
atThrowStmnt(st);
else if (op == TRY)
atTryStmnt(st);
+ else if (op == SWITCH)
+ atSwitchStmnt(st);
else if (op == SYNCHRONIZED) {
hasReturned = false;
throw new CompileError("sorry, synchronized is not supported");
}
- else if (op == SWITCH) {
- hasReturned = false;
- throw new CompileError("sorry, switch is not supported");
- }
else {
// LABEL, SWITCH label stament might be null?.
hasReturned = false;
@@ -474,6 +473,79 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
hasReturned = false;
}
+ private void atSwitchStmnt(Stmnt st) throws CompileError {
+ compileExpr(st.head());
+
+ ArrayList prevBreakList = breakList;
+ breakList = new ArrayList();
+ int opcodePc = bytecode.currentPc();
+ bytecode.addOpcode(LOOKUPSWITCH);
+ int npads = 3 - (opcodePc & 3);
+ while (npads-- > 0)
+ bytecode.add(0);
+
+ Stmnt body = (Stmnt)st.tail();
+ int npairs = 0;
+ for (ASTList list = body; list != null; list = list.tail())
+ if (((Stmnt)list.head()).getOperator() == CASE)
+ ++npairs;
+
+ // opcodePc2 is the position at which the default jump offset is.
+ int opcodePc2 = bytecode.currentPc();
+ bytecode.addGap(4);
+ bytecode.add32bit(npairs);
+ bytecode.addGap(npairs * 8);
+
+ long[] pairs = new long[npairs];
+ int ipairs = 0;
+ int defaultPc = -1;
+ for (ASTList list = body; list != null; list = list.tail()) {
+ Stmnt label = (Stmnt)list.head();
+ int op = label.getOperator();
+ if (op == DEFAULT)
+ defaultPc = bytecode.currentPc();
+ else if (op != CASE)
+ fatal();
+ else {
+ pairs[ipairs++]
+ = ((long)computeLabel(label.head()) << 32) +
+ ((long)(bytecode.currentPc() - opcodePc) & 0xffffffff);
+ }
+
+ hasReturned = false;
+ ((Stmnt)label.tail()).accept(this);
+ }
+
+ Arrays.sort(pairs);
+ int pc = opcodePc2 + 8;
+ for (int i = 0; i < npairs; ++i) {
+ bytecode.write32bit(pc, (int)(pairs[i] >>> 32));
+ bytecode.write32bit(pc + 4, (int)pairs[i]);
+ pc += 8;
+ }
+
+ if (defaultPc < 0 || breakList.size() > 0)
+ hasReturned = false;
+
+ int endPc = bytecode.currentPc();
+ if (defaultPc < 0)
+ defaultPc = endPc;
+
+ bytecode.write32bit(opcodePc2, defaultPc - opcodePc);
+
+ patchGoto(breakList, endPc);
+ breakList = prevBreakList;
+ }
+
+ private int computeLabel(ASTree expr) throws CompileError {
+ doTypeCheck(expr);
+ expr = TypeChecker.stripPlusExpr(expr);
+ if (expr instanceof IntConst)
+ return (int)((IntConst)expr).get();
+ else
+ throw new CompileError("bad case label");
+ }
+
private void atBreakStmnt(Stmnt st, boolean notCont)
throws CompileError
{
diff --git a/src/main/javassist/compiler/TypeChecker.java b/src/main/javassist/compiler/TypeChecker.java
index 9b505afb..3ce286cf 100644
--- a/src/main/javassist/compiler/TypeChecker.java
+++ b/src/main/javassist/compiler/TypeChecker.java
@@ -347,7 +347,9 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
}
}
- private static ASTree stripPlusExpr(ASTree expr) {
+ /* CodeGen.atSwitchStmnt() also calls stripPlusExpr().
+ */
+ static ASTree stripPlusExpr(ASTree expr) {
if (expr instanceof BinExpr) {
BinExpr e = (BinExpr)expr;
if (e.getOperator() == '+' && e.oprand2() == null)
diff --git a/tutorial/tutorial2.html b/tutorial/tutorial2.html
index 9c158377..778f44ee 100644
--- a/tutorial/tutorial2.html
+++ b/tutorial/tutorial2.html
@@ -1395,8 +1395,7 @@ supported.
<p><li>Inner classes or anonymous classes are not supported.
-<p><li><code>switch</code> or <code>synchronized</code>
-statements are not supported yet.
+<p><li><code>synchronized</code> statements are not supported yet.
<p><li>Labeled <code>continue</code> and <code>break</code> statements
are not supported.