Browse Source

Now the compiler supports a switch statement.


git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@131 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
tags/rel_3_17_1_ga
chiba 19 years ago
parent
commit
0e6ebb79d3

+ 1
- 0
Readme.html View File

@@ -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.

+ 52
- 1
src/main/javassist/bytecode/Bytecode.java View File

@@ -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.

+ 76
- 4
src/main/javassist/compiler/CodeGen.java View File

@@ -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
{

+ 3
- 1
src/main/javassist/compiler/TypeChecker.java View File

@@ -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)

+ 1
- 2
tutorial/tutorial2.html View File

@@ -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.

Loading…
Cancel
Save