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