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