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