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