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