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