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