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.
* 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.
*/
}
}
+ /**
+ * 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.
package javassist.compiler;
import java.util.ArrayList;
+import java.util.Arrays;
import javassist.compiler.ast.*;
import javassist.bytecode.*;
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;
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
{