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