gcclass hints (YOU NEED TO UPDATE upstream/build/gcclass)
[nestedvm.git] / src / org / ibex / nestedvm / ClassFileCompiler.java
1 package org.ibex.nestedvm;
2
3 import java.io.*;
4
5 import org.ibex.nestedvm.util.*;
6 import org.ibex.classgen.*;
7
8 // FEATURE: Eliminate unnecessary use of SWAP
9 // FEATURE: Put regs in low (<=3) local vars, small classfile size
10
11 /* FEATURE: Span large binaries across several classfiles
12  * We should be able to do this with no performance penalty
13  * Every method in the inner classes is static and takes the main class as an arg
14  * This makes them look just like methods in the main class because arg1 gets loaded into
15  * local register 0
16  */
17
18 /* FEATURE: smarter with local regs
19  * Be even smarter with the use of local registers. We need to only load fields into
20  * local regs when they are actually used and only write to fields if the regs could have
21  * changed. This should allow us to put more regs in local vars. Right now putting all used 
22  * regs local vars makes code like this slower.
23  * 
24  * void work(int a, int b) {
25  *    if(a == b) {
26  *       fast path
27  *       return;
28  *    }
29  *    real work
30  * }
31  * Because all the regs used in "real work" are loaded/restored even for fast path
32  */
33
34
35 public class ClassFileCompiler extends Compiler implements CGConst  {
36     private static final boolean OPTIMIZE_CP = true;
37     
38     /** The stream to write the compiled output to */
39     private OutputStream os;
40     private File outDir;
41     private PrintStream warn = System.err;
42
43     private final Type.Object me;
44     
45     private ClassGen cg;
46     private MethodGen clinit, init;
47     
48     public ClassFileCompiler(String path, String className, OutputStream os) throws IOException { this(new Seekable.File(path),className,os); }
49     public ClassFileCompiler(Seekable binary, String className, OutputStream os) throws IOException {
50         this(binary,className);
51         if(os == null) throw new NullPointerException();
52         this.os = os;
53     }
54     public ClassFileCompiler(Seekable binary, String className, File outDir) throws IOException {
55         this(binary,className);
56         if(outDir == null) throw new NullPointerException();
57         this.outDir = outDir;
58     }
59     private ClassFileCompiler(Seekable binary, String className) throws IOException {
60         super(binary,className);
61         me = new Type.Object(fullClassName);
62     }
63     
64     public void setWarnWriter(PrintStream warn) { this.warn = warn; }
65         
66     protected void _go() throws Exn, IOException {
67         try {
68             __go();
69         } catch(ClassGen.Exn e) {
70             e.printStackTrace(warn);
71             throw new Exn("Class generation exception: " + e.toString());
72         }
73     }
74         
75     private void __go() throws Exn, IOException {
76         if(!pruneCases) throw new Exn("-o prunecases MUST be enabled for ClassFileCompiler");
77
78         // Class
79         Type.Object superClass = new Type.Object(runtimeClass);
80         cg = new ClassGen(me,superClass,ACC_PUBLIC|ACC_FINAL|ACC_SUPER);
81         if(source != null) cg.setSourceFile(source);
82         
83         // Fields
84         cg.addField("pc",Type.INT,ACC_PRIVATE);
85         cg.addField("hi",Type.INT,ACC_PRIVATE);
86         cg.addField("lo",Type.INT,ACC_PRIVATE);
87         cg.addField("fcsr",Type.INT,ACC_PRIVATE);
88         for(int i=1;i<32;i++) cg.addField("r" + i,Type.INT,ACC_PRIVATE);
89         for(int i=0;i<32;i++) cg.addField("f" + i,singleFloat ? Type.FLOAT : Type.INT,ACC_PRIVATE);
90
91         // <clinit>
92         clinit = cg.addMethod("<clinit>",Type.VOID,Type.NO_ARGS,ACC_PRIVATE|ACC_STATIC);
93
94         // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.UnixRuntime.<init>
95
96         // <init>
97         init = cg.addMethod("<init>",Type.VOID,Type.NO_ARGS,ACC_PUBLIC);        
98         init.add(ALOAD_0);
99         init.add(LDC,pageSize);
100         init.add(LDC,totalPages);
101         init.add(INVOKESPECIAL,new MethodRef(me,"<init>",Type.VOID,new Type[]{Type.INT,Type.INT}));
102         init.add(RETURN);
103
104         // <init>(Z)
105         init = cg.addMethod("<init>",Type.VOID,new Type[]{Type.BOOLEAN},ACC_PUBLIC);        
106         init.add(ALOAD_0);
107         init.add(LDC,pageSize);
108         init.add(LDC,totalPages);
109         init.add(ILOAD_1);
110         init.add(INVOKESPECIAL,new MethodRef(me,"<init>",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN}));
111         init.add(RETURN);
112         
113         // <init>(II)
114         init = cg.addMethod("<init>",Type.VOID,new Type[]{Type.INT,Type.INT},ACC_PUBLIC);
115         init.add(ALOAD_0);
116         init.add(ILOAD_1);
117         init.add(ILOAD_2);
118         init.add(ICONST_0);
119         init.add(INVOKESPECIAL,new MethodRef(me,"<init>",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN}));
120         init.add(RETURN);
121         
122         // <init>(IIZ)
123         init = cg.addMethod("<init>",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN},ACC_PUBLIC);
124         init.add(ALOAD_0);
125         init.add(ILOAD_1);
126         init.add(ILOAD_2);
127         init.add(ILOAD_3);
128         init.add(INVOKESPECIAL,new MethodRef(superClass,"<init>",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN}));
129         
130         if(onePage) {
131             cg.addField("page",Type.arrayType(Type.INT),ACC_PRIVATE|ACC_FINAL);
132             init.add(ALOAD_0);
133             init.add(DUP);
134             init.add(GETFIELD,new FieldRef(me,"readPages",Type.arrayType(Type.INT,2)));
135             init.add(LDC,0);
136             init.add(AALOAD);
137             init.add(PUTFIELD,new FieldRef(me,"page",Type.arrayType(Type.INT)));
138         }
139         
140         if(supportCall)
141             cg.addField("symbols",new Type.Object(hashClass),ACC_PRIVATE|ACC_STATIC|ACC_FINAL);
142         
143         int highestAddr = 0;
144         
145         for(int i=0;i<elf.sheaders.length;i++) {
146             ELF.SHeader sheader = elf.sheaders[i];
147             String name = sheader.name;
148             // if this section doesn't get loaded into our address space don't worry about it
149             if(sheader.addr == 0x0) continue;
150             
151             highestAddr = Math.max(highestAddr, sheader.addr + sheader.size);
152             
153             if(name.equals(".text"))
154                 emitText(sheader.addr, new DataInputStream(sheader.getInputStream()),sheader.size);
155             else if(name.equals(".data") || name.equals(".sdata") || name.equals(".rodata") || name.equals(".ctors") || name.equals(".dtors"))
156                 emitData(sheader.addr, new DataInputStream(sheader.getInputStream()), sheader.size,name.equals(".rodata")); 
157             else if(name.equals(".bss") || name.equals(".sbss"))                
158                 emitBSS(sheader.addr,sheader.size);
159             else
160                 throw new Exn("Unknown segment: " + name);
161         }
162         
163         // Finish init
164         init.add(RETURN);
165         
166         // Finish clinit
167         if(supportCall) {
168             Type.Object hash = new Type.Object(hashClass);
169             clinit.add(NEW,hash);
170             clinit.add(DUP);
171             clinit.add(DUP);
172             clinit.add(INVOKESPECIAL,new MethodRef(hash,"<init>",Type.VOID,Type.NO_ARGS));
173             clinit.add(PUTSTATIC,new FieldRef(me,"symbols",hash));
174             ELF.Symbol[] symbols = elf.getSymtab().symbols;
175             for(int i=0;i<symbols.length;i++) {
176                 ELF.Symbol s = symbols[i];
177                 if(s.type == ELF.Symbol.STT_FUNC && s.binding == ELF.Symbol.STB_GLOBAL && (s.name.equals("_call_helper") || !s.name.startsWith("_"))) {
178                     clinit.add(DUP);
179                     clinit.add(LDC,s.name);
180                     clinit.add(NEW,Type.INTEGER_OBJECT);
181                     clinit.add(DUP);
182                     clinit.add(LDC,s.addr);
183                     clinit.add(INVOKESPECIAL,new MethodRef(Type.INTEGER_OBJECT,"<init>",Type.VOID,new Type[]{Type.INT}));
184                     clinit.add(INVOKEVIRTUAL,new MethodRef(hash,"put",Type.OBJECT,new Type[]{Type.OBJECT,Type.OBJECT}));
185                     clinit.add(POP);
186                 }
187             }
188             clinit.add(POP);
189         }
190         
191         clinit.add(RETURN);
192         
193         ELF.SHeader text = elf.sectionWithName(".text");
194         
195         // Trampoline
196         MethodGen tramp = cg.addMethod("trampoline",Type.VOID,Type.NO_ARGS,ACC_PRIVATE);
197         
198         int start = tramp.size();
199         tramp.add(ALOAD_0);
200         tramp.add(GETFIELD,new FieldRef(me,"state",Type.INT));
201         tramp.add(IFEQ,tramp.size()+2);
202         tramp.add(RETURN);
203         
204         tramp.add(ALOAD_0);
205         tramp.add(ALOAD_0);
206         tramp.add(GETFIELD,new FieldRef(me,"pc",Type.INT));
207         tramp.add(LDC,methodShift);
208         tramp.add(IUSHR);
209         
210         int beg = text.addr >>> methodShift;
211         int end = ((text.addr + text.size + maxBytesPerMethod - 1) >>> methodShift);
212
213         MethodGen.TSI tsi = new MethodGen.TSI(beg,end-1);
214         tramp.add(TABLESWITCH,tsi);
215         for(int n=beg;n<end;n++) {
216             tsi.setTargetForVal(n,tramp.size());
217             tramp.add(INVOKESPECIAL,new MethodRef(me,"run_"+toHex(n<<methodShift),Type.VOID,Type.NO_ARGS));
218             tramp.add(GOTO,start);
219         }
220         tsi.setDefaultTarget(tramp.size());
221         
222         tramp.add(POP);
223         tramp.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
224         tramp.add(DUP);
225         tramp.add(NEW, Type.STRINGBUFFER);
226         tramp.add(DUP);
227         tramp.add(LDC,"Jumped to invalid address in trampoline (r2: ");
228         tramp.add(INVOKESPECIAL,new MethodRef(Type.STRINGBUFFER,"<init>",Type.VOID,new Type[]{Type.STRING}));
229         tramp.add(ALOAD_0);
230         tramp.add(GETFIELD, new FieldRef(me,"r2",Type.INT));
231         tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.INT}));
232         tramp.add(LDC," pc: ");
233         tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.STRING}));
234         tramp.add(ALOAD_0);
235         tramp.add(GETFIELD, new FieldRef(me,"pc",Type.INT));        
236         tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.INT}));
237         tramp.add(LDC,")");
238         tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.STRING}));
239         tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"toString",Type.STRING,Type.NO_ARGS));
240         // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime$ExecutionException.<init>
241         tramp.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"<init>",Type.VOID,new Type[]{Type.STRING}));
242         tramp.add(ATHROW);
243                 
244         
245         if(false) {
246         try {
247             tramp.finish();
248         } catch(ClassGen.Exn e) {
249             e.printStackTrace(warn);
250             throw new Exn("Generation of the trampoline method failed. Try increasing maxInsnPerMethod");
251         }
252         }
253         
254         addConstReturnMethod("gp",gp.addr);
255         addConstReturnMethod("entryPoint",elf.header.entry);
256         addConstReturnMethod("heapStart",highestAddr);
257                 
258         if(userInfo != null) {
259             addConstReturnMethod("userInfoBase",userInfo.addr);
260             addConstReturnMethod("userInfoSize",userInfo.size);
261         }
262         
263         if(supportCall) {
264             Type.Object hashClassType = new Type.Object(hashClass);
265             MethodGen ls = cg.addMethod("lookupSymbol",Type.INT,new Type[]{Type.STRING},ACC_PROTECTED);
266             ls.add(GETSTATIC,new FieldRef(me,"symbols",hashClassType));
267             ls.add(ALOAD_1);
268             ls.add(INVOKEVIRTUAL,new MethodRef(hashClassType,"get",Type.OBJECT,new Type[]{Type.OBJECT}));
269             ls.add(DUP);
270             int b = ls.add(IFNULL);
271             ls.add(CHECKCAST,Type.INTEGER_OBJECT);
272             ls.add(INVOKEVIRTUAL,new MethodRef(Type.INTEGER_OBJECT,"intValue",Type.INT,Type.NO_ARGS));
273             ls.add(IRETURN);
274             ls.setArg(b,ls.size());
275             ls.add(POP);
276             ls.add(ICONST_M1);
277             ls.add(IRETURN);
278         }
279         
280         // Kind of a hack, referencing dup() gets us all the fields for free
281         // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime$CPUState.dup
282         Type.Object cpuStateType = new Type.Object("org.ibex.nestedvm.Runtime$CPUState");
283         MethodGen setCPUState = cg.addMethod("setCPUState",Type.VOID,new Type[]{cpuStateType},ACC_PROTECTED);
284         MethodGen getCPUState = cg.addMethod("getCPUState",Type.VOID,new Type[]{cpuStateType},ACC_PROTECTED);
285         
286         setCPUState.add(ALOAD_1);
287         getCPUState.add(ALOAD_1);
288         setCPUState.add(GETFIELD,new FieldRef(cpuStateType,"r",Type.arrayType(Type.INT)));
289         getCPUState.add(GETFIELD,new FieldRef(cpuStateType,"r",Type.arrayType(Type.INT)));
290         setCPUState.add(ASTORE_2);
291         getCPUState.add(ASTORE_2);
292         
293         for(int i=1;i<32;i++) {
294             setCPUState.add(ALOAD_0);
295             setCPUState.add(ALOAD_2);
296             setCPUState.add(LDC,i);
297             setCPUState.add(IALOAD);
298             setCPUState.add(PUTFIELD,new FieldRef(me,"r"+i,Type.INT));
299             
300             getCPUState.add(ALOAD_2);
301             getCPUState.add(LDC,i);
302             getCPUState.add(ALOAD_0);
303             getCPUState.add(GETFIELD,new FieldRef(me,"r"+i,Type.INT));
304             getCPUState.add(IASTORE);
305         }
306         
307         setCPUState.add(ALOAD_1);
308         getCPUState.add(ALOAD_1);
309         setCPUState.add(GETFIELD,new FieldRef(cpuStateType,"f",Type.arrayType(Type.INT)));
310         getCPUState.add(GETFIELD,new FieldRef(cpuStateType,"f",Type.arrayType(Type.INT)));
311         setCPUState.add(ASTORE_2);
312         getCPUState.add(ASTORE_2);
313         
314         for(int i=0;i<32;i++) {
315             setCPUState.add(ALOAD_0);
316             setCPUState.add(ALOAD_2);
317             setCPUState.add(LDC,i);
318             setCPUState.add(IALOAD);
319             if(singleFloat) setCPUState.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"intBitsToFloat",Type.FLOAT,new Type[]{Type.INT}));
320             setCPUState.add(PUTFIELD,new FieldRef(me,"f"+i,singleFloat ? Type.FLOAT : Type.INT));
321             
322             getCPUState.add(ALOAD_2);
323             getCPUState.add(LDC,i);
324             getCPUState.add(ALOAD_0);
325             getCPUState.add(GETFIELD,new FieldRef(me,"f"+i,singleFloat ? Type.FLOAT: Type.INT));
326             if(singleFloat) getCPUState.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"floatToIntBits",Type.INT,new Type[]{Type.FLOAT}));
327             getCPUState.add(IASTORE);            
328         }
329         
330         String[] each = new String[] { "hi","lo","fcsr","pc" };
331         for(int i=0;i<each.length;i++) {
332             setCPUState.add(ALOAD_0);
333             setCPUState.add(ALOAD_1);
334             setCPUState.add(GETFIELD,new FieldRef(cpuStateType,each[i],Type.INT));
335             setCPUState.add(PUTFIELD,new FieldRef(me,each[i],Type.INT));
336
337             getCPUState.add(ALOAD_1);
338             getCPUState.add(ALOAD_0);
339             getCPUState.add(GETFIELD,new FieldRef(me,each[i],Type.INT));
340             getCPUState.add(PUTFIELD,new FieldRef(cpuStateType,each[i],Type.INT));
341         }
342         setCPUState.add(RETURN);
343         getCPUState.add(RETURN);
344         
345
346         MethodGen execute = cg.addMethod("_execute",Type.VOID,Type.NO_ARGS,ACC_PROTECTED);
347         int tryStart = execute.size();
348         execute.add(ALOAD_0);
349         execute.add(INVOKESPECIAL,new MethodRef(me,"trampoline",Type.VOID,Type.NO_ARGS));
350         int tryEnd = execute.size();
351         execute.add(RETURN);
352         
353         int catchInsn = execute.size();
354         execute.add(ASTORE_1);
355         execute.add(NEW, new Type.Object("org.ibex.nestedvm.Runtime$FaultException"));
356         execute.add(DUP);
357         execute.add(ALOAD_1);
358         // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime$FaultException.<init>
359         execute.add(INVOKESPECIAL,new MethodRef("org.ibex.nestedvm.Runtime$FaultException","<init>",Type.VOID,new Type[]{new Type.Object("java.lang.RuntimeException")}));
360         execute.add(ATHROW);
361         
362         execute.addExceptionHandler(tryStart,tryEnd,catchInsn,new Type.Object("java.lang.RuntimeException"));
363         execute.addThrow(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
364
365         MethodGen main = cg.addMethod("main",Type.VOID,new Type[]{Type.arrayType(Type.STRING)},ACC_STATIC|ACC_PUBLIC);
366         main.add(NEW,me);
367         main.add(DUP);
368         main.add(INVOKESPECIAL,new MethodRef(me,"<init>",Type.VOID,Type.NO_ARGS));
369         main.add(LDC,fullClassName);
370         main.add(ALOAD_0);
371         if(unixRuntime) {
372             Type.Object ur = new Type.Object("org.ibex.nestedvm.UnixRuntime");
373             // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.runAndExec
374             main.add(INVOKESTATIC,new MethodRef(ur,"runAndExec",Type.INT,new Type[]{ur,Type.STRING,Type.arrayType(Type.STRING)}));
375         } else {
376             // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.run
377             main.add(INVOKEVIRTUAL,new MethodRef(me,"run",Type.INT,new Type[]{Type.STRING,Type.arrayType(Type.STRING)}));
378         }
379         main.add(INVOKESTATIC,new MethodRef(new Type.Object("java.lang.System"),"exit",Type.VOID,new Type[]{Type.INT}));
380         main.add(RETURN);
381         
382         if(outDir != null) {
383             if(!outDir.isDirectory()) throw new IOException("" + outDir + " isn't a directory");
384             cg.dump(outDir);
385         } else {
386             cg.dump(os);
387         }
388     }
389     
390     private void addConstReturnMethod(String name, int val) {
391         MethodGen  m = cg.addMethod(name,Type.INT,Type.NO_ARGS,ACC_PROTECTED);
392         m.add(LDC,val);
393         m.add(IRETURN);
394     }
395         
396     private static int initDataCount;
397     private void emitData(int addr, DataInputStream dis, int size, boolean readOnly) throws Exn,IOException {
398         if((addr&3)!=0 || (size&3)!=0) throw new Exn("Data section on weird boundaries");
399         int last = addr + size;
400         while(addr < last) {
401             int segSize = Math.min(size,28000); // must be a multiple of 56
402             StringBuffer sb = new StringBuffer();
403             for(int i=0;i<segSize;i+=7) {
404                 long l = 0;
405                 for(int j=0;j<7;j++) {
406                     l <<= 8;
407                     byte b = (i+j < size) ? dis.readByte() : 1;
408                     l |= (b & 0xffL);
409                 }
410                 for(int j=0;j<8;j++)
411                     sb.append((char) ((l>>>(7*(7-j)))&0x7f));
412             }
413             String fieldname =  "_data" + (++initDataCount);
414             cg.addField(fieldname,Type.arrayType(Type.INT),ACC_PRIVATE|ACC_STATIC|ACC_FINAL);
415             
416             clinit.add(LDC,sb.toString());
417             clinit.add(LDC,segSize/4);
418             // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.decodeData
419             clinit.add(INVOKESTATIC,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime"),"decodeData",Type.arrayType(Type.INT),new Type[]{Type.STRING,Type.INT}));
420             clinit.add(PUTSTATIC,new FieldRef(me,fieldname,Type.arrayType(Type.INT)));
421             init.add(ALOAD_0);
422             init.add(GETSTATIC,new FieldRef(me,fieldname,Type.arrayType(Type.INT)));
423             init.add(LDC,addr);
424             init.add(LDC,readOnly ? 1 : 0);
425             // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.initPages
426             init.add(INVOKEVIRTUAL,new MethodRef(me,"initPages",Type.VOID,new Type[]{Type.arrayType(Type.INT),Type.INT,Type.BOOLEAN}));
427             
428             addr += segSize;
429             size -= segSize;
430         }
431         dis.close();
432     }
433     
434     private void emitBSS(int addr, int size) throws Exn {
435         if((addr&3)!=0) throw new Exn("BSS section on weird boundaries");
436         size = (size+3)&~3;
437         int count = size/4;
438         
439         init.add(ALOAD_0);
440         init.add(LDC,addr);
441         init.add(LDC,count);
442         // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.clearPages
443         init.add(INVOKEVIRTUAL,new MethodRef(me,"clearPages",Type.VOID,new Type[]{Type.INT,Type.INT}));
444     }
445     
446     // Method state info
447     private int startOfMethod = 0; // the start of this method (not necessarily the first instruction)
448     private int endOfMethod = 0; // the maximum end of this method (could end before it is full)
449     
450     private MethodGen.PhantomTarget returnTarget; // where to jump when exiting the method
451     private MethodGen.PhantomTarget defaultTarget; // the default switch target (throws exn)
452     private MethodGen.PhantomTarget[] insnTargets; // the targets for each jumpable instruction
453     private MethodGen mg; // the method itself
454     
455     private boolean jumpable(int addr) { return jumpableAddresses.get(new Integer(addr)) != null; }
456     
457     private static final int UNREACHABLE = 1;
458     private static final int SKIP_NEXT = 2;
459     
460     private boolean textDone; // a text segment was already processed
461     private void emitText(int addr, DataInputStream dis, int size) throws Exn,IOException {
462         if(textDone) throw new Exn("Multiple text segments");
463         textDone = true;
464         
465         if((addr&3)!=0 || (size&3)!=0) throw new Exn("Section on weird boundaries");
466         int count = size/4;
467         int insn,nextInsn=-1;
468         
469         boolean skipNext = true;
470         boolean unreachable = false;
471         
472         for(int i=0;i<count;i++,addr+=4) {
473             insn = skipNext ? dis.readInt() : nextInsn;
474             nextInsn = (i == count-1) ? -1 : dis.readInt();
475             if(addr >= endOfMethod) { endMethod(addr,unreachable); startMethod(addr); }
476             if(insnTargets[i%maxInsnPerMethod] != null) {
477                 insnTargets[i%maxInsnPerMethod].setTarget(mg.size());
478                 unreachable = false;
479             } else if(unreachable) {
480                 continue;
481             }
482             try {
483                 int ret = emitInstruction(addr,insn,nextInsn);
484                 unreachable =  (ret & UNREACHABLE) != 0;
485                 skipNext = (ret & SKIP_NEXT) != 0;
486             } catch(Exn e) {
487                 e.printStackTrace(warn);
488                 warn.println("Exception at " + toHex(addr));
489                 throw e;                
490             } catch(RuntimeException e) {
491                 warn.println("Exception at " + toHex(addr));
492                 throw e;
493             }
494             if(skipNext) { addr+=4; i++; }
495         }
496         endMethod(0,unreachable);
497         dis.close();
498     }
499     
500     private void startMethod(int first) {
501         startOfMethod = first & methodMask;
502         endOfMethod = startOfMethod + maxBytesPerMethod;
503         
504         mg = cg.addMethod("run_" + toHex(startOfMethod),Type.VOID,Type.NO_ARGS,ACC_PRIVATE|ACC_FINAL);
505         if(onePage) {
506             mg.add(ALOAD_0);
507             mg.add(GETFIELD,new FieldRef(me,"page",Type.arrayType(Type.INT)));
508             mg.add(ASTORE_2);
509         } else {
510             mg.add(ALOAD_0);
511             mg.add(GETFIELD,new FieldRef(me,"readPages",Type.arrayType(Type.INT,2)));
512             mg.add(ASTORE_2);
513             mg.add(ALOAD_0);
514             mg.add(GETFIELD,new FieldRef(me,"writePages",Type.arrayType(Type.INT,2)));
515             mg.add(ASTORE_3);
516         }
517         
518         returnTarget = new MethodGen.PhantomTarget();
519         insnTargets = new MethodGen.PhantomTarget[maxBytesPerMethod/4];
520         
521         int[] buf = new int[maxBytesPerMethod/4];
522         Object[] targetBuf = new Object[maxBytesPerMethod/4];
523         int n = 0;
524         for(int addr=first;addr<endOfMethod;addr+=4) {
525             if(jumpable(addr)) {
526                 targetBuf[n] = insnTargets[(addr-startOfMethod)/4] = new MethodGen.PhantomTarget();
527                 buf[n] = addr;
528                 n++;
529             }
530         }
531
532         MethodGen.LSI lsi = new MethodGen.LSI(n);
533         System.arraycopy(buf,0,lsi.vals,0,n);
534         System.arraycopy(targetBuf,0,lsi.targets,0,n);
535         lsi.setDefaultTarget(defaultTarget = new MethodGen.PhantomTarget());
536         
537         fixupRegsStart();
538         
539         mg.add(ALOAD_0);
540         mg.add(GETFIELD,new FieldRef(me,"pc",Type.INT));
541         mg.add(LOOKUPSWITCH,lsi);
542     }
543     
544     private void endMethod(int firstAddrOfNext,boolean unreachable) {
545         if(startOfMethod == 0) return;
546         
547         if(!unreachable) {
548             preSetPC();
549             mg.add(LDC,firstAddrOfNext);
550             setPC();
551             // mark the start of the next method as jumpable
552             jumpableAddresses.put(new Integer(firstAddrOfNext),Boolean.TRUE);
553         }
554         
555         returnTarget.setTarget(mg.size());
556         
557         fixupRegsEnd();
558         
559         mg.add(RETURN);
560         
561         defaultTarget.setTarget(mg.size());
562         
563         if(debugCompiler) {
564             mg.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
565             mg.add(DUP);
566             mg.add(NEW,Type.STRINGBUFFER);
567             mg.add(DUP);
568             mg.add(LDC,"Jumped to invalid address: ");
569             mg.add(INVOKESPECIAL,new MethodRef(Type.STRINGBUFFER,"<init>",Type.VOID,new Type[]{Type.STRING}));
570             mg.add(ALOAD_0);
571             mg.add(GETFIELD,new FieldRef(me,"pc",Type.INT));
572             mg.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.INT}));
573             mg.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"toString",Type.STRING,Type.NO_ARGS));
574             mg.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"<init>",Type.VOID,new Type[]{Type.STRING}));
575             mg.add(ATHROW);
576         } else {
577             mg.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
578             mg.add(DUP);
579             mg.add(LDC,"Jumped to invalid address");
580             mg.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"<init>",Type.VOID,new Type[]{Type.STRING}));
581             mg.add(ATHROW);
582         }
583         
584         endOfMethod = startOfMethod = 0;
585     }
586
587
588     private void leaveMethod() {
589         mg.add(GOTO,returnTarget);
590     }
591     
592     private void link(int mypc) {
593         preSetReg(R+RA);
594         if(lessConstants){
595             int ref = (mypc+8 + 32768) & ~65535;
596             int diff = (mypc+8) - ref;
597             if(diff < -32768 || diff > 32767) throw new Error("should never happen " + diff);
598             mg.add(LDC,ref);
599             mg.add(LDC,diff);
600             mg.add(IADD);
601         } else {
602             mg.add(LDC,mypc+8);
603         }
604         setReg();
605     }
606
607     private void branch(int pc, int target) {
608         if((pc&methodMask) == (target&methodMask)) {
609             mg.add(GOTO,insnTargets[(target-startOfMethod)/4]);
610         } else {
611             preSetPC();
612             mg.add(LDC,target);
613             setPC();
614             leaveMethod();
615         }
616     }
617     
618     // This assumes everything needed by ifInsn is already on the stack
619     private int doIfInstruction(byte op, int pc, int target, int nextInsn) throws Exn {
620         emitInstruction(-1,nextInsn,-1); // delay slot
621         if((target&methodMask) == (pc&methodMask)) {
622             mg.add(op,insnTargets[(target-startOfMethod)/4]);
623         } else {
624             int h = mg.add(MethodGen.negate(op));
625             branch(pc,target);
626             mg.setArg(h,mg.size());
627         }
628         if(!jumpable(pc+4)) return SKIP_NEXT; // done - skip it
629         
630         //System.err.println("Delay slot is jumpable - This code is untested + " + toHex(nextInsn));
631         if(pc+4==endOfMethod) {
632             // the delay slot is at the start of the next method
633             jumpableAddresses.put(new Integer(pc+8),Boolean.TRUE); // make the 2nd insn of the next method jumpable
634             branch(pc,pc+8); // jump over it
635             //System.err.println("delay slot: " + toHex(pc+8)); */
636             //unreachable = true;
637             //return false; // we still need to output it
638             return UNREACHABLE;
639         } else {
640             //System.err.println("jumped over delay slot: " + toHex(pc+4));
641             // add another copy and jump over
642             
643             int b = mg.add(GOTO);
644             insnTargets[(pc+4-startOfMethod)/4].setTarget(mg.size());
645             emitInstruction(-1,nextInsn,01); // delay slot
646             mg.setArg(b,mg.size());
647             
648             return SKIP_NEXT;
649         }
650     }
651     
652     private static final Float POINT_5_F = new Float(0.5f);
653     private static final Double POINT_5_D = new Double(0.5f);
654     private static final Long FFFFFFFF = new Long(0xffffffffL);
655     
656     private int emitInstruction(int pc, int insn, int nextInsn) throws Exn {
657         MethodGen mg = this.mg; // smaller bytecode
658         if(insn == -1) throw new Exn("insn is -1");
659         
660         int ret = 0;
661         
662         int op = (insn >>> 26) & 0xff;                 // bits 26-31
663         int rs = (insn >>> 21) & 0x1f;                 // bits 21-25
664         int rt = (insn >>> 16) & 0x1f;                 // bits 16-20 
665         int ft = (insn >>> 16) & 0x1f;
666         int rd = (insn >>> 11) & 0x1f;                 // bits 11-15
667         int fs = (insn >>> 11) & 0x1f;
668         int shamt = (insn >>> 6) & 0x1f;               // bits 6-10
669         int fd = (insn >>> 6) & 0x1f;
670         int subcode = insn & 0x3f;                     // bits 0-5 
671         int breakCode = (insn >>> 6) & 0xfffff;         // bits 6-20
672     
673         int jumpTarget = (insn & 0x03ffffff);          // bits 0-25
674         int unsignedImmediate = insn & 0xffff;
675         int signedImmediate = (insn << 16) >> 16;
676         int branchTarget = signedImmediate;
677     
678         // temporaries
679         int b1,b2;
680         
681         switch(op) {
682         case 0: {
683             switch(subcode) {
684             case 0: // SLL
685                 if(insn == 0) break; 
686                 preSetReg(R+rd);
687                 pushRegWZ(R+rt);
688                 mg.add(LDC,shamt);
689                 mg.add(ISHL);
690                 setReg();
691                 break;
692             case 2: // SRL
693                 preSetReg(R+rd);
694                 pushRegWZ(R+rt);
695                 mg.add(LDC,shamt);
696                 mg.add(IUSHR);
697                 setReg();
698                 break;
699             case 3: // SRA
700                 preSetReg(R+rd);
701                 pushRegWZ(R+rt);
702                 mg.add(LDC,shamt);
703                 mg.add(ISHR);
704                 setReg();
705                 break;
706             case 4: // SLLV
707                 preSetReg(R+rd);
708                 pushRegWZ(R+rt);
709                 pushRegWZ(R+rs);
710                 mg.add(ISHL);
711                 setReg();
712                 break;
713             case 6: // SRLV
714                 preSetReg(R+rd);
715                 pushRegWZ(R+rt);
716                 pushRegWZ(R+rs);
717                 mg.add(IUSHR);
718                 setReg();
719                 break;
720             case 7: // SRAV
721                 preSetReg(R+rd);
722                 pushRegWZ(R+rt);
723                 pushRegWZ(R+rs);
724                 mg.add(ISHR);
725                 setReg();
726                 break;
727             case 8: // JR
728                 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
729                 emitInstruction(-1,nextInsn,-1);
730                 preSetPC();
731                 pushRegWZ(R+rs);
732                 setPC();
733                 leaveMethod();
734                 ret |= UNREACHABLE;
735                 break;
736             case 9: // JALR
737                 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
738                 emitInstruction(-1,nextInsn,-1);
739                 link(pc);
740                 preSetPC();
741                 pushRegWZ(R+rs);
742                 setPC();
743                 leaveMethod();
744                 ret |= UNREACHABLE;
745                 break;
746             case 12: // SYSCALL
747                 preSetPC();
748                 mg.add(LDC,pc);
749                 setPC();
750                 
751                 // FEATURE: This is actually broken, but it happens to work for our code
752                 // a func could theoretically jump back to here from a future point
753                 restoreChangedRegs();
754                 
755                 preSetReg(R+V0);
756                 mg.add(ALOAD_0);
757                 pushRegZ(R+V0);
758                 pushRegZ(R+A0);
759                 pushRegZ(R+A1);
760                 pushRegZ(R+A2);
761                 pushRegZ(R+A3);
762                 pushRegZ(R+T0);
763                 pushRegZ(R+T1);
764                 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.syscall
765                 mg.add(INVOKEVIRTUAL,new MethodRef(me,"syscall",Type.INT,new Type[]{Type.INT,Type.INT,Type.INT,Type.INT,Type.INT,Type.INT,Type.INT}));
766                 setReg();
767                 
768                 mg.add(ALOAD_0);
769                 mg.add(GETFIELD,new FieldRef(me,"state",Type.INT));
770                 b1 = mg.add(IFEQ);
771                 preSetPC();
772                 mg.add(LDC,pc+4);
773                 setPC();
774                 leaveMethod();
775                 mg.setArg(b1,mg.size());
776                 break;
777             case 13: // BREAK
778                 mg.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
779                 mg.add(DUP);
780                 mg.add(LDC,"BREAK Code " + toHex(breakCode));
781                 mg.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"<init>",Type.VOID,new Type[]{Type.STRING}));
782                 mg.add(ATHROW);
783                 ret |= UNREACHABLE;
784                 break;
785             case 16: // MFHI
786                 preSetReg(R+rd);
787                 pushReg(HI);
788                 setReg();
789                 break;
790             case 17: // MTHI
791                 preSetReg(HI);
792                 pushRegZ(R+rs);
793                 setReg();
794                 break;
795             case 18: // MFLO
796                 preSetReg(R+rd);
797                 pushReg(LO);
798                 setReg();
799                 break;
800             case 19: // MTLO
801                 preSetReg(LO);
802                 pushRegZ(R+rs);
803                 setReg();
804                 break;
805             case 24: // MULT
806                 pushRegWZ(R+rs);
807                 mg.add(I2L);
808                 pushRegWZ(R+rt);
809                 mg.add(I2L);
810                 mg.add(LMUL);
811                 mg.add(DUP2);
812                 
813                 mg.add(L2I);
814                 if(preSetReg(LO))
815                     mg.add(SWAP); //a(InstructionConstants.SWAP);
816                 setReg();
817                 
818                 mg.add(LDC,32);
819                 mg.add(LUSHR);
820                 mg.add(L2I);
821                 if(preSetReg(HI))
822                     mg.add(SWAP); //a(InstructionConstants.SWAP);
823                 setReg();
824                 
825                 break;
826             case 25: // MULTU
827                 pushRegWZ(R+rs);
828                 mg.add(I2L);
829                 mg.add(LDC,FFFFFFFF);
830                 mg.add(LAND);
831                 pushRegWZ(R+rt);
832                 mg.add(I2L);
833                 mg.add(LDC,FFFFFFFF);
834                 mg.add(LAND);
835                 mg.add(LMUL);
836                 mg.add(DUP2);
837                 
838                 mg.add(L2I);
839                 if(preSetReg(LO))
840                     mg.add(SWAP);
841                 setReg();
842                 
843                 mg.add(LDC,32);
844                 mg.add(LUSHR);
845                 mg.add(L2I);
846                 if(preSetReg(HI))
847                     mg.add(SWAP);
848                 setReg();
849                 
850                 break;
851             case 26: // DIV
852                 pushRegWZ(R+rs);
853                 pushRegWZ(R+rt);
854                 mg.add(DUP2);
855                 
856                 mg.add(IDIV);
857                 if(preSetReg(LO))
858                     mg.add(SWAP);
859                 setReg();
860                 
861                 mg.add(IREM);
862                 if(preSetReg(HI))
863                     mg.add(SWAP);
864                 setReg();
865                 
866                 break;
867             case 27: { // DIVU
868                 pushRegWZ(R+rt);
869                 mg.add(DUP);
870                 setTmp();
871                 b1 = mg.add(IFEQ);
872                 
873                 pushRegWZ(R+rs);
874                 mg.add(I2L);
875                 mg.add(LDC,FFFFFFFF);
876                 mg.add(LAND);
877                 mg.add(DUP2);
878                 pushTmp();
879                 mg.add(I2L);
880                 mg.add(LDC,FFFFFFFF);
881                 
882                 mg.add(LAND);
883                 mg.add(DUP2_X2);
884                 mg.add(LDIV);
885                 
886                 mg.add(L2I);
887                 if(preSetReg(LO))
888                     mg.add(SWAP);
889                 setReg();
890                 
891                 mg.add(LREM);
892                 mg.add(L2I);
893                 if(preSetReg(HI))
894                     mg.add(SWAP);
895                 setReg();
896                 
897                 mg.setArg(b1,mg.size());
898                 
899                 break;
900             }
901             case 32: // ADD
902                 throw new Exn("ADD (add with oveflow trap) not suported");
903             case 33: // ADDU
904                 preSetReg(R+rd);
905                 if(rt != 0 && rs != 0) {
906                     pushReg(R+rs);
907                     pushReg(R+rt);
908                     mg.add(IADD);
909                 } else if(rs != 0) {
910                     pushReg(R+rs);
911                 } else {
912                     pushRegZ(R+rt);
913                 }
914                 setReg();
915                 break;
916             case 34: // SUB
917                 throw new Exn("SUB (add with oveflow trap) not suported");
918             case 35: // SUBU
919                 preSetReg(R+rd);
920                 if(rt != 0 && rs != 0) {
921                     pushReg(R+rs);
922                     pushReg(R+rt);
923                     mg.add(ISUB);
924                 } else if(rt != 0) {
925                     pushReg(R+rt);
926                     mg.add(INEG);
927                 } else {
928                     pushRegZ(R+rs);
929                 }
930                 setReg();                
931                 break;
932             case 36: // AND
933                 preSetReg(R+rd);
934                 pushRegWZ(R+rs);
935                 pushRegWZ(R+rt);
936                 mg.add(IAND);
937                 setReg();
938                 break;
939             case 37: // OR
940                 preSetReg(R+rd);
941                 pushRegWZ(R+rs);
942                 pushRegWZ(R+rt);
943                 mg.add(IOR);
944                 setReg();
945                 break;
946             case 38: // XOR
947                 preSetReg(R+rd);
948                 pushRegWZ(R+rs);
949                 pushRegWZ(R+rt);
950                 mg.add(IXOR);
951                 setReg();
952                 break;
953             case 39: // NOR
954                 preSetReg(R+rd);
955                 if(rs != 0 || rt != 0) {
956                     if(rs != 0 && rt != 0) {
957                         pushReg(R+rs);
958                         pushReg(R+rt);
959                         mg.add(IOR);
960                     } else if(rs != 0) {
961                         pushReg(R+rs);
962                     } else {
963                         pushReg(R+rt);
964                     }
965                     mg.add(ICONST_M1);
966                     mg.add(IXOR);
967                 } else {
968                     mg.add(LDC,-1);
969                 }
970                 setReg();
971                 break;
972             case 42: // SLT
973                 preSetReg(R+rd);
974                 if(rs != rt) {
975                     pushRegZ(R+rs);
976                     pushRegZ(R+rt);
977                     b1 = mg.add(IF_ICMPLT);
978                     mg.add(ICONST_0);
979                     b2 = mg.add(GOTO);
980                     mg.setArg(b1,mg.add(ICONST_1));
981                     mg.setArg(b2,mg.size());
982                 } else {
983                     mg.add(LDC,0);
984                 }
985                 setReg();
986                 break;
987             case 43: // SLTU
988                 preSetReg(R+rd);
989                 if(rs != rt) {
990                     if(rs != 0) {
991                         pushReg(R+rs);
992                         mg.add(I2L);
993                         mg.add(LDC,FFFFFFFF);
994                         mg.add(LAND);
995                         pushReg(R+rt);
996                         mg.add(I2L);
997                         mg.add(LDC,FFFFFFFF);
998                         mg.add(LAND);
999                         mg.add(LCMP);
1000                         b1 = mg.add(IFLT);
1001                     } else {
1002                         pushReg(R+rt);
1003                         b1 = mg.add(IFNE);
1004                     }
1005                     mg.add(ICONST_0);
1006                     b2 = mg.add(GOTO);
1007                     mg.setArg(b1,mg.add(ICONST_1));
1008                     mg.setArg(b2,mg.size());
1009                 } else {
1010                     mg.add(LDC,0);
1011                 }
1012                 setReg();
1013                 break;
1014             default:
1015                 throw new Exn("Illegal instruction 0/" + subcode);
1016             }
1017             break;
1018         }
1019         case 1: {
1020             switch(rt) {
1021             case 0: // BLTZ
1022                 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1023                 pushRegWZ(R+rs);
1024                 return doIfInstruction(IFLT,pc,pc+branchTarget*4+4,nextInsn);
1025             case 1: // BGEZ
1026                 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1027                 pushRegWZ(R+rs);
1028                 return doIfInstruction(IFGE,pc,pc+branchTarget*4+4,nextInsn);
1029             case 16: // BLTZAL
1030                 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1031                 pushRegWZ(R+rs);
1032                 b1 = mg.add(IFGE);
1033                 emitInstruction(-1,nextInsn,-1);
1034                 link(pc);
1035                 branch(pc,pc+branchTarget*4+4);
1036                 mg.setArg(b1,mg.size());
1037                 break;
1038             case 17: // BGEZAL
1039                 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1040                 b1 = -1;
1041                 if(rs != 0) { // r0 is always >= 0
1042                     pushRegWZ(R+rs);
1043                     b1 = mg.add(IFLT);
1044                 }
1045                 emitInstruction(-1,nextInsn,-1);
1046                 link(pc);
1047                 branch(pc,pc+branchTarget*4+4);
1048                 if(b1 != -1) mg.setArg(b1,mg.size());
1049                 if(b1 == -1) ret |= UNREACHABLE;
1050                 break;
1051             default:
1052                 throw new Exn("Illegal Instruction 1/" + rt);
1053             }
1054             break;
1055         }
1056         case 2: { // J
1057             if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1058             emitInstruction(-1,nextInsn,-1);
1059             branch(pc,(pc&0xf0000000)|(jumpTarget << 2));
1060             ret |= UNREACHABLE;
1061             break;
1062         }
1063         case 3: { // JAL
1064             if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1065             int target = (pc&0xf0000000)|(jumpTarget << 2);
1066             emitInstruction(-1,nextInsn,-1);
1067             link(pc);
1068             branch(pc, target);
1069             ret |= UNREACHABLE;
1070             break;
1071         }
1072         case 4: // BEQ
1073             if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1074             if(rs == rt) {
1075                 emitInstruction(-1,nextInsn,-1);
1076                 branch(pc,pc+branchTarget*4+4);
1077                 ret |= UNREACHABLE;
1078             } else if(rs == 0 || rt == 0) {
1079                 pushReg(rt == 0 ? R+rs : R+rt);
1080                 return doIfInstruction(IFEQ,pc,pc+branchTarget*4+4,nextInsn);
1081             } else {
1082                 pushReg(R+rs);
1083                 pushReg(R+rt);
1084                 return doIfInstruction(IF_ICMPEQ,pc,pc+branchTarget*4+4,nextInsn);
1085             }
1086             break;
1087         case 5: // BNE       
1088             if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1089             pushRegWZ(R+rs);
1090             if(rt == 0) {
1091                 return doIfInstruction(IFNE,pc,pc+branchTarget*4+4,nextInsn);
1092             } else {
1093                 pushReg(R+rt);
1094                 return doIfInstruction(IF_ICMPNE,pc,pc+branchTarget*4+4,nextInsn);
1095             }
1096         case 6: //BLEZ
1097             if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1098             pushRegWZ(R+rs);
1099             return doIfInstruction(IFLE,pc,pc+branchTarget*4+4,nextInsn);
1100         case 7: //BGTZ
1101             if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1102             pushRegWZ(R+rs);
1103             return doIfInstruction(IFGT,pc,pc+branchTarget*4+4,nextInsn);
1104         case 8: // ADDI
1105             throw new Exn("ADDI (add immediate with oveflow trap) not suported");
1106         case 9: // ADDIU
1107             if(rs != 0 && signedImmediate != 0 && rs == rt && doLocal(rt) && signedImmediate >= -32768 && signedImmediate <= 32767) {
1108                 // HACK: This should be a little cleaner
1109                 regLocalWritten[rt] = true;
1110                 mg.add(IINC, new MethodGen.Pair(getLocalForReg(rt),signedImmediate));
1111             } else {
1112                 preSetReg(R+rt);
1113                 addiu(rs,signedImmediate);
1114                 setReg();
1115             }
1116             break;
1117         case 10: // SLTI
1118             preSetReg(R+rt);
1119             pushRegWZ(R+rs);
1120             mg.add(LDC,signedImmediate);
1121             b1 = mg.add(IF_ICMPLT);
1122             mg.add(ICONST_0);
1123             b2 = mg.add(GOTO);
1124             mg.setArg(b1,mg.add(ICONST_1));
1125             mg.setArg(b2,mg.size());
1126             setReg();
1127             break;
1128         case 11: // SLTIU
1129             preSetReg(R+rt);
1130             pushRegWZ(R+rs);
1131             mg.add(I2L);
1132             mg.add(LDC,FFFFFFFF);
1133             mg.add(LAND);
1134             // Yes, this is correct, you have to sign extend the immediate then do an UNSIGNED comparison
1135             mg.add(LDC,new Long(signedImmediate&0xffffffffL));
1136             mg.add(LCMP);
1137             
1138             b1 = mg.add(IFLT);
1139             mg.add(ICONST_0);
1140             b2 = mg.add(GOTO);
1141             mg.setArg(b1,mg.add(ICONST_1));
1142             mg.setArg(b2,mg.size());            
1143             setReg();
1144             break;            
1145         case 12: // ANDI
1146             preSetReg(R+rt);
1147             pushRegWZ(R+rs);
1148             mg.add(LDC,unsignedImmediate);
1149             mg.add(IAND);
1150             setReg();
1151             break;
1152         case 13: // ORI
1153             preSetReg(R+rt);
1154             if(rs != 0 && unsignedImmediate != 0) {
1155                 pushReg(R+rs);
1156                 mg.add(LDC,unsignedImmediate);
1157                 mg.add(IOR);
1158             } else if(rs != 0){
1159                 pushReg(R+rs);
1160             } else {
1161                 mg.add(LDC,unsignedImmediate);
1162             }
1163             setReg();
1164             break;
1165         case 14: // XORI
1166             preSetReg(R+rt);
1167             pushRegWZ(R+rs);
1168             mg.add(LDC,unsignedImmediate);
1169             mg.add(IXOR);
1170             setReg();
1171             break;
1172         case 15: // LUI
1173             preSetReg(R+rt);
1174             mg.add(LDC,unsignedImmediate << 16);
1175             setReg();
1176             break;
1177         case 16:
1178             throw new Exn("TLB/Exception support not implemented");
1179         case 17: { // FPU
1180             switch(rs) {
1181             case 0: // MFC.1
1182                 preSetReg(R+rt);
1183                 pushReg(F+rd);
1184                 setReg();
1185                 break;
1186             case 2: // CFC.1
1187                 if(fs != 31) throw new Exn("FCR " + fs + " unavailable");
1188                 preSetReg(R+rt);
1189                 pushReg(FCSR);
1190                 setReg();
1191                 break;
1192             case 4: // MTC.1
1193                 preSetReg(F+rd);
1194                 if(rt != 0) pushReg(R+rt);
1195                 else mg.add(ICONST_0);
1196                 setReg();
1197                 break;
1198             case 6: // CTC.1
1199                 if(fs != 31) throw new Exn("FCR " + fs + " unavailable");
1200                 preSetReg(FCSR);
1201                 pushReg(R+rt);
1202                 setReg();
1203                 break;
1204             case 8: {// BC1F, BC1T
1205                 pushReg(FCSR);
1206                 mg.add(LDC,0x800000);
1207                 mg.add(IAND);
1208                 return doIfInstruction(((insn>>>16)&1) == 0 ? IFEQ : IFNE,pc,pc+branchTarget*4+4,nextInsn);
1209             }
1210             case 16:
1211             case 17: 
1212             { // Single/Double math
1213                 boolean d = rs == 17;
1214                 switch(subcode) {
1215                 case 0: // ADD.X
1216                     preSetDouble(F+fd,d);
1217                     pushDouble(F+fs,d);
1218                     pushDouble(F+ft,d);
1219                     mg.add(d ? DADD : FADD);
1220                     setDouble(d);
1221                     break;
1222                 case 1: // SUB.X
1223                     preSetDouble(F+fd,d);
1224                     pushDouble(F+fs,d);
1225                     pushDouble(F+ft,d);
1226                     mg.add(d ? DSUB : FSUB);
1227                     setDouble(d);
1228                     break;
1229                 case 2: // MUL.X
1230                     preSetDouble(F+fd,d);
1231                     pushDouble(F+fs,d);
1232                     pushDouble(F+ft,d);
1233                     mg.add(d ? DMUL : FMUL);
1234                     setDouble(d);                    
1235                     break;
1236                 case 3: // DIV.X
1237                     preSetDouble(F+fd,d);
1238                     pushDouble(F+fs,d);
1239                     pushDouble(F+ft,d);
1240                     mg.add(d ? DDIV : FDIV);
1241                     setDouble(d);                    
1242                     break;
1243                 case 5: // ABS.X
1244                     preSetDouble(F+fd,d);
1245                     // NOTE: We can't use fneg/dneg here since they'll turn +0.0 into -0.0
1246                     
1247                     pushDouble(F+fs,d);
1248                     mg.add(d ? DUP2 : DUP);
1249                     mg.add(d ? DCONST_0 : FCONST_0);
1250                     mg.add(d ? DCMPG : FCMPG);
1251                     
1252                     b1 = mg.add(IFGT);
1253                     mg.add(d ? DCONST_0 : FCONST_0);
1254                     if(d) {
1255                         mg.add(DUP2_X2);
1256                         mg.add(POP2);
1257                     } else {
1258                         mg.add(SWAP);
1259                     }
1260                     mg.add(d ? DSUB : FSUB);
1261                     
1262                     mg.setArg(b1,mg.size());
1263                     setDouble(d);
1264                     
1265                     break;
1266                 case 6: // MOV.X
1267                     preSetReg(F+fd);
1268                     pushReg(F+fs);
1269                     setReg();
1270                 
1271                     if(d) {
1272                         preSetReg(F+fd+1);
1273                         pushReg(F+fs+1);
1274                         setReg();
1275                     }
1276                     break;
1277                 case 7: // NEG.X
1278                     preSetDouble(F+fd,d);
1279                     pushDouble(F+fs,d);
1280                     mg.add(d ? DNEG : FNEG);
1281                     setDouble(d);
1282                     break;
1283                 case 32: // CVT.S.X
1284                     preSetFloat(F+fd);
1285                     pushDouble(F+fs,d);
1286                     if(d) mg.add(D2F);
1287                     setFloat();
1288                     break;
1289                 case 33: // CVT.D.X
1290                     preSetDouble(F+fd);
1291                     pushDouble(F+fs,d);
1292                     if(!d) mg.add(F2D);
1293                     setDouble();
1294                     break;
1295                 case 36: { // CVT.W.D
1296                     MethodGen.TSI tsi = new MethodGen.TSI(0,3);
1297                     preSetReg(F+fd);
1298                     pushDouble(F+fs,d);
1299                     pushReg(FCSR);
1300                     mg.add(ICONST_3);
1301                     mg.add(IAND);
1302                     mg.add(TABLESWITCH,tsi);
1303                     
1304                     // Round towards plus infinity
1305                     tsi.setTarget(2,mg.size());
1306                     if(!d) mg.add(F2D); // Ugh.. java.lang.Math doesn't have a float ceil/floor
1307                     mg.add(INVOKESTATIC,new MethodRef("java.lang.Math","ceil",Type.DOUBLE,new Type[]{Type.DOUBLE}));
1308                     if(!d) mg.add(D2F);
1309                     b1 = mg.add(GOTO);
1310                     
1311                     // Round to nearest
1312                     tsi.setTarget(0,mg.size());
1313                     mg.add(LDC,d ? (Object)POINT_5_D : (Object)POINT_5_F);
1314                     mg.add(d ? DADD : FADD);
1315                     // fall through
1316                     
1317                     // Round towards minus infinity
1318                     tsi.setTarget(3,mg.size());
1319                     if(!d) mg.add(F2D);
1320                     mg.add(INVOKESTATIC,new MethodRef("java.lang.Math","floor",Type.DOUBLE,new Type[]{Type.DOUBLE}));
1321                     if(!d) mg.add(D2F);
1322                     
1323                     tsi.setTarget(1,mg.size());
1324                     tsi.setDefaultTarget(mg.size());
1325                     mg.setArg(b1,mg.size());
1326                     
1327                     mg.add(d ? D2I : F2I);
1328                     setReg();
1329                     
1330                     break;
1331                 }
1332                 case 50: // C.EQ.D
1333                 case 60: // C.LT.D
1334                 case 62: // C.LE.D
1335                     preSetReg(FCSR);
1336                     pushReg(FCSR);
1337                     mg.add(LDC,~0x800000);
1338                     mg.add(IAND);
1339                     pushDouble(F+fs,d);
1340                     pushDouble(F+ft,d);
1341                     mg.add(d ? DCMPG : FCMPG);
1342                     switch(subcode) {
1343                         case 50: b1 = mg.add(IFNE); break;
1344                         case 60: b1 = mg.add(IFGE); break;
1345                         case 62: b1 = mg.add(IFGT); break;
1346                         default: b1 = -1;
1347                     }
1348                     mg.add(LDC,0x800000);
1349                     mg.add(IOR);
1350                     mg.setArg(b1,mg.size());
1351                     setReg();
1352                     break;
1353                 default: throw new Exn("Invalid Instruction 17/" + rs + "/" + subcode);
1354                 }
1355                 break;
1356             }
1357             case 20: { // Integer
1358                 switch(subcode) {
1359                 case 32: // CVT.S.W
1360                     preSetFloat(F+fd);
1361                     pushReg(F+fs);
1362                     mg.add(I2F);
1363                     setFloat();
1364                     break;
1365                 case 33: // CVT.D.W
1366                     preSetDouble(F+fd);
1367                     pushReg(F+fs);
1368                     mg.add(I2D);
1369                     setDouble();
1370                     break;
1371                 default: throw new Exn("Invalid Instruction 17/" + rs + "/" + subcode);
1372                 }
1373                 break; 
1374             }
1375             default:
1376                 throw new Exn("Invalid Instruction 17/" + rs);
1377             }
1378             break;
1379         }
1380         case 18: case 19:
1381             throw new Exn("coprocessor 2 and 3 instructions not available");
1382         case 32: { // LB
1383             preSetReg(R+rt);
1384             addiu(R+rs,signedImmediate);
1385             setTmp();
1386             preMemRead();
1387             pushTmp();
1388             memRead(true);
1389             pushTmp();
1390             
1391             mg.add(ICONST_M1);
1392             mg.add(IXOR);
1393             mg.add(ICONST_3);
1394             mg.add(IAND);
1395             mg.add(ICONST_3);
1396             mg.add(ISHL);
1397             mg.add(IUSHR);
1398             mg.add(I2B);
1399             setReg();
1400             break; 
1401         }
1402         case 33: { // LH
1403             preSetReg(R+rt);
1404             addiu(R+rs,signedImmediate);
1405             setTmp();
1406             preMemRead();
1407             pushTmp();
1408             memRead(true);
1409             pushTmp();
1410             
1411             mg.add(ICONST_M1);
1412             mg.add(IXOR);
1413             mg.add(ICONST_2);
1414             mg.add(IAND);
1415             mg.add(ICONST_3);
1416             mg.add(ISHL);
1417             mg.add(IUSHR);
1418             mg.add(I2S);
1419             setReg();            
1420             break; 
1421         }
1422         case 34: { // LWL;
1423             preSetReg(R+rt);
1424             addiu(R+rs,signedImmediate);
1425             setTmp(); // addr
1426             
1427             pushRegWZ(R+rt);
1428             mg.add(LDC,0x00ffffff);
1429             pushTmp();
1430             
1431             mg.add(ICONST_M1);
1432             mg.add(IXOR);
1433             mg.add(ICONST_3);
1434             mg.add(IAND);
1435             mg.add(ICONST_3);
1436             mg.add(ISHL);
1437             mg.add(IUSHR);
1438             mg.add(IAND);
1439             
1440             preMemRead();
1441             pushTmp();
1442             memRead(true);
1443             pushTmp();
1444             
1445             mg.add(ICONST_3);
1446             mg.add(IAND);
1447             mg.add(ICONST_3);
1448             mg.add(ISHL);
1449             mg.add(ISHL);
1450             mg.add(IOR);
1451             
1452             setReg();
1453             
1454             break;
1455             
1456         }
1457         case 35: // LW
1458             preSetReg(R+rt);
1459             memRead(R+rs,signedImmediate);
1460             setReg();
1461             break;
1462         case 36: { // LBU
1463             preSetReg(R+rt);
1464             addiu(R+rs,signedImmediate);
1465             setTmp();
1466             preMemRead();
1467             pushTmp();
1468             memRead(true);
1469             pushTmp();
1470             
1471             mg.add(ICONST_M1);
1472             mg.add(IXOR);
1473             mg.add(ICONST_3);
1474             mg.add(IAND);
1475             mg.add(ICONST_3);
1476             mg.add(ISHL);
1477             mg.add(IUSHR);
1478             mg.add(LDC,0xff);
1479             mg.add(IAND);
1480             setReg();
1481             break; 
1482         }
1483         case 37: { // LHU
1484             preSetReg(R+rt);
1485             addiu(R+rs,signedImmediate);
1486             setTmp();
1487             preMemRead();
1488             pushTmp();
1489             memRead(true);
1490             pushTmp();
1491             
1492             mg.add(ICONST_M1);
1493             mg.add(IXOR);
1494             mg.add(ICONST_2);
1495             mg.add(IAND);
1496             mg.add(ICONST_3);
1497             mg.add(ISHL);
1498             mg.add(IUSHR);
1499             
1500             // chars are unsigend so this works
1501             mg.add(I2C);
1502             setReg();
1503             break; 
1504         }
1505         case 38: { // LWR            
1506             preSetReg(R+rt);
1507             addiu(R+rs,signedImmediate);
1508             setTmp(); // addr
1509             
1510             pushRegWZ(R+rt);
1511             mg.add(LDC,0xffffff00);
1512             pushTmp();
1513             
1514             mg.add(ICONST_3);
1515             mg.add(IAND);
1516             mg.add(ICONST_3);
1517             mg.add(ISHL);
1518             mg.add(ISHL);
1519             mg.add(IAND);
1520             
1521             preMemRead();
1522             pushTmp();
1523             memRead(true);
1524             pushTmp();
1525             
1526             mg.add(ICONST_M1);
1527             mg.add(IXOR);
1528             mg.add(ICONST_3);
1529             mg.add(IAND);
1530             mg.add(ICONST_3);
1531             mg.add(ISHL);
1532             mg.add(IUSHR);
1533             mg.add(IOR);
1534             
1535             
1536             setReg();
1537             break;
1538         }
1539         case 40: { // SB            
1540             addiu(R+rs,signedImmediate);
1541             setTmp(); // addr
1542             
1543             preMemRead(true);
1544             pushTmp();
1545             memRead(true);
1546             
1547             mg.add(LDC,0xff000000);
1548             pushTmp();
1549             
1550             mg.add(ICONST_3);
1551             mg.add(IAND);
1552             mg.add(ICONST_3);
1553             mg.add(ISHL);
1554             mg.add(IUSHR);
1555             mg.add(ICONST_M1);
1556             mg.add(IXOR);
1557             mg.add(IAND);
1558             
1559             if(rt != 0) {
1560                 pushReg(R+rt);
1561                 mg.add(LDC,0xff);
1562                 mg.add(IAND);
1563             } else {
1564                 mg.add(LDC,0);
1565             }
1566             pushTmp();
1567             
1568             mg.add(ICONST_M1);
1569             mg.add(IXOR);
1570             mg.add(ICONST_3);
1571             mg.add(IAND);
1572             mg.add(ICONST_3);
1573             mg.add(ISHL);
1574             mg.add(ISHL);
1575             mg.add(IOR);
1576             
1577             memWrite();
1578             
1579             break;
1580         }
1581         case 41: { // SH    
1582             addiu(R+rs,signedImmediate);
1583             setTmp();
1584             
1585             preMemRead(true);
1586             pushTmp();
1587             memRead(true);
1588                        
1589             mg.add(LDC,0xffff);
1590             pushTmp();
1591             
1592             mg.add(ICONST_2);
1593             mg.add(IAND);
1594             mg.add(ICONST_3);
1595             mg.add(ISHL);
1596             mg.add(ISHL);
1597             mg.add(IAND);
1598             
1599             if(rt != 0) {
1600                 pushReg(R+rt);
1601                 mg.add(LDC,0xffff);
1602                 mg.add(IAND);
1603             } else {
1604                 mg.add(LDC,0);
1605             }
1606             pushTmp();
1607             
1608             mg.add(ICONST_M1);
1609             mg.add(IXOR);
1610             mg.add(ICONST_2);
1611             mg.add(IAND);
1612             mg.add(ICONST_3);
1613             mg.add(ISHL);
1614             mg.add(ISHL);
1615             mg.add(IOR);
1616             
1617             memWrite();
1618             
1619             break;            
1620         }
1621         case 42: { // SWL
1622             addiu(R+rs,signedImmediate);
1623             setTmp();
1624             
1625             preMemRead(true);            
1626             pushTmp();
1627             memRead(true);
1628             
1629             mg.add(LDC,0xffffff00);
1630             pushTmp();
1631             
1632             mg.add(ICONST_M1);
1633             mg.add(IXOR);
1634             mg.add(ICONST_3);
1635             mg.add(IAND);
1636             mg.add(ICONST_3);
1637             mg.add(ISHL);
1638             mg.add(ISHL);
1639             mg.add(IAND);
1640             
1641             pushRegWZ(R+rt);
1642             pushTmp();
1643             
1644             mg.add(ICONST_3);
1645             mg.add(IAND);
1646             mg.add(ICONST_3);
1647             mg.add(ISHL);
1648             mg.add(IUSHR);
1649             mg.add(IOR);
1650             
1651             memWrite();
1652             break;
1653             
1654         }
1655         case 43: // SW
1656             preMemWrite1();
1657             preMemWrite2(R+rs,signedImmediate);
1658             pushRegZ(R+rt);
1659             memWrite();
1660             break;
1661         case 46: { // SWR
1662             addiu(R+rs,signedImmediate);
1663             setTmp();
1664             
1665             preMemRead(true);
1666             pushTmp();
1667             memRead(true);
1668             
1669             mg.add(LDC,0x00ffffff);
1670             pushTmp();
1671             
1672             mg.add(ICONST_3);
1673             mg.add(IAND);
1674             mg.add(ICONST_3);
1675             mg.add(ISHL);
1676             mg.add(IUSHR);
1677             mg.add(IAND);
1678             
1679             pushRegWZ(R+rt);
1680             pushTmp();
1681             
1682             mg.add(ICONST_M1);
1683             mg.add(IXOR);
1684             mg.add(ICONST_3);
1685             mg.add(IAND);
1686             mg.add(ICONST_3);
1687             mg.add(ISHL);
1688             mg.add(ISHL);
1689             mg.add(IOR);
1690                     
1691             memWrite();
1692             break;
1693         }
1694         // This need to be atomic if we ever support threads (see SWC0/SC)
1695         case 48: // LWC0/LL
1696             preSetReg(R+rt);
1697             memRead(R+rs,signedImmediate);
1698             setReg();
1699             break;
1700             
1701         case 49: // LWC1
1702             preSetReg(F+rt);
1703             memRead(R+rs,signedImmediate);
1704             setReg();
1705             break;
1706         
1707         /* This needs to fail (set rt to 0) if the memory location was modified
1708          * between the LL and SC if we ever support threads.
1709          */
1710         case 56: // SWC0/SC
1711             preSetReg(R+rt);
1712             preMemWrite1();
1713             preMemWrite2(R+rs,signedImmediate);
1714             pushReg(R+rt);
1715             memWrite();
1716             mg.add(LDC,1);
1717             setReg();
1718             break;
1719             
1720         case 57: // SWC1
1721             preMemWrite1();
1722             preMemWrite2(R+rs,signedImmediate);
1723             pushReg(F+rt);
1724             memWrite();
1725             break;
1726         default:
1727             throw new Exn("Invalid Instruction: " + op + " at " + toHex(pc));
1728         }
1729         return ret; 
1730     }
1731     
1732     // Helper functions for emitText
1733     
1734     private static final int R = 0;
1735     private static final int F = 32;
1736     private static final int HI = 64;
1737     private static final int LO = 65;
1738     private static final int FCSR = 66;
1739     private static final int REG_COUNT=67;
1740     private static final String[] regField = {
1741             "r0","r1","r2","r3","r4","r5","r6","r7",
1742             "r8","r9","r10","r11","r12","r13","r14","r15",
1743             "r16","r17","r18","r19","r20","r21","r22","r23",
1744             "r24","r25","r26","r27","r28","r29","r30","r31",
1745             "f0","f1","f2","f3","f4","f5","f6","f7",
1746             "f8","f9","f10","f11","f12","f13","f14","f15",
1747             "f16","f17","f18","f19","f20","f21","f22","f23",
1748             "f24","f25","f26","f27","f28","f29","f30","f31",
1749             "hi","lo","fcsr"
1750     };
1751     private static final int MAX_LOCALS = 4; // doLocal can return true for this many regs
1752     private static final int LOAD_LENGTH = 3; // number of instructions needed to load a field to a reg
1753     
1754     // Local register state info
1755     private int[] regLocalMapping = new int[REG_COUNT];  
1756     private boolean[] regLocalWritten = new boolean[REG_COUNT];
1757     private int nextAvailLocal;
1758     private int loadsStart;
1759     
1760     private boolean doLocal(int reg) {
1761         return reg == R+2 || reg == R+3 || reg == R+4 || reg == R+29;
1762     }
1763     
1764     private int getLocalForReg(int reg) {
1765         if(regLocalMapping[reg] != 0) return regLocalMapping[reg];
1766         regLocalMapping[reg] = nextAvailLocal++;
1767         return regLocalMapping[reg];
1768     }
1769     
1770     private void fixupRegsStart() {
1771         for(int i=0;i<REG_COUNT;i++) {
1772             regLocalMapping[i] = 0;
1773             regLocalWritten[i] = false;
1774         }
1775         nextAvailLocal = onePage ? 4 : 5;
1776         loadsStart = mg.size();
1777         for(int i=0;i<MAX_LOCALS*LOAD_LENGTH;i++)
1778             mg.add(NOP);
1779     }
1780     
1781     private void fixupRegsEnd() {
1782         int p = loadsStart;
1783         for(int i=0;i<REG_COUNT;i++) {
1784             if(regLocalMapping[i] == 0) continue;
1785             mg.set(p++,ALOAD_0);
1786             mg.set(p++,GETFIELD,new FieldRef(me,regField[i],Type.INT));
1787             mg.set(p++,ISTORE,regLocalMapping[i]);
1788             
1789             if(regLocalWritten[i]) {
1790                 mg.add(ALOAD_0);
1791                 mg.add(ILOAD,regLocalMapping[i]);
1792                 mg.add(PUTFIELD,new FieldRef(me,regField[i],Type.INT));
1793             }
1794         }
1795     }
1796         
1797     private void restoreChangedRegs() {
1798         for(int i=0;i<REG_COUNT;i++) {
1799             if(regLocalWritten[i]) {
1800                 mg.add(ALOAD_0);
1801                 mg.add(ILOAD,regLocalMapping[i]);
1802                 mg.add(PUTFIELD,new FieldRef(me,regField[i],Type.INT));
1803             }
1804         }
1805     }
1806             
1807     private int pushRegWZ(int reg) {
1808         if(reg == R+0) {
1809             warn.println("Warning: Pushing r0!");
1810             new Exception().printStackTrace(warn);
1811         }
1812         return pushRegZ(reg);
1813     }
1814     
1815     private int pushRegZ(int reg) {
1816         if(reg == R+0) return mg.add(ICONST_0);
1817         else return pushReg(reg);
1818     }
1819     
1820     
1821     private int pushReg(int reg) {
1822         int h = mg.size();
1823         if(doLocal(reg)) {
1824             mg.add(ILOAD,getLocalForReg(reg));
1825         } else if(reg >= F+0 && reg <= F+31 && singleFloat) {
1826             mg.add(ALOAD_0);
1827             mg.add(GETFIELD,new FieldRef(me,regField[reg],Type.FLOAT));
1828             mg.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"floatToIntBits",Type.INT,new Type[]{Type.FLOAT}));
1829         } else {
1830             mg.add(ALOAD_0);
1831             mg.add(GETFIELD,new FieldRef(me,regField[reg],Type.INT));
1832         }
1833         return h;
1834     }
1835     
1836     private int preSetRegStackPos;
1837     private int[] preSetRegStack = new int[8];
1838     
1839     // This can push ONE or ZERO words to the stack. If it pushed one it returns true
1840     private boolean preSetReg(int reg) {
1841         preSetRegStack[preSetRegStackPos] = reg;
1842         preSetRegStackPos++;
1843         if(doLocal(reg)) {
1844             return false;
1845         } else {
1846             mg.add(ALOAD_0);
1847             return true;
1848         }
1849     }
1850     
1851     private int setReg() {
1852         if(preSetRegStackPos==0) throw new RuntimeException("didn't do preSetReg");
1853         preSetRegStackPos--;
1854         int reg = preSetRegStack[preSetRegStackPos];
1855         int h = mg.size();
1856         if(doLocal(reg)) {
1857             mg.add(ISTORE,getLocalForReg(reg));
1858             regLocalWritten[reg] = true;
1859         } else if(reg >= F+0 && reg <= F+31 && singleFloat) {
1860             mg.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"intBitsToFloat",Type.FLOAT,new Type[]{Type.INT}));
1861             mg.add(PUTFIELD,new FieldRef(me,regField[reg],Type.FLOAT));            
1862         } else {
1863             mg.add(PUTFIELD,new FieldRef(me,regField[reg],Type.INT));
1864         }
1865         return h;
1866     }
1867     
1868     private int preSetPC() { return mg.add(ALOAD_0); }
1869     private int setPC() {
1870         return mg.add(PUTFIELD,new FieldRef(me,"pc",Type.INT));
1871     }
1872     
1873     //unused - private InstructionHandle pushDouble(int reg) throws CompilationException { return pushDouble(reg,true); }
1874     private int pushFloat(int reg) throws Exn { return pushDouble(reg,false); }
1875     private int pushDouble(int reg, boolean d) throws Exn {
1876         if(reg < F || reg >= F+32) throw new IllegalArgumentException(""+reg);
1877         int h = mg.size();
1878         if(d) {
1879             if(singleFloat) throw new Exn("Double operations not supported when singleFloat is enabled");
1880             if(reg == F+31) throw new Exn("Tried to use a double in f31");
1881             pushReg(reg+1);
1882             mg.add(I2L);
1883             mg.add(LDC,32);
1884             mg.add(LSHL);
1885             pushReg(reg);
1886             mg.add(I2L);
1887             mg.add(LDC,FFFFFFFF);
1888             mg.add(LAND);
1889             mg.add(LOR);
1890             mg.add(INVOKESTATIC,new MethodRef(Type.DOUBLE_OBJECT,"longBitsToDouble",Type.DOUBLE,new Type[]{Type.LONG}));
1891         } else if(singleFloat) {
1892             mg.add(ALOAD_0);
1893             mg.add(GETFIELD,new FieldRef(me,regField[reg],Type.FLOAT));
1894         } else {
1895             pushReg(reg);
1896             mg.add(INVOKESTATIC,new MethodRef("java.lang.Float","intBitsToFloat",Type.FLOAT,new Type[]{Type.INT}));
1897         }
1898         return h;
1899     }
1900     
1901     private void preSetFloat(int reg) { preSetDouble(reg,false); }
1902     private void preSetDouble(int reg) { preSetDouble(reg,true); }
1903     private void preSetDouble(int reg, boolean d) { preSetReg(reg); }
1904     
1905     private int setFloat() throws Exn { return setDouble(false); }
1906     private int setDouble() throws Exn { return setDouble(true); }
1907     private int setDouble(boolean d) throws Exn {
1908         int reg = preSetRegStack[preSetRegStackPos-1];
1909         if(reg < F || reg >= F+32) throw new IllegalArgumentException(""+reg);
1910         int h = mg.size();
1911         if(d) {
1912             if(singleFloat) throw new Exn("Double operations not supported when singleFloat is enabled");
1913             if(reg == F+31) throw new Exn("Tried to use a double in f31");
1914             mg.add(INVOKESTATIC,new MethodRef(Type.DOUBLE_OBJECT,"doubleToLongBits",Type.LONG,new Type[]{Type.DOUBLE}));
1915             mg.add(DUP2);
1916             mg.add(LDC,32);
1917             mg.add(LUSHR);
1918             mg.add(L2I);
1919             if(preSetReg(reg+1))
1920                 mg.add(SWAP);
1921             setReg();
1922             mg.add(L2I);
1923             setReg(); // preSetReg was already done for this by preSetDouble
1924         } else if(singleFloat) {
1925             // HACK: Clean this up
1926             preSetRegStackPos--;
1927             mg.add(PUTFIELD,new FieldRef(me,regField[reg],Type.FLOAT));
1928         } else {
1929             //h = a(fac.createInvoke("java.lang.Float","floatToRawIntBits",Type.INT,new Type[]{Type.FLOAT},INVOKESTATIC));
1930             mg.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"floatToRawIntBits",Type.INT,new Type[]{Type.FLOAT}));
1931             setReg();   
1932         }
1933         return h;
1934     }
1935     
1936     private void pushTmp() { mg.add(ILOAD_1); }
1937     private void setTmp() { mg.add(ISTORE_1); }
1938     
1939     private void addiu(int reg, int offset) {
1940         if(reg != R+0 && offset != 0) {
1941             pushReg(reg);
1942             mg.add(LDC,offset);
1943             mg.add(IADD);
1944         } else if(reg != R+0) {
1945             pushReg(reg);
1946         } else {
1947             mg.add(LDC,offset);
1948         }        
1949     }
1950     private int memWriteStage;
1951     private void preMemWrite1() {
1952         if(memWriteStage!=0) throw new Error("pending preMemWrite1/2");
1953         memWriteStage=1;
1954         if(onePage)
1955             mg.add(ALOAD_2);
1956         else if(fastMem)
1957             mg.add(ALOAD,3);
1958         else
1959             mg.add(ALOAD_0);
1960     }
1961     
1962     private void preMemWrite2(int reg, int offset) {
1963         addiu(reg,offset);
1964         preMemWrite2();
1965     }
1966     
1967     private void preMemWrite2() { preMemWrite2(false); }
1968     private void preMemWrite2(boolean addrInTmp) {
1969         if(memWriteStage!=1) throw new Error("pending preMemWrite2 or no preMemWrite1");
1970         memWriteStage=2;
1971         
1972         if(nullPointerCheck) {
1973             mg.add(DUP);
1974             mg.add(ALOAD_0);
1975             mg.add(SWAP);
1976             // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.nullPointerCheck
1977             mg.add(INVOKEVIRTUAL,new MethodRef(me,"nullPointerCheck",Type.VOID,new Type[]{Type.INT}));
1978         }
1979         
1980         if(onePage) {
1981             mg.add(ICONST_2);
1982             mg.add(IUSHR);
1983         } else if(fastMem) {
1984             if(!addrInTmp)
1985                 mg.add(DUP_X1);
1986             mg.add(LDC,pageShift);
1987             mg.add(IUSHR);
1988             mg.add(AALOAD);
1989             if(addrInTmp)
1990                 pushTmp();
1991             else
1992                 mg.add(SWAP);
1993             mg.add(ICONST_2);
1994             mg.add(IUSHR);
1995             mg.add(LDC,(pageSize>>2)-1);
1996             mg.add(IAND);            
1997         }
1998     }
1999     
2000     // pops an address and value off the stack, sets *addr to value
2001     private void memWrite() {
2002         if(memWriteStage!=2) throw new Error("didn't do preMemWrite1 or preMemWrite2");
2003         memWriteStage=0;
2004                 
2005         if(onePage) {
2006             mg.add(IASTORE);
2007         } else if(fastMem) {
2008             mg.add(IASTORE);
2009         } else {
2010             // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.unsafeMemWrite
2011             mg.add(INVOKEVIRTUAL,new MethodRef(me,"unsafeMemWrite",Type.VOID,new Type[]{Type.INT,Type.INT}));
2012         }
2013         
2014     }
2015     
2016     // reads the word at r[reg]+offset
2017     private void memRead(int reg, int offset) {
2018         preMemRead();
2019         addiu(reg,offset);
2020         memRead();
2021     }
2022     
2023     private boolean didPreMemRead;
2024     private boolean preMemReadDoPreWrite;
2025     
2026     private void preMemRead() { preMemRead(false); }
2027     private void preMemRead(boolean preWrite) {
2028         if(didPreMemRead) throw new Error("pending preMemRead");
2029         didPreMemRead = true;
2030         preMemReadDoPreWrite = preWrite;
2031         if(onePage)
2032             mg.add(ALOAD_2);
2033         else if(fastMem)
2034             mg.add(ALOAD,preWrite ? 3 : 2);
2035         else
2036             mg.add(ALOAD_0);
2037     }
2038     // memRead pops an address off the stack, reads the value at that addr, and pushed the value
2039     // preMemRead MUST be called BEFORE the addresses is pushed
2040     private void memRead() { memRead(false); }
2041     
2042     private void memRead(boolean addrInTmp) {
2043         if(!didPreMemRead) throw new Error("didn't do preMemRead");
2044         didPreMemRead = false;
2045         if(preMemReadDoPreWrite)
2046             memWriteStage=2; 
2047             
2048         if(nullPointerCheck) {
2049             mg.add(DUP);
2050             mg.add(ALOAD_0);
2051             mg.add(SWAP);
2052             mg.add(INVOKEVIRTUAL,new MethodRef(me,"nullPointerCheck",Type.VOID,new Type[]{Type.INT}));
2053         }
2054         
2055         if(onePage) {
2056             mg.add(ICONST_2);
2057             mg.add(IUSHR);
2058             if(preMemReadDoPreWrite)
2059                 mg.add(DUP2);
2060             mg.add(IALOAD);
2061         } else if(fastMem) {
2062             if(!addrInTmp)
2063                 mg.add(DUP_X1);
2064             mg.add(LDC,pageShift);
2065             mg.add(IUSHR);
2066             mg.add(AALOAD);
2067             if(addrInTmp)
2068                 pushTmp();
2069             else
2070                 mg.add(SWAP);
2071             mg.add(ICONST_2);
2072             mg.add(IUSHR);
2073             mg.add(LDC,(pageSize>>2)-1);
2074             mg.add(IAND);
2075             if(preMemReadDoPreWrite)
2076                 mg.add(DUP2);
2077             mg.add(IALOAD);
2078             
2079         } else {
2080             if(preMemReadDoPreWrite)
2081                 mg.add(DUP2);
2082             // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.unsafeMemRead
2083             mg.add(INVOKEVIRTUAL,new MethodRef(me,"unsafeMemRead",Type.INT,new Type[]{Type.INT}));
2084         }
2085     }
2086     
2087     
2088     // This might come in handy for something else
2089     /*private boolean touchesReg(int insn, int reg) {
2090         if((reg < R+0 || reg >= R+32) && reg != FCSR) throw new IllegalArgumentException(""+reg);
2091         if(reg == R+0) return false; // r0 is never modified
2092         int op = (insn >>> 26) & 0xff;                 // bits 26-31
2093         int subcode = insn & 0x3f;                     // bits 0-5 
2094         int rd = (insn >>> 11) & 0x1f;                 // bits 11-15
2095         int rt = (insn >>> 16) & 0x1f;                 // bits 16-20 
2096         int rs = (insn >>> 21) & 0x1f;                 // bits 21-25
2097         
2098         switch(op) {
2099         case 0:
2100             if(subcode >= 0 && subcode <= 7) return reg == R+rd; // Shift ops
2101             if(subcode >= 32 && subcode <= 43) return reg == R+rd; // Other math ops 
2102             if(subcode >= 24 && subcode <= 27) return reg == HI || reg == LO; // MULT/DIV
2103             break;
2104         case 13: return false; // BREAK
2105         case 17:
2106             switch(rs) {
2107                 case 0: return reg == R+rt; // MFC.1
2108                 case 2: return reg == R+rt; // CFC.1
2109                 case 4: return false; // MTC.1
2110                 case 6: return false; // CTC.1
2111                 case 16: // Single 
2112                 case 17: // Double
2113                     if(subcode == 50 || subcode == 60 || subcode == 62) return reg == FCSR;
2114                     return false; // everything else just touches f0-f31
2115                 case 20: return false; // Integer - just touches f0-f31
2116             }
2117             break;
2118         default:
2119             if(op >= 8 && op <= 15) return reg == R+rt; // XXXI instructions
2120             if(op >= 40 && op <= 46) return false; // Memory WRITE ops
2121             if(op == 49) return reg == F+rt; // LWC1
2122             if(op == 57) return false; // SWC1
2123             break;
2124         }
2125         warn.println("Unknown instruction in touchesReg()- assuming it modifies all regs " + op + " " + subcode);
2126         new Exception().fillInStackTrace().printStackTrace(warn);
2127         return true;
2128     }*/
2129 }