bugfix for jumpable delay slot
[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             insnTargets[(pc+4-startOfMethod)/4].setTarget(mg.size());
562             emitInstruction(-1,nextInsn,01); // delay slot
563             mg.setArg(b,mg.size());
564             
565             return true;
566         }
567     }
568     
569     private static final Float POINT_5_F = new Float(0.5f);
570     private static final Double POINT_5_D = new Double(0.5f);
571     private static final Long FFFFFFFF = new Long(0xffffffffL);
572     
573     private boolean emitInstruction(int pc, int insn, int nextInsn) throws Exn {
574         MethodGen mg = this.mg; // smaller bytecode
575         if(insn == -1) throw new Exn("insn is -1");
576         
577         int op = (insn >>> 26) & 0xff;                 // bits 26-31
578         int rs = (insn >>> 21) & 0x1f;                 // bits 21-25
579         int rt = (insn >>> 16) & 0x1f;                 // bits 16-20 
580         int ft = (insn >>> 16) & 0x1f;
581         int rd = (insn >>> 11) & 0x1f;                 // bits 11-15
582         int fs = (insn >>> 11) & 0x1f;
583         int shamt = (insn >>> 6) & 0x1f;               // bits 6-10
584         int fd = (insn >>> 6) & 0x1f;
585         int subcode = insn & 0x3f;                     // bits 0-5 
586         int breakCode = (insn >>> 6) & 0xfffff;         // bits 6-20
587
588         int jumpTarget = (insn & 0x03ffffff);          // bits 0-25
589         int unsignedImmediate = insn & 0xffff;
590         int signedImmediate = (insn << 16) >> 16;
591         int branchTarget = signedImmediate;
592
593         // temporaries
594         int b1,b2;
595         
596         switch(op) {
597         case 0: {
598             switch(subcode) {
599             case 0: // SLL
600                 if(insn == 0) break; 
601                 preSetReg(R+rd);
602                 pushRegWZ(R+rt);
603                 mg.add(LDC,shamt);
604                 mg.add(ISHL);
605                 setReg();
606                 break;
607             case 2: // SRL
608                 preSetReg(R+rd);
609                 pushRegWZ(R+rt);
610                 mg.add(LDC,shamt);
611                 mg.add(IUSHR);
612                 setReg();
613                 break;
614             case 3: // SRA
615                 preSetReg(R+rd);
616                 pushRegWZ(R+rt);
617                 mg.add(LDC,shamt);
618                 mg.add(ISHR);
619                 setReg();
620                 break;
621             case 4: // SLLV
622                 preSetReg(R+rd);
623                 pushRegWZ(R+rt);
624                 pushRegWZ(R+rs);
625                 mg.add(ISHL);
626                 setReg();
627                 break;
628             case 6: // SRLV
629                 preSetReg(R+rd);
630                 pushRegWZ(R+rt);
631                 pushRegWZ(R+rs);
632                 mg.add(IUSHR);
633                 setReg();
634                 break;
635             case 7: // SRAV
636                 preSetReg(R+rd);
637                 pushRegWZ(R+rt);
638                 pushRegWZ(R+rs);
639                 mg.add(ISHR);
640                 setReg();
641                 break;
642             case 8: // JR
643                 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
644                 emitInstruction(-1,nextInsn,-1);
645                 preSetPC();
646                 pushRegWZ(R+rs);
647                 setPC();
648                 leaveMethod();
649                 unreachable = true;
650                 break;
651             case 9: // JALR
652                 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
653                 emitInstruction(-1,nextInsn,-1);
654                 preSetPC();
655                 pushRegWZ(R+rs);
656                 setPC();
657                 
658                 preSetReg(R+RA);
659                 mg.add(LDC,pc+8);
660                 setReg();
661                 leaveMethod();
662                 unreachable = true;
663                 break;
664             case 12: // SYSCALL
665                 preSetPC();
666                 mg.add(LDC,pc);
667                 setPC();
668                 
669                 // FEATURE: This is actually broken, but it happens to work for our code
670                 // a func could theoretically jump back to here from a future point
671                 restoreChangedRegs();
672                 
673                 preSetReg(R+V0);
674                 mg.add(ALOAD_0);
675                 pushRegZ(R+V0);
676                 pushRegZ(R+A0);
677                 pushRegZ(R+A1);
678                 pushRegZ(R+A2);
679                 pushRegZ(R+A3);
680                 pushRegZ(R+T0);
681                 pushRegZ(R+T1);
682                 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}));
683                 setReg();
684                 
685                 mg.add(ALOAD_0);
686                 mg.add(GETFIELD,new FieldRef(me,"state",Type.INT));
687                 b1 = mg.add(IFEQ);
688                 preSetPC();
689                 mg.add(LDC,pc+4);
690                 setPC();
691                 leaveMethod();
692                 mg.setArg(b1,mg.size());
693                 break;
694             case 13: // BREAK
695                 mg.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
696                 mg.add(DUP);
697                 mg.add(LDC,"BREAK Code " + toHex(breakCode));
698                 mg.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"<init>",Type.VOID,new Type[]{Type.STRING}));
699                 mg.add(ATHROW);
700                 unreachable = true;
701                 break;
702             case 16: // MFHI
703                 preSetReg(R+rd);
704                 pushReg(HI);
705                 setReg();
706                 break;
707             case 17: // MTHI
708                 preSetReg(HI);
709                 pushRegZ(R+rs);
710                 setReg();
711                 break;
712             case 18: // MFLO
713                 preSetReg(R+rd);
714                 pushReg(LO);
715                 setReg();
716                 break;
717             case 19: // MTLO
718                 preSetReg(LO);
719                 pushRegZ(R+rs);
720                 setReg();
721                 break;
722             case 24: // MULT
723                 pushRegWZ(R+rs);
724                 mg.add(I2L);
725                 pushRegWZ(R+rt);
726                 mg.add(I2L);
727                 mg.add(LMUL);
728                 mg.add(DUP2);
729                 
730                 mg.add(L2I);
731                 if(preSetReg(LO))
732                     mg.add(SWAP); //a(InstructionConstants.SWAP);
733                 setReg();
734                 
735                 mg.add(LDC,32);
736                 mg.add(LUSHR);
737                 mg.add(L2I);
738                 if(preSetReg(HI))
739                     mg.add(SWAP); //a(InstructionConstants.SWAP);
740                 setReg();
741                 
742                 break;
743             case 25: // MULTU
744                 pushRegWZ(R+rs);
745                 mg.add(I2L);
746                 mg.add(LDC,FFFFFFFF);
747                 mg.add(LAND);
748                 pushRegWZ(R+rt);
749                 mg.add(I2L);
750                 mg.add(LDC,FFFFFFFF);
751                 mg.add(LAND);
752                 mg.add(LMUL);
753                 mg.add(DUP2);
754                 
755                 mg.add(L2I);
756                 if(preSetReg(LO))
757                     mg.add(SWAP);
758                 setReg();
759                 
760                 mg.add(LDC,32);
761                 mg.add(LUSHR);
762                 mg.add(L2I);
763                 if(preSetReg(HI))
764                     mg.add(SWAP);
765                 setReg();
766                 
767                 break;
768             case 26: // DIV
769                 pushRegWZ(R+rs);
770                 pushRegWZ(R+rt);
771                 mg.add(DUP2);
772                 
773                 mg.add(IDIV);
774                 if(preSetReg(LO))
775                     mg.add(SWAP);
776                 setReg();
777                 
778                 mg.add(IREM);
779                 if(preSetReg(HI))
780                     mg.add(SWAP);
781                 setReg();
782                 
783                 break;
784             case 27: { // DIVU
785                 pushRegWZ(R+rt);
786                 mg.add(DUP);
787                 setTmp();
788                 b1 = mg.add(IFEQ);
789                 
790                 pushRegWZ(R+rs);
791                 mg.add(I2L);
792                 mg.add(LDC,FFFFFFFF);
793                 mg.add(LAND);
794                 mg.add(DUP2);
795                 pushTmp();
796                 mg.add(I2L);
797                 mg.add(LDC,FFFFFFFF);
798                 
799                 mg.add(LAND);
800                 mg.add(DUP2_X2);
801                 mg.add(LDIV);
802                 
803                 mg.add(L2I);
804                 if(preSetReg(LO))
805                     mg.add(SWAP);
806                 setReg();
807                 
808                 mg.add(LREM);
809                 mg.add(L2I);
810                 if(preSetReg(HI))
811                     mg.add(SWAP);
812                 setReg();
813                 
814                 mg.setArg(b1,mg.size());
815                 
816                 break;
817             }
818             case 32: // ADD
819                 throw new Exn("ADD (add with oveflow trap) not suported");
820             case 33: // ADDU
821                 preSetReg(R+rd);
822                 if(rt != 0 && rs != 0) {
823                     pushReg(R+rs);
824                     pushReg(R+rt);
825                     mg.add(IADD);
826                 } else if(rs != 0) {
827                     pushReg(R+rs);
828                 } else {
829                     pushRegZ(R+rt);
830                 }
831                 setReg();
832                 break;
833             case 34: // SUB
834                 throw new Exn("SUB (add with oveflow trap) not suported");
835             case 35: // SUBU
836                 preSetReg(R+rd);
837                 if(rt != 0 && rs != 0) {
838                     pushReg(R+rs);
839                     pushReg(R+rt);
840                     mg.add(ISUB);
841                 } else if(rt != 0) {
842                     pushReg(R+rt);
843                     mg.add(INEG);
844                 } else {
845                     pushRegZ(R+rs);
846                 }
847                 setReg();                
848                 break;
849             case 36: // AND
850                 preSetReg(R+rd);
851                 pushRegWZ(R+rs);
852                 pushRegWZ(R+rt);
853                 mg.add(IAND);
854                 setReg();
855                 break;
856             case 37: // OR
857                 preSetReg(R+rd);
858                 pushRegWZ(R+rs);
859                 pushRegWZ(R+rt);
860                 mg.add(IOR);
861                 setReg();
862                 break;
863             case 38: // XOR
864                 preSetReg(R+rd);
865                 pushRegWZ(R+rs);
866                 pushRegWZ(R+rt);
867                 mg.add(IXOR);
868                 setReg();
869                 break;
870             case 39: // NOR
871                 preSetReg(R+rd);
872                 if(rs != 0 || rt != 0) {
873                     if(rs != 0 && rt != 0) {
874                         pushReg(R+rs);
875                         pushReg(R+rt);
876                         mg.add(IOR);
877                     } else if(rs != 0) {
878                         pushReg(R+rs);
879                     } else {
880                         pushReg(R+rt);
881                     }
882                     mg.add(ICONST_M1);
883                     mg.add(IXOR);
884                 } else {
885                     mg.add(LDC,-1);
886                 }
887                 setReg();
888                 break;
889             case 42: // SLT
890                 preSetReg(R+rd);
891                 if(rs != rt) {
892                     pushRegZ(R+rs);
893                     pushRegZ(R+rt);
894                     b1 = mg.add(IF_ICMPLT);
895                     mg.add(ICONST_0);
896                     b2 = mg.add(GOTO);
897                     mg.setArg(b1,mg.add(ICONST_1));
898                     mg.setArg(b2,mg.size());
899                 } else {
900                     mg.add(LDC,0);
901                 }
902                 setReg();
903                 break;
904             case 43: // SLTU
905                 preSetReg(R+rd);
906                 if(rs != rt) {
907                     if(rs != 0) {
908                         pushReg(R+rs);
909                         mg.add(I2L);
910                         mg.add(LDC,FFFFFFFF);
911                         mg.add(LAND);
912                         pushReg(R+rt);
913                         mg.add(I2L);
914                         mg.add(LDC,FFFFFFFF);
915                         mg.add(LAND);
916                         mg.add(LCMP);
917                         b1 = mg.add(IFLT);
918                     } else {
919                         pushReg(R+rt);
920                         b1 = mg.add(IFNE);
921                     }
922                     mg.add(ICONST_0);
923                     b2 = mg.add(GOTO);
924                     mg.setArg(b1,mg.add(ICONST_1));
925                     mg.setArg(b2,mg.size());
926                 } else {
927                     mg.add(LDC,0);
928                 }
929                 setReg();
930                 break;
931             default:
932                 throw new Exn("Illegal instruction 0/" + subcode);
933             }
934             break;
935         }
936         case 1: {
937             switch(rt) {
938             case 0: // BLTZ
939                 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
940                 pushRegWZ(R+rs);
941                 return doIfInstruction(IFLT,pc,pc+branchTarget*4+4,nextInsn);
942             case 1: // BGEZ
943                 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
944                 pushRegWZ(R+rs);
945                 return doIfInstruction(IFGE,pc,pc+branchTarget*4+4,nextInsn);
946             case 16: // BLTZAL
947                 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
948                 pushRegWZ(R+rs);
949                 b1 = mg.add(IFGE);
950                 emitInstruction(-1,nextInsn,-1);
951                 preSetReg(R+RA);
952                 mg.add(LDC,pc+8);
953                 setReg();
954                 branch(pc,pc+branchTarget*4+4);
955                 mg.setArg(b1,mg.size());
956                 break;
957             case 17: // BGEZAL
958                 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
959                 b1 = -1;
960                 if(rs != 0) { // r0 is always >= 0
961                     pushRegWZ(R+rs);
962                     b1 = mg.add(IFLT);
963                 }
964                 emitInstruction(-1,nextInsn,-1);
965                 preSetReg(R+RA);
966                 mg.add(LDC,pc+8);
967                 setReg();
968                 branch(pc,pc+branchTarget*4+4);
969                 if(b1 != -1) mg.setArg(b1,mg.size());
970                 if(b1 == -1) unreachable = true;
971                 break;
972             default:
973                 throw new Exn("Illegal Instruction 1/" + rt);
974             }
975             break;
976         }
977         case 2: { // J
978             if(pc == -1) throw new Exn("pc modifying insn in delay slot");
979             emitInstruction(-1,nextInsn,-1);
980             branch(pc,(pc&0xf0000000)|(jumpTarget << 2));
981             unreachable = true;
982             break;
983         }
984         case 3: { // JAL
985             if(pc == -1) throw new Exn("pc modifying insn in delay slot");
986             int target = (pc&0xf0000000)|(jumpTarget << 2);
987             emitInstruction(-1,nextInsn,-1);
988             preSetReg(R+RA);
989             mg.add(LDC,pc+8);
990             setReg();
991             branch(pc, target);
992             unreachable = true;
993             break;
994         }
995         case 4: // BEQ
996             if(pc == -1) throw new Exn("pc modifying insn in delay slot");
997             if(rs == rt) {
998                 emitInstruction(-1,nextInsn,-1);
999                 branch(pc,pc+branchTarget*4+4);
1000                 unreachable = true;
1001             } else if(rs == 0 || rt == 0) {
1002                 pushReg(rt == 0 ? R+rs : R+rt);
1003                 return doIfInstruction(IFEQ,pc,pc+branchTarget*4+4,nextInsn);
1004             } else {
1005                 pushReg(R+rs);
1006                 pushReg(R+rt);
1007                 return doIfInstruction(IF_ICMPEQ,pc,pc+branchTarget*4+4,nextInsn);
1008             }
1009             break;
1010         case 5: // BNE       
1011             if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1012             pushRegWZ(R+rs);
1013             if(rt == 0) {
1014                 return doIfInstruction(IFNE,pc,pc+branchTarget*4+4,nextInsn);
1015             } else {
1016                 pushReg(R+rt);
1017                 return doIfInstruction(IF_ICMPNE,pc,pc+branchTarget*4+4,nextInsn);
1018             }
1019         case 6: //BLEZ
1020             if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1021             pushRegWZ(R+rs);
1022             return doIfInstruction(IFLE,pc,pc+branchTarget*4+4,nextInsn);
1023         case 7: //BGTZ
1024             if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1025             pushRegWZ(R+rs);
1026             return doIfInstruction(IFGT,pc,pc+branchTarget*4+4,nextInsn);
1027         case 8: // ADDI
1028             throw new Exn("ADDI (add immediate with oveflow trap) not suported");
1029         case 9: // ADDIU
1030             preSetReg(R+rt);
1031             addiu(rs,signedImmediate);
1032             setReg();            
1033             break;
1034         case 10: // SLTI
1035             preSetReg(R+rt);
1036             pushRegWZ(R+rs);
1037             mg.add(LDC,signedImmediate);
1038             b1 = mg.add(IF_ICMPLT);
1039             mg.add(ICONST_0);
1040             b2 = mg.add(GOTO);
1041             mg.setArg(b1,mg.add(ICONST_1));
1042             mg.setArg(b2,mg.size());
1043             setReg();
1044             break;
1045         case 11: // SLTIU
1046             preSetReg(R+rt);
1047             pushRegWZ(R+rs);
1048             mg.add(I2L);
1049             mg.add(LDC,FFFFFFFF);
1050             mg.add(LAND);
1051             // Yes, this is correct, you have to sign extend the immediate then do an UNSIGNED comparison
1052             mg.add(LDC,new Long(signedImmediate&0xffffffffL));
1053             mg.add(LCMP);
1054             
1055             b1 = mg.add(IFLT);
1056             mg.add(ICONST_0);
1057             b2 = mg.add(GOTO);
1058             mg.setArg(b1,mg.add(ICONST_1));
1059             mg.setArg(b2,mg.size());            
1060             setReg();
1061             break;            
1062         case 12: // ANDI
1063             preSetReg(R+rt);
1064             pushRegWZ(R+rs);
1065             mg.add(LDC,unsignedImmediate);
1066             mg.add(IAND);
1067             setReg();
1068             break;
1069         case 13: // ORI
1070             preSetReg(R+rt);
1071             if(rs != 0 && unsignedImmediate != 0) {
1072                 pushReg(R+rs);
1073                 mg.add(LDC,unsignedImmediate);
1074                 mg.add(IOR);
1075             } else if(rs != 0){
1076                 pushReg(R+rs);
1077             } else {
1078                 mg.add(LDC,unsignedImmediate);
1079             }
1080             setReg();
1081             break;
1082         case 14: // XORI
1083             preSetReg(R+rt);
1084             pushRegWZ(R+rs);
1085             mg.add(LDC,unsignedImmediate);
1086             mg.add(IXOR);
1087             setReg();
1088             break;
1089         case 15: // LUI
1090             preSetReg(R+rt);
1091             mg.add(LDC,unsignedImmediate << 16);
1092             setReg();
1093             break;
1094         case 16:
1095             throw new Exn("TLB/Exception support not implemented");
1096         case 17: { // FPU
1097             switch(rs) {
1098             case 0: // MFC.1
1099                 preSetReg(R+rt);
1100                 pushReg(F+rd);
1101                 setReg();
1102                 break;
1103             case 2: // CFC.1
1104                 if(fs != 31) throw new Exn("FCR " + fs + " unavailable");
1105                 preSetReg(R+rt);
1106                 pushReg(FCSR);
1107                 setReg();
1108                 break;
1109             case 4: // MTC.1
1110                 preSetReg(F+rd);
1111                 if(rt != 0)
1112                     pushReg(R+rt);
1113                 else
1114                     mg.add(LDC,0);
1115                 setReg();
1116                 break;
1117             case 6: // CTC.1
1118                 if(fs != 31) throw new Exn("FCR " + fs + " unavailable");
1119                 preSetReg(FCSR);
1120                 pushReg(R+rt);
1121                 setReg();
1122                 break;
1123             case 8: {// BC1F, BC1T
1124                 pushReg(FCSR);
1125                 mg.add(LDC,0x800000);
1126                 mg.add(IAND);
1127                 return doIfInstruction(((insn>>>16)&1) == 0 ? IFEQ : IFNE,pc,pc+branchTarget*4+4,nextInsn);
1128             }
1129             case 16:
1130             case 17: 
1131             { // Single/Double math
1132                 boolean d = rs == 17;
1133                 switch(subcode) {
1134                 case 0: // ADD.X
1135                     preSetDouble(F+fd,d);
1136                     pushDouble(F+fs,d);
1137                     pushDouble(F+ft,d);
1138                     mg.add(d ? DADD : FADD);
1139                     setDouble(d);
1140                     break;
1141                 case 1: // SUB.X
1142                     preSetDouble(F+fd,d);
1143                     pushDouble(F+fs,d);
1144                     pushDouble(F+ft,d);
1145                     mg.add(d ? DSUB : FSUB);
1146                     setDouble(d);
1147                     break;
1148                 case 2: // MUL.X
1149                     preSetDouble(F+fd,d);
1150                     pushDouble(F+fs,d);
1151                     pushDouble(F+ft,d);
1152                     mg.add(d ? DMUL : FMUL);
1153                     setDouble(d);                    
1154                     break;
1155                 case 3: // DIV.X
1156                     preSetDouble(F+fd,d);
1157                     pushDouble(F+fs,d);
1158                     pushDouble(F+ft,d);
1159                     mg.add(d ? DDIV : FDIV);
1160                     setDouble(d);                    
1161                     break;
1162                 case 5: // ABS.X
1163                     preSetDouble(F+fd,d);
1164                     // NOTE: We can't use fneg/dneg here since they'll turn +0.0 into -0.0
1165                     
1166                     pushDouble(F+fs,d);
1167                     mg.add(d ? DUP2 : DUP);
1168                     mg.add(d ? DCONST_0 : FCONST_0);
1169                     mg.add(d ? DCMPG : FCMPG);
1170                     
1171                     b1 = mg.add(IFGT);
1172                     mg.add(d ? DCONST_0 : FCONST_0);
1173                     if(d) {
1174                         mg.add(DUP2_X2);
1175                         mg.add(POP2);
1176                     } else {
1177                         mg.add(SWAP);
1178                     }
1179                     mg.add(d ? DSUB : FSUB);
1180                     
1181                     mg.setArg(b1,mg.size());
1182                     setDouble(d);
1183                     
1184                     break;
1185                 case 6: // MOV.X
1186                     preSetReg(F+fd);
1187                     pushReg(F+fs);
1188                     setReg();
1189                     
1190                     if(d) {
1191                         preSetReg(F+fd+1);
1192                         pushReg(F+fs+1);
1193                         setReg();
1194                     }
1195                     
1196                     break;
1197                 case 7: // NEG.X
1198                     preSetDouble(F+fd,d);
1199                     pushDouble(F+fs,d);
1200                     mg.add(d ? DNEG : FNEG);
1201                     setDouble(d);
1202                     break;
1203                 case 32: // CVT.S.X
1204                     preSetFloat(F+fd);
1205                     pushDouble(F+fs,d);
1206                     if(d) mg.add(D2F);
1207                     setFloat();
1208                     break;
1209                 case 33: // CVT.D.X
1210                     preSetDouble(F+fd);
1211                     pushDouble(F+fs,d);
1212                     if(!d) mg.add(F2D);
1213                     setDouble();
1214                     break;
1215                 case 36: { // CVT.W.D
1216                     MethodGen.TSI tsi = new MethodGen.TSI(0,3);
1217                     preSetReg(F+fd);
1218                     pushDouble(F+fs,d);
1219                     pushReg(FCSR);
1220                     mg.add(ICONST_3);
1221                     mg.add(IAND);
1222                     mg.add(TABLESWITCH,tsi);
1223                     
1224                     // Round towards plus infinity
1225                     tsi.setTarget(2,mg.size());
1226                     if(!d) mg.add(F2D); // Ugh.. java.lang.Math doesn't have a float ceil/floor
1227                     mg.add(INVOKESTATIC,new MethodRef("java.lang.Math","ceil",Type.DOUBLE,new Type[]{Type.DOUBLE}));
1228                     if(!d) mg.add(D2F);
1229                     b1 = mg.add(GOTO);
1230                     
1231                     // Round to nearest
1232                     tsi.setTarget(0,mg.size());
1233                     mg.add(LDC,d ? (Object)POINT_5_D : (Object)POINT_5_F);
1234                     mg.add(d ? DADD : FADD);
1235                     // fall through
1236                     
1237                     // Round towards minus infinity
1238                     tsi.setTarget(3,mg.size());
1239                     if(!d) mg.add(F2D);
1240                     mg.add(INVOKESTATIC,new MethodRef("java.lang.Math","floor",Type.DOUBLE,new Type[]{Type.DOUBLE}));
1241                     if(!d) mg.add(D2F);
1242                     
1243                     tsi.setTarget(1,mg.size());
1244                     tsi.setDefaultTarget(mg.size());
1245                     mg.setArg(b1,mg.size());
1246                     
1247                     mg.add(d ? D2I : F2I);
1248                     setReg();
1249                     
1250                     break;
1251                 }
1252                 case 50: // C.EQ.D
1253                 case 60: // C.LT.D
1254                 case 62: // C.LE.D
1255                     preSetReg(FCSR);
1256                     pushReg(FCSR);
1257                     mg.add(LDC,~0x800000);
1258                     mg.add(IAND);
1259                     pushDouble(F+fs,d);
1260                     pushDouble(F+ft,d);
1261                     mg.add(d ? DCMPG : FCMPG);
1262                     switch(subcode) {
1263                         case 50: b1 = mg.add(IFNE); break;
1264                         case 60: b1 = mg.add(IFGE); break;
1265                         case 62: b1 = mg.add(IFGT); break;
1266                         default: b1 = -1;
1267                     }
1268                     mg.add(LDC,0x800000);
1269                     mg.add(IOR);
1270                     mg.setArg(b1,mg.size());
1271                     setReg();
1272                     break;
1273                 default: throw new Exn("Invalid Instruction 17/" + rs + "/" + subcode);
1274                 }
1275                 break;
1276             }
1277             case 20: { // Integer
1278                 switch(subcode) {
1279                 case 32: // CVT.S.W
1280                     preSetFloat(F+fd);
1281                     pushReg(F+fs);
1282                     mg.add(I2F);
1283                     setFloat();
1284                     break;
1285                 case 33: // CVT.D.W
1286                     preSetDouble(F+fd);
1287                     pushReg(F+fs);
1288                     mg.add(I2D);
1289                     setDouble();
1290                     break;
1291                 default: throw new Exn("Invalid Instruction 17/" + rs + "/" + subcode);
1292                 }
1293                 break; 
1294             }
1295             default:
1296                 throw new Exn("Invalid Instruction 17/" + rs);
1297             }
1298             break;
1299         }
1300         case 18: case 19:
1301             throw new Exn("coprocessor 2 and 3 instructions not available");
1302         case 32: { // LB
1303             preSetReg(R+rt);
1304             addiu(R+rs,signedImmediate);
1305             setTmp();
1306             preMemRead();
1307             pushTmp();
1308             memRead(true);
1309             pushTmp();
1310             
1311             mg.add(ICONST_M1);
1312             mg.add(IXOR);
1313             mg.add(ICONST_3);
1314             mg.add(IAND);
1315             mg.add(ICONST_3);
1316             mg.add(ISHL);
1317             mg.add(IUSHR);
1318             mg.add(I2B);
1319             setReg();
1320             break; 
1321         }
1322         case 33: { // LH
1323             preSetReg(R+rt);
1324             addiu(R+rs,signedImmediate);
1325             setTmp();
1326             preMemRead();
1327             pushTmp();
1328             memRead(true);
1329             pushTmp();
1330             
1331             mg.add(ICONST_M1);
1332             mg.add(IXOR);
1333             mg.add(ICONST_2);
1334             mg.add(IAND);
1335             mg.add(ICONST_3);
1336             mg.add(ISHL);
1337             mg.add(IUSHR);
1338             mg.add(I2S);
1339             setReg();            
1340             break; 
1341         }
1342         case 34: { // LWL;
1343             preSetReg(R+rt);
1344             addiu(R+rs,signedImmediate);
1345             setTmp(); // addr
1346             
1347             pushRegWZ(R+rt);
1348             mg.add(LDC,0x00ffffff);
1349             pushTmp();
1350             
1351             mg.add(ICONST_M1);
1352             mg.add(IXOR);
1353             mg.add(ICONST_3);
1354             mg.add(IAND);
1355             mg.add(ICONST_3);
1356             mg.add(ISHL);
1357             mg.add(IUSHR);
1358             mg.add(IAND);
1359             
1360             preMemRead();
1361             pushTmp();
1362             memRead(true);
1363             pushTmp();
1364             
1365             mg.add(ICONST_3);
1366             mg.add(IAND);
1367             mg.add(ICONST_3);
1368             mg.add(ISHL);
1369             mg.add(ISHL);
1370             mg.add(IOR);
1371             
1372             setReg();
1373             
1374             break;
1375             
1376         }
1377         case 35: // LW
1378             preSetReg(R+rt);
1379             memRead(R+rs,signedImmediate);
1380             setReg();
1381             break;
1382         case 36: { // LBU
1383             preSetReg(R+rt);
1384             addiu(R+rs,signedImmediate);
1385             setTmp();
1386             preMemRead();
1387             pushTmp();
1388             memRead(true);
1389             pushTmp();
1390             
1391             mg.add(ICONST_M1);
1392             mg.add(IXOR);
1393             mg.add(ICONST_3);
1394             mg.add(IAND);
1395             mg.add(ICONST_3);
1396             mg.add(ISHL);
1397             mg.add(IUSHR);
1398             mg.add(LDC,0xff);
1399             mg.add(IAND);
1400             setReg();
1401             break; 
1402         }
1403         case 37: { // LHU
1404             preSetReg(R+rt);
1405             addiu(R+rs,signedImmediate);
1406             setTmp();
1407             preMemRead();
1408             pushTmp();
1409             memRead(true);
1410             pushTmp();
1411             
1412             mg.add(ICONST_M1);
1413             mg.add(IXOR);
1414             mg.add(ICONST_2);
1415             mg.add(IAND);
1416             mg.add(ICONST_3);
1417             mg.add(ISHL);
1418             mg.add(IUSHR);
1419             
1420             // chars are unsigend so this works
1421             mg.add(I2C);
1422             setReg();
1423             break; 
1424         }
1425         case 38: { // LWR            
1426             preSetReg(R+rt);
1427             addiu(R+rs,signedImmediate);
1428             setTmp(); // addr
1429             
1430             pushRegWZ(R+rt);
1431             mg.add(LDC,0xffffff00);
1432             pushTmp();
1433             
1434             mg.add(ICONST_3);
1435             mg.add(IAND);
1436             mg.add(ICONST_3);
1437             mg.add(ISHL);
1438             mg.add(ISHL);
1439             mg.add(IAND);
1440             
1441             preMemRead();
1442             pushTmp();
1443             memRead(true);
1444             pushTmp();
1445             
1446             mg.add(ICONST_M1);
1447             mg.add(IXOR);
1448             mg.add(ICONST_3);
1449             mg.add(IAND);
1450             mg.add(ICONST_3);
1451             mg.add(ISHL);
1452             mg.add(IUSHR);
1453             mg.add(IOR);
1454             
1455             
1456             setReg();
1457             break;
1458         }
1459         case 40: { // SB            
1460             addiu(R+rs,signedImmediate);
1461             setTmp(); // addr
1462             
1463             // FEATURE: DO the preMemRead(true) thing for the rest of the S* instructions
1464             preMemRead(true);
1465             pushTmp();
1466             memRead(true);
1467             
1468             mg.add(LDC,0xff000000);
1469             pushTmp();
1470             
1471             mg.add(ICONST_3);
1472             mg.add(IAND);
1473             mg.add(ICONST_3);
1474             mg.add(ISHL);
1475             mg.add(IUSHR);
1476             mg.add(ICONST_M1);
1477             mg.add(IXOR);
1478             mg.add(IAND);
1479             
1480             if(rt != 0) {
1481                 pushReg(R+rt);
1482                 mg.add(LDC,0xff);
1483                 mg.add(IAND);
1484             } else {
1485                 mg.add(LDC,0);
1486             }
1487             pushTmp();
1488             
1489             mg.add(ICONST_M1);
1490             mg.add(IXOR);
1491             mg.add(ICONST_3);
1492             mg.add(IAND);
1493             mg.add(ICONST_3);
1494             mg.add(ISHL);
1495             mg.add(ISHL);
1496             mg.add(IOR);
1497             
1498             memWrite();
1499             
1500             break;
1501         }
1502         case 41: { // SH    
1503             preMemWrite1();
1504             
1505             addiu(R+rs,signedImmediate);
1506             
1507             mg.add(DUP);
1508             setTmp(); // addr
1509             
1510             preMemWrite2(true);
1511             
1512             preMemRead();
1513             pushTmp();
1514             memRead(true);
1515             
1516             mg.add(LDC,0xffff);
1517             pushTmp();
1518             
1519             mg.add(ICONST_2);
1520             mg.add(IAND);
1521             mg.add(ICONST_3);
1522             mg.add(ISHL);
1523             mg.add(ISHL);
1524             mg.add(IAND);
1525             
1526             if(rt != 0) {
1527                 pushReg(R+rt);
1528                 mg.add(LDC,0xffff);
1529                 mg.add(IAND);
1530             } else {
1531                 mg.add(LDC,0);
1532             }
1533             pushTmp();
1534             
1535             mg.add(ICONST_M1);
1536             mg.add(IXOR);
1537             mg.add(ICONST_2);
1538             mg.add(IAND);
1539             mg.add(ICONST_3);
1540             mg.add(ISHL);
1541             mg.add(ISHL);
1542             mg.add(IOR);
1543             
1544             memWrite();
1545             
1546             break;            
1547         }
1548         case 42: { // SWL
1549             preMemWrite1();
1550             
1551             addiu(R+rs,signedImmediate);
1552             mg.add(DUP);
1553             setTmp(); // addr
1554
1555             preMemWrite2(true);
1556             
1557             preMemRead();
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             preMemWrite1();
1595             
1596             addiu(R+rs,signedImmediate);
1597             mg.add(DUP);
1598             setTmp(); // addr
1599             
1600             preMemWrite2(true);
1601             
1602             preMemRead();
1603             pushTmp();
1604             memRead(true);
1605             
1606             mg.add(LDC,0x00ffffff);
1607             pushTmp();
1608             
1609             mg.add(ICONST_3);
1610             mg.add(IAND);
1611             mg.add(ICONST_3);
1612             mg.add(ISHL);
1613             mg.add(IUSHR);
1614             mg.add(IAND);
1615             
1616             pushRegWZ(R+rt);
1617             pushTmp();
1618             
1619             mg.add(ICONST_M1);
1620             mg.add(IXOR);
1621             mg.add(ICONST_3);
1622             mg.add(IAND);
1623             mg.add(ICONST_3);
1624             mg.add(ISHL);
1625             mg.add(ISHL);
1626             mg.add(IOR);
1627                     
1628             memWrite();
1629             break;
1630         }
1631         // This need to be atomic if we ever support threads (see SWC0/SC)
1632         case 48: // LWC0/LL
1633             preSetReg(R+rt);
1634             memRead(R+rs,signedImmediate);
1635             setReg();
1636             break;
1637             
1638         case 49: // LWC1
1639             preSetReg(F+rt);
1640             memRead(R+rs,signedImmediate);
1641             setReg();
1642             break;
1643         
1644         /* This needs to fail (set rt to 0) if the memory location was modified
1645          * between the LL and SC if we ever support threads.
1646          */
1647         case 56: // SWC0/SC
1648             preSetReg(R+rt);
1649             preMemWrite1();
1650             preMemWrite2(R+rs,signedImmediate);
1651             pushReg(R+rt);
1652             memWrite();
1653             mg.add(LDC,1);
1654             setReg();
1655             break;
1656             
1657         case 57: // SWC1
1658             preMemWrite1();
1659             preMemWrite2(R+rs,signedImmediate);
1660             pushReg(F+rt);
1661             memWrite();
1662             break;
1663         default:
1664             throw new Exn("Invalid Instruction: " + op + " at " + toHex(pc));
1665         }
1666         return false; 
1667     }
1668     
1669     // Helper functions for emitText
1670     
1671     private static final int R = 0;
1672     private static final int F = 32;
1673     private static final int HI = 64;
1674     private static final int LO = 65;
1675     private static final int FCSR = 66;
1676     private static final int REG_COUNT=67;
1677         
1678     private int[] regLocalMapping = new int[REG_COUNT];  
1679     private int[] regLocalReadCount = new int[REG_COUNT];
1680     private int[] regLocalWriteCount = new int[REG_COUNT];
1681     private int nextAvailLocal; 
1682     private int loadsStart;
1683     private static final int MAX_LOCALS = 4;
1684     private static final int LOAD_LENGTH = 3;
1685     
1686     private boolean doLocal(int reg) {
1687         return reg == R+2 || reg == R+3 || reg == R+4 || reg == R+29;
1688     }
1689     
1690     private int getLocalForReg(int reg) {
1691         if(regLocalMapping[reg] != 0) return regLocalMapping[reg];
1692         if(nextAvailLocal == 0) nextAvailLocal = onePage ? 3 : 4;
1693         regLocalMapping[reg] = nextAvailLocal++;
1694         return regLocalMapping[reg];
1695     }
1696     
1697     private void fixupRegsStart() {
1698         for(int i=0;i<REG_COUNT;i++)
1699             regLocalMapping[i] = regLocalReadCount[i] = regLocalWriteCount[i] = 0;
1700         nextAvailLocal = 0;
1701         loadsStart = mg.size();
1702         for(int i=0;i<MAX_LOCALS*LOAD_LENGTH;i++)
1703             mg.add(NOP);
1704     }
1705     
1706     private void fixupRegsEnd() {
1707         int p = loadsStart;
1708         for(int i=0;i<REG_COUNT;i++) {
1709             if(regLocalMapping[i] == 0) continue;
1710             mg.set(p++,ALOAD_0);
1711             mg.set(p++,GETFIELD,new FieldRef(me,regField(i),Type.INT));
1712             mg.set(p++,ISTORE,regLocalMapping[i]);
1713             
1714             if(regLocalWriteCount[i] > 0) {
1715                 mg.add(ALOAD_0);
1716                 mg.add(ILOAD,regLocalMapping[i]);
1717                 mg.add(PUTFIELD,new FieldRef(me,regField(i),Type.INT));
1718             }
1719         }
1720     }
1721         
1722     private void restoreChangedRegs() {
1723         for(int i=0;i<REG_COUNT;i++) {
1724             if(regLocalWriteCount[i] > 0) {
1725                 mg.add(ALOAD_0);
1726                 mg.add(ILOAD,regLocalMapping[i]);
1727                 mg.add(PUTFIELD,new FieldRef(me,regField(i),Type.INT));
1728             }
1729         }
1730     }
1731     
1732     private static final String[] regField = {
1733             "r0","r1","r2","r3","r4","r5","r6","r7",
1734             "r8","r9","r10","r11","r12","r13","r14","r15",
1735             "r16","r17","r18","r19","r20","r21","r22","r23",
1736             "r24","r25","r26","r27","r28","r29","r30","r31",
1737             
1738             "f0","f1","f2","f3","f4","f5","f6","f7",
1739             "f8","f9","f10","f11","f12","f13","f14","f15",
1740             "f16","f17","f18","f19","f20","f21","f22","f23",
1741             "f24","f25","f26","f27","f28","f29","f30","f31",
1742             
1743             "hi","lo","fcsr"
1744     };
1745     
1746     private static String regField(int reg) { return regField[reg]; }
1747         
1748     private int pushRegWZ(int reg) {
1749         if(reg == R+0) {
1750             warn.println("Warning: Pushing r0!");
1751             new Exception().printStackTrace(warn);
1752         }
1753         return pushRegZ(reg);
1754     }
1755     
1756     private int pushRegZ(int reg) {
1757         if(reg == R+0) return mg.add(ICONST_0);
1758         else return pushReg(reg);
1759     }
1760     
1761     
1762     private int pushReg(int reg) {
1763         int h = mg.size();
1764         if(doLocal(reg)) {
1765             regLocalReadCount[reg]++;
1766             mg.add(ILOAD,getLocalForReg(reg));
1767             
1768         } else {
1769             mg.add(ALOAD_0);
1770             mg.add(GETFIELD,new FieldRef(me,regField(reg),Type.INT));
1771         }
1772         return h;
1773     }
1774     
1775     private int preSetRegStackPos;
1776     private int[] preSetRegStack = new int[8];
1777     
1778     // This can push ONE or ZERO words to the stack. If it pushed one it returns true
1779     private boolean preSetReg(int reg) {
1780         regField(reg); // just to check for validity
1781         preSetRegStack[preSetRegStackPos] = reg;
1782         preSetRegStackPos++;
1783         if(doLocal(reg)) {
1784             return false;
1785         } else {
1786             mg.add(ALOAD_0);
1787             return true;
1788         }
1789     }
1790     
1791     private int setReg() {
1792         if(preSetRegStackPos==0) throw new RuntimeException("didn't do preSetReg");
1793         preSetRegStackPos--;
1794         int reg = preSetRegStack[preSetRegStackPos];
1795         int h = mg.size();
1796         if(doLocal(reg)) {
1797             mg.add(ISTORE,getLocalForReg(reg));
1798             regLocalWriteCount[reg]++;
1799         } else {
1800             mg.add(PUTFIELD,new FieldRef(me,regField(reg),Type.INT));
1801         }
1802         return h;
1803     }
1804     
1805     private int preSetPC() { return mg.add(ALOAD_0); }
1806     private int setPC() {
1807         return mg.add(PUTFIELD,new FieldRef(me,"pc",Type.INT));
1808     }
1809     
1810     //unused - private InstructionHandle pushFloat(int reg) throws CompilationException { return pushDouble(reg,false); }
1811     //unused - private InstructionHandle pushDouble(int reg) throws CompilationException { return pushDouble(reg,true); }
1812     private int pushDouble(int reg, boolean d) throws Exn {
1813         if(reg < F || reg >= F+32) throw new IllegalArgumentException(""+reg);
1814         int h = mg.size();
1815         if(d) {
1816             if(reg == F+31) throw new Exn("Tried to use a double in f31");
1817             pushReg(reg+1);
1818             mg.add(I2L);
1819             mg.add(LDC,32);
1820             mg.add(LSHL);
1821             pushReg(reg);
1822             mg.add(I2L);
1823             mg.add(LDC,FFFFFFFF);
1824             mg.add(LAND);
1825             mg.add(LOR);
1826             mg.add(INVOKESTATIC,new MethodRef(Type.DOUBLE_OBJECT,"longBitsToDouble",Type.DOUBLE,new Type[]{Type.LONG}));
1827         } else {
1828             pushReg(reg);
1829             mg.add(INVOKESTATIC,new MethodRef("java.lang.Float","intToFloatBits",Type.FLOAT,new Type[]{Type.INT}));
1830         }
1831         return h;
1832     }
1833     
1834     private void preSetFloat(int reg) { preSetDouble(reg,false); }
1835     private void preSetDouble(int reg) { preSetDouble(reg,true); }
1836     private void preSetDouble(int reg, boolean d) { preSetReg(reg); }
1837     
1838     private int setFloat() throws Exn { return setDouble(false); }
1839     private int setDouble() throws Exn { return setDouble(true); }
1840     private int setDouble(boolean d) throws Exn {
1841         int reg = preSetRegStack[preSetRegStackPos-1];
1842         if(reg < F || reg >= F+32) throw new IllegalArgumentException(""+reg);
1843         int h = mg.size();
1844         if(d) {
1845             if(reg == F+31) throw new Exn("Tried to use a double in f31");
1846             mg.add(INVOKESTATIC,new MethodRef(Type.DOUBLE_OBJECT,"doubleToLongBits",Type.LONG,new Type[]{Type.DOUBLE}));
1847             mg.add(DUP2);
1848             mg.add(LDC,32);
1849             mg.add(LUSHR);
1850             mg.add(L2I);
1851             if(preSetReg(reg+1))
1852                 mg.add(SWAP);
1853             setReg();
1854             mg.add(L2I);
1855             setReg(); // preSetReg was already done for this by preSetDouble
1856         } else {
1857             //h = a(fac.createInvoke("java.lang.Float","floatToRawIntBits",Type.INT,new Type[]{Type.FLOAT},INVOKESTATIC));
1858             mg.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"floatToRawIntBits",Type.INT,new Type[]{Type.FLOAT}));
1859             setReg();   
1860         }
1861         return h;
1862     }
1863     
1864     private void pushTmp() { mg.add(ILOAD_1); }
1865     private void setTmp() { mg.add(ISTORE_1); }
1866     
1867     private void addiu(int reg, int offset) {
1868         if(reg != R+0 && offset != 0) {
1869             pushReg(reg);
1870             mg.add(LDC,offset);
1871             mg.add(IADD);
1872         } else if(reg != R+0) {
1873             pushReg(reg);
1874         } else {
1875             mg.add(LDC,offset);
1876         }        
1877     }
1878     private int memWriteStage;
1879     private void preMemWrite1() {
1880         if(memWriteStage!=0) throw new Error("pending preMemWrite1/2");
1881         memWriteStage=1;
1882         if(onePage)
1883             mg.add(ALOAD_2);
1884         else if(fastMem)
1885             mg.add(ALOAD,3);
1886         else
1887             mg.add(ALOAD_0);
1888     }
1889     
1890     private void preMemWrite2(int reg, int offset) {
1891         addiu(reg,offset);
1892         preMemWrite2();
1893     }
1894     
1895     private void preMemWrite2() { preMemWrite2(false); }
1896     private void preMemWrite2(boolean addrInTmp) {
1897         if(memWriteStage!=1) throw new Error("pending preMemWrite2 or no preMemWrite1");
1898         memWriteStage=2;
1899         
1900         if(nullPointerCheck) {
1901             mg.add(DUP);
1902             mg.add(ALOAD_0);
1903             mg.add(SWAP);
1904             mg.add(INVOKEVIRTUAL,new MethodRef(me,"nullPointerCheck",Type.VOID,new Type[]{Type.INT}));
1905         }
1906         
1907         if(onePage) {
1908             mg.add(ICONST_2);
1909             mg.add(IUSHR);
1910         } else if(fastMem) {
1911             if(!addrInTmp)
1912                 mg.add(DUP_X1);
1913             mg.add(LDC,pageShift);
1914             mg.add(IUSHR);
1915             mg.add(AALOAD);
1916             if(addrInTmp)
1917                 pushTmp();
1918             else
1919                 mg.add(SWAP);
1920             mg.add(ICONST_2);
1921             mg.add(IUSHR);
1922             mg.add(LDC,(pageSize>>2)-1);
1923             mg.add(IAND);            
1924         }
1925     }
1926     
1927     // pops an address and value off the stack, sets *addr to value
1928     private void memWrite() {
1929         if(memWriteStage!=2) throw new Error("didn't do preMemWrite1 or preMemWrite2");
1930         memWriteStage=0;
1931                 
1932         if(onePage) {
1933             mg.add(IASTORE);
1934         } else if(fastMem) {
1935             mg.add(IASTORE);
1936         } else {
1937             mg.add(INVOKEVIRTUAL,new MethodRef(me,"unsafeMemWrite",Type.VOID,new Type[]{Type.INT,Type.INT}));
1938         }
1939         
1940     }
1941     
1942     // reads the word at r[reg]+offset
1943     private void memRead(int reg, int offset) {
1944         preMemRead();
1945         addiu(reg,offset);
1946         memRead();
1947     }
1948     
1949     private boolean didPreMemRead;
1950     private boolean preMemReadDoPreWrite;
1951     
1952     private void preMemRead() { preMemRead(false); }
1953     private void preMemRead(boolean preWrite) {
1954         if(didPreMemRead) throw new Error("pending preMemRead");
1955         didPreMemRead = true;
1956         preMemReadDoPreWrite = preWrite;
1957         if(onePage)
1958             mg.add(ALOAD_2);
1959         else if(fastMem)
1960             mg.add(ALOAD,preWrite ? 3 : 2);
1961         else
1962             mg.add(ALOAD_0);
1963     }
1964     // memRead pops an address off the stack, reads the value at that addr, and pushed the value
1965     // preMemRead MUST be called BEFORE the addresses is pushed
1966     private void memRead() { memRead(false); }
1967     
1968     private void memRead(boolean addrInTmp) {
1969         if(!didPreMemRead) throw new Error("didn't do preMemRead");
1970         didPreMemRead = false;
1971         if(preMemReadDoPreWrite)
1972             memWriteStage=2; 
1973             
1974         if(nullPointerCheck) {
1975             mg.add(DUP);
1976             mg.add(ALOAD_0);
1977             mg.add(SWAP);
1978             mg.add(INVOKEVIRTUAL,new MethodRef(me,"nullPointerCheck",Type.VOID,new Type[]{Type.INT}));
1979         }
1980         
1981         if(onePage) {
1982             mg.add(ICONST_2);
1983             mg.add(IUSHR);
1984             if(preMemReadDoPreWrite)
1985                 mg.add(DUP2);
1986             mg.add(IALOAD);
1987         } else if(fastMem) {
1988             if(!addrInTmp)
1989                 mg.add(DUP_X1);
1990             mg.add(LDC,pageShift);
1991             mg.add(IUSHR);
1992             mg.add(AALOAD);
1993             if(addrInTmp)
1994                 pushTmp();
1995             else
1996                 mg.add(SWAP);
1997             mg.add(ICONST_2);
1998             mg.add(IUSHR);
1999             mg.add(LDC,(pageSize>>2)-1);
2000             mg.add(IAND);
2001             if(preMemReadDoPreWrite)
2002                 mg.add(DUP2);
2003             mg.add(IALOAD);
2004             
2005         } else {
2006             if(preMemReadDoPreWrite)
2007                 mg.add(DUP2);
2008             mg.add(INVOKEVIRTUAL,new MethodRef(me,"unsafeMemRead",Type.INT,new Type[]{Type.INT}));
2009         }
2010     }
2011     
2012     
2013     // This might come in handy for something else
2014     /*private boolean touchesReg(int insn, int reg) {
2015         if((reg < R+0 || reg >= R+32) && reg != FCSR) throw new IllegalArgumentException(""+reg);
2016         if(reg == R+0) return false; // r0 is never modified
2017         int op = (insn >>> 26) & 0xff;                 // bits 26-31
2018         int subcode = insn & 0x3f;                     // bits 0-5 
2019         int rd = (insn >>> 11) & 0x1f;                 // bits 11-15
2020         int rt = (insn >>> 16) & 0x1f;                 // bits 16-20 
2021         int rs = (insn >>> 21) & 0x1f;                 // bits 21-25
2022         
2023         switch(op) {
2024         case 0:
2025             if(subcode >= 0 && subcode <= 7) return reg == R+rd; // Shift ops
2026             if(subcode >= 32 && subcode <= 43) return reg == R+rd; // Other math ops 
2027             if(subcode >= 24 && subcode <= 27) return reg == HI || reg == LO; // MULT/DIV
2028             break;
2029         case 13: return false; // BREAK
2030         case 17:
2031             switch(rs) {
2032                 case 0: return reg == R+rt; // MFC.1
2033                 case 2: return reg == R+rt; // CFC.1
2034                 case 4: return false; // MTC.1
2035                 case 6: return false; // CTC.1
2036                 case 16: // Single 
2037                 case 17: // Double
2038                     if(subcode == 50 || subcode == 60 || subcode == 62) return reg == FCSR;
2039                     return false; // everything else just touches f0-f31
2040                 case 20: return false; // Integer - just touches f0-f31
2041             }
2042             break;
2043         default:
2044             if(op >= 8 && op <= 15) return reg == R+rt; // XXXI instructions
2045             if(op >= 40 && op <= 46) return false; // Memory WRITE ops
2046             if(op == 49) return reg == F+rt; // LWC1
2047             if(op == 57) return false; // SWC1
2048             break;
2049         }
2050         warn.println("Unknown instruction in touchesReg()- assuming it modifies all regs " + op + " " + subcode);
2051         new Exception().fillInStackTrace().printStackTrace(warn);
2052         return true;
2053     }*/
2054 }