update nestedvm for new classgen api again
[nestedvm.git] / src / org / ibex / nestedvm / ClassFileCompiler.java
index 931f1b9..8695445 100644 (file)
@@ -1,12 +1,16 @@
+// 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.*;
-import org.ibex.nestedvm.util.*;
 
-import org.apache.bcel.generic.*;
+import org.ibex.nestedvm.util.*;
+import org.ibex.classgen.*;
 
-// FEATURE: Use BCEL to do 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
@@ -32,82 +36,113 @@ import org.apache.bcel.generic.*;
  */
 
 
-public class ClassFileCompiler extends Compiler implements org.apache.bcel.Constants  {    
+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 cl;
-    private ConstantPoolGen cp;
-    private InstructionList clinitExtras = new InstructionList();
-    private InstructionList initExtras = new InstructionList();
-    private InstructionFactory fac; 
-    
-    // Handy wrappers around the BCEL functions
-    private InstructionList insnList;
-    private void selectMethod(MethodGen m) { insnList = m.getInstructionList();    }
-    private void selectList(InstructionList l) { insnList = l; }
-    private InstructionHandle a(Instruction i) { return insnList.append(i); }
-    private BranchHandle a(BranchInstruction i) { return insnList.append(i); }
-    private InstructionHandle a(InstructionList l) { return insnList.append(l); }
-    private InstructionHandle a(CompoundInstruction c) { return insnList.append(c); }
-    
-    // This works around a bug in InstructionList
-    // FEATURE: fix this in bcel, send them a patch, etc
-    private static class FixedInstructionList extends InstructionList {
-        public void move(InstructionHandle start, InstructionHandle end, InstructionHandle target) {
-            InstructionHandle extra = target != null && target == getEnd() ? append(InstructionConstants.NOP) : null;
-            super.move(start,end,target);
-            if(extra != null) try { delete(extra); } catch (TargetLostException e) { /* won't happen */ }
-        }
-    }
-    
-    private MethodGen newMethod(int flags, Type ret, Type[] args, String name) {
-        return new MethodGen(flags,ret,args,null,name,fullClassName,new FixedInstructionList(),cp);
-    }
+    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
-        cl = new ClassGen(fullClassName,runtimeClass,source,ACC_SUPER|ACC_PUBLIC|ACC_FINAL,null);
-        cp = cl.getConstantPool();
-        fac = new InstructionFactory(cl,cp);
+        Type.Class superClass = Type.fromClass(runtimeClass);
+        cg = new ClassFile(me,superClass,PUBLIC|FINAL|SUPER);
+        if(source != null) cg.setSourceFile(source);
         
         // Fields
-        cl.addField(new FieldGen(ACC_PRIVATE,Type.INT,"pc",cp).getField());
-        for(int i=1;i<32;i++)
-            cl.addField(new FieldGen(ACC_PRIVATE,Type.INT,"r"+i,cp).getField());
-        for(int i=0;i<32;i++)
-            cl.addField(new FieldGen(ACC_PRIVATE,Type.INT,"f"+i,cp).getField());
+        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>
 
-        cl.addField(new FieldGen(ACC_PRIVATE,Type.INT,"hi",cp).getField());
-        cl.addField(new FieldGen(ACC_PRIVATE,Type.INT,"lo",cp).getField());
-        cl.addField(new FieldGen(ACC_PRIVATE,Type.INT,"fcsr",cp).getField());
+        // <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,me.method("<init>",Type.VOID,new Type[]{Type.INT,Type.INT}));
+        init.add(RETURN);
+
+        // <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(ILOAD_3);
+        init.add(INVOKESPECIAL,superClass.method("<init>",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN}));
         
         if(onePage) {
-            cl.addField(new FieldGen(ACC_PRIVATE|ACC_FINAL,new ArrayType(Type.INT,1),"page",cp).getField());
-
-            selectList(initExtras);
-            a(InstructionConstants.ALOAD_0);
-            a(InstructionConstants.DUP);
-            a(fac.createFieldAccess(fullClassName,"readPages",new ArrayType(Type.INT, 2), GETFIELD));
-            pushConst(0);
-            a(InstructionConstants.AALOAD);
-            a(fac.createFieldAccess(fullClassName,"page",new ArrayType(Type.INT,1), PUTFIELD));
+            cg.addField("page",Type.INT.makeArray(),PRIVATE|FINAL);
+            init.add(ALOAD_0);
+            init.add(DUP);
+            init.add(GETFIELD,me.field("readPages",Type.INT.makeArray(2)));
+            init.add(LDC,0);
+            init.add(AALOAD);
+            init.add(PUTFIELD,me.field("page",Type.INT.makeArray()));
         }
         
         if(supportCall)
-            cl.addField(new FieldGen(ACC_PRIVATE|ACC_STATIC|ACC_FINAL,Type.getType("L"+hashClass.replace('.','/')+";"),"symbols",cp).getField()); 
+            cg.addField("symbols",Type.fromClass(hashClass),PRIVATE|STATIC|FINAL);
         
         int highestAddr = 0;
         
@@ -129,69 +164,86 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
                 throw new Exn("Unknown segment: " + name);
         }
         
+        // Finish init
+        init.add(RETURN);
+        
+        // Finish clinit
+        if(supportCall) {
+            Type.Class hash = Type.fromClass(hashClass);
+            clinit.add(NEW,hash);
+            clinit.add(DUP);
+            clinit.add(DUP);
+            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];
+                if(s.type == ELF.Symbol.STT_FUNC && s.binding == ELF.Symbol.STB_GLOBAL && (s.name.equals("_call_helper") || !s.name.startsWith("_"))) {
+                    clinit.add(DUP);
+                    clinit.add(LDC,s.name);
+                    clinit.add(NEW,Type.INTEGER_OBJECT);
+                    clinit.add(DUP);
+                    clinit.add(LDC,s.addr);
+                    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);
+                }
+            }
+            clinit.add(POP);
+        }
+        
+        clinit.add(RETURN);
+        
         ELF.SHeader text = elf.sectionWithName(".text");
         
         // Trampoline
-        MethodGen tramp = newMethod(ACC_PRIVATE,Type.VOID, Type.NO_ARGS, "trampoline");
-        tramp.addException("org.ibex.nestedvm.Runtime$ExecutionException");
-        selectMethod(tramp);
+        MethodGen tramp = cg.addMethod("trampoline",Type.VOID,Type.NO_ARGS,PRIVATE);
+        
+        int start = tramp.size();
+        tramp.add(ALOAD_0);
+        tramp.add(GETFIELD,me.field("state",Type.INT));
+        tramp.add(IFEQ,tramp.size()+2);
+        tramp.add(RETURN);
         
-        InstructionHandle start = a(InstructionConstants.ALOAD_0);
-        a(fac.createFieldAccess(fullClassName,"state",Type.INT, GETFIELD));
-        pushConst(Runtime.RUNNING);
-        BranchInstruction stateCheck =  InstructionFactory.createBranchInstruction(IF_ICMPNE,null);
-        a(stateCheck);
-        a(InstructionConstants.ALOAD_0);
-        a(InstructionConstants.ALOAD_0);
-        a(fac.createFieldAccess(fullClassName,"pc",Type.INT, GETFIELD));
-        pushConst(methodShift);
-        a(InstructionConstants.IUSHR);
+        tramp.add(ALOAD_0);
+        tramp.add(ALOAD_0);
+        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) >>> methodShift);
+        int end = ((text.addr + text.size + maxBytesPerMethod - 1) >>> methodShift);
 
-        // This data is redundant but BCEL wants it
-        int[] matches = new int[end-beg];
-        for(int i=beg;i<end;i++)  matches[i-beg] = i;
-        TABLESWITCH ts = new TABLESWITCH(matches,new InstructionHandle[matches.length],null);
-        a(ts);
-        for(int n=beg;n<end;n++){
-            InstructionHandle h = a(fac.createInvoke(fullClassName,"run_"+toHex(n<<methodShift),Type.VOID,Type.NO_ARGS,INVOKESPECIAL));
-            a(InstructionFactory.createBranchInstruction(GOTO,start));
-            ts.setTarget(n-beg,h);
+        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,me.method("run_"+toHex(n<<methodShift),Type.VOID,Type.NO_ARGS));
+            tramp.add(GOTO,start);
         }
+        tsi.setDefaultTarget(tramp.size());
         
-        ts.setTarget(a(InstructionConstants.POP)); // default case
-        a(fac.createNew("org.ibex.nestedvm.Runtime$ExecutionException"));
-        a(InstructionConstants.DUP);
-        a(fac.createNew("java.lang.StringBuffer"));
-        a(InstructionConstants.DUP);
-        a(new PUSH(cp,"Jumped to invalid address in trampoline (r2: "));
-        a(fac.createInvoke("java.lang.StringBuffer","<init>",Type.VOID,new Type[]{Type.STRING},INVOKESPECIAL));
-        a(InstructionConstants.ALOAD_0);
-        a(fac.createFieldAccess(fullClassName,"r2",Type.INT, GETFIELD));
-        a(fac.createInvoke("java.lang.StringBuffer","append",Type.STRINGBUFFER,new Type[]{Type.INT},INVOKEVIRTUAL));
-        a(new PUSH(cp," pc:"));
-        a(fac.createInvoke("java.lang.StringBuffer","append",Type.STRINGBUFFER,new Type[]{Type.STRING},INVOKEVIRTUAL));
-        a(InstructionConstants.ALOAD_0);
-        a(fac.createFieldAccess(fullClassName,"pc",Type.INT, GETFIELD));
-        a(fac.createInvoke("java.lang.StringBuffer","append",Type.STRINGBUFFER,new Type[]{Type.INT},INVOKEVIRTUAL));
-        a(new PUSH(cp,')'));
-        a(fac.createInvoke("java.lang.StringBuffer","append",Type.STRINGBUFFER,new Type[]{Type.CHAR},INVOKEVIRTUAL));
-        a(fac.createInvoke("java.lang.StringBuffer","toString",Type.STRING,Type.NO_ARGS,INVOKEVIRTUAL));
-        a(fac.createInvoke("org.ibex.nestedvm.Runtime$ExecutionException","<init>",Type.VOID,new Type[]{Type.STRING},INVOKESPECIAL));
-        a(InstructionConstants.ATHROW);
-        
-        stateCheck.setTarget(a(InstructionConstants.RETURN));
-        
-        tramp.setMaxStack();
-        tramp.setMaxLocals();
-        try {
-            cl.addMethod(tramp.getMethod());
-        } catch(ClassGenException e) {
-            e.printStackTrace(warn);
-            throw new Exn("Generation of the trampoline method failed. Try increasing maxInsnPerMethod");
-        }
+        tramp.add(POP);
+        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,Type.STRINGBUFFER.method("<init>",Type.VOID,new Type[]{Type.STRING}));
+        tramp.add(ALOAD_0);
+        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,Type.STRINGBUFFER.method("append",Type.STRINGBUFFER,new Type[]{Type.STRING}));
+        tramp.add(ALOAD_0);
+        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,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);
         
         addConstReturnMethod("gp",gp.addr);
         addConstReturnMethod("entryPoint",elf.header.entry);
@@ -202,215 +254,137 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
             addConstReturnMethod("userInfoSize",userInfo.size);
         }
         
-        // FEATURE: Allow specification of memory size at runtime (numpages)
-        // Constructor
-        MethodGen init = newMethod(ACC_PUBLIC,Type.VOID, Type.NO_ARGS, "<init>");
-        selectMethod(init);
-        a(InstructionConstants.ALOAD_0);
-        pushConst(pageSize);
-        pushConst(totalPages);
-        a(fac.createInvoke(runtimeClass,"<init>",Type.VOID,new Type[]{Type.INT,Type.INT},INVOKESPECIAL));
-        
-        a(initExtras);
-        
-        a(InstructionConstants.RETURN);
-        
-        init.setMaxLocals();
-        init.setMaxStack();
-        cl.addMethod(init.getMethod());
-        
-        
-        MethodGen clinit = newMethod(ACC_PRIVATE|ACC_STATIC,Type.VOID, Type.NO_ARGS, "<clinit>");
-        selectMethod(clinit);
-        a(clinitExtras);
-        
         if(supportCall) {
-            a(fac.createNew(hashClass));
-            a(InstructionConstants.DUP);
-            a(InstructionConstants.DUP);
-            a(fac.createInvoke(hashClass,"<init>",Type.VOID,Type.NO_ARGS,INVOKESPECIAL));
-            a(fac.createFieldAccess(fullClassName,"symbols",Type.getType("L"+hashClass.replace('.','/')+";"), PUTSTATIC));
-            ELF.Symbol[] symbols = elf.getSymtab().symbols;
-            for(int i=0;i<symbols.length;i++) {
-                ELF.Symbol s = symbols[i];
-                if(s.type == ELF.Symbol.STT_FUNC && s.binding == ELF.Symbol.STB_GLOBAL && (s.name.equals("_call_helper") || !s.name.startsWith("_"))) {
-                    a(InstructionConstants.DUP);
-                    a(new PUSH(cp,s.name));
-                    a(fac.createNew("java.lang.Integer"));
-                    a(InstructionConstants.DUP);
-                    a(new PUSH(cp,s.addr));
-                    a(fac.createInvoke("java.lang.Integer","<init>",Type.VOID,new Type[]{Type.INT},INVOKESPECIAL));
-                    a(fac.createInvoke(hashClass,"put",Type.OBJECT,new Type[]{Type.OBJECT,Type.OBJECT},INVOKEVIRTUAL));
-                    a(InstructionConstants.POP);
-                }
-            }
-            a(InstructionConstants.POP);
+            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,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,Type.INTEGER_OBJECT.method("intValue",Type.INT,Type.NO_ARGS));
+            ls.add(IRETURN);
+            ls.setArg(b,ls.size());
+            ls.add(POP);
+            ls.add(ICONST_M1);
+            ls.add(IRETURN);
         }
         
-        a(InstructionConstants.RETURN);
-        clinit.setMaxLocals();
-        clinit.setMaxStack();
-        cl.addMethod(clinit.getMethod());
+        // 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);
         
-        if(supportCall) {
-            MethodGen lookupSymbol = newMethod(ACC_PROTECTED,Type.INT,new Type[]{Type.STRING},"lookupSymbol");
-            selectMethod(lookupSymbol);
-            a(fac.createFieldAccess(fullClassName,"symbols",Type.getType("L"+hashClass.replace('.','/')+";"), GETSTATIC));
-            a(InstructionConstants.ALOAD_1);
-            a(fac.createInvoke(hashClass,"get",Type.OBJECT,new Type[]{Type.OBJECT},INVOKEVIRTUAL));
-            a(InstructionConstants.DUP);
-            BranchHandle bh = a(InstructionFactory.createBranchInstruction(IFNULL,null));
-            a(fac.createCheckCast(new ObjectType("java.lang.Integer")));
-            a(fac.createInvoke("java.lang.Integer","intValue",Type.INT,Type.NO_ARGS,INVOKEVIRTUAL));
-            a(InstructionConstants.IRETURN);
-            bh.setTarget(a(InstructionConstants.ICONST_M1));
-            a(InstructionConstants.IRETURN);     
-            lookupSymbol.setMaxLocals();
-            lookupSymbol.setMaxStack();
-            cl.addMethod(lookupSymbol.getMethod());
-        }
+        setCPUState.add(ALOAD_1);
+        getCPUState.add(ALOAD_1);
+        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);
         
-        MethodGen setCPUState = newMethod(ACC_PROTECTED,Type.VOID,new Type[]{Type.getType("Lorg/ibex/nestedvm/Runtime$CPUState;")},"setCPUState");
-        selectMethod(setCPUState);
-        a(InstructionConstants.ALOAD_1);
-        a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","r",new ArrayType(Type.INT,1),GETFIELD));
-        a(InstructionConstants.ASTORE_2);
         for(int i=1;i<32;i++) {
-            a(InstructionConstants.ALOAD_0);
-            a(InstructionConstants.ALOAD_2);
-            pushConst(i);
-            a(InstructionConstants.IALOAD);
-            a(fac.createFieldAccess(fullClassName,"r"+i,Type.INT, PUTFIELD));
+            setCPUState.add(ALOAD_0);
+            setCPUState.add(ALOAD_2);
+            setCPUState.add(LDC,i);
+            setCPUState.add(IALOAD);
+            setCPUState.add(PUTFIELD,me.field("r"+i,Type.INT));
+            
+            getCPUState.add(ALOAD_2);
+            getCPUState.add(LDC,i);
+            getCPUState.add(ALOAD_0);
+            getCPUState.add(GETFIELD,me.field("r"+i,Type.INT));
+            getCPUState.add(IASTORE);
         }
-        a(InstructionConstants.ALOAD_1);
-        a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","f",new ArrayType(Type.INT,1),GETFIELD));
-        a(InstructionConstants.ASTORE_2);
-        for(int i=0;i<32;i++) {
-            a(InstructionConstants.ALOAD_0);
-            a(InstructionConstants.ALOAD_2);
-            pushConst(i);
-            a(InstructionConstants.IALOAD);
-            a(fac.createFieldAccess(fullClassName,"f"+i,Type.INT, PUTFIELD));
-        }
-        a(InstructionConstants.ALOAD_0);
-        a(InstructionConstants.ALOAD_1);
-        a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","hi",Type.INT,GETFIELD));
-        a(fac.createFieldAccess(fullClassName,"hi",Type.INT, PUTFIELD));
-        a(InstructionConstants.ALOAD_0);
-        a(InstructionConstants.ALOAD_1);
-        a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","lo",Type.INT,GETFIELD));
-        a(fac.createFieldAccess(fullClassName,"lo",Type.INT, PUTFIELD));
-        a(InstructionConstants.ALOAD_0);
-        a(InstructionConstants.ALOAD_1);
-        a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","fcsr",Type.INT,GETFIELD));
-        a(fac.createFieldAccess(fullClassName,"fcsr",Type.INT, PUTFIELD));
-        a(InstructionConstants.ALOAD_0);
-        a(InstructionConstants.ALOAD_1);
-        a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","pc",Type.INT,GETFIELD));
-        a(fac.createFieldAccess(fullClassName,"pc",Type.INT, PUTFIELD));
-        
-        a(InstructionConstants.RETURN);
-        setCPUState.setMaxLocals();
-        setCPUState.setMaxStack();
-        cl.addMethod(setCPUState.getMethod());
         
-        MethodGen getCPUState = newMethod(ACC_PROTECTED,Type.VOID,new Type[]{Type.getType("Lorg/ibex/nestedvm/Runtime$CPUState;")},"getCPUState");
-        selectMethod(getCPUState);
-        a(InstructionConstants.ALOAD_1);
-        a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","r",new ArrayType(Type.INT,1),GETFIELD));
-        a(InstructionConstants.ASTORE_2);
-        for(int i=1;i<32;i++) {
-            a(InstructionConstants.ALOAD_2);
-            pushConst(i);
-            a(InstructionConstants.ALOAD_0);
-            a(fac.createFieldAccess(fullClassName,"r"+i,Type.INT, GETFIELD));
-            a(InstructionConstants.IASTORE);
-        }
+        setCPUState.add(ALOAD_1);
+        getCPUState.add(ALOAD_1);
+        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);
         
-        a(InstructionConstants.ALOAD_1);
-        a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","f",new ArrayType(Type.INT,1),GETFIELD));
-        a(InstructionConstants.ASTORE_2);
         for(int i=0;i<32;i++) {
-            a(InstructionConstants.ALOAD_2);
-            pushConst(i);
-            a(InstructionConstants.ALOAD_0);
-            a(fac.createFieldAccess(fullClassName,"f"+i,Type.INT, GETFIELD));
-            a(InstructionConstants.IASTORE);
+            setCPUState.add(ALOAD_0);
+            setCPUState.add(ALOAD_2);
+            setCPUState.add(LDC,i);
+            setCPUState.add(IALOAD);
+            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,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);            
         }
-        a(InstructionConstants.ALOAD_1);
-        a(InstructionConstants.ALOAD_0);
-        a(fac.createFieldAccess(fullClassName,"hi",Type.INT, GETFIELD));
-        a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","hi",Type.INT,PUTFIELD));
-        a(InstructionConstants.ALOAD_1);
-        a(InstructionConstants.ALOAD_0);
-        a(fac.createFieldAccess(fullClassName,"lo",Type.INT, GETFIELD));
-        a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","lo",Type.INT,PUTFIELD));
-        a(InstructionConstants.ALOAD_1);
-        a(InstructionConstants.ALOAD_0);
-        a(fac.createFieldAccess(fullClassName,"fcsr",Type.INT, GETFIELD));
-        a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","fcsr",Type.INT,PUTFIELD));
-        a(InstructionConstants.ALOAD_1);
-        a(InstructionConstants.ALOAD_0);
-        a(fac.createFieldAccess(fullClassName,"pc",Type.INT, GETFIELD));
-        a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","pc",Type.INT,PUTFIELD));
         
-        a(InstructionConstants.RETURN);
-        getCPUState.setMaxLocals();
-        getCPUState.setMaxStack();
-        cl.addMethod(getCPUState.getMethod());
-
+        String[] each = new String[] { "hi","lo","fcsr","pc" };
+        for(int i=0;i<each.length;i++) {
+            setCPUState.add(ALOAD_0);
+            setCPUState.add(ALOAD_1);
+            setCPUState.add(GETFIELD,cpuStateType.field(each[i],Type.INT));
+            setCPUState.add(PUTFIELD,me.field(each[i],Type.INT));
 
-        MethodGen execute = newMethod(ACC_PROTECTED,Type.VOID,Type.NO_ARGS,"_execute");
-        selectMethod(execute);
-        InstructionHandle tryStart = a(InstructionConstants.ALOAD_0);
-        InstructionHandle tryEnd = a(fac.createInvoke(fullClassName,"trampoline",Type.VOID,Type.NO_ARGS,INVOKESPECIAL));
-        a(InstructionConstants.RETURN);
-        
-        InstructionHandle catchInsn = a(InstructionConstants.ASTORE_1);
-        a(fac.createNew("org.ibex.nestedvm.Runtime$FaultException"));
-        a(InstructionConstants.DUP);
-        a(InstructionConstants.ALOAD_1);
-        a(fac.createInvoke("org.ibex.nestedvm.Runtime$FaultException","<init>",Type.VOID,new Type[]{new ObjectType("java.lang.RuntimeException")},INVOKESPECIAL));
-        a(InstructionConstants.ATHROW);
+            getCPUState.add(ALOAD_1);
+            getCPUState.add(ALOAD_0);
+            getCPUState.add(GETFIELD,me.field(each[i],Type.INT));
+            getCPUState.add(PUTFIELD,cpuStateType.field(each[i],Type.INT));
+        }
+        setCPUState.add(RETURN);
+        getCPUState.add(RETURN);
         
-        execute.addExceptionHandler(tryStart,tryEnd,catchInsn,new ObjectType("java.lang.RuntimeException"));
-        execute.setMaxLocals();
-        execute.setMaxStack();
-        cl.addMethod(execute.getMethod());
+
+        MethodGen execute = cg.addMethod("_execute",Type.VOID,Type.NO_ARGS,PROTECTED);
+        int tryStart = execute.size();
+        execute.add(ALOAD_0);
+        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, Type.fromClass("org.ibex.nestedvm.Runtime$FaultException"));
+        execute.add(DUP);
+        execute.add(ALOAD_1);
+        // 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);
         
-        MethodGen main = newMethod(ACC_STATIC|ACC_PUBLIC,Type.VOID,new Type[]{new ArrayType(Type.STRING,1)},"main");
-        selectMethod(main);
-        a(fac.createNew(fullClassName));
-        a(InstructionConstants.DUP);
-        a(fac.createInvoke(fullClassName,"<init>",Type.VOID,Type.NO_ARGS,INVOKESPECIAL));
-        a(new PUSH(cp,fullClassName));
-        a(InstructionConstants.ALOAD_0);
-        if(unixRuntime)
-            a(fac.createInvoke("org.ibex.nestedvm.UnixRuntime","runAndExec",Type.INT,
-                    new Type[]{Type.getType("Lorg/ibex/nestedvm/UnixRuntime;"),Type.STRING,new ArrayType(Type.STRING,1)},
-                    INVOKESTATIC));
-        else
-                   a(fac.createInvoke(fullClassName,"run",Type.INT,new Type[]{Type.STRING,new ArrayType(Type.STRING,1)},INVOKEVIRTUAL));
-        a(fac.createInvoke("java.lang.System","exit",Type.VOID,new Type[]{Type.INT},INVOKESTATIC));
-        a(InstructionConstants.RETURN);
-        main.setMaxLocals();
-        main.setMaxStack();
-        cl.addMethod(main.getMethod());
+        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.STRING.makeArray()},STATIC|PUBLIC);
+        main.add(NEW,me);
+        main.add(DUP);
+        main.add(INVOKESPECIAL,me.method("<init>",Type.VOID,Type.NO_ARGS));
+        main.add(LDC,fullClassName);
+        main.add(ALOAD_0);
+        if(unixRuntime) {
+            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 {
+            // 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,Type.fromClass("java.lang.System").method("exit",Type.VOID,new Type[]{Type.INT}));
+        main.add(RETURN);
         
-        if(printStats)
-            System.out.println("Constant Pool Size: " + cp.getSize());
-        cl.getJavaClass().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 method = newMethod(ACC_PROTECTED,Type.INT, Type.NO_ARGS,name);
-        selectMethod(method);
-        pushConst(val);
-        a(InstructionConstants.IRETURN);
-        method.setMaxLocals();
-        method.setMaxStack();
-        cl.addMethod(method.getMethod());
+        MethodGen  m = cg.addMethod(name,Type.INT,Type.NO_ARGS,PROTECTED);
+        m.add(LDC,val);
+        m.add(IRETURN);
     }
         
     private static int initDataCount;
@@ -431,20 +405,19 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
                     sb.append((char) ((l>>>(7*(7-j)))&0x7f));
             }
             String fieldname =  "_data" + (++initDataCount);
-            cl.addField(new FieldGen(ACC_PRIVATE|ACC_STATIC|ACC_FINAL,new ArrayType(Type.INT,1),fieldname,cp).getField());
-            
-            selectList(clinitExtras);
-            a(new PUSH(cp,sb.toString()));
-            a(new PUSH(cp,segSize/4));
-            a(fac.createInvoke("org.ibex.nestedvm.Runtime","decodeData",new ArrayType(Type.INT,1),new Type[]{Type.STRING,Type.INT},INVOKESTATIC));
-            a(fac.createPutStatic(fullClassName,fieldname,new ArrayType(Type.INT,1)));
-
-            selectList(initExtras);
-            a(InstructionConstants.ALOAD_0);
-            a(fac.createGetStatic(fullClassName,fieldname,new ArrayType(Type.INT,1)));
-            a(new PUSH(cp,addr));
-            a(new PUSH(cp,readOnly));
-            a(fac.createInvoke(fullClassName,"initPages",Type.VOID,new Type[]{new ArrayType(Type.INT,1),Type.INT,Type.BOOLEAN},INVOKEVIRTUAL));
+            cg.addField(fieldname,Type.INT.makeArray(),PRIVATE|STATIC|FINAL);
+            
+            clinit.add(LDC,sb.toString());
+            clinit.add(LDC,segSize/4);
+            // 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,me.field(fieldname,Type.INT.makeArray()));
+            init.add(LDC,addr);
+            init.add(LDC,readOnly ? 1 : 0);
+            // 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;
@@ -456,26 +429,29 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
         if((addr&3)!=0) throw new Exn("BSS section on weird boundaries");
         size = (size+3)&~3;
         int count = size/4;
-        selectList(initExtras);
-        a(InstructionConstants.ALOAD_0);
-        a(new PUSH(cp,addr));
-        a(new PUSH(cp,count));
-        a(fac.createInvoke(fullClassName,"clearPages",Type.VOID,new Type[]{Type.INT,Type.INT},INVOKEVIRTUAL));
+        
+        init.add(ALOAD_0);
+        init.add(LDC,addr);
+        init.add(LDC,count);
+        // 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;
-    private int startOfMethod = 0;
-    private int endOfMethod = 0;
-    private boolean unreachable = false;
-    private InstructionHandle[] jumpHandles;
-    private InstructionHandle defaultHandle;
-    private InstructionHandle returnHandle;
-    private InstructionHandle realStart;
-    private MethodGen curMethod;
+    // Method state info
+    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 jumpable(int addr) { return jumpableAddresses.contains(new Integer(addr)); }
+    private MethodGen.PhantomTarget returnTarget; // where to jump when exiting the method
+    private MethodGen.PhantomTarget defaultTarget; // the default switch target (throws exn)
+    private MethodGen.PhantomTarget[] insnTargets; // the targets for each jumpable instruction
+    private MethodGen mg; // the method itself
     
+    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;
@@ -483,187 +459,200 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
         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(jumpHandles[(addr-startOfMethod)/4] != null) {
-                // Move the fake jump target to the current location
-                insnList.move(jumpHandles[(addr-startOfMethod)/4],insnList.getEnd());
+            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();
     }
     
     private void startMethod(int first) {
         startOfMethod = first & methodMask;
         endOfMethod = startOfMethod + maxBytesPerMethod;
-        curMethod = newMethod(ACC_PRIVATE,Type.VOID,Type.NO_ARGS,"run_" + toHex(startOfMethod));
-        selectMethod(curMethod);
+        
+        mg = cg.addMethod("run_" + toHex(startOfMethod),Type.VOID,Type.NO_ARGS,PRIVATE|FINAL);
+        if(onePage) {
+            mg.add(ALOAD_0);
+            mg.add(GETFIELD,me.field("page",Type.INT.makeArray()));
+            mg.add(ASTORE_2);
+        } else {
+            mg.add(ALOAD_0);
+            mg.add(GETFIELD,me.field("readPages",Type.INT.makeArray(2)));
+            mg.add(ASTORE_2);
+            mg.add(ALOAD_0);
+            mg.add(GETFIELD,me.field("writePages",Type.INT.makeArray(2)));
+            mg.add(ASTORE_3);
+        }
+        
+        returnTarget = new MethodGen.PhantomTarget();
+        insnTargets = new MethodGen.PhantomTarget[maxBytesPerMethod/4];
         
         int[] buf = new int[maxBytesPerMethod/4];
-        jumpHandles = new InstructionHandle[maxBytesPerMethod/4];
-        int n=0;
+        Object[] targetBuf = new Object[maxBytesPerMethod/4];
+        int n = 0;
         for(int addr=first;addr<endOfMethod;addr+=4) {
             if(jumpable(addr)) {
-                buf[n++] = addr;
-                // append NOPs for GOTO jumps (these will be moved to the correct location later)
-                jumpHandles[(addr-startOfMethod)/4] = a(InstructionConstants.NOP);
+                targetBuf[n] = insnTargets[(addr-startOfMethod)/4] = new MethodGen.PhantomTarget();
+                buf[n] = addr;
+                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());
         
-        // append NOP for default case (throw exn) (this will be moved later)
-        defaultHandle = a(InstructionConstants.NOP);
-        returnHandle = a(InstructionConstants.NOP);
-        
-        int[] matches = new int[n];
-        System.arraycopy(buf,0,matches,0,n);
-        InstructionHandle[] targets = new InstructionHandle[n];
-        for(int i=0;i<matches.length;i++)
-            targets[i] = jumpHandles[(matches[i]-startOfMethod)/4];
-        
-        
-        // First instruction of the actual method - everything above this should be removed
-        // before we get to the end
-        realStart = a(InstructionConstants.NOP);
-        
-        if(onePage) {
-            a(InstructionConstants.ALOAD_0);
-            a(fac.createFieldAccess(fullClassName,"page",new ArrayType(Type.INT,1), GETFIELD));
-            a(InstructionConstants.ASTORE_2);
-        } else {
-            a(InstructionConstants.ALOAD_0);
-            a(fac.createFieldAccess(fullClassName,"readPages",new ArrayType(Type.INT,2), GETFIELD));
-            a(InstructionConstants.ASTORE_2);
-            a(InstructionConstants.ALOAD_0);
-            a(fac.createFieldAccess(fullClassName,"writePages",new ArrayType(Type.INT,2), GETFIELD));
-            a(InstructionFactory.createStore(Type.OBJECT,3));
-        }
+        fixupRegsStart();
         
-        LOOKUPSWITCH initialSwitch = new LOOKUPSWITCH(matches,targets,defaultHandle);
-        a(InstructionConstants.ALOAD_0);
-        a(fac.createFieldAccess(fullClassName,"pc",Type.INT, GETFIELD));
-        a(initialSwitch);     
+        mg.add(ALOAD_0);
+        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) {
             preSetPC();
-            pushConst(firstAddrOfNext);
+            mg.add(LDC,firstAddrOfNext);
             setPC();
             // mark the start of the next method as jumpable
-            jumpableAddresses.add(new Integer(firstAddrOfNext));
+            jumpableAddresses.put(new Integer(firstAddrOfNext),Boolean.TRUE);
         }
         
-        insnList.move(returnHandle,insnList.getEnd());
-        fixupRegs();
-        a(InstructionConstants.RETURN);
+        returnTarget.setTarget(mg.size());
+        
+        fixupRegsEnd();
+        
+        mg.add(RETURN);
+        
+        defaultTarget.setTarget(mg.size());
         
-        // move the default jump target (lookupswitch) to before the throw
-        insnList.move(defaultHandle,insnList.getEnd());
         if(debugCompiler) {
-            a(fac.createNew("org.ibex.nestedvm.Runtime$ExecutionException"));
-            a(InstructionConstants.DUP);
-            a(fac.createNew("java.lang.StringBuffer"));
-            a(InstructionConstants.DUP);
-            a(new PUSH(cp,"Jumped to invalid address: "));
-            a(fac.createInvoke("java.lang.StringBuffer","<init>",Type.VOID,new Type[]{Type.STRING},INVOKESPECIAL));
-            a(InstructionConstants.ALOAD_0);
-            a(fac.createFieldAccess(fullClassName,"pc",Type.INT, GETFIELD));
-            a(fac.createInvoke("java.lang.StringBuffer","append",Type.STRINGBUFFER,new Type[]{Type.INT},INVOKEVIRTUAL));
-            a(fac.createInvoke("java.lang.StringBuffer","toString",Type.STRING,Type.NO_ARGS,INVOKEVIRTUAL));
-            a(fac.createInvoke("org.ibex.nestedvm.Runtime$ExecutionException","<init>",Type.VOID,new Type[]{Type.STRING},INVOKESPECIAL));
-            a(InstructionConstants.ATHROW);
+            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,Type.STRINGBUFFER.method("<init>",Type.VOID,new Type[]{Type.STRING}));
+            mg.add(ALOAD_0);
+            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 {
-            a(fac.createNew("org.ibex.nestedvm.Runtime$ExecutionException"));
-            a(InstructionConstants.DUP);
-            a(new PUSH(cp,"Jumped to invalid address"));
-            a(fac.createInvoke("org.ibex.nestedvm.Runtime$ExecutionException","<init>",Type.VOID,new Type[]{Type.STRING},INVOKESPECIAL));
-            a(InstructionConstants.ATHROW);
-        }
-
-        if(insnList.getStart() != realStart) {
-            System.err.println(insnList);
-            throw new Error("A jumpHandle wasn't moved into place");
+            mg.add(NEW,Type.fromClass("org.ibex.nestedvm.Runtime$ExecutionException"));
+            mg.add(DUP);
+            mg.add(LDC,"Jumped to invalid address");
+            mg.add(INVOKESPECIAL,Type.fromClass("org.ibex.nestedvm.Runtime$ExecutionException").method("<init>",Type.VOID,new Type[]{Type.STRING}));
+            mg.add(ATHROW);
         }
         
-        curMethod.removeNOPs();
-        curMethod.setMaxLocals();
-        curMethod.setMaxStack();
-        
-        cl.addMethod(curMethod.getMethod());
-        
         endOfMethod = startOfMethod = 0;
     }
 
 
     private void leaveMethod() {
-        a(InstructionFactory.createBranchInstruction(GOTO,returnHandle));
+        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)) {
-            a(InstructionFactory.createBranchInstruction(GOTO,jumpHandles[(target-startOfMethod)/4]));
+            mg.add(GOTO,insnTargets[(target-startOfMethod)/4]);
         } else {
             preSetPC();
-            pushConst(target);
+            mg.add(LDC,target);
             setPC();
             leaveMethod();
         }
     }
     
     // This assumes everything needed by ifInsn is already on the stack
-    private boolean doIfInstruction(short 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
-        BranchHandle h;
-        IfInstruction ifInsn = (IfInstruction) InstructionFactory.createBranchInstruction(op,null);
         if((target&methodMask) == (pc&methodMask)) {
-            h = a(ifInsn);
-            h.setTarget(jumpHandles[(target-startOfMethod)/4]);
+            mg.add(op,insnTargets[(target-startOfMethod)/4]);
         } else {
-            h = a(ifInsn.negate());
+            int h = mg.add(MethodGen.negate(op));
             branch(pc,target);
-            h.setTarget(a(InstructionConstants.NOP));
+            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) {
             // the delay slot is at the start of the next method
-            jumpableAddresses.add(new Integer(pc+8)); // make the 2nd insn of the next method jumpable
+            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
+            //System.err.println("delay slot: " + toHex(pc+8)); */
+            //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
-            h = a(InstructionFactory.createBranchInstruction(GOTO,null));
-            insnList.move(jumpHandles[(pc+4-startOfMethod)/4],insnList.getEnd());
-            emitInstruction(-1,nextInsn,-1); // delay slot
-            h.setTarget(a(InstructionConstants.NOP));
-            return true;
+            
+            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 SKIP_NEXT;
         }
     }
     
-    private boolean emitInstruction(int pc, int insn, int nextInsn) throws Exn {
+    private static final Float POINT_5_F = new Float(0.5f);
+    private static final Double POINT_5_D = new Double(0.5f);
+    private static final Long FFFFFFFF = new Long(0xffffffffL);
+    
+    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 
@@ -674,14 +663,14 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
         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
-        BranchHandle b1,b2;
+        int b1,b2;
         
         switch(op) {
         case 0: {
@@ -690,43 +679,43 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
                 if(insn == 0) break; 
                 preSetReg(R+rd);
                 pushRegWZ(R+rt);
-                pushConst(shamt);
-                a(InstructionConstants.ISHL);
+                mg.add(LDC,shamt);
+                mg.add(ISHL);
                 setReg();
                 break;
             case 2: // SRL
                 preSetReg(R+rd);
                 pushRegWZ(R+rt);
-                pushConst(shamt);
-                a(InstructionConstants.IUSHR);
+                mg.add(LDC,shamt);
+                mg.add(IUSHR);
                 setReg();
                 break;
             case 3: // SRA
                 preSetReg(R+rd);
                 pushRegWZ(R+rt);
-                pushConst(shamt);
-                a(InstructionConstants.ISHR);        
+                mg.add(LDC,shamt);
+                mg.add(ISHR);
                 setReg();
                 break;
             case 4: // SLLV
                 preSetReg(R+rd);
                 pushRegWZ(R+rt);
                 pushRegWZ(R+rs);
-                a(InstructionConstants.ISHL);
+                mg.add(ISHL);
                 setReg();
                 break;
             case 6: // SRLV
                 preSetReg(R+rd);
                 pushRegWZ(R+rt);
                 pushRegWZ(R+rs);
-                a(InstructionConstants.IUSHR);
+                mg.add(IUSHR);
                 setReg();
                 break;
             case 7: // SRAV
                 preSetReg(R+rd);
                 pushRegWZ(R+rt);
                 pushRegWZ(R+rs);
-                a(InstructionConstants.ISHR);
+                mg.add(ISHR);
                 setReg();
                 break;
             case 8: // JR
@@ -736,56 +725,56 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
                 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);
-                pushConst(pc+8);
-                setReg();
                 leaveMethod();
-                unreachable = true;
+                ret |= UNREACHABLE;
                 break;
             case 12: // SYSCALL
                 preSetPC();
-                pushConst(pc);
+                mg.add(LDC,pc);
                 setPC();
                 
+                // FEATURE: This is actually broken, but it happens to work for our code
+                // a func could theoretically jump back to here from a future point
                 restoreChangedRegs();
                 
                 preSetReg(R+V0);
-                a(InstructionConstants.ALOAD_0);
+                mg.add(ALOAD_0);
                 pushRegZ(R+V0);
                 pushRegZ(R+A0);
                 pushRegZ(R+A1);
                 pushRegZ(R+A2);
                 pushRegZ(R+A3);
-                a(fac.createInvoke(fullClassName,"syscall",Type.INT,new Type[]{Type.INT,Type.INT,Type.INT,Type.INT,Type.INT},INVOKEVIRTUAL));
+                pushRegZ(R+T0);
+                pushRegZ(R+T1);
+                // 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();
                 
-                a(InstructionConstants.ALOAD_0);
-                a(fac.createFieldAccess(fullClassName,"state",Type.INT, GETFIELD));
-                pushConst(Runtime.RUNNING);
-                b1 = a(InstructionFactory.createBranchInstruction(IF_ICMPEQ,null));
+                mg.add(ALOAD_0);
+                mg.add(GETFIELD,me.field("state",Type.INT));
+                b1 = mg.add(IFEQ);
                 preSetPC();
-                pushConst(pc+4);
+                mg.add(LDC,pc+4);
                 setPC();
                 leaveMethod();
-                b1.setTarget(a(InstructionConstants.NOP));
-                
+                mg.setArg(b1,mg.size());
                 break;
             case 13: // BREAK
-                a(fac.createNew("org.ibex.nestedvm.Runtime$ExecutionException"));
-                a(InstructionConstants.DUP);
-                a(new PUSH(cp,"BREAK Code " + toHex(breakCode)));
-                a(fac.createInvoke("org.ibex.nestedvm.Runtime$ExecutionException","<init>",Type.VOID,new Type[]{Type.STRING},INVOKESPECIAL));
-                a(InstructionConstants.ATHROW);
-                unreachable = true;
+                mg.add(NEW,Type.fromClass("org.ibex.nestedvm.Runtime$ExecutionException"));
+                mg.add(DUP);
+                mg.add(LDC,"BREAK Code " + toHex(breakCode));
+                mg.add(INVOKESPECIAL,Type.fromClass("org.ibex.nestedvm.Runtime$ExecutionException").method("<init>",Type.VOID,new Type[]{Type.STRING}));
+                mg.add(ATHROW);
+                ret |= UNREACHABLE;
                 break;
             case 16: // MFHI
                 preSetReg(R+rd);
@@ -809,108 +798,108 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
                 break;
             case 24: // MULT
                 pushRegWZ(R+rs);
-                a(InstructionConstants.I2L);
+                mg.add(I2L);
                 pushRegWZ(R+rt);
-                a(InstructionConstants.I2L);
-                a(InstructionConstants.LMUL);
-                a(InstructionConstants.DUP2);
+                mg.add(I2L);
+                mg.add(LMUL);
+                mg.add(DUP2);
                 
-                a(InstructionConstants.L2I);
+                mg.add(L2I);
                 if(preSetReg(LO))
-                    a(InstructionConstants.SWAP);
+                    mg.add(SWAP); //a(InstructionConstants.SWAP);
                 setReg();
                 
-                pushConst(32);
-                a(InstructionConstants.LUSHR);
-                a(InstructionConstants.L2I);
+                mg.add(LDC,32);
+                mg.add(LUSHR);
+                mg.add(L2I);
                 if(preSetReg(HI))
-                    a(InstructionConstants.SWAP);
+                    mg.add(SWAP); //a(InstructionConstants.SWAP);
                 setReg();
                 
                 break;
             case 25: // MULTU
                 pushRegWZ(R+rs);
-                a(InstructionConstants.I2L);
-                pushConst(0xffffffffL);
-                a(InstructionConstants.LAND);
+                mg.add(I2L);
+                mg.add(LDC,FFFFFFFF);
+                mg.add(LAND);
                 pushRegWZ(R+rt);
-                a(InstructionConstants.I2L);
-                pushConst(0xffffffffL);
-                a(InstructionConstants.LAND);
-                a(InstructionConstants.LMUL);
-                a(InstructionConstants.DUP2);
+                mg.add(I2L);
+                mg.add(LDC,FFFFFFFF);
+                mg.add(LAND);
+                mg.add(LMUL);
+                mg.add(DUP2);
                 
-                a(InstructionConstants.L2I);
+                mg.add(L2I);
                 if(preSetReg(LO))
-                    a(InstructionConstants.SWAP);
+                    mg.add(SWAP);
                 setReg();
                 
-                pushConst(32);
-                a(InstructionConstants.LUSHR);
-                a(InstructionConstants.L2I);
+                mg.add(LDC,32);
+                mg.add(LUSHR);
+                mg.add(L2I);
                 if(preSetReg(HI))
-                    a(InstructionConstants.SWAP);
+                    mg.add(SWAP);
                 setReg();
                 
                 break;
             case 26: // DIV
                 pushRegWZ(R+rs);
                 pushRegWZ(R+rt);
-                a(InstructionConstants.DUP2);
+                mg.add(DUP2);
                 
-                a(InstructionConstants.IDIV);
+                mg.add(IDIV);
                 if(preSetReg(LO))
-                    a(InstructionConstants.SWAP);
+                    mg.add(SWAP);
                 setReg();
                 
-                a(InstructionConstants.IREM);
+                mg.add(IREM);
                 if(preSetReg(HI))
-                    a(InstructionConstants.SWAP);
+                    mg.add(SWAP);
                 setReg();
                 
                 break;
             case 27: { // DIVU
                 pushRegWZ(R+rt);
-                a(InstructionConstants.DUP);
+                mg.add(DUP);
                 setTmp();
-                b1 = a(InstructionFactory.createBranchInstruction(IFEQ,null));
+                b1 = mg.add(IFEQ);
                 
                 pushRegWZ(R+rs);
-                a(InstructionConstants.I2L);
-                pushConst(0xffffffffL);
-                a(InstructionConstants.LAND);
-                a(InstructionConstants.DUP2);
+                mg.add(I2L);
+                mg.add(LDC,FFFFFFFF);
+                mg.add(LAND);
+                mg.add(DUP2);
                 pushTmp();
-                a(InstructionConstants.I2L);
-                pushConst(0xffffffffL);
+                mg.add(I2L);
+                mg.add(LDC,FFFFFFFF);
                 
-                a(InstructionConstants.LAND);
-                a(InstructionConstants.DUP2_X2);
-                a(InstructionConstants.LDIV);
+                mg.add(LAND);
+                mg.add(DUP2_X2);
+                mg.add(LDIV);
                 
-                a(InstructionConstants.L2I);
+                mg.add(L2I);
                 if(preSetReg(LO))
-                    a(InstructionConstants.SWAP);
+                    mg.add(SWAP);
                 setReg();
                 
-                a(InstructionConstants.LREM);
-                a(InstructionConstants.L2I);
+                mg.add(LREM);
+                mg.add(L2I);
                 if(preSetReg(HI))
-                    a(InstructionConstants.SWAP);
+                    mg.add(SWAP);
                 setReg();
                 
-                b1.setTarget(a(InstructionConstants.NOP));
+                mg.setArg(b1,mg.size());
                 
                 break;
             }
             case 32: // ADD
                 throw new Exn("ADD (add with oveflow trap) not suported");
             case 33: // ADDU
-                   preSetReg(R+rd);
+                preSetReg(R+rd);
                 if(rt != 0 && rs != 0) {
                     pushReg(R+rs);
                     pushReg(R+rt);
-                    a(InstructionConstants.IADD);
+                    mg.add(IADD);
                 } else if(rs != 0) {
                     pushReg(R+rs);
                 } else {
@@ -925,10 +914,10 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
                 if(rt != 0 && rs != 0) {
                     pushReg(R+rs);
                     pushReg(R+rt);
-                    a(InstructionConstants.ISUB);
+                    mg.add(ISUB);
                 } else if(rt != 0) {
                     pushReg(R+rt);
-                    a(InstructionConstants.INEG);
+                    mg.add(INEG);
                 } else {
                     pushRegZ(R+rs);
                 }
@@ -938,21 +927,21 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
                 preSetReg(R+rd);
                 pushRegWZ(R+rs);
                 pushRegWZ(R+rt);
-                a(InstructionConstants.IAND);
+                mg.add(IAND);
                 setReg();
                 break;
             case 37: // OR
                 preSetReg(R+rd);
                 pushRegWZ(R+rs);
                 pushRegWZ(R+rt);
-                a(InstructionConstants.IOR);
+                mg.add(IOR);
                 setReg();
                 break;
             case 38: // XOR
                 preSetReg(R+rd);
                 pushRegWZ(R+rs);
                 pushRegWZ(R+rt);
-                a(InstructionConstants.IXOR);
+                mg.add(IXOR);
                 setReg();
                 break;
             case 39: // NOR
@@ -961,16 +950,16 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
                     if(rs != 0 && rt != 0) {
                         pushReg(R+rs);
                         pushReg(R+rt);
-                        a(InstructionConstants.IOR);
+                        mg.add(IOR);
                     } else if(rs != 0) {
                         pushReg(R+rs);
                     } else {
                         pushReg(R+rt);
                     }
-                    a(InstructionConstants.ICONST_M1);
-                    a(InstructionConstants.IXOR);
+                    mg.add(ICONST_M1);
+                    mg.add(IXOR);
                 } else {
-                    pushConst(-1);
+                    mg.add(LDC,-1);
                 }
                 setReg();
                 break;
@@ -979,13 +968,13 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
                 if(rs != rt) {
                     pushRegZ(R+rs);
                     pushRegZ(R+rt);
-                    b1 = a(InstructionFactory.createBranchInstruction(IF_ICMPLT,null));
-                    a(InstructionConstants.ICONST_0);
-                    b2 = a(InstructionFactory.createBranchInstruction(GOTO,null));
-                    b1.setTarget(a(InstructionConstants.ICONST_1));
-                    b2.setTarget(a(InstructionConstants.NOP));
+                    b1 = mg.add(IF_ICMPLT);
+                    mg.add(ICONST_0);
+                    b2 = mg.add(GOTO);
+                    mg.setArg(b1,mg.add(ICONST_1));
+                    mg.setArg(b2,mg.size());
                 } else {
-                    pushConst(0);
+                    mg.add(LDC,0);
                 }
                 setReg();
                 break;
@@ -994,30 +983,30 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
                 if(rs != rt) {
                     if(rs != 0) {
                         pushReg(R+rs);
-                        a(InstructionConstants.I2L);
-                        pushConst(0xffffffffL);
-                        a(InstructionConstants.LAND);
+                        mg.add(I2L);
+                        mg.add(LDC,FFFFFFFF);
+                        mg.add(LAND);
                         pushReg(R+rt);
-                        a(InstructionConstants.I2L);
-                        pushConst(0xffffffffL);
-                        a(InstructionConstants.LAND);
-                        a(InstructionConstants.LCMP);
-                        b1 = a(InstructionFactory.createBranchInstruction(IFLT,null));
+                        mg.add(I2L);
+                        mg.add(LDC,FFFFFFFF);
+                        mg.add(LAND);
+                        mg.add(LCMP);
+                        b1 = mg.add(IFLT);
                     } else {
                         pushReg(R+rt);
-                        b1 = a(InstructionFactory.createBranchInstruction(IFNE,null));
+                        b1 = mg.add(IFNE);
                     }
-                    a(InstructionConstants.ICONST_0);
-                    b2 = a(InstructionFactory.createBranchInstruction(GOTO,null));
-                    b1.setTarget(a(InstructionConstants.ICONST_1));
-                    b2.setTarget(a(InstructionConstants.NOP));
+                    mg.add(ICONST_0);
+                    b2 = mg.add(GOTO);
+                    mg.setArg(b1,mg.add(ICONST_1));
+                    mg.setArg(b2,mg.size());
                 } else {
-                    pushConst(0);
+                    mg.add(LDC,0);
                 }
                 setReg();
                 break;
             default:
-                throw new RuntimeException("Illegal instruction 0/" + subcode);
+                throw new Exn("Illegal instruction 0/" + subcode);
             }
             break;
         }
@@ -1034,31 +1023,27 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
             case 16: // BLTZAL
                 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
                 pushRegWZ(R+rs);
-                b1 = a(InstructionFactory.createBranchInstruction(IFGE,null));
+                b1 = mg.add(IFGE);
                 emitInstruction(-1,nextInsn,-1);
-                preSetReg(R+RA);
-                pushConst(pc+8);
-                setReg();
+                link(pc);
                 branch(pc,pc+branchTarget*4+4);
-                b1.setTarget(a(InstructionConstants.NOP));
+                mg.setArg(b1,mg.size());
                 break;
             case 17: // BGEZAL
                 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
-                b1 = null;
+                b1 = -1;
                 if(rs != 0) { // r0 is always >= 0
                     pushRegWZ(R+rs);
-                    b1 = a(InstructionFactory.createBranchInstruction(IFLT,null));
+                    b1 = mg.add(IFLT);
                 }
                 emitInstruction(-1,nextInsn,-1);
-                preSetReg(R+RA);
-                pushConst(pc+8);
-                setReg();
+                link(pc);
                 branch(pc,pc+branchTarget*4+4);
-                if(b1 != null) b1.setTarget(a(InstructionConstants.NOP));
-                if(b1 == null) unreachable = true;
+                if(b1 != -1) mg.setArg(b1,mg.size());
+                if(b1 == -1) ret |= UNREACHABLE;
                 break;
             default:
-                throw new RuntimeException("Illegal Instruction 1/" + rt);
+                throw new Exn("Illegal Instruction 1/" + rt);
             }
             break;
         }
@@ -1066,18 +1051,16 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
             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);
-            pushConst(pc+8);
-            setReg();
+            link(pc);
             branch(pc, target);
-            unreachable = true;
+            ret |= UNREACHABLE;
             break;
         }
         case 4: // BEQ
@@ -1085,7 +1068,7 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
             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);
@@ -1115,68 +1098,74 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
         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);
             pushRegWZ(R+rs);
-            pushConst(signedImmediate);
-            b1 = a(InstructionFactory.createBranchInstruction(IF_ICMPLT,null));
-            a(InstructionConstants.ICONST_0);
-            b2 = a(InstructionFactory.createBranchInstruction(GOTO,null));
-            b1.setTarget(a(InstructionConstants.ICONST_1));
-            b2.setTarget(a(InstructionConstants.NOP));
+            mg.add(LDC,signedImmediate);
+            b1 = mg.add(IF_ICMPLT);
+            mg.add(ICONST_0);
+            b2 = mg.add(GOTO);
+            mg.setArg(b1,mg.add(ICONST_1));
+            mg.setArg(b2,mg.size());
             setReg();
             break;
         case 11: // SLTIU
             preSetReg(R+rt);
             pushRegWZ(R+rs);
-            a(InstructionConstants.I2L);
-            pushConst(0xffffffffL);
-            a(InstructionConstants.LAND);
-            pushConst((long)unsignedImmediate);
-            a(InstructionConstants.LCMP);
-            
-            b1 = a(InstructionFactory.createBranchInstruction(IFLT,null));
-            a(InstructionConstants.ICONST_0);
-            b2 = a(InstructionFactory.createBranchInstruction(GOTO,null));
-            b1.setTarget(a(InstructionConstants.ICONST_1));
-            b2.setTarget(a(InstructionConstants.NOP));
-            
+            mg.add(I2L);
+            mg.add(LDC,FFFFFFFF);
+            mg.add(LAND);
+            // Yes, this is correct, you have to sign extend the immediate then do an UNSIGNED comparison
+            mg.add(LDC,new Long(signedImmediate&0xffffffffL));
+            mg.add(LCMP);
+            
+            b1 = mg.add(IFLT);
+            mg.add(ICONST_0);
+            b2 = mg.add(GOTO);
+            mg.setArg(b1,mg.add(ICONST_1));
+            mg.setArg(b2,mg.size());            
             setReg();
             break;            
         case 12: // ANDI
             preSetReg(R+rt);
             pushRegWZ(R+rs);
-            pushConst(unsignedImmediate);
-            a(InstructionConstants.IAND);
+            mg.add(LDC,unsignedImmediate);
+            mg.add(IAND);
             setReg();
             break;
         case 13: // ORI
             preSetReg(R+rt);
             if(rs != 0 && unsignedImmediate != 0) {
                 pushReg(R+rs);
-                pushConst(unsignedImmediate);
-                a(InstructionConstants.IOR);
+                mg.add(LDC,unsignedImmediate);
+                mg.add(IOR);
             } else if(rs != 0){
                 pushReg(R+rs);
             } else {
-                pushConst(unsignedImmediate);
+                mg.add(LDC,unsignedImmediate);
             }
             setReg();
             break;
         case 14: // XORI
             preSetReg(R+rt);
             pushRegWZ(R+rs);
-            pushConst(unsignedImmediate);
-            a(InstructionConstants.IXOR);
+            mg.add(LDC,unsignedImmediate);
+            mg.add(IXOR);
             setReg();
             break;
         case 15: // LUI
             preSetReg(R+rt);
-            pushConst(unsignedImmediate << 16);
+            mg.add(LDC,unsignedImmediate << 16);
             setReg();
             break;
         case 16:
@@ -1196,10 +1185,8 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
                 break;
             case 4: // MTC.1
                 preSetReg(F+rd);
-                if(rt != 0)
-                    pushReg(R+rt);
-                else
-                    pushConst(0);
+                if(rt != 0) pushReg(R+rt);
+                else mg.add(ICONST_0);
                 setReg();
                 break;
             case 6: // CTC.1
@@ -1210,8 +1197,8 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
                 break;
             case 8: {// BC1F, BC1T
                 pushReg(FCSR);
-                pushConst(0x800000);
-                a(InstructionConstants.IAND);
+                mg.add(LDC,0x800000);
+                mg.add(IAND);
                 return doIfInstruction(((insn>>>16)&1) == 0 ? IFEQ : IFNE,pc,pc+branchTarget*4+4,nextInsn);
             }
             case 16:
@@ -1223,28 +1210,28 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
                     preSetDouble(F+fd,d);
                     pushDouble(F+fs,d);
                     pushDouble(F+ft,d);
-                    a(d ? InstructionConstants.DADD : InstructionConstants.FADD);
+                    mg.add(d ? DADD : FADD);
                     setDouble(d);
                     break;
                 case 1: // SUB.X
                     preSetDouble(F+fd,d);
                     pushDouble(F+fs,d);
                     pushDouble(F+ft,d);
-                    a(d ? InstructionConstants.DSUB : InstructionConstants.FSUB);
-                    setDouble(d);                    
+                    mg.add(d ? DSUB : FSUB);
+                    setDouble(d);
                     break;
                 case 2: // MUL.X
                     preSetDouble(F+fd,d);
                     pushDouble(F+fs,d);
                     pushDouble(F+ft,d);
-                    a(d ? InstructionConstants.DMUL : InstructionConstants.FMUL);
+                    mg.add(d ? DMUL : FMUL);
                     setDouble(d);                    
                     break;
                 case 3: // DIV.X
                     preSetDouble(F+fd,d);
                     pushDouble(F+fs,d);
                     pushDouble(F+ft,d);
-                    a(d ? InstructionConstants.DDIV : InstructionConstants.FDIV);
+                    mg.add(d ? DDIV : FDIV);
                     setDouble(d);                    
                     break;
                 case 5: // ABS.X
@@ -1252,89 +1239,88 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
                     // NOTE: We can't use fneg/dneg here since they'll turn +0.0 into -0.0
                     
                     pushDouble(F+fs,d);
-                    a(d ? InstructionConstants.DUP2 : InstructionConstants.DUP);
-                    a(d ? InstructionConstants.DCONST_0 : InstructionConstants.FCONST_0);
-                    a(d ? InstructionConstants.DCMPG : InstructionConstants.FCMPG);
+                    mg.add(d ? DUP2 : DUP);
+                    mg.add(d ? DCONST_0 : FCONST_0);
+                    mg.add(d ? DCMPG : FCMPG);
                     
-                    b1 = a(InstructionFactory.createBranchInstruction(IFGT,null));
-                    a(d ? InstructionConstants.DCONST_0 : InstructionConstants.FCONST_0);
+                    b1 = mg.add(IFGT);
+                    mg.add(d ? DCONST_0 : FCONST_0);
                     if(d) {
-                        a(InstructionConstants.DUP2_X2);
-                        a(InstructionConstants.POP2);
+                        mg.add(DUP2_X2);
+                        mg.add(POP2);
                     } else {
-                        a(InstructionConstants.POP);
+                        mg.add(SWAP);
                     }
-                    a(InstructionConstants.DSUB);
+                    mg.add(d ? DSUB : FSUB);
                     
-                    b1.setTarget(setDouble(d));
+                    mg.setArg(b1,mg.size());
+                    setDouble(d);
                     
                     break;
                 case 6: // MOV.X
                     preSetReg(F+fd);
                     pushReg(F+fs);
                     setReg();
-                    
-                    preSetReg(F+fd+1);
-                    pushReg(F+fs+1);
-                    setReg();
-                    
+                
+                    if(d) {
+                        preSetReg(F+fd+1);
+                        pushReg(F+fs+1);
+                        setReg();
+                    }
                     break;
                 case 7: // NEG.X
                     preSetDouble(F+fd,d);
                     pushDouble(F+fs,d);
-                    a(d ? InstructionConstants.DNEG : InstructionConstants.FNEG);
-                    setDouble(d);                    
+                    mg.add(d ? DNEG : FNEG);
+                    setDouble(d);
                     break;
                 case 32: // CVT.S.X
                     preSetFloat(F+fd);
-                    pushDouble(F+fd,d);
-                    if(d) a(InstructionConstants.D2F);
+                    pushDouble(F+fs,d);
+                    if(d) mg.add(D2F);
                     setFloat();
                     break;
                 case 33: // CVT.D.X
                     preSetDouble(F+fd);
-                    pushDouble(F+fd,d);
-                    if(!d) a(InstructionConstants.F2D);
+                    pushDouble(F+fs,d);
+                    if(!d) mg.add(F2D);
                     setDouble();
                     break;
                 case 36: { // CVT.W.D
-                    int[] matches = new int[4];
-                    for(int i=0;i<4;i++) matches[i] = i;
-                    
-                    TABLESWITCH ts = new  TABLESWITCH(matches,new InstructionHandle[4], null);
-                    
+                    MethodGen.Switch.Table tsi = new MethodGen.Switch.Table(0,3);
                     preSetReg(F+fd);
                     pushDouble(F+fs,d);
                     pushReg(FCSR);
-                    a(InstructionConstants.ICONST_3);
-                    a(InstructionConstants.IAND);
-                    a(ts);
+                    mg.add(ICONST_3);
+                    mg.add(IAND);
+                    mg.add(TABLESWITCH,tsi);
                     
                     // Round towards plus infinity
-                    ts.setTarget(2,a(InstructionConstants.NOP));
-                    if(!d) a(InstructionConstants.F2D); // Ugh.. java.lang.Math doesn't have a float ceil/floor
-                    a(fac.createInvoke("java.lang.Math","ceil",Type.DOUBLE,new Type[]{Type.DOUBLE},INVOKESTATIC));
-                    if(!d) a(InstructionConstants.D2F);
-                    b1 = a(InstructionFactory.createBranchInstruction(GOTO,null));
+                    tsi.setTarget(2,mg.size());
+                    if(!d) mg.add(F2D); // Ugh.. java.lang.Math doesn't have a float ceil/floor
+                    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);
                     
                     // Round to nearest
-                    ts.setTarget(0,d ? pushConst(0.5d) : pushConst(0.5f));
-                    a(d ? InstructionConstants.DADD : InstructionConstants.FADD);
+                    tsi.setTarget(0,mg.size());
+                    mg.add(LDC,d ? (Object)POINT_5_D : (Object)POINT_5_F);
+                    mg.add(d ? DADD : FADD);
                     // fall through
                     
                     // Round towards minus infinity
-                    ts.setTarget(3,a(InstructionConstants.NOP));
-                    if(!d) a(InstructionConstants.F2D);
-                    a(fac.createInvoke("java.lang.Math","floor",Type.DOUBLE,new Type[]{Type.DOUBLE},INVOKESTATIC));
-                    if(!d) a(InstructionConstants.D2F);
+                    tsi.setTarget(3,mg.size());
+                    if(!d) mg.add(F2D);
+                    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());
+                    tsi.setDefaultTarget(mg.size());
+                    mg.setArg(b1,mg.size());
                     
-                    InstructionHandle h = a(d ? InstructionConstants.D2I : InstructionConstants.F2I);
+                    mg.add(d ? D2I : F2I);
                     setReg();
                     
-                    ts.setTarget(1,h);
-                    ts.setTarget(h);
-                    b1.setTarget(h);
-                                        
                     break;
                 }
                 case 50: // C.EQ.D
@@ -1342,22 +1328,20 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
                 case 62: // C.LE.D
                     preSetReg(FCSR);
                     pushReg(FCSR);
-                    pushConst(~0x800000);
-                    a(InstructionConstants.IAND);
+                    mg.add(LDC,~0x800000);
+                    mg.add(IAND);
                     pushDouble(F+fs,d);
                     pushDouble(F+ft,d);
-                    a(d ? InstructionConstants.DCMPG : InstructionConstants.FCMPG);
+                    mg.add(d ? DCMPG : FCMPG);
                     switch(subcode) {
-                        case 50: b1 = a(InstructionFactory.createBranchInstruction(IFEQ,null)); break;
-                        case 60: b1 = a(InstructionFactory.createBranchInstruction(IFLT,null)); break;
-                        case 62: b1 = a(InstructionFactory.createBranchInstruction(IFLE,null)); break;
-                        default: b1 = null;
+                        case 50: b1 = mg.add(IFNE); break;
+                        case 60: b1 = mg.add(IFGE); break;
+                        case 62: b1 = mg.add(IFGT); break;
+                        default: b1 = -1;
                     }
-                    
-                    pushConst(0x000000);
-                    b2 = a(InstructionFactory.createBranchInstruction(GOTO,null));
-                    b1.setTarget(pushConst(0x800000));
-                    b2.setTarget(a(InstructionConstants.IOR));
+                    mg.add(LDC,0x800000);
+                    mg.add(IOR);
+                    mg.setArg(b1,mg.size());
                     setReg();
                     break;
                 default: throw new Exn("Invalid Instruction 17/" + rs + "/" + subcode);
@@ -1369,13 +1353,13 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
                 case 32: // CVT.S.W
                     preSetFloat(F+fd);
                     pushReg(F+fs);
-                    a(InstructionConstants.I2F);
+                    mg.add(I2F);
                     setFloat();
                     break;
                 case 33: // CVT.D.W
                     preSetDouble(F+fd);
                     pushReg(F+fs);
-                    a(InstructionConstants.I2D);
+                    mg.add(I2D);
                     setDouble();
                     break;
                 default: throw new Exn("Invalid Instruction 17/" + rs + "/" + subcode);
@@ -1398,14 +1382,14 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
             memRead(true);
             pushTmp();
             
-            a(InstructionConstants.ICONST_M1);
-            a(InstructionConstants.IXOR);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.IAND);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.IUSHR);
-            a(InstructionConstants.I2B);
+            mg.add(ICONST_M1);
+            mg.add(IXOR);
+            mg.add(ICONST_3);
+            mg.add(IAND);
+            mg.add(ICONST_3);
+            mg.add(ISHL);
+            mg.add(IUSHR);
+            mg.add(I2B);
             setReg();
             break; 
         }
@@ -1418,14 +1402,14 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
             memRead(true);
             pushTmp();
             
-            a(InstructionConstants.ICONST_M1);
-            a(InstructionConstants.IXOR);
-            a(InstructionConstants.ICONST_2);
-            a(InstructionConstants.IAND);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.IUSHR);
-            a(InstructionConstants.I2S);
+            mg.add(ICONST_M1);
+            mg.add(IXOR);
+            mg.add(ICONST_2);
+            mg.add(IAND);
+            mg.add(ICONST_3);
+            mg.add(ISHL);
+            mg.add(IUSHR);
+            mg.add(I2S);
             setReg();            
             break; 
         }
@@ -1435,29 +1419,29 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
             setTmp(); // addr
             
             pushRegWZ(R+rt);
-            pushConst(0x00ffffff);
+            mg.add(LDC,0x00ffffff);
             pushTmp();
             
-            a(InstructionConstants.ICONST_M1);
-            a(InstructionConstants.IXOR);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.IAND);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.IUSHR);
-            a(InstructionConstants.IAND);
+            mg.add(ICONST_M1);
+            mg.add(IXOR);
+            mg.add(ICONST_3);
+            mg.add(IAND);
+            mg.add(ICONST_3);
+            mg.add(ISHL);
+            mg.add(IUSHR);
+            mg.add(IAND);
             
             preMemRead();
             pushTmp();
             memRead(true);
             pushTmp();
             
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.IAND);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.IOR);
+            mg.add(ICONST_3);
+            mg.add(IAND);
+            mg.add(ICONST_3);
+            mg.add(ISHL);
+            mg.add(ISHL);
+            mg.add(IOR);
             
             setReg();
             
@@ -1478,15 +1462,15 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
             memRead(true);
             pushTmp();
             
-            a(InstructionConstants.ICONST_M1);
-            a(InstructionConstants.IXOR);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.IAND);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.IUSHR);
-            pushConst(0xff);
-            a(InstructionConstants.IAND);
+            mg.add(ICONST_M1);
+            mg.add(IXOR);
+            mg.add(ICONST_3);
+            mg.add(IAND);
+            mg.add(ICONST_3);
+            mg.add(ISHL);
+            mg.add(IUSHR);
+            mg.add(LDC,0xff);
+            mg.add(IAND);
             setReg();
             break; 
         }
@@ -1499,16 +1483,16 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
             memRead(true);
             pushTmp();
             
-            a(InstructionConstants.ICONST_M1);
-            a(InstructionConstants.IXOR);
-            a(InstructionConstants.ICONST_2);
-            a(InstructionConstants.IAND);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.IUSHR);
+            mg.add(ICONST_M1);
+            mg.add(IXOR);
+            mg.add(ICONST_2);
+            mg.add(IAND);
+            mg.add(ICONST_3);
+            mg.add(ISHL);
+            mg.add(IUSHR);
             
             // chars are unsigend so this works
-            a(InstructionConstants.I2C);
+            mg.add(I2C);
             setReg();
             break; 
         }
@@ -1518,29 +1502,29 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
             setTmp(); // addr
             
             pushRegWZ(R+rt);
-            pushConst(0xffffff00);
+            mg.add(LDC,0xffffff00);
             pushTmp();
             
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.IAND);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.IAND);
+            mg.add(ICONST_3);
+            mg.add(IAND);
+            mg.add(ICONST_3);
+            mg.add(ISHL);
+            mg.add(ISHL);
+            mg.add(IAND);
             
             preMemRead();
             pushTmp();
             memRead(true);
             pushTmp();
             
-            a(InstructionConstants.ICONST_M1);
-            a(InstructionConstants.IXOR);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.IAND);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.IUSHR);
-            a(InstructionConstants.IOR);
+            mg.add(ICONST_M1);
+            mg.add(IXOR);
+            mg.add(ICONST_3);
+            mg.add(IAND);
+            mg.add(ICONST_3);
+            mg.add(ISHL);
+            mg.add(IUSHR);
+            mg.add(IOR);
             
             
             setReg();
@@ -1550,125 +1534,113 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
             addiu(R+rs,signedImmediate);
             setTmp(); // addr
             
-            // FEATURE: DO the preMemRead(true) thing for the rest of the S* instructions
             preMemRead(true);
             pushTmp();
             memRead(true);
             
-            pushConst(0xff000000);
+            mg.add(LDC,0xff000000);
             pushTmp();
             
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.IAND);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.IUSHR);
-            a(InstructionConstants.ICONST_M1);
-            a(InstructionConstants.IXOR);
-            a(InstructionConstants.IAND);
+            mg.add(ICONST_3);
+            mg.add(IAND);
+            mg.add(ICONST_3);
+            mg.add(ISHL);
+            mg.add(IUSHR);
+            mg.add(ICONST_M1);
+            mg.add(IXOR);
+            mg.add(IAND);
             
             if(rt != 0) {
                 pushReg(R+rt);
-                pushConst(0xff);
-                a(InstructionConstants.IAND);
+                mg.add(LDC,0xff);
+                mg.add(IAND);
             } else {
-                pushConst(0);
+                mg.add(LDC,0);
             }
             pushTmp();
             
-            a(InstructionConstants.ICONST_M1);
-            a(InstructionConstants.IXOR);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.IAND);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.IOR);
+            mg.add(ICONST_M1);
+            mg.add(IXOR);
+            mg.add(ICONST_3);
+            mg.add(IAND);
+            mg.add(ICONST_3);
+            mg.add(ISHL);
+            mg.add(ISHL);
+            mg.add(IOR);
             
             memWrite();
             
             break;
         }
         case 41: { // SH    
-            preMemWrite1();
-            
             addiu(R+rs,signedImmediate);
+            setTmp();
             
-            a(InstructionConstants.DUP);
-            setTmp(); // addr
-            
-            preMemWrite2(true);
-            
-            preMemRead();
+            preMemRead(true);
             pushTmp();
             memRead(true);
-            
-            pushConst(0xffff);
+                       
+            mg.add(LDC,0xffff);
             pushTmp();
             
-            a(InstructionConstants.ICONST_2);
-            a(InstructionConstants.IAND);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.IAND);
+            mg.add(ICONST_2);
+            mg.add(IAND);
+            mg.add(ICONST_3);
+            mg.add(ISHL);
+            mg.add(ISHL);
+            mg.add(IAND);
             
             if(rt != 0) {
                 pushReg(R+rt);
-                pushConst(0xffff);
-                a(InstructionConstants.IAND);
+                mg.add(LDC,0xffff);
+                mg.add(IAND);
             } else {
-                pushConst(0);
+                mg.add(LDC,0);
             }
             pushTmp();
             
-            a(InstructionConstants.ICONST_M1);
-            a(InstructionConstants.IXOR);
-            a(InstructionConstants.ICONST_2);
-            a(InstructionConstants.IAND);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.IOR);
+            mg.add(ICONST_M1);
+            mg.add(IXOR);
+            mg.add(ICONST_2);
+            mg.add(IAND);
+            mg.add(ICONST_3);
+            mg.add(ISHL);
+            mg.add(ISHL);
+            mg.add(IOR);
             
             memWrite();
             
             break;            
         }
         case 42: { // SWL
-            preMemWrite1();
-            
             addiu(R+rs,signedImmediate);
-            a(InstructionConstants.DUP);
-            setTmp(); // addr
-
-            preMemWrite2(true);
+            setTmp();
             
-            preMemRead();
+            preMemRead(true);            
             pushTmp();
             memRead(true);
             
-            pushConst(0xffffff00);
+            mg.add(LDC,0xffffff00);
             pushTmp();
             
-            a(InstructionConstants.ICONST_M1);
-            a(InstructionConstants.IXOR);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.IAND);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.IAND);
+            mg.add(ICONST_M1);
+            mg.add(IXOR);
+            mg.add(ICONST_3);
+            mg.add(IAND);
+            mg.add(ICONST_3);
+            mg.add(ISHL);
+            mg.add(ISHL);
+            mg.add(IAND);
             
             pushRegWZ(R+rt);
             pushTmp();
             
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.IAND);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.IUSHR);
-            a(InstructionConstants.IOR);
+            mg.add(ICONST_3);
+            mg.add(IAND);
+            mg.add(ICONST_3);
+            mg.add(ISHL);
+            mg.add(IUSHR);
+            mg.add(IOR);
             
             memWrite();
             break;
@@ -1681,39 +1653,34 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
             memWrite();
             break;
         case 46: { // SWR
-            preMemWrite1();
-            
             addiu(R+rs,signedImmediate);
-            a(InstructionConstants.DUP);
-            setTmp(); // addr
-            
-            preMemWrite2(true);
+            setTmp();
             
-            preMemRead();
+            preMemRead(true);
             pushTmp();
             memRead(true);
             
-            pushConst(0x00ffffff);
+            mg.add(LDC,0x00ffffff);
             pushTmp();
             
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.IAND);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.IUSHR);
-            a(InstructionConstants.IAND);
+            mg.add(ICONST_3);
+            mg.add(IAND);
+            mg.add(ICONST_3);
+            mg.add(ISHL);
+            mg.add(IUSHR);
+            mg.add(IAND);
             
             pushRegWZ(R+rt);
             pushTmp();
             
-            a(InstructionConstants.ICONST_M1);
-            a(InstructionConstants.IXOR);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.IAND);
-            a(InstructionConstants.ICONST_3);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.ISHL);
-            a(InstructionConstants.IOR);
+            mg.add(ICONST_M1);
+            mg.add(IXOR);
+            mg.add(ICONST_3);
+            mg.add(IAND);
+            mg.add(ICONST_3);
+            mg.add(ISHL);
+            mg.add(ISHL);
+            mg.add(IOR);
                     
             memWrite();
             break;
@@ -1732,7 +1699,7 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
             break;
         
         /* This needs to fail (set rt to 0) if the memory location was modified
-         * between the LL and SC if we every support threads.
+         * between the LL and SC if we ever support threads.
          */
         case 56: // SWC0/SC
             preSetReg(R+rt);
@@ -1740,7 +1707,7 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
             preMemWrite2(R+rs,signedImmediate);
             pushReg(R+rt);
             memWrite();
-            pushConst(1);
+            mg.add(LDC,1);
             setReg();
             break;
             
@@ -1753,7 +1720,7 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
         default:
             throw new Exn("Invalid Instruction: " + op + " at " + toHex(pc));
         }
-        return false; 
+        return ret; 
     }
     
     // Helper functions for emitText
@@ -1764,69 +1731,74 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
     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 boolean doLocal(int reg) {
+        return reg == R+2 || reg == R+3 || reg == R+4 || reg == R+29;
+    }
     
     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 fixupRegs() {
-        InstructionHandle prev = realStart;
+    private void fixupRegsStart() {
         for(int i=0;i<REG_COUNT;i++) {
-            if(regLocalMapping[i] == 0) continue; 
-            
-            prev = insnList.append(prev,InstructionConstants.ALOAD_0);
-            prev = insnList.append(prev,fac.createFieldAccess(fullClassName,regField(i),Type.INT, GETFIELD));
-            prev = insnList.append(prev,InstructionFactory.createStore(Type.INT,regLocalMapping[i]));
-            
-            if(regLocalWriteCount[i] > 0) {
-                a(InstructionConstants.ALOAD_0);
-                a(InstructionFactory.createLoad(Type.INT,regLocalMapping[i]));
-                a(fac.createFieldAccess(fullClassName,regField(i),Type.INT, PUTFIELD));
-            }
-            
-            regLocalMapping[i] = regLocalReadCount[i] = regLocalWriteCount[i] = 0;
+            regLocalMapping[i] = 0;
+            regLocalWritten[i] = false;
         }
-        nextAvailLocal = 0;
+        nextAvailLocal = onePage ? 4 : 5;
+        loadsStart = mg.size();
+        for(int i=0;i<MAX_LOCALS*LOAD_LENGTH;i++)
+            mg.add(NOP);
     }
     
-    private void restoreChangedRegs() {
+    private void fixupRegsEnd() {
+        int p = loadsStart;
         for(int i=0;i<REG_COUNT;i++) {
-            if(regLocalWriteCount[i] > 0) {
-                a(InstructionConstants.ALOAD_0);
-                a(InstructionFactory.createLoad(Type.INT,regLocalMapping[i]));
-                a(fac.createFieldAccess(fullClassName,regField(i),Type.INT, PUTFIELD));                
+            if(regLocalMapping[i] == 0) continue;
+            mg.set(p++,ALOAD_0);
+            mg.set(p++,GETFIELD,me.field(regField[i],Type.INT));
+            mg.set(p++,ISTORE,regLocalMapping[i]);
+            
+            if(regLocalWritten[i]) {
+                mg.add(ALOAD_0);
+                mg.add(ILOAD,regLocalMapping[i]);
+                mg.add(PUTFIELD,me.field(regField[i],Type.INT));
             }
         }
     }
-    
-    private String regField(int reg) {
-        String field;
-        switch(reg) {
-            case HI: field = "hi"; break;
-            case LO: field = "lo"; break;
-            case FCSR: field = "fcsr"; break;
-            default:
-                if(reg > R && reg < R+32) field="r"+(reg-R);
-                else if(reg >= F && reg < F+32) field="f"+(reg-F);
-                else throw new IllegalArgumentException(""+reg);
+        
+    private void restoreChangedRegs() {
+        for(int i=0;i<REG_COUNT;i++) {
+            if(regLocalWritten[i]) {
+                mg.add(ALOAD_0);
+                mg.add(ILOAD,regLocalMapping[i]);
+                mg.add(PUTFIELD,me.field(regField[i],Type.INT));
+            }
         }
-        return field;
-    }
-    
-    private boolean doLocal(int reg) {
-        //return false;
-        return reg == R+2 || reg == R+3 || reg == R+4 || reg == R+29;
     }
-    
-    private InstructionHandle pushRegWZ(int reg) {
+            
+    private int pushRegWZ(int reg) {
         if(reg == R+0) {
             warn.println("Warning: Pushing r0!");
             new Exception().printStackTrace(warn);
@@ -1834,20 +1806,23 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
         return pushRegZ(reg);
     }
     
-    private InstructionHandle pushRegZ(int reg) {
-        if(reg == R+0) return pushConst(0);
+    private int pushRegZ(int reg) {
+        if(reg == R+0) return mg.add(ICONST_0);
         else return pushReg(reg);
     }
     
     
-    private InstructionHandle pushReg(int reg) {
-        InstructionHandle h;
+    private int pushReg(int reg) {
+        int h = mg.size();
         if(doLocal(reg)) {
-            regLocalReadCount[reg]++;
-            h = a(InstructionFactory.createLoad(Type.INT,getLocalForReg(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 {
-            h = a(InstructionConstants.ALOAD_0);
-            a(fac.createFieldAccess(fullClassName,regField(reg),Type.INT, GETFIELD));
+            mg.add(ALOAD_0);
+            mg.add(GETFIELD,me.field(regField[reg],Type.INT));
         }
         return h;
     }
@@ -1857,55 +1832,62 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
     
     // 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)) {
             return false;
         } else {
-            a(InstructionConstants.ALOAD_0);
+            mg.add(ALOAD_0);
             return true;
         }
     }
     
-    private InstructionHandle setReg() {
+    private int setReg() {
         if(preSetRegStackPos==0) throw new RuntimeException("didn't do preSetReg");
         preSetRegStackPos--;
         int reg = preSetRegStack[preSetRegStackPos];
-        InstructionHandle h;
+        int h = mg.size();
         if(doLocal(reg)) {
-            h = a(InstructionFactory.createStore(Type.INT,getLocalForReg(reg)));
-            regLocalWriteCount[reg]++;
+            mg.add(ISTORE,getLocalForReg(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 {
-            h = a(fac.createFieldAccess(fullClassName,regField(reg),Type.INT, PUTFIELD));
+            mg.add(PUTFIELD,me.field(regField[reg],Type.INT));
         }
         return h;
     }
     
-    private InstructionHandle preSetPC() { return a(InstructionConstants.ALOAD_0); }
-    private InstructionHandle setPC() { return a(fac.createFieldAccess(fullClassName,"pc",Type.INT, PUTFIELD)); }
+    private int preSetPC() { return mg.add(ALOAD_0); }
+    private int setPC() {
+        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 InstructionHandle pushDouble(int reg, boolean d) throws Exn {
+    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);
-        InstructionHandle h;
+        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");
-            h = pushReg(reg+1);
-            a(InstructionConstants.I2L);
-            pushConst(32);
-            a(InstructionConstants.LSHL);
+            pushReg(reg+1);
+            mg.add(I2L);
+            mg.add(LDC,32);
+            mg.add(LSHL);
             pushReg(reg);
-            a(InstructionConstants.I2L);
-            pushConst(0xffffffffL);
-            a(InstructionConstants.LAND);
-            a(InstructionConstants.LOR);
-            //p("invokestatic java/lang/Double/longBitsToDouble(J)D");
-            a(fac.createInvoke("java.lang.Double","longBitsToDouble",Type.DOUBLE,new Type[]{Type.LONG},INVOKESTATIC));
+            mg.add(I2L);
+            mg.add(LDC,FFFFFFFF);
+            mg.add(LAND);
+            mg.add(LOR);
+            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 {
-            h = pushReg(reg);
-            a(fac.createInvoke("java.lang.Float","intBitsToFloat",Type.FLOAT,new Type[]{Type.INT},INVOKESTATIC));
+            pushReg(reg);
+            mg.add(INVOKESTATIC,Type.fromClass("java.lang.Float").method("intBitsToFloat",Type.FLOAT,new Type[]{Type.INT}));
         }
         return h;
     }
@@ -1914,70 +1896,49 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
     private void preSetDouble(int reg) { preSetDouble(reg,true); }
     private void preSetDouble(int reg, boolean d) { preSetReg(reg); }
     
-    private InstructionHandle setFloat() throws Exn { return setDouble(false); }
-    private InstructionHandle setDouble() throws Exn { return setDouble(true); }
-    private InstructionHandle setDouble(boolean d) throws Exn {
+    private int setFloat() throws Exn { return setDouble(false); }
+    private int setDouble() throws Exn { return setDouble(true); }
+    private int setDouble(boolean d) throws Exn {
         int reg = preSetRegStack[preSetRegStackPos-1];
         if(reg < F || reg >= F+32) throw new IllegalArgumentException(""+reg);
-        //p("invokestatic java/lang/Double/doubleToLongBits(D)J");
-        InstructionHandle h;
+        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");
-            h = a(fac.createInvoke("java.lang.Double","doubleToLongBits",Type.LONG,new Type[]{Type.DOUBLE},INVOKESTATIC));
-            a(InstructionConstants.DUP2);
-            pushConst(32);
-            a(InstructionConstants.LUSHR);
-            a(InstructionConstants.L2I);
+            mg.add(INVOKESTATIC,Type.DOUBLE_OBJECT.method("doubleToLongBits",Type.LONG,new Type[]{Type.DOUBLE}));
+            mg.add(DUP2);
+            mg.add(LDC,32);
+            mg.add(LUSHR);
+            mg.add(L2I);
             if(preSetReg(reg+1))
-                a(InstructionConstants.SWAP);
+                mg.add(SWAP);
             setReg();
-            a(InstructionConstants.L2I);
+            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));
+            //h = a(fac.createInvoke("java.lang.Float","floatToRawIntBits",Type.INT,new Type[]{Type.FLOAT},INVOKESTATIC));
+            mg.add(INVOKESTATIC,Type.FLOAT_OBJECT.method("floatToRawIntBits",Type.INT,new Type[]{Type.FLOAT}));
             setReg();   
         }
         return h;
     }
-        
-    private InstructionHandle pushConst(int n) {
-        if(n >= 0 && n <= 5) {
-            switch(n) {
-                case 0: return a(InstructionConstants.ICONST_0);
-                case 1: return a(InstructionConstants.ICONST_1);
-                case 2: return a(InstructionConstants.ICONST_2);
-                case 3: return a(InstructionConstants.ICONST_3);
-                case 4: return a(InstructionConstants.ICONST_4);
-                case 5: return a(InstructionConstants.ICONST_5);
-                default: return null;
-            }
-        } else if(n == -1) {
-            return a(InstructionConstants.ICONST_M1);
-        } else if(n >= -128 && n <= 127) {
-            return a(new BIPUSH((byte) n));
-        } else if(n >= -32768 && n <= 32767) {
-            return a(new SIPUSH((short) n));
-        } else {
-            return a(new PUSH(cp,n));
-        }
-    }
-    
-    private InstructionHandle pushConst(long l) { return a(new PUSH(cp,l)); }
-    private InstructionHandle pushConst(float f) { return a(new PUSH(cp,f)); }
-    private InstructionHandle pushConst(double d) { return a(new PUSH(cp,d)); }
     
-    private void pushTmp() { a(InstructionConstants.ILOAD_1); }
-    private void setTmp() { a(InstructionConstants.ISTORE_1); }
+    private void pushTmp() { mg.add(ILOAD_1); }
+    private void setTmp() { mg.add(ISTORE_1); }
     
     private void addiu(int reg, int offset) {
         if(reg != R+0 && offset != 0) {
             pushReg(reg);
-            pushConst(offset);
-            a(InstructionConstants.IADD);
+            mg.add(LDC,offset);
+            mg.add(IADD);
         } else if(reg != R+0) {
             pushReg(reg);
         } else {
-            pushConst(offset);
+            mg.add(LDC,offset);
         }        
     }
     private int memWriteStage;
@@ -1985,11 +1946,11 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
         if(memWriteStage!=0) throw new Error("pending preMemWrite1/2");
         memWriteStage=1;
         if(onePage)
-            a(InstructionConstants.ALOAD_2);
+            mg.add(ALOAD_2);
         else if(fastMem)
-            a(InstructionFactory.createLoad(Type.OBJECT,3));
+            mg.add(ALOAD,3);
         else
-            a(InstructionConstants.ALOAD_0);
+            mg.add(ALOAD_0);
     }
     
     private void preMemWrite2(int reg, int offset) {
@@ -2003,29 +1964,30 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
         memWriteStage=2;
         
         if(nullPointerCheck) {
-            a(InstructionConstants.DUP);
-            a(InstructionConstants.ALOAD_0);
-            a(InstructionConstants.SWAP);
-            a(fac.createInvoke(fullClassName,"nullPointerCheck",Type.VOID,new Type[]{Type.INT},INVOKEVIRTUAL));
+            mg.add(DUP);
+            mg.add(ALOAD_0);
+            mg.add(SWAP);
+            // 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) {
-            a(InstructionConstants.ICONST_2);
-            a(InstructionConstants.IUSHR);
+            mg.add(ICONST_2);
+            mg.add(IUSHR);
         } else if(fastMem) {
             if(!addrInTmp)
-                a(InstructionConstants.DUP_X1);
-            pushConst(pageShift);
-            a(InstructionConstants.IUSHR);
-            a(InstructionConstants.AALOAD);
+                mg.add(DUP_X1);
+            mg.add(LDC,pageShift);
+            mg.add(IUSHR);
+            mg.add(AALOAD);
             if(addrInTmp)
                 pushTmp();
             else
-                a(InstructionConstants.SWAP);
-            a(InstructionConstants.ICONST_2);
-            a(InstructionConstants.IUSHR);
-            pushConst((pageSize>>2)-1);
-            a(InstructionConstants.IAND);            
+                mg.add(SWAP);
+            mg.add(ICONST_2);
+            mg.add(IUSHR);
+            mg.add(LDC,(pageSize>>2)-1);
+            mg.add(IAND);            
         }
     }
     
@@ -2035,11 +1997,12 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
         memWriteStage=0;
                 
         if(onePage) {
-            a(InstructionConstants.IASTORE);
+            mg.add(IASTORE);
         } else if(fastMem) {
-            a(InstructionConstants.IASTORE);
+            mg.add(IASTORE);
         } else {
-            a(fac.createInvoke(fullClassName,"unsafeMemWrite",Type.VOID,new Type[]{Type.INT,Type.INT},INVOKEVIRTUAL));
+            // 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}));
         }
         
     }
@@ -2060,11 +2023,11 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
         didPreMemRead = true;
         preMemReadDoPreWrite = preWrite;
         if(onePage)
-            a(InstructionConstants.ALOAD_2);
+            mg.add(ALOAD_2);
         else if(fastMem)
-            a(InstructionFactory.createLoad(Type.OBJECT,preWrite ? 3 : 2));
+            mg.add(ALOAD,preWrite ? 3 : 2);
         else
-            a(InstructionConstants.ALOAD_0);
+            mg.add(ALOAD_0);
     }
     // memRead pops an address off the stack, reads the value at that addr, and pushed the value
     // preMemRead MUST be called BEFORE the addresses is pushed
@@ -2077,43 +2040,41 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const
             memWriteStage=2; 
             
         if(nullPointerCheck) {
-            a(InstructionConstants.DUP);
-            a(InstructionConstants.ALOAD_0);
-            a(InstructionConstants.SWAP);
-            a(fac.createInvoke(fullClassName,"nullPointerCheck",Type.VOID,new Type[]{Type.INT},INVOKEVIRTUAL));
+            mg.add(DUP);
+            mg.add(ALOAD_0);
+            mg.add(SWAP);
+            mg.add(INVOKEVIRTUAL,me.method("nullPointerCheck",Type.VOID,new Type[]{Type.INT}));
         }
         
         if(onePage) {
-            // p(target + "= page[(" + addr + ")>>>2];");
-            a(InstructionConstants.ICONST_2);
-            a(InstructionConstants.IUSHR);
+            mg.add(ICONST_2);
+            mg.add(IUSHR);
             if(preMemReadDoPreWrite)
-                a(InstructionConstants.DUP2);
-            a(InstructionConstants.IALOAD);
+                mg.add(DUP2);
+            mg.add(IALOAD);
         } else if(fastMem) {
-            //p(target  + " = readPages[("+addr+")>>>"+pageShift+"][(("+addr+")>>>2)&"+toHex((pageSize>>2)-1)+"];");
-            
             if(!addrInTmp)
-                a(InstructionConstants.DUP_X1);
-            pushConst(pageShift);
-            a(InstructionConstants.IUSHR);
-            a(InstructionConstants.AALOAD);
+                mg.add(DUP_X1);
+            mg.add(LDC,pageShift);
+            mg.add(IUSHR);
+            mg.add(AALOAD);
             if(addrInTmp)
                 pushTmp();
             else
-                a(InstructionConstants.SWAP);
-            a(InstructionConstants.ICONST_2);
-            a(InstructionConstants.IUSHR);
-            pushConst((pageSize>>2)-1);
-            a(InstructionConstants.IAND);
+                mg.add(SWAP);
+            mg.add(ICONST_2);
+            mg.add(IUSHR);
+            mg.add(LDC,(pageSize>>2)-1);
+            mg.add(IAND);
             if(preMemReadDoPreWrite)
-                a(InstructionConstants.DUP2);
-            a(InstructionConstants.IALOAD);
+                mg.add(DUP2);
+            mg.add(IALOAD);
             
         } else {
             if(preMemReadDoPreWrite)
-                a(InstructionConstants.DUP2);
-            a(fac.createInvoke(fullClassName,"unsafeMemWrite",Type.INT,new Type[]{Type.INT},INVOKEVIRTUAL));
+                mg.add(DUP2);
+            // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.unsafeMemRead
+            mg.add(INVOKEVIRTUAL,me.method("unsafeMemRead",Type.INT,new Type[]{Type.INT}));
         }
     }