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