update nestedvm for new classgen api again
[nestedvm.git] / src / org / ibex / nestedvm / ClassFileCompiler.java
index 64269fb..8695445 100644 (file)
@@ -1,3 +1,7 @@
+// Copyright 2000-2005 the Contributors, as shown in the revision logs.
+// Licensed under the Apache Public Source License 2.0 ("the License").
+// You may not use this file except in compliance with the License.
+
 package org.ibex.nestedvm;
 
 import java.io.*;
@@ -5,9 +9,8 @@ import java.io.*;
 import org.ibex.nestedvm.util.*;
 import org.ibex.classgen.*;
 
-// FEATURE: Use IINC where possible
-// FEATURE: Some kind of peephole optimization
-// FEATURE: Special mode to support single-precision only - regs are floats not ints
+// FEATURE: Eliminate unnecessary use of SWAP
+// FEATURE: Put regs in low (<=3) local vars, small classfile size
 
 /* FEATURE: Span large binaries across several classfiles
  * We should be able to do this with no performance penalty
@@ -33,70 +36,113 @@ import org.ibex.classgen.*;
  */
 
 
-public class ClassFileCompiler extends Compiler implements CGConst  {    
+public class ClassFileCompiler extends Compiler implements CGConst  {
+    private static final boolean OPTIMIZE_CP = true;
+    
     /** The stream to write the compiled output to */
     private OutputStream os;
+    private File outDir;
     private PrintStream warn = System.err;
+
+    private final Type.Class me;
     
-    private ClassGen cg;
-    private MethodGen clinit;
-    private MethodGen init;
-    private Type.Object me;
-    private Type.Object superClass;
+    private ClassFile cg;
+    private MethodGen clinit, init;
     
     public ClassFileCompiler(String path, String className, OutputStream os) throws IOException { this(new Seekable.File(path),className,os); }
     public ClassFileCompiler(Seekable binary, String className, OutputStream os) throws IOException {
-        super(binary,className);
+        this(binary,className);
+        if(os == null) throw new NullPointerException();
         this.os = os;
     }
+    public ClassFileCompiler(Seekable binary, String className, File outDir) throws IOException {
+        this(binary,className);
+        if(outDir == null) throw new NullPointerException();
+        this.outDir = outDir;
+    }
+    private ClassFileCompiler(Seekable binary, String className) throws IOException {
+        super(binary,className);
+        me = Type.fromClass(fullClassName);
+    }
     
     public void setWarnWriter(PrintStream warn) { this.warn = warn; }
         
     protected void _go() throws Exn, IOException {
-        if(lessConstants) throw new Exn("ClassFileCompiler doesn't support -o lessconstants");
+        try {
+            __go();
+        } catch(ClassFile.Exn e) {
+            e.printStackTrace(warn);
+            throw new Exn("Class generation exception: " + e.toString());
+        }
+    }
+        
+    private void __go() throws Exn, IOException {
         if(!pruneCases) throw new Exn("-o prunecases MUST be enabled for ClassFileCompiler");
 
         // Class
-        me = new Type.Object(fullClassName);
-        superClass = new Type.Object(runtimeClass);
-        cg = new ClassGen(me,superClass,ACC_PUBLIC|ACC_FINAL|ACC_SUPER);
+        Type.Class superClass = Type.fromClass(runtimeClass);
+        cg = new ClassFile(me,superClass,PUBLIC|FINAL|SUPER);
         if(source != null) cg.setSourceFile(source);
         
         // Fields
-        cg.addField("pc",Type.INT,ACC_PRIVATE);
-        cg.addField("hi",Type.INT,ACC_PRIVATE);
-        cg.addField("lo",Type.INT,ACC_PRIVATE);
-        cg.addField("fcsr",Type.INT,ACC_PRIVATE);
-        for(int i=1;i<32;i++) cg.addField("r" + i,Type.INT,ACC_PRIVATE);
-        for(int i=0;i<32;i++) cg.addField("f" + i,Type.INT,ACC_PRIVATE);
-        
-        clinit = cg.addMethod("<clinit>",Type.VOID,Type.NO_ARGS,ACC_PRIVATE|ACC_STATIC);
-        
-        init = cg.addMethod("<init>",Type.VOID,Type.NO_ARGS,ACC_PUBLIC);        
+        cg.addField("pc",Type.INT,PRIVATE);
+        cg.addField("hi",Type.INT,PRIVATE);
+        cg.addField("lo",Type.INT,PRIVATE);
+        cg.addField("fcsr",Type.INT,PRIVATE);
+        for(int i=1;i<32;i++) cg.addField("r" + i,Type.INT,PRIVATE);
+        for(int i=0;i<32;i++) cg.addField("f" + i,singleFloat ? Type.FLOAT : Type.INT,PRIVATE);
+
+        // <clinit>
+        clinit = cg.addMethod("<clinit>",Type.VOID,Type.NO_ARGS,PRIVATE|STATIC);
+
+        // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.UnixRuntime.<init>
+
+        // <init>
+        init = cg.addMethod("<init>",Type.VOID,Type.NO_ARGS,PUBLIC);        
         init.add(ALOAD_0);
         init.add(LDC,pageSize);
         init.add(LDC,totalPages);
-        init.add(INVOKESPECIAL,new MethodRef(me,"<init>",Type.VOID,new Type[]{Type.INT,Type.INT}));
+        init.add(INVOKESPECIAL,me.method("<init>",Type.VOID,new Type[]{Type.INT,Type.INT}));
         init.add(RETURN);
 
-        init = cg.addMethod("<init>",Type.VOID,new Type[]{Type.INT,Type.INT},ACC_PUBLIC);
+        // <init>(Z)
+        init = cg.addMethod("<init>",Type.VOID,new Type[]{Type.BOOLEAN},PUBLIC);        
+        init.add(ALOAD_0);
+        init.add(LDC,pageSize);
+        init.add(LDC,totalPages);
+        init.add(ILOAD_1);
+        init.add(INVOKESPECIAL,me.method("<init>",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN}));
+        init.add(RETURN);
+        
+        // <init>(II)
+        init = cg.addMethod("<init>",Type.VOID,new Type[]{Type.INT,Type.INT},PUBLIC);
+        init.add(ALOAD_0);
+        init.add(ILOAD_1);
+        init.add(ILOAD_2);
+        init.add(ICONST_0);
+        init.add(INVOKESPECIAL,me.method("<init>",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN}));
+        init.add(RETURN);
+        
+        // <init>(IIZ)
+        init = cg.addMethod("<init>",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN},PUBLIC);
         init.add(ALOAD_0);
         init.add(ILOAD_1);
         init.add(ILOAD_2);
-        init.add(INVOKESPECIAL,new MethodRef(superClass,"<init>",Type.VOID,new Type[]{Type.INT,Type.INT}));
+        init.add(ILOAD_3);
+        init.add(INVOKESPECIAL,superClass.method("<init>",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN}));
         
         if(onePage) {
-            cg.addField("page",Type.arrayType(Type.INT),ACC_PRIVATE|ACC_FINAL);
+            cg.addField("page",Type.INT.makeArray(),PRIVATE|FINAL);
             init.add(ALOAD_0);
             init.add(DUP);
-            init.add(GETFIELD,new FieldRef(me,"readPages",Type.arrayType(Type.INT,2)));
+            init.add(GETFIELD,me.field("readPages",Type.INT.makeArray(2)));
             init.add(LDC,0);
             init.add(AALOAD);
-            init.add(PUTFIELD,new FieldRef(me,"page",Type.arrayType(Type.INT)));
+            init.add(PUTFIELD,me.field("page",Type.INT.makeArray()));
         }
         
         if(supportCall)
-            cg.addField("symbols",new Type.Object(hashClass),ACC_PRIVATE|ACC_STATIC|ACC_FINAL);
+            cg.addField("symbols",Type.fromClass(hashClass),PRIVATE|STATIC|FINAL);
         
         int highestAddr = 0;
         
@@ -123,12 +169,12 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         
         // Finish clinit
         if(supportCall) {
-            Type.Object hash = new Type.Object(hashClass);
+            Type.Class hash = Type.fromClass(hashClass);
             clinit.add(NEW,hash);
             clinit.add(DUP);
             clinit.add(DUP);
-            clinit.add(INVOKESPECIAL,new MethodRef(hash,"<init>",Type.VOID,Type.NO_ARGS));
-            clinit.add(PUTSTATIC,new FieldRef(me,"symbols",hash));
+            clinit.add(INVOKESPECIAL,hash.method("<init>",Type.VOID,Type.NO_ARGS));
+            clinit.add(PUTSTATIC,me.field("symbols",hash));
             ELF.Symbol[] symbols = elf.getSymtab().symbols;
             for(int i=0;i<symbols.length;i++) {
                 ELF.Symbol s = symbols[i];
@@ -138,8 +184,8 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
                     clinit.add(NEW,Type.INTEGER_OBJECT);
                     clinit.add(DUP);
                     clinit.add(LDC,s.addr);
-                    clinit.add(INVOKESPECIAL,new MethodRef(Type.INTEGER_OBJECT,"<init>",Type.VOID,new Type[]{Type.INT}));
-                    clinit.add(INVOKEVIRTUAL,new MethodRef(hash,"put",Type.OBJECT,new Type[]{Type.OBJECT,Type.OBJECT}));
+                    clinit.add(INVOKESPECIAL,Type.INTEGER_OBJECT.method("<init>",Type.VOID,new Type[]{Type.INT}));
+                    clinit.add(INVOKEVIRTUAL,hash.method("put",Type.OBJECT,new Type[]{Type.OBJECT,Type.OBJECT}));
                     clinit.add(POP);
                 }
             }
@@ -151,62 +197,54 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         ELF.SHeader text = elf.sectionWithName(".text");
         
         // Trampoline
-        MethodGen tramp = cg.addMethod("trampoline",Type.VOID,Type.NO_ARGS,ACC_PRIVATE);
+        MethodGen tramp = cg.addMethod("trampoline",Type.VOID,Type.NO_ARGS,PRIVATE);
         
         int start = tramp.size();
         tramp.add(ALOAD_0);
-        tramp.add(GETFIELD,new FieldRef(me,"state",Type.INT));
-        int stateCheck = tramp.add(IFNE);
+        tramp.add(GETFIELD,me.field("state",Type.INT));
+        tramp.add(IFEQ,tramp.size()+2);
+        tramp.add(RETURN);
         
         tramp.add(ALOAD_0);
         tramp.add(ALOAD_0);
-        tramp.add(GETFIELD,new FieldRef(me,"pc",Type.INT));
+        tramp.add(GETFIELD,me.field("pc",Type.INT));
         tramp.add(LDC,methodShift);
         tramp.add(IUSHR);
         
         int beg = text.addr >>> methodShift;
         int end = ((text.addr + text.size + maxBytesPerMethod - 1) >>> methodShift);
 
-        MethodGen.TSI tsi = new MethodGen.TSI(beg,end-1);
+        MethodGen.Switch.Table tsi = new MethodGen.Switch.Table(beg,end-1);
         tramp.add(TABLESWITCH,tsi);
         for(int n=beg;n<end;n++) {
             tsi.setTargetForVal(n,tramp.size());
-            tramp.add(INVOKESPECIAL,new MethodRef(me,"run_"+toHex(n<<methodShift),Type.VOID,Type.NO_ARGS));
+            tramp.add(INVOKESPECIAL,me.method("run_"+toHex(n<<methodShift),Type.VOID,Type.NO_ARGS));
             tramp.add(GOTO,start);
         }
         tsi.setDefaultTarget(tramp.size());
         
         tramp.add(POP);
-        tramp.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
+        tramp.add(NEW,Type.fromClass("org.ibex.nestedvm.Runtime$ExecutionException"));
         tramp.add(DUP);
         tramp.add(NEW, Type.STRINGBUFFER);
         tramp.add(DUP);
         tramp.add(LDC,"Jumped to invalid address in trampoline (r2: ");
-        tramp.add(INVOKESPECIAL,new MethodRef(Type.STRINGBUFFER,"<init>",Type.VOID,new Type[]{Type.STRING}));
+        tramp.add(INVOKESPECIAL,Type.STRINGBUFFER.method("<init>",Type.VOID,new Type[]{Type.STRING}));
         tramp.add(ALOAD_0);
-        tramp.add(GETFIELD, new FieldRef(me,"r2",Type.INT));
-        tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.INT}));
+        tramp.add(GETFIELD, me.field("r2",Type.INT));
+        tramp.add(INVOKEVIRTUAL,Type.STRINGBUFFER.method("append",Type.STRINGBUFFER,new Type[]{Type.INT}));
         tramp.add(LDC," pc: ");
-        tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.STRING}));
+        tramp.add(INVOKEVIRTUAL,Type.STRINGBUFFER.method("append",Type.STRINGBUFFER,new Type[]{Type.STRING}));
         tramp.add(ALOAD_0);
-        tramp.add(GETFIELD, new FieldRef(me,"pc",Type.INT));        
-        tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.INT}));
+        tramp.add(GETFIELD, me.field("pc",Type.INT));        
+        tramp.add(INVOKEVIRTUAL,Type.STRINGBUFFER.method("append",Type.STRINGBUFFER,new Type[]{Type.INT}));
         tramp.add(LDC,")");
-        tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.STRING}));
-        tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"toString",Type.STRING,Type.NO_ARGS));
-        tramp.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"<init>",Type.VOID,new Type[]{Type.STRING}));
+        tramp.add(INVOKEVIRTUAL,Type.STRINGBUFFER.method("append",Type.STRINGBUFFER,new Type[]{Type.STRING}));
+        tramp.add(INVOKEVIRTUAL,Type.STRINGBUFFER.method("toString",Type.STRING,Type.NO_ARGS));
+        // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime$ExecutionException.<init>
+        tramp.add(INVOKESPECIAL,Type.fromClass("org.ibex.nestedvm.Runtime$ExecutionException").method("<init>",Type.VOID,new Type[]{Type.STRING}));
         tramp.add(ATHROW);
         
-        tramp.setArg(stateCheck,tramp.size());
-        tramp.add(RETURN);
-                
-        try {
-            tramp.finish();
-        } catch(ClassGen.Exn e) {
-            e.printStackTrace(warn);
-            throw new Exn("Generation of the trampoline method failed. Try increasing maxInsnPerMethod");
-        }
-        
         addConstReturnMethod("gp",gp.addr);
         addConstReturnMethod("entryPoint",elf.header.entry);
         addConstReturnMethod("heapStart",highestAddr);
@@ -217,15 +255,15 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         }
         
         if(supportCall) {
-            Type.Object hashClassType = new Type.Object(hashClass);
-            MethodGen ls = cg.addMethod("lookupSymbol",Type.INT,new Type[]{Type.STRING},ACC_PROTECTED);
-            ls.add(GETSTATIC,new FieldRef(me,"symbols",hashClassType));
+            Type.Class hashClassType = Type.fromClass(hashClass);
+            MethodGen ls = cg.addMethod("lookupSymbol",Type.INT,new Type[]{Type.STRING},PROTECTED);
+            ls.add(GETSTATIC,me.field("symbols",hashClassType));
             ls.add(ALOAD_1);
-            ls.add(INVOKEVIRTUAL,new MethodRef(hashClassType,"get",Type.OBJECT,new Type[]{Type.OBJECT}));
+            ls.add(INVOKEVIRTUAL,hashClassType.method("get",Type.OBJECT,new Type[]{Type.OBJECT}));
             ls.add(DUP);
             int b = ls.add(IFNULL);
             ls.add(CHECKCAST,Type.INTEGER_OBJECT);
-            ls.add(INVOKEVIRTUAL,new MethodRef(Type.INTEGER_OBJECT,"intValue",Type.INT,Type.NO_ARGS));
+            ls.add(INVOKEVIRTUAL,Type.INTEGER_OBJECT.method("intValue",Type.INT,Type.NO_ARGS));
             ls.add(IRETURN);
             ls.setArg(b,ls.size());
             ls.add(POP);
@@ -233,14 +271,16 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             ls.add(IRETURN);
         }
         
-        Type.Object cpuStateType = new Type.Object("org.ibex.nestedvm.Runtime$CPUState");
-        MethodGen setCPUState = cg.addMethod("setCPUState",Type.VOID,new Type[]{cpuStateType},ACC_PROTECTED);
-        MethodGen getCPUState = cg.addMethod("getCPUState",Type.VOID,new Type[]{cpuStateType},ACC_PROTECTED);
+        // Kind of a hack, referencing dup() gets us all the fields for free
+        // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime$CPUState.dup
+        Type.Class cpuStateType = Type.fromClass("org.ibex.nestedvm.Runtime$CPUState");
+        MethodGen setCPUState = cg.addMethod("setCPUState",Type.VOID,new Type[]{cpuStateType},PROTECTED);
+        MethodGen getCPUState = cg.addMethod("getCPUState",Type.VOID,new Type[]{cpuStateType},PROTECTED);
         
         setCPUState.add(ALOAD_1);
         getCPUState.add(ALOAD_1);
-        setCPUState.add(GETFIELD,new FieldRef(cpuStateType,"r",Type.arrayType(Type.INT)));
-        getCPUState.add(GETFIELD,new FieldRef(cpuStateType,"r",Type.arrayType(Type.INT)));
+        setCPUState.add(GETFIELD,cpuStateType.field("r",Type.INT.makeArray()));
+        getCPUState.add(GETFIELD,cpuStateType.field("r",Type.INT.makeArray()));
         setCPUState.add(ASTORE_2);
         getCPUState.add(ASTORE_2);
         
@@ -249,19 +289,19 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             setCPUState.add(ALOAD_2);
             setCPUState.add(LDC,i);
             setCPUState.add(IALOAD);
-            setCPUState.add(PUTFIELD,new FieldRef(me,"r"+i,Type.INT));
+            setCPUState.add(PUTFIELD,me.field("r"+i,Type.INT));
             
             getCPUState.add(ALOAD_2);
             getCPUState.add(LDC,i);
             getCPUState.add(ALOAD_0);
-            getCPUState.add(GETFIELD,new FieldRef(me,"r"+i,Type.INT));
+            getCPUState.add(GETFIELD,me.field("r"+i,Type.INT));
             getCPUState.add(IASTORE);
         }
         
         setCPUState.add(ALOAD_1);
         getCPUState.add(ALOAD_1);
-        setCPUState.add(GETFIELD,new FieldRef(cpuStateType,"f",Type.arrayType(Type.INT)));
-        getCPUState.add(GETFIELD,new FieldRef(cpuStateType,"f",Type.arrayType(Type.INT)));
+        setCPUState.add(GETFIELD,cpuStateType.field("f",Type.INT.makeArray()));
+        getCPUState.add(GETFIELD,cpuStateType.field("f",Type.INT.makeArray()));
         setCPUState.add(ASTORE_2);
         getCPUState.add(ASTORE_2);
         
@@ -270,12 +310,14 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             setCPUState.add(ALOAD_2);
             setCPUState.add(LDC,i);
             setCPUState.add(IALOAD);
-            setCPUState.add(PUTFIELD,new FieldRef(me,"f"+i,Type.INT));
+            if(singleFloat) setCPUState.add(INVOKESTATIC,Type.FLOAT_OBJECT.method("intBitsToFloat",Type.FLOAT,new Type[]{Type.INT}));
+            setCPUState.add(PUTFIELD,me.field("f"+i,singleFloat ? Type.FLOAT : Type.INT));
             
             getCPUState.add(ALOAD_2);
             getCPUState.add(LDC,i);
             getCPUState.add(ALOAD_0);
-            getCPUState.add(GETFIELD,new FieldRef(me,"f"+i,Type.INT));
+            getCPUState.add(GETFIELD,me.field("f"+i,singleFloat ? Type.FLOAT: Type.INT));
+            if(singleFloat) getCPUState.add(INVOKESTATIC,Type.FLOAT_OBJECT.method("floatToIntBits",Type.INT,new Type[]{Type.FLOAT}));
             getCPUState.add(IASTORE);            
         }
         
@@ -283,56 +325,64 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         for(int i=0;i<each.length;i++) {
             setCPUState.add(ALOAD_0);
             setCPUState.add(ALOAD_1);
-            setCPUState.add(GETFIELD,new FieldRef(cpuStateType,each[i],Type.INT));
-            setCPUState.add(PUTFIELD,new FieldRef(me,each[i],Type.INT));
+            setCPUState.add(GETFIELD,cpuStateType.field(each[i],Type.INT));
+            setCPUState.add(PUTFIELD,me.field(each[i],Type.INT));
 
             getCPUState.add(ALOAD_1);
             getCPUState.add(ALOAD_0);
-            getCPUState.add(GETFIELD,new FieldRef(me,each[i],Type.INT));
-            getCPUState.add(PUTFIELD,new FieldRef(cpuStateType,each[i],Type.INT));
+            getCPUState.add(GETFIELD,me.field(each[i],Type.INT));
+            getCPUState.add(PUTFIELD,cpuStateType.field(each[i],Type.INT));
         }
         setCPUState.add(RETURN);
         getCPUState.add(RETURN);
         
 
-        MethodGen execute = cg.addMethod("_execute",Type.VOID,Type.NO_ARGS,ACC_PROTECTED);
+        MethodGen execute = cg.addMethod("_execute",Type.VOID,Type.NO_ARGS,PROTECTED);
         int tryStart = execute.size();
         execute.add(ALOAD_0);
-        execute.add(INVOKESPECIAL,new MethodRef(me,"trampoline",Type.VOID,Type.NO_ARGS));
+        execute.add(INVOKESPECIAL,me.method("trampoline",Type.VOID,Type.NO_ARGS));
         int tryEnd = execute.size();
         execute.add(RETURN);
         
         int catchInsn = execute.size();
         execute.add(ASTORE_1);
-        execute.add(NEW, new Type.Object("org.ibex.nestedvm.Runtime$FaultException"));
+        execute.add(NEW, Type.fromClass("org.ibex.nestedvm.Runtime$FaultException"));
         execute.add(DUP);
         execute.add(ALOAD_1);
-        execute.add(INVOKESPECIAL,new MethodRef("org.ibex.nestedvm.Runtime$FaultException","<init>",Type.VOID,new Type[]{new Type.Object("java.lang.RuntimeException")}));
+        // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime$FaultException.<init>
+        execute.add(INVOKESPECIAL,Type.fromClass("org.ibex.nestedvm.Runtime$FaultException").method("<init>",Type.VOID,new Type[]{Type.fromClass("java.lang.RuntimeException")}));
         execute.add(ATHROW);
         
-        execute.addExceptionHandler(tryStart,tryEnd,catchInsn,new Type.Object("java.lang.RuntimeException"));
-        execute.addThrow(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
+        execute.addExceptionHandler(tryStart,tryEnd,catchInsn,Type.fromClass("java.lang.RuntimeException"));
+        execute.addThrow(Type.fromClass("org.ibex.nestedvm.Runtime$ExecutionException"));
 
-        MethodGen main = cg.addMethod("main",Type.VOID,new Type[]{Type.arrayType(Type.STRING)},ACC_STATIC|ACC_PUBLIC);
+        MethodGen main = cg.addMethod("main",Type.VOID,new Type[]{Type.STRING.makeArray()},STATIC|PUBLIC);
         main.add(NEW,me);
         main.add(DUP);
-        main.add(INVOKESPECIAL,new MethodRef(me,"<init>",Type.VOID,Type.NO_ARGS));
+        main.add(INVOKESPECIAL,me.method("<init>",Type.VOID,Type.NO_ARGS));
         main.add(LDC,fullClassName);
         main.add(ALOAD_0);
         if(unixRuntime) {
-            Type.Object ur = new Type.Object("org.ibex.nestedvm.UnixRuntime");
-            main.add(INVOKESTATIC,new MethodRef(ur,"runAndExec",Type.INT,new Type[]{ur,Type.STRING,Type.arrayType(Type.STRING)}));
+            Type.Class ur = Type.fromClass("org.ibex.nestedvm.UnixRuntime");
+            // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.runAndExec
+            main.add(INVOKESTATIC,ur.method("runAndExec",Type.INT,new Type[]{ur,Type.STRING,Type.STRING.makeArray()}));
         } else {
-            main.add(INVOKEVIRTUAL,new MethodRef(me,"run",Type.INT,new Type[]{Type.STRING,Type.arrayType(Type.STRING)}));
+            // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.run
+            main.add(INVOKEVIRTUAL,me.method("run",Type.INT,new Type[]{Type.STRING,Type.STRING.makeArray()}));
         }
-        main.add(INVOKESTATIC,new MethodRef(new Type.Object("java.lang.System"),"exit",Type.VOID,new Type[]{Type.INT}));
+        main.add(INVOKESTATIC,Type.fromClass("java.lang.System").method("exit",Type.VOID,new Type[]{Type.INT}));
         main.add(RETURN);
         
-        cg.dump(os);
+        if(outDir != null) {
+            if(!outDir.isDirectory()) throw new IOException("" + outDir + " isn't a directory");
+            cg.dump(outDir);
+        } else {
+            cg.dump(os);
+        }
     }
     
     private void addConstReturnMethod(String name, int val) {
-        MethodGen  m = cg.addMethod(name,Type.INT,Type.NO_ARGS,ACC_PROTECTED);
+        MethodGen  m = cg.addMethod(name,Type.INT,Type.NO_ARGS,PROTECTED);
         m.add(LDC,val);
         m.add(IRETURN);
     }
@@ -355,18 +405,19 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
                     sb.append((char) ((l>>>(7*(7-j)))&0x7f));
             }
             String fieldname =  "_data" + (++initDataCount);
-            cg.addField(fieldname,Type.arrayType(Type.INT),ACC_PRIVATE|ACC_STATIC|ACC_FINAL);
+            cg.addField(fieldname,Type.INT.makeArray(),PRIVATE|STATIC|FINAL);
             
             clinit.add(LDC,sb.toString());
             clinit.add(LDC,segSize/4);
-            clinit.add(INVOKESTATIC,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime"),"decodeData",Type.arrayType(Type.INT),new Type[]{Type.STRING,Type.INT}));
-            clinit.add(PUTSTATIC,new FieldRef(me,fieldname,Type.arrayType(Type.INT)));
-
+            // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.decodeData
+            clinit.add(INVOKESTATIC,Type.fromClass("org.ibex.nestedvm.Runtime").method("decodeData",Type.INT.makeArray(),new Type[]{Type.STRING,Type.INT}));
+            clinit.add(PUTSTATIC,me.field(fieldname,Type.INT.makeArray()));
             init.add(ALOAD_0);
-            init.add(GETSTATIC,new FieldRef(me,fieldname,Type.arrayType(Type.INT)));
+            init.add(GETSTATIC,me.field(fieldname,Type.INT.makeArray()));
             init.add(LDC,addr);
             init.add(LDC,readOnly ? 1 : 0);
-            init.add(INVOKEVIRTUAL,new MethodRef(me,"initPages",Type.VOID,new Type[]{Type.arrayType(Type.INT),Type.INT,Type.BOOLEAN}));
+            // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.initPages
+            init.add(INVOKEVIRTUAL,me.method("initPages",Type.VOID,new Type[]{Type.INT.makeArray(),Type.INT,Type.BOOLEAN}));
             
             addr += segSize;
             size -= segSize;
@@ -382,14 +433,13 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         init.add(ALOAD_0);
         init.add(LDC,addr);
         init.add(LDC,count);
-        init.add(INVOKEVIRTUAL,new MethodRef(me,"clearPages",Type.VOID,new Type[]{Type.INT,Type.INT}));
+        // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.clearPages
+        init.add(INVOKEVIRTUAL,me.method("clearPages",Type.VOID,new Type[]{Type.INT,Type.INT}));
     }
     
     // Method state info
-    private boolean textDone; // a text segment was already processed
     private int startOfMethod = 0; // the start of this method (not necessarily the first instruction)
     private int endOfMethod = 0; // the maximum end of this method (could end before it is full)
-    private boolean unreachable = false; // is the current pc is reachable
     
     private MethodGen.PhantomTarget returnTarget; // where to jump when exiting the method
     private MethodGen.PhantomTarget defaultTarget; // the default switch target (throws exn)
@@ -398,6 +448,10 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
     
     private boolean jumpable(int addr) { return jumpableAddresses.get(new Integer(addr)) != null; }
     
+    private static final int UNREACHABLE = 1;
+    private static final int SKIP_NEXT = 2;
+    
+    private boolean textDone; // a text segment was already processed
     private void emitText(int addr, DataInputStream dis, int size) throws Exn,IOException {
         if(textDone) throw new Exn("Multiple text segments");
         textDone = true;
@@ -405,46 +459,53 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         if((addr&3)!=0 || (size&3)!=0) throw new Exn("Section on weird boundaries");
         int count = size/4;
         int insn,nextInsn=-1;
+        
         boolean skipNext = true;
+        boolean unreachable = false;
         
         for(int i=0;i<count;i++,addr+=4) {
             insn = skipNext ? dis.readInt() : nextInsn;
             nextInsn = (i == count-1) ? -1 : dis.readInt();
-            if(addr >= endOfMethod) { endMethod(addr); startMethod(addr); }
-            if(insnTargets[(addr-startOfMethod)/4] != null) {
-                insnTargets[(addr-startOfMethod)/4].setTarget(mg.size());
+            if(addr >= endOfMethod) { endMethod(addr,unreachable); startMethod(addr); }
+            if(insnTargets[i%maxInsnPerMethod] != null) {
+                insnTargets[i%maxInsnPerMethod].setTarget(mg.size());
                 unreachable = false;
             } else if(unreachable) {
                 continue;
             }
             try {
-                skipNext = emitInstruction(addr,insn,nextInsn);
+                int ret = emitInstruction(addr,insn,nextInsn);
+                unreachable =  (ret & UNREACHABLE) != 0;
+                skipNext = (ret & SKIP_NEXT) != 0;
+            } catch(Exn e) {
+                e.printStackTrace(warn);
+                warn.println("Exception at " + toHex(addr));
+                throw e;                
             } catch(RuntimeException e) {
                 warn.println("Exception at " + toHex(addr));
                 throw e;
             }
             if(skipNext) { addr+=4; i++; }
         }
-        endMethod(0);
+        endMethod(0,unreachable);
         dis.close();
-        mg.finish();
     }
     
     private void startMethod(int first) {
         startOfMethod = first & methodMask;
         endOfMethod = startOfMethod + maxBytesPerMethod;
         
-        mg = cg.addMethod("run_" + toHex(startOfMethod),Type.VOID,Type.NO_ARGS,ACC_PRIVATE|ACC_FINAL);
+        mg = cg.addMethod("run_" + toHex(startOfMethod),Type.VOID,Type.NO_ARGS,PRIVATE|FINAL);
         if(onePage) {
             mg.add(ALOAD_0);
-            mg.add(GETFIELD,new FieldRef(me,"page",Type.arrayType(Type.INT)));
+            mg.add(GETFIELD,me.field("page",Type.INT.makeArray()));
             mg.add(ASTORE_2);
         } else {
             mg.add(ALOAD_0);
-            mg.add(GETFIELD,new FieldRef(me,"readPages",Type.arrayType(Type.INT,2)));
+            mg.add(GETFIELD,me.field("readPages",Type.INT.makeArray(2)));
             mg.add(ASTORE_2);
             mg.add(ALOAD_0);
-            mg.add(GETFIELD,new FieldRef(me,"writePages",Type.arrayType(Type.INT,2)));
+            mg.add(GETFIELD,me.field("writePages",Type.INT.makeArray(2)));
             mg.add(ASTORE_3);
         }
         
@@ -462,7 +523,7 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             }
         }
 
-        MethodGen.LSI lsi = new MethodGen.LSI(n);
+        MethodGen.Switch.Lookup lsi = new MethodGen.Switch.Lookup(n);
         System.arraycopy(buf,0,lsi.vals,0,n);
         System.arraycopy(targetBuf,0,lsi.targets,0,n);
         lsi.setDefaultTarget(defaultTarget = new MethodGen.PhantomTarget());
@@ -470,11 +531,11 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         fixupRegsStart();
         
         mg.add(ALOAD_0);
-        mg.add(GETFIELD,new FieldRef(me,"pc",Type.INT));
+        mg.add(GETFIELD,me.field("pc",Type.INT));
         mg.add(LOOKUPSWITCH,lsi);
     }
     
-    private void endMethod(int firstAddrOfNext) {
+    private void endMethod(int firstAddrOfNext,boolean unreachable) {
         if(startOfMethod == 0) return;
         
         if(!unreachable) {
@@ -494,23 +555,23 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         defaultTarget.setTarget(mg.size());
         
         if(debugCompiler) {
-            mg.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
+            mg.add(NEW,Type.fromClass("org.ibex.nestedvm.Runtime$ExecutionException"));
             mg.add(DUP);
             mg.add(NEW,Type.STRINGBUFFER);
             mg.add(DUP);
             mg.add(LDC,"Jumped to invalid address: ");
-            mg.add(INVOKESPECIAL,new MethodRef(Type.STRINGBUFFER,"<init>",Type.VOID,new Type[]{Type.STRING}));
+            mg.add(INVOKESPECIAL,Type.STRINGBUFFER.method("<init>",Type.VOID,new Type[]{Type.STRING}));
             mg.add(ALOAD_0);
-            mg.add(GETFIELD,new FieldRef(me,"pc",Type.INT));
-            mg.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.INT}));
-            mg.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"toString",Type.STRING,Type.NO_ARGS));
-            mg.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"<init>",Type.VOID,new Type[]{Type.STRING}));
+            mg.add(GETFIELD,me.field("pc",Type.INT));
+            mg.add(INVOKEVIRTUAL,Type.STRINGBUFFER.method("append",Type.STRINGBUFFER,new Type[]{Type.INT}));
+            mg.add(INVOKEVIRTUAL,Type.STRINGBUFFER.method("toString",Type.STRING,Type.NO_ARGS));
+            mg.add(INVOKESPECIAL,Type.fromClass("org.ibex.nestedvm.Runtime$ExecutionException").method("<init>",Type.VOID,new Type[]{Type.STRING}));
             mg.add(ATHROW);
         } else {
-            mg.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
+            mg.add(NEW,Type.fromClass("org.ibex.nestedvm.Runtime$ExecutionException"));
             mg.add(DUP);
             mg.add(LDC,"Jumped to invalid address");
-            mg.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"<init>",Type.VOID,new Type[]{Type.STRING}));
+            mg.add(INVOKESPECIAL,Type.fromClass("org.ibex.nestedvm.Runtime$ExecutionException").method("<init>",Type.VOID,new Type[]{Type.STRING}));
             mg.add(ATHROW);
         }
         
@@ -521,6 +582,21 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
     private void leaveMethod() {
         mg.add(GOTO,returnTarget);
     }
+    
+    private void link(int mypc) {
+        preSetReg(R+RA);
+        if(lessConstants){
+            int ref = (mypc+8 + 32768) & ~65535;
+            int diff = (mypc+8) - ref;
+            if(diff < -32768 || diff > 32767) throw new Error("should never happen " + diff);
+            mg.add(LDC,ref);
+            mg.add(LDC,diff);
+            mg.add(IADD);
+        } else {
+            mg.add(LDC,mypc+8);
+        }
+        setReg();
+    }
 
     private void branch(int pc, int target) {
         if((pc&methodMask) == (target&methodMask)) {
@@ -534,7 +610,7 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
     }
     
     // This assumes everything needed by ifInsn is already on the stack
-    private boolean doIfInstruction(byte op, int pc, int target, int nextInsn) throws Exn {
+    private int doIfInstruction(byte op, int pc, int target, int nextInsn) throws Exn {
         emitInstruction(-1,nextInsn,-1); // delay slot
         if((target&methodMask) == (pc&methodMask)) {
             mg.add(op,insnTargets[(target-startOfMethod)/4]);
@@ -543,7 +619,7 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             branch(pc,target);
             mg.setArg(h,mg.size());
         }
-        if(!jumpable(pc+4)) return true; // done - skip it
+        if(!jumpable(pc+4)) return SKIP_NEXT; // done - skip it
         
         //System.err.println("Delay slot is jumpable - This code is untested + " + toHex(nextInsn));
         if(pc+4==endOfMethod) {
@@ -551,17 +627,19 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             jumpableAddresses.put(new Integer(pc+8),Boolean.TRUE); // make the 2nd insn of the next method jumpable
             branch(pc,pc+8); // jump over it
             //System.err.println("delay slot: " + toHex(pc+8)); */
-            unreachable = true;
-            return false; // we still need to output it
+            //unreachable = true;
+            //return false; // we still need to output it
+            return UNREACHABLE;
         } else {
             //System.err.println("jumped over delay slot: " + toHex(pc+4));
             // add another copy and jump over
             
             int b = mg.add(GOTO);
+            insnTargets[(pc+4-startOfMethod)/4].setTarget(mg.size());
             emitInstruction(-1,nextInsn,01); // delay slot
             mg.setArg(b,mg.size());
             
-            return true;
+            return SKIP_NEXT;
         }
     }
     
@@ -569,10 +647,12 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
     private static final Double POINT_5_D = new Double(0.5f);
     private static final Long FFFFFFFF = new Long(0xffffffffL);
     
-    private boolean emitInstruction(int pc, int insn, int nextInsn) throws Exn {
+    private int emitInstruction(int pc, int insn, int nextInsn) throws Exn {
         MethodGen mg = this.mg; // smaller bytecode
         if(insn == -1) throw new Exn("insn is -1");
         
+        int ret = 0;
+        
         int op = (insn >>> 26) & 0xff;                 // bits 26-31
         int rs = (insn >>> 21) & 0x1f;                 // bits 21-25
         int rt = (insn >>> 16) & 0x1f;                 // bits 16-20 
@@ -583,12 +663,12 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         int fd = (insn >>> 6) & 0x1f;
         int subcode = insn & 0x3f;                     // bits 0-5 
         int breakCode = (insn >>> 6) & 0xfffff;         // bits 6-20
-
+    
         int jumpTarget = (insn & 0x03ffffff);          // bits 0-25
         int unsignedImmediate = insn & 0xffff;
         int signedImmediate = (insn << 16) >> 16;
         int branchTarget = signedImmediate;
-
+    
         // temporaries
         int b1,b2;
         
@@ -645,20 +725,17 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
                 pushRegWZ(R+rs);
                 setPC();
                 leaveMethod();
-                unreachable = true;
+                ret |= UNREACHABLE;
                 break;
             case 9: // JALR
                 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
                 emitInstruction(-1,nextInsn,-1);
+                link(pc);
                 preSetPC();
                 pushRegWZ(R+rs);
                 setPC();
-                
-                preSetReg(R+RA);
-                mg.add(LDC,pc+8);
-                setReg();
                 leaveMethod();
-                unreachable = true;
+                ret |= UNREACHABLE;
                 break;
             case 12: // SYSCALL
                 preSetPC();
@@ -678,11 +755,12 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
                 pushRegZ(R+A3);
                 pushRegZ(R+T0);
                 pushRegZ(R+T1);
-                mg.add(INVOKEVIRTUAL,new MethodRef(me,"syscall",Type.INT,new Type[]{Type.INT,Type.INT,Type.INT,Type.INT,Type.INT,Type.INT,Type.INT}));
+                // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.syscall
+                mg.add(INVOKEVIRTUAL,me.method("syscall",Type.INT,new Type[]{Type.INT,Type.INT,Type.INT,Type.INT,Type.INT,Type.INT,Type.INT}));
                 setReg();
                 
                 mg.add(ALOAD_0);
-                mg.add(GETFIELD,new FieldRef(me,"state",Type.INT));
+                mg.add(GETFIELD,me.field("state",Type.INT));
                 b1 = mg.add(IFEQ);
                 preSetPC();
                 mg.add(LDC,pc+4);
@@ -691,12 +769,12 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
                 mg.setArg(b1,mg.size());
                 break;
             case 13: // BREAK
-                mg.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
+                mg.add(NEW,Type.fromClass("org.ibex.nestedvm.Runtime$ExecutionException"));
                 mg.add(DUP);
                 mg.add(LDC,"BREAK Code " + toHex(breakCode));
-                mg.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"<init>",Type.VOID,new Type[]{Type.STRING}));
+                mg.add(INVOKESPECIAL,Type.fromClass("org.ibex.nestedvm.Runtime$ExecutionException").method("<init>",Type.VOID,new Type[]{Type.STRING}));
                 mg.add(ATHROW);
-                unreachable = true;
+                ret |= UNREACHABLE;
                 break;
             case 16: // MFHI
                 preSetReg(R+rd);
@@ -947,9 +1025,7 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
                 pushRegWZ(R+rs);
                 b1 = mg.add(IFGE);
                 emitInstruction(-1,nextInsn,-1);
-                preSetReg(R+RA);
-                mg.add(LDC,pc+8);
-                setReg();
+                link(pc);
                 branch(pc,pc+branchTarget*4+4);
                 mg.setArg(b1,mg.size());
                 break;
@@ -961,12 +1037,10 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
                     b1 = mg.add(IFLT);
                 }
                 emitInstruction(-1,nextInsn,-1);
-                preSetReg(R+RA);
-                mg.add(LDC,pc+8);
-                setReg();
+                link(pc);
                 branch(pc,pc+branchTarget*4+4);
                 if(b1 != -1) mg.setArg(b1,mg.size());
-                if(b1 == -1) unreachable = true;
+                if(b1 == -1) ret |= UNREACHABLE;
                 break;
             default:
                 throw new Exn("Illegal Instruction 1/" + rt);
@@ -977,18 +1051,16 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             if(pc == -1) throw new Exn("pc modifying insn in delay slot");
             emitInstruction(-1,nextInsn,-1);
             branch(pc,(pc&0xf0000000)|(jumpTarget << 2));
-            unreachable = true;
+            ret |= UNREACHABLE;
             break;
         }
         case 3: { // JAL
             if(pc == -1) throw new Exn("pc modifying insn in delay slot");
             int target = (pc&0xf0000000)|(jumpTarget << 2);
             emitInstruction(-1,nextInsn,-1);
-            preSetReg(R+RA);
-            mg.add(LDC,pc+8);
-            setReg();
+            link(pc);
             branch(pc, target);
-            unreachable = true;
+            ret |= UNREACHABLE;
             break;
         }
         case 4: // BEQ
@@ -996,7 +1068,7 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             if(rs == rt) {
                 emitInstruction(-1,nextInsn,-1);
                 branch(pc,pc+branchTarget*4+4);
-                unreachable = true;
+                ret |= UNREACHABLE;
             } else if(rs == 0 || rt == 0) {
                 pushReg(rt == 0 ? R+rs : R+rt);
                 return doIfInstruction(IFEQ,pc,pc+branchTarget*4+4,nextInsn);
@@ -1026,9 +1098,15 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         case 8: // ADDI
             throw new Exn("ADDI (add immediate with oveflow trap) not suported");
         case 9: // ADDIU
-            preSetReg(R+rt);
-            addiu(rs,signedImmediate);
-            setReg();            
+            if(rs != 0 && signedImmediate != 0 && rs == rt && doLocal(rt) && signedImmediate >= -32768 && signedImmediate <= 32767) {
+                // HACK: This should be a little cleaner
+                regLocalWritten[rt] = true;
+                mg.add(IINC, new MethodGen.Pair(getLocalForReg(rt),signedImmediate));
+            } else {
+                preSetReg(R+rt);
+                addiu(rs,signedImmediate);
+                setReg();
+            }
             break;
         case 10: // SLTI
             preSetReg(R+rt);
@@ -1107,10 +1185,8 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
                 break;
             case 4: // MTC.1
                 preSetReg(F+rd);
-                if(rt != 0)
-                    pushReg(R+rt);
-                else
-                    mg.add(LDC,0);
+                if(rt != 0) pushReg(R+rt);
+                else mg.add(ICONST_0);
                 setReg();
                 break;
             case 6: // CTC.1
@@ -1185,13 +1261,12 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
                     preSetReg(F+fd);
                     pushReg(F+fs);
                     setReg();
-                    
+                
                     if(d) {
                         preSetReg(F+fd+1);
                         pushReg(F+fs+1);
                         setReg();
                     }
-                    
                     break;
                 case 7: // NEG.X
                     preSetDouble(F+fd,d);
@@ -1212,7 +1287,7 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
                     setDouble();
                     break;
                 case 36: { // CVT.W.D
-                    MethodGen.TSI tsi = new MethodGen.TSI(0,3);
+                    MethodGen.Switch.Table tsi = new MethodGen.Switch.Table(0,3);
                     preSetReg(F+fd);
                     pushDouble(F+fs,d);
                     pushReg(FCSR);
@@ -1223,7 +1298,7 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
                     // Round towards plus infinity
                     tsi.setTarget(2,mg.size());
                     if(!d) mg.add(F2D); // Ugh.. java.lang.Math doesn't have a float ceil/floor
-                    mg.add(INVOKESTATIC,new MethodRef("java.lang.Math","ceil",Type.DOUBLE,new Type[]{Type.DOUBLE}));
+                    mg.add(INVOKESTATIC,Type.fromClass("java.lang.Math").method("ceil",Type.DOUBLE,new Type[]{Type.DOUBLE}));
                     if(!d) mg.add(D2F);
                     b1 = mg.add(GOTO);
                     
@@ -1236,7 +1311,7 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
                     // Round towards minus infinity
                     tsi.setTarget(3,mg.size());
                     if(!d) mg.add(F2D);
-                    mg.add(INVOKESTATIC,new MethodRef("java.lang.Math","floor",Type.DOUBLE,new Type[]{Type.DOUBLE}));
+                    mg.add(INVOKESTATIC,Type.fromClass("java.lang.Math").method("floor",Type.DOUBLE,new Type[]{Type.DOUBLE}));
                     if(!d) mg.add(D2F);
                     
                     tsi.setTarget(1,mg.size());
@@ -1459,7 +1534,6 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             addiu(R+rs,signedImmediate);
             setTmp(); // addr
             
-            // FEATURE: DO the preMemRead(true) thing for the rest of the S* instructions
             preMemRead(true);
             pushTmp();
             memRead(true);
@@ -1499,19 +1573,13 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             break;
         }
         case 41: { // SH    
-            preMemWrite1();
-            
             addiu(R+rs,signedImmediate);
+            setTmp();
             
-            mg.add(DUP);
-            setTmp(); // addr
-            
-            preMemWrite2(true);
-            
-            preMemRead();
+            preMemRead(true);
             pushTmp();
             memRead(true);
-            
+                       
             mg.add(LDC,0xffff);
             pushTmp();
             
@@ -1545,15 +1613,10 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             break;            
         }
         case 42: { // SWL
-            preMemWrite1();
-            
             addiu(R+rs,signedImmediate);
-            mg.add(DUP);
-            setTmp(); // addr
-
-            preMemWrite2(true);
+            setTmp();
             
-            preMemRead();
+            preMemRead(true);            
             pushTmp();
             memRead(true);
             
@@ -1590,15 +1653,10 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             memWrite();
             break;
         case 46: { // SWR
-            preMemWrite1();
-            
             addiu(R+rs,signedImmediate);
-            mg.add(DUP);
-            setTmp(); // addr
-            
-            preMemWrite2(true);
+            setTmp();
             
-            preMemRead();
+            preMemRead(true);
             pushTmp();
             memRead(true);
             
@@ -1662,7 +1720,7 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         default:
             throw new Exn("Invalid Instruction: " + op + " at " + toHex(pc));
         }
-        return false; 
+        return ret; 
     }
     
     // Helper functions for emitText
@@ -1673,14 +1731,25 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
     private static final int LO = 65;
     private static final int FCSR = 66;
     private static final int REG_COUNT=67;
-        
+    private static final String[] regField = {
+            "r0","r1","r2","r3","r4","r5","r6","r7",
+            "r8","r9","r10","r11","r12","r13","r14","r15",
+            "r16","r17","r18","r19","r20","r21","r22","r23",
+            "r24","r25","r26","r27","r28","r29","r30","r31",
+            "f0","f1","f2","f3","f4","f5","f6","f7",
+            "f8","f9","f10","f11","f12","f13","f14","f15",
+            "f16","f17","f18","f19","f20","f21","f22","f23",
+            "f24","f25","f26","f27","f28","f29","f30","f31",
+            "hi","lo","fcsr"
+    };
+    private static final int MAX_LOCALS = 4; // doLocal can return true for this many regs
+    private static final int LOAD_LENGTH = 3; // number of instructions needed to load a field to a reg
+    
+    // Local register state info
     private int[] regLocalMapping = new int[REG_COUNT];  
-    private int[] regLocalReadCount = new int[REG_COUNT];
-    private int[] regLocalWriteCount = new int[REG_COUNT];
-    private int nextAvailLocal; 
+    private boolean[] regLocalWritten = new boolean[REG_COUNT];
+    private int nextAvailLocal;
     private int loadsStart;
-    private static final int MAX_LOCALS = 4;
-    private static final int LOAD_LENGTH = 3;
     
     private boolean doLocal(int reg) {
         return reg == R+2 || reg == R+3 || reg == R+4 || reg == R+29;
@@ -1688,15 +1757,16 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
     
     private int getLocalForReg(int reg) {
         if(regLocalMapping[reg] != 0) return regLocalMapping[reg];
-        if(nextAvailLocal == 0) nextAvailLocal = onePage ? 3 : 4;
         regLocalMapping[reg] = nextAvailLocal++;
         return regLocalMapping[reg];
     }
     
     private void fixupRegsStart() {
-        for(int i=0;i<REG_COUNT;i++)
-            regLocalMapping[i] = regLocalReadCount[i] = regLocalWriteCount[i] = 0;
-        nextAvailLocal = 0;
+        for(int i=0;i<REG_COUNT;i++) {
+            regLocalMapping[i] = 0;
+            regLocalWritten[i] = false;
+        }
+        nextAvailLocal = onePage ? 4 : 5;
         loadsStart = mg.size();
         for(int i=0;i<MAX_LOCALS*LOAD_LENGTH;i++)
             mg.add(NOP);
@@ -1707,43 +1777,27 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         for(int i=0;i<REG_COUNT;i++) {
             if(regLocalMapping[i] == 0) continue;
             mg.set(p++,ALOAD_0);
-            mg.set(p++,GETFIELD,new FieldRef(me,regField(i),Type.INT));
+            mg.set(p++,GETFIELD,me.field(regField[i],Type.INT));
             mg.set(p++,ISTORE,regLocalMapping[i]);
             
-            if(regLocalWriteCount[i] > 0) {
+            if(regLocalWritten[i]) {
                 mg.add(ALOAD_0);
                 mg.add(ILOAD,regLocalMapping[i]);
-                mg.add(PUTFIELD,new FieldRef(me,regField(i),Type.INT));
+                mg.add(PUTFIELD,me.field(regField[i],Type.INT));
             }
         }
     }
         
     private void restoreChangedRegs() {
         for(int i=0;i<REG_COUNT;i++) {
-            if(regLocalWriteCount[i] > 0) {
+            if(regLocalWritten[i]) {
                 mg.add(ALOAD_0);
                 mg.add(ILOAD,regLocalMapping[i]);
-                mg.add(PUTFIELD,new FieldRef(me,regField(i),Type.INT));
+                mg.add(PUTFIELD,me.field(regField[i],Type.INT));
             }
         }
     }
-    
-    private static final String[] regField = {
-            "r0","r1","r2","r3","r4","r5","r6","r7",
-            "r8","r9","r10","r11","r12","r13","r14","r15",
-            "r16","r17","r18","r19","r20","r21","r22","r23",
-            "r24","r25","r26","r27","r28","r29","r30","r31",
-            
-            "f0","f1","f2","f3","f4","f5","f6","f7",
-            "f8","f9","f10","f11","f12","f13","f14","f15",
-            "f16","f17","f18","f19","f20","f21","f22","f23",
-            "f24","f25","f26","f27","f28","f29","f30","f31",
             
-            "hi","lo","fcsr"
-    };
-    
-    private static String regField(int reg) { return regField[reg]; }
-        
     private int pushRegWZ(int reg) {
         if(reg == R+0) {
             warn.println("Warning: Pushing r0!");
@@ -1761,12 +1815,14 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
     private int pushReg(int reg) {
         int h = mg.size();
         if(doLocal(reg)) {
-            regLocalReadCount[reg]++;
             mg.add(ILOAD,getLocalForReg(reg));
-            
+        } else if(reg >= F+0 && reg <= F+31 && singleFloat) {
+            mg.add(ALOAD_0);
+            mg.add(GETFIELD,me.field(regField[reg],Type.FLOAT));
+            mg.add(INVOKESTATIC,Type.FLOAT_OBJECT.method("floatToIntBits",Type.INT,new Type[]{Type.FLOAT}));
         } else {
             mg.add(ALOAD_0);
-            mg.add(GETFIELD,new FieldRef(me,regField(reg),Type.INT));
+            mg.add(GETFIELD,me.field(regField[reg],Type.INT));
         }
         return h;
     }
@@ -1776,7 +1832,6 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
     
     // This can push ONE or ZERO words to the stack. If it pushed one it returns true
     private boolean preSetReg(int reg) {
-        regField(reg); // just to check for validity
         preSetRegStack[preSetRegStackPos] = reg;
         preSetRegStackPos++;
         if(doLocal(reg)) {
@@ -1794,24 +1849,28 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         int h = mg.size();
         if(doLocal(reg)) {
             mg.add(ISTORE,getLocalForReg(reg));
-            regLocalWriteCount[reg]++;
+            regLocalWritten[reg] = true;
+        } else if(reg >= F+0 && reg <= F+31 && singleFloat) {
+            mg.add(INVOKESTATIC,Type.FLOAT_OBJECT.method("intBitsToFloat",Type.FLOAT,new Type[]{Type.INT}));
+            mg.add(PUTFIELD,me.field(regField[reg],Type.FLOAT));            
         } else {
-            mg.add(PUTFIELD,new FieldRef(me,regField(reg),Type.INT));
+            mg.add(PUTFIELD,me.field(regField[reg],Type.INT));
         }
         return h;
     }
     
     private int preSetPC() { return mg.add(ALOAD_0); }
     private int setPC() {
-        return mg.add(PUTFIELD,new FieldRef(me,"pc",Type.INT));
+        return mg.add(PUTFIELD,me.field("pc",Type.INT));
     }
     
-    //unused - private InstructionHandle pushFloat(int reg) throws CompilationException { return pushDouble(reg,false); }
     //unused - private InstructionHandle pushDouble(int reg) throws CompilationException { return pushDouble(reg,true); }
+    private int pushFloat(int reg) throws Exn { return pushDouble(reg,false); }
     private int pushDouble(int reg, boolean d) throws Exn {
         if(reg < F || reg >= F+32) throw new IllegalArgumentException(""+reg);
         int h = mg.size();
         if(d) {
+            if(singleFloat) throw new Exn("Double operations not supported when singleFloat is enabled");
             if(reg == F+31) throw new Exn("Tried to use a double in f31");
             pushReg(reg+1);
             mg.add(I2L);
@@ -1822,10 +1881,13 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             mg.add(LDC,FFFFFFFF);
             mg.add(LAND);
             mg.add(LOR);
-            mg.add(INVOKESTATIC,new MethodRef(Type.DOUBLE_OBJECT,"longBitsToDouble",Type.DOUBLE,new Type[]{Type.LONG}));
+            mg.add(INVOKESTATIC,Type.DOUBLE_OBJECT.method("longBitsToDouble",Type.DOUBLE,new Type[]{Type.LONG}));
+        } else if(singleFloat) {
+            mg.add(ALOAD_0);
+            mg.add(GETFIELD,me.field(regField[reg],Type.FLOAT));
         } else {
             pushReg(reg);
-            mg.add(INVOKESTATIC,new MethodRef("java.lang.Float","intToFloatBits",Type.FLOAT,new Type[]{Type.INT}));
+            mg.add(INVOKESTATIC,Type.fromClass("java.lang.Float").method("intBitsToFloat",Type.FLOAT,new Type[]{Type.INT}));
         }
         return h;
     }
@@ -1841,8 +1903,9 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         if(reg < F || reg >= F+32) throw new IllegalArgumentException(""+reg);
         int h = mg.size();
         if(d) {
+            if(singleFloat) throw new Exn("Double operations not supported when singleFloat is enabled");
             if(reg == F+31) throw new Exn("Tried to use a double in f31");
-            mg.add(INVOKESTATIC,new MethodRef(Type.DOUBLE_OBJECT,"doubleToLongBits",Type.LONG,new Type[]{Type.DOUBLE}));
+            mg.add(INVOKESTATIC,Type.DOUBLE_OBJECT.method("doubleToLongBits",Type.LONG,new Type[]{Type.DOUBLE}));
             mg.add(DUP2);
             mg.add(LDC,32);
             mg.add(LUSHR);
@@ -1852,9 +1915,13 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             setReg();
             mg.add(L2I);
             setReg(); // preSetReg was already done for this by preSetDouble
+        } else if(singleFloat) {
+            // HACK: Clean this up
+            preSetRegStackPos--;
+            mg.add(PUTFIELD,me.field(regField[reg],Type.FLOAT));
         } else {
             //h = a(fac.createInvoke("java.lang.Float","floatToRawIntBits",Type.INT,new Type[]{Type.FLOAT},INVOKESTATIC));
-            mg.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"floatToRawIntBits",Type.INT,new Type[]{Type.FLOAT}));
+            mg.add(INVOKESTATIC,Type.FLOAT_OBJECT.method("floatToRawIntBits",Type.INT,new Type[]{Type.FLOAT}));
             setReg();   
         }
         return h;
@@ -1900,7 +1967,8 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             mg.add(DUP);
             mg.add(ALOAD_0);
             mg.add(SWAP);
-            mg.add(INVOKEVIRTUAL,new MethodRef(me,"nullPointerCheck",Type.VOID,new Type[]{Type.INT}));
+            // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.nullPointerCheck
+            mg.add(INVOKEVIRTUAL,me.method("nullPointerCheck",Type.VOID,new Type[]{Type.INT}));
         }
         
         if(onePage) {
@@ -1933,7 +2001,8 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         } else if(fastMem) {
             mg.add(IASTORE);
         } else {
-            mg.add(INVOKEVIRTUAL,new MethodRef(me,"unsafeMemWrite",Type.VOID,new Type[]{Type.INT,Type.INT}));
+            // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.unsafeMemWrite
+            mg.add(INVOKEVIRTUAL,me.method("unsafeMemWrite",Type.VOID,new Type[]{Type.INT,Type.INT}));
         }
         
     }
@@ -1974,7 +2043,7 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
             mg.add(DUP);
             mg.add(ALOAD_0);
             mg.add(SWAP);
-            mg.add(INVOKEVIRTUAL,new MethodRef(me,"nullPointerCheck",Type.VOID,new Type[]{Type.INT}));
+            mg.add(INVOKEVIRTUAL,me.method("nullPointerCheck",Type.VOID,new Type[]{Type.INT}));
         }
         
         if(onePage) {
@@ -2004,7 +2073,8 @@ public class ClassFileCompiler extends Compiler implements CGConst  {
         } else {
             if(preMemReadDoPreWrite)
                 mg.add(DUP2);
-            mg.add(INVOKEVIRTUAL,new MethodRef(me,"unsafeMemRead",Type.INT,new Type[]{Type.INT}));
+            // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.unsafeMemRead
+            mg.add(INVOKEVIRTUAL,me.method("unsafeMemRead",Type.INT,new Type[]{Type.INT}));
         }
     }