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