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