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