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