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