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