]> source.dussan.org Git - javassist.git/commitdiff
Now the compiler supports a switch statement.
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Fri, 3 Sep 2004 14:00:20 +0000 (14:00 +0000)
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Fri, 3 Sep 2004 14:00:20 +0000 (14:00 +0000)
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@131 30ef5769-5b8d-40dd-aea6-55b5d6557bb3

Readme.html
src/main/javassist/bytecode/Bytecode.java
src/main/javassist/compiler/CodeGen.java
src/main/javassist/compiler/TypeChecker.java
tutorial/tutorial2.html

index 035bd6bd706e537502e164c0aadb1c622216355f..9b90986c503f83b370158bdaaeca828e0c22c8b4 100644 (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.
index b606359e36becd04c88084b7ea141548e4cf3208..d634ad26db890ad3eacf0ccfeee458e433a8cc20 100644 (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.
index bf6c97efa0779a8dc9536d3fbf76aede73472822..221cbfcd496d7c7727b136db2839b8aca13e1a2b 100644 (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
     {
index 9b505afb68135b65d15e8e42e888d389e2147f6e..3ce286cf18d85f5802fa40282d2020db0b0d0361 100644 (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)
index 9c158377b7e37b6bdc65cc2af45e74ab3db01c94..778f44eeb579e03d8de019caadb4bbfc3f90c387 100644 (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.