git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@131 30ef5769-5b8d-40dd-aea6-55b5d6557bb3tags/rel_3_17_1_ga
@@ -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. |
@@ -298,6 +298,16 @@ public class Bytecode implements Opcode { | |||
return (v1 << 8) + (v2 & 0xff); | |||
} | |||
/** | |||
* 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,10 +331,19 @@ 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. | |||
*/ | |||
@@ -339,6 +358,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. |
@@ -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 | |||
{ |
@@ -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) |
@@ -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. |