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