size chart fix
[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+fs,d);
1235                     pushDouble(F+ft,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                     if(d) {
1281                         preSetReg(F+fd+1);
1282                         pushReg(F+fs+1);
1283                         setReg();
1284                     }
1285                     
1286                     break;
1287                 case 7: // NEG.X
1288                     preSetDouble(F+fd,d);
1289                     pushDouble(F+fs,d);
1290                     a(d ? InstructionConstants.DNEG : InstructionConstants.FNEG);
1291                     setDouble(d);
1292                     break;
1293                 case 32: // CVT.S.X
1294                     preSetFloat(F+fd);
1295                     pushDouble(F+fs,d);
1296                     if(d) a(InstructionConstants.D2F);
1297                     setFloat();
1298                     break;
1299                 case 33: // CVT.D.X
1300                     preSetDouble(F+fd);
1301                     pushDouble(F+fs,d);
1302                     if(!d) a(InstructionConstants.F2D);
1303                     setDouble();
1304                     break;
1305                 case 36: { // CVT.W.D
1306                     int[] matches = new int[4];
1307                     for(int i=0;i<4;i++) matches[i] = i;
1308                     
1309                     TABLESWITCH ts = new  TABLESWITCH(matches,new InstructionHandle[4], null);
1310                     
1311                     preSetReg(F+fd);
1312                     pushDouble(F+fs,d);
1313                     pushReg(FCSR);
1314                     a(InstructionConstants.ICONST_3);
1315                     a(InstructionConstants.IAND);
1316                     a(ts);
1317                     
1318                     // Round towards plus infinity
1319                     ts.setTarget(2,a(InstructionConstants.NOP));
1320                     if(!d) a(InstructionConstants.F2D); // Ugh.. java.lang.Math doesn't have a float ceil/floor
1321                     a(fac.createInvoke("java.lang.Math","ceil",Type.DOUBLE,new Type[]{Type.DOUBLE},INVOKESTATIC));
1322                     if(!d) a(InstructionConstants.D2F);
1323                     b1 = a(InstructionFactory.createBranchInstruction(GOTO,null));
1324                     
1325                     // Round to nearest
1326                     ts.setTarget(0,d ? pushConst(0.5d) : pushConst(0.5f));
1327                     a(d ? InstructionConstants.DADD : InstructionConstants.FADD);
1328                     // fall through
1329                     
1330                     // Round towards minus infinity
1331                     ts.setTarget(3,a(InstructionConstants.NOP));
1332                     if(!d) a(InstructionConstants.F2D);
1333                     a(fac.createInvoke("java.lang.Math","floor",Type.DOUBLE,new Type[]{Type.DOUBLE},INVOKESTATIC));
1334                     if(!d) a(InstructionConstants.D2F);
1335                     
1336                     InstructionHandle h = a(d ? InstructionConstants.D2I : InstructionConstants.F2I);
1337                     setReg();
1338                     
1339                     ts.setTarget(1,h);
1340                     ts.setTarget(h);
1341                     b1.setTarget(h);
1342                                         
1343                     break;
1344                 }
1345                 case 50: // C.EQ.D
1346                 case 60: // C.LT.D
1347                 case 62: // C.LE.D
1348                     preSetReg(FCSR);
1349                     pushReg(FCSR);
1350                     pushConst(~0x800000);
1351                     a(InstructionConstants.IAND);
1352                     pushDouble(F+fs,d);
1353                     pushDouble(F+ft,d);
1354                     a(d ? InstructionConstants.DCMPG : InstructionConstants.FCMPG);
1355                     switch(subcode) {
1356                         case 50: b1 = a(InstructionFactory.createBranchInstruction(IFEQ,null)); break;
1357                         case 60: b1 = a(InstructionFactory.createBranchInstruction(IFLT,null)); break;
1358                         case 62: b1 = a(InstructionFactory.createBranchInstruction(IFLE,null)); break;
1359                         default: b1 = null;
1360                     }
1361                     // FIXME: We probably don't need to pushConst(0x00000)
1362                     pushConst(0x000000);
1363                     b2 = a(InstructionFactory.createBranchInstruction(GOTO,null));
1364                     b1.setTarget(pushConst(0x800000));
1365                     b2.setTarget(a(InstructionConstants.IOR));
1366                     setReg();
1367                     break;
1368                 default: throw new Exn("Invalid Instruction 17/" + rs + "/" + subcode);
1369                 }
1370                 break;
1371             }
1372             case 20: { // Integer
1373                 switch(subcode) {
1374                 case 32: // CVT.S.W
1375                     preSetFloat(F+fd);
1376                     pushReg(F+fs);
1377                     a(InstructionConstants.I2F);
1378                     setFloat();
1379                     break;
1380                 case 33: // CVT.D.W
1381                     preSetDouble(F+fd);
1382                     pushReg(F+fs);
1383                     a(InstructionConstants.I2D);
1384                     setDouble();
1385                     break;
1386                 default: throw new Exn("Invalid Instruction 17/" + rs + "/" + subcode);
1387                 }
1388                 break; 
1389             }
1390             default:
1391                 throw new Exn("Invalid Instruction 17/" + rs);
1392             }
1393             break;
1394         }
1395         case 18: case 19:
1396             throw new Exn("coprocessor 2 and 3 instructions not available");
1397         case 32: { // LB
1398             preSetReg(R+rt);
1399             addiu(R+rs,signedImmediate);
1400             setTmp();
1401             preMemRead();
1402             pushTmp();
1403             memRead(true);
1404             pushTmp();
1405             
1406             a(InstructionConstants.ICONST_M1);
1407             a(InstructionConstants.IXOR);
1408             a(InstructionConstants.ICONST_3);
1409             a(InstructionConstants.IAND);
1410             a(InstructionConstants.ICONST_3);
1411             a(InstructionConstants.ISHL);
1412             a(InstructionConstants.IUSHR);
1413             a(InstructionConstants.I2B);
1414             setReg();
1415             break; 
1416         }
1417         case 33: { // LH
1418             preSetReg(R+rt);
1419             addiu(R+rs,signedImmediate);
1420             setTmp();
1421             preMemRead();
1422             pushTmp();
1423             memRead(true);
1424             pushTmp();
1425             
1426             a(InstructionConstants.ICONST_M1);
1427             a(InstructionConstants.IXOR);
1428             a(InstructionConstants.ICONST_2);
1429             a(InstructionConstants.IAND);
1430             a(InstructionConstants.ICONST_3);
1431             a(InstructionConstants.ISHL);
1432             a(InstructionConstants.IUSHR);
1433             a(InstructionConstants.I2S);
1434             setReg();            
1435             break; 
1436         }
1437         case 34: { // LWL;
1438             preSetReg(R+rt);
1439             addiu(R+rs,signedImmediate);
1440             setTmp(); // addr
1441             
1442             pushRegWZ(R+rt);
1443             pushConst(0x00ffffff);
1444             pushTmp();
1445             
1446             a(InstructionConstants.ICONST_M1);
1447             a(InstructionConstants.IXOR);
1448             a(InstructionConstants.ICONST_3);
1449             a(InstructionConstants.IAND);
1450             a(InstructionConstants.ICONST_3);
1451             a(InstructionConstants.ISHL);
1452             a(InstructionConstants.IUSHR);
1453             a(InstructionConstants.IAND);
1454             
1455             preMemRead();
1456             pushTmp();
1457             memRead(true);
1458             pushTmp();
1459             
1460             a(InstructionConstants.ICONST_3);
1461             a(InstructionConstants.IAND);
1462             a(InstructionConstants.ICONST_3);
1463             a(InstructionConstants.ISHL);
1464             a(InstructionConstants.ISHL);
1465             a(InstructionConstants.IOR);
1466             
1467             setReg();
1468             
1469             break;
1470             
1471         }
1472         case 35: // LW
1473             preSetReg(R+rt);
1474             memRead(R+rs,signedImmediate);
1475             setReg();
1476             break;
1477         case 36: { // LBU
1478             preSetReg(R+rt);
1479             addiu(R+rs,signedImmediate);
1480             setTmp();
1481             preMemRead();
1482             pushTmp();
1483             memRead(true);
1484             pushTmp();
1485             
1486             a(InstructionConstants.ICONST_M1);
1487             a(InstructionConstants.IXOR);
1488             a(InstructionConstants.ICONST_3);
1489             a(InstructionConstants.IAND);
1490             a(InstructionConstants.ICONST_3);
1491             a(InstructionConstants.ISHL);
1492             a(InstructionConstants.IUSHR);
1493             pushConst(0xff);
1494             a(InstructionConstants.IAND);
1495             setReg();
1496             break; 
1497         }
1498         case 37: { // LHU
1499             preSetReg(R+rt);
1500             addiu(R+rs,signedImmediate);
1501             setTmp();
1502             preMemRead();
1503             pushTmp();
1504             memRead(true);
1505             pushTmp();
1506             
1507             a(InstructionConstants.ICONST_M1);
1508             a(InstructionConstants.IXOR);
1509             a(InstructionConstants.ICONST_2);
1510             a(InstructionConstants.IAND);
1511             a(InstructionConstants.ICONST_3);
1512             a(InstructionConstants.ISHL);
1513             a(InstructionConstants.IUSHR);
1514             
1515             // chars are unsigend so this works
1516             a(InstructionConstants.I2C);
1517             setReg();
1518             break; 
1519         }
1520         case 38: { // LWR            
1521             preSetReg(R+rt);
1522             addiu(R+rs,signedImmediate);
1523             setTmp(); // addr
1524             
1525             pushRegWZ(R+rt);
1526             pushConst(0xffffff00);
1527             pushTmp();
1528             
1529             a(InstructionConstants.ICONST_3);
1530             a(InstructionConstants.IAND);
1531             a(InstructionConstants.ICONST_3);
1532             a(InstructionConstants.ISHL);
1533             a(InstructionConstants.ISHL);
1534             a(InstructionConstants.IAND);
1535             
1536             preMemRead();
1537             pushTmp();
1538             memRead(true);
1539             pushTmp();
1540             
1541             a(InstructionConstants.ICONST_M1);
1542             a(InstructionConstants.IXOR);
1543             a(InstructionConstants.ICONST_3);
1544             a(InstructionConstants.IAND);
1545             a(InstructionConstants.ICONST_3);
1546             a(InstructionConstants.ISHL);
1547             a(InstructionConstants.IUSHR);
1548             a(InstructionConstants.IOR);
1549             
1550             
1551             setReg();
1552             break;
1553         }
1554         case 40: { // SB            
1555             addiu(R+rs,signedImmediate);
1556             setTmp(); // addr
1557             
1558             // FEATURE: DO the preMemRead(true) thing for the rest of the S* instructions
1559             preMemRead(true);
1560             pushTmp();
1561             memRead(true);
1562             
1563             pushConst(0xff000000);
1564             pushTmp();
1565             
1566             a(InstructionConstants.ICONST_3);
1567             a(InstructionConstants.IAND);
1568             a(InstructionConstants.ICONST_3);
1569             a(InstructionConstants.ISHL);
1570             a(InstructionConstants.IUSHR);
1571             a(InstructionConstants.ICONST_M1);
1572             a(InstructionConstants.IXOR);
1573             a(InstructionConstants.IAND);
1574             
1575             if(rt != 0) {
1576                 pushReg(R+rt);
1577                 pushConst(0xff);
1578                 a(InstructionConstants.IAND);
1579             } else {
1580                 pushConst(0);
1581             }
1582             pushTmp();
1583             
1584             a(InstructionConstants.ICONST_M1);
1585             a(InstructionConstants.IXOR);
1586             a(InstructionConstants.ICONST_3);
1587             a(InstructionConstants.IAND);
1588             a(InstructionConstants.ICONST_3);
1589             a(InstructionConstants.ISHL);
1590             a(InstructionConstants.ISHL);
1591             a(InstructionConstants.IOR);
1592             
1593             memWrite();
1594             
1595             break;
1596         }
1597         case 41: { // SH    
1598             preMemWrite1();
1599             
1600             addiu(R+rs,signedImmediate);
1601             
1602             a(InstructionConstants.DUP);
1603             setTmp(); // addr
1604             
1605             preMemWrite2(true);
1606             
1607             preMemRead();
1608             pushTmp();
1609             memRead(true);
1610             
1611             pushConst(0xffff);
1612             pushTmp();
1613             
1614             a(InstructionConstants.ICONST_2);
1615             a(InstructionConstants.IAND);
1616             a(InstructionConstants.ICONST_3);
1617             a(InstructionConstants.ISHL);
1618             a(InstructionConstants.ISHL);
1619             a(InstructionConstants.IAND);
1620             
1621             if(rt != 0) {
1622                 pushReg(R+rt);
1623                 pushConst(0xffff);
1624                 a(InstructionConstants.IAND);
1625             } else {
1626                 pushConst(0);
1627             }
1628             pushTmp();
1629             
1630             a(InstructionConstants.ICONST_M1);
1631             a(InstructionConstants.IXOR);
1632             a(InstructionConstants.ICONST_2);
1633             a(InstructionConstants.IAND);
1634             a(InstructionConstants.ICONST_3);
1635             a(InstructionConstants.ISHL);
1636             a(InstructionConstants.ISHL);
1637             a(InstructionConstants.IOR);
1638             
1639             memWrite();
1640             
1641             break;            
1642         }
1643         case 42: { // SWL
1644             preMemWrite1();
1645             
1646             addiu(R+rs,signedImmediate);
1647             a(InstructionConstants.DUP);
1648             setTmp(); // addr
1649
1650             preMemWrite2(true);
1651             
1652             preMemRead();
1653             pushTmp();
1654             memRead(true);
1655             
1656             pushConst(0xffffff00);
1657             pushTmp();
1658             
1659             a(InstructionConstants.ICONST_M1);
1660             a(InstructionConstants.IXOR);
1661             a(InstructionConstants.ICONST_3);
1662             a(InstructionConstants.IAND);
1663             a(InstructionConstants.ICONST_3);
1664             a(InstructionConstants.ISHL);
1665             a(InstructionConstants.ISHL);
1666             a(InstructionConstants.IAND);
1667             
1668             pushRegWZ(R+rt);
1669             pushTmp();
1670             
1671             a(InstructionConstants.ICONST_3);
1672             a(InstructionConstants.IAND);
1673             a(InstructionConstants.ICONST_3);
1674             a(InstructionConstants.ISHL);
1675             a(InstructionConstants.IUSHR);
1676             a(InstructionConstants.IOR);
1677             
1678             memWrite();
1679             break;
1680             
1681         }
1682         case 43: // SW
1683             preMemWrite1();
1684             preMemWrite2(R+rs,signedImmediate);
1685             pushRegZ(R+rt);
1686             memWrite();
1687             break;
1688         case 46: { // SWR
1689             preMemWrite1();
1690             
1691             addiu(R+rs,signedImmediate);
1692             a(InstructionConstants.DUP);
1693             setTmp(); // addr
1694             
1695             preMemWrite2(true);
1696             
1697             preMemRead();
1698             pushTmp();
1699             memRead(true);
1700             
1701             pushConst(0x00ffffff);
1702             pushTmp();
1703             
1704             a(InstructionConstants.ICONST_3);
1705             a(InstructionConstants.IAND);
1706             a(InstructionConstants.ICONST_3);
1707             a(InstructionConstants.ISHL);
1708             a(InstructionConstants.IUSHR);
1709             a(InstructionConstants.IAND);
1710             
1711             pushRegWZ(R+rt);
1712             pushTmp();
1713             
1714             a(InstructionConstants.ICONST_M1);
1715             a(InstructionConstants.IXOR);
1716             a(InstructionConstants.ICONST_3);
1717             a(InstructionConstants.IAND);
1718             a(InstructionConstants.ICONST_3);
1719             a(InstructionConstants.ISHL);
1720             a(InstructionConstants.ISHL);
1721             a(InstructionConstants.IOR);
1722                     
1723             memWrite();
1724             break;
1725         }
1726         // This need to be atomic if we ever support threads (see SWC0/SC)
1727         case 48: // LWC0/LL
1728             preSetReg(R+rt);
1729             memRead(R+rs,signedImmediate);
1730             setReg();
1731             break;
1732             
1733         case 49: // LWC1
1734             preSetReg(F+rt);
1735             memRead(R+rs,signedImmediate);
1736             setReg();
1737             break;
1738         
1739         /* This needs to fail (set rt to 0) if the memory location was modified
1740          * between the LL and SC if we every support threads.
1741          */
1742         case 56: // SWC0/SC
1743             preSetReg(R+rt);
1744             preMemWrite1();
1745             preMemWrite2(R+rs,signedImmediate);
1746             pushReg(R+rt);
1747             memWrite();
1748             pushConst(1);
1749             setReg();
1750             break;
1751             
1752         case 57: // SWC1
1753             preMemWrite1();
1754             preMemWrite2(R+rs,signedImmediate);
1755             pushReg(F+rt);
1756             memWrite();
1757             break;
1758         default:
1759             throw new Exn("Invalid Instruction: " + op + " at " + toHex(pc));
1760         }
1761         return false; 
1762     }
1763     
1764     // Helper functions for emitText
1765     
1766     private static final int R = 0;
1767     private static final int F = 32;
1768     private static final int HI = 64;
1769     private static final int LO = 65;
1770     private static final int FCSR = 66;
1771     private static final int REG_COUNT=67;
1772         
1773     private int[] regLocalMapping = new int[REG_COUNT];  
1774     private int[] regLocalReadCount = new int[REG_COUNT];
1775     private int[] regLocalWriteCount = new int[REG_COUNT];
1776     private int nextAvailLocal; 
1777     
1778     private int getLocalForReg(int reg) {
1779         if(regLocalMapping[reg] != 0) return regLocalMapping[reg];
1780         if(nextAvailLocal == 0) nextAvailLocal = onePage ? 3 : 4;
1781         regLocalMapping[reg] = nextAvailLocal++;
1782         return regLocalMapping[reg];
1783     }
1784     
1785     private void fixupRegs() {
1786         InstructionHandle prev = realStart;
1787         for(int i=0;i<REG_COUNT;i++) {
1788             if(regLocalMapping[i] == 0) continue; 
1789             
1790             prev = insnList.append(prev,InstructionConstants.ALOAD_0);
1791             prev = insnList.append(prev,fac.createFieldAccess(fullClassName,regField(i),Type.INT, GETFIELD));
1792             prev = insnList.append(prev,InstructionFactory.createStore(Type.INT,regLocalMapping[i]));
1793             
1794             if(regLocalWriteCount[i] > 0) {
1795                 a(InstructionConstants.ALOAD_0);
1796                 a(InstructionFactory.createLoad(Type.INT,regLocalMapping[i]));
1797                 a(fac.createFieldAccess(fullClassName,regField(i),Type.INT, PUTFIELD));
1798             }
1799             
1800             regLocalMapping[i] = regLocalReadCount[i] = regLocalWriteCount[i] = 0;
1801         }
1802         nextAvailLocal = 0;
1803     }
1804     
1805     private void restoreChangedRegs() {
1806         for(int i=0;i<REG_COUNT;i++) {
1807             if(regLocalWriteCount[i] > 0) {
1808                 a(InstructionConstants.ALOAD_0);
1809                 a(InstructionFactory.createLoad(Type.INT,regLocalMapping[i]));
1810                 a(fac.createFieldAccess(fullClassName,regField(i),Type.INT, PUTFIELD));                
1811             }
1812         }
1813     }
1814     
1815     private static final String[] regField = {
1816             "r0","r1","r2","r3","r4","r5","r6","r7",
1817             "r8","r9","r10","r11","r12","r13","r14","r15",
1818             "r16","r17","r18","r19","r20","r21","r22","r23",
1819             "r24","r25","r26","r27","r28","r29","r30","r31",
1820             
1821             "f0","f1","f2","f3","f4","f5","f6","f7",
1822             "f8","f9","f10","f11","f12","f13","f14","f15",
1823             "f16","f17","f18","f19","f20","f21","f22","f23",
1824             "f24","f25","f26","f27","f28","f29","f30","f31",
1825             
1826             "hi","lo","fcsr"
1827     };
1828     
1829     private static String regField(int reg) {
1830         return regField[reg];
1831                                    
1832         /*String field;
1833         switch(reg) {
1834             case HI: field = "hi"; break;
1835             case LO: field = "lo"; break;
1836             case FCSR: field = "fcsr"; break;
1837             default:
1838                 if(reg > R && reg < R+32) regFieldR[reg-R];
1839                 else if(reg >= F && reg < F+32) return regFieldF[
1840                 else throw new IllegalArgumentException(""+reg);
1841         }
1842         return field;*/
1843     }
1844     
1845     private boolean doLocal(int reg) {
1846         //return false;
1847         return reg == R+2 || reg == R+3 || reg == R+4 || reg == R+29;
1848     }
1849     
1850     private InstructionHandle pushRegWZ(int reg) {
1851         if(reg == R+0) {
1852             warn.println("Warning: Pushing r0!");
1853             new Exception().printStackTrace(warn);
1854         }
1855         return pushRegZ(reg);
1856     }
1857     
1858     private InstructionHandle pushRegZ(int reg) {
1859         if(reg == R+0) return pushConst(0);
1860         else return pushReg(reg);
1861     }
1862     
1863     
1864     private InstructionHandle pushReg(int reg) {
1865         InstructionHandle h;
1866         if(doLocal(reg)) {
1867             regLocalReadCount[reg]++;
1868             h = a(InstructionFactory.createLoad(Type.INT,getLocalForReg(reg)));
1869         } else {
1870             h = a(InstructionConstants.ALOAD_0);
1871             a(fac.createFieldAccess(fullClassName,regField(reg),Type.INT, GETFIELD));
1872         }
1873         return h;
1874     }
1875     
1876     private int preSetRegStackPos;
1877     private int[] preSetRegStack = new int[8];
1878     
1879     // This can push ONE or ZERO words to the stack. If it pushed one it returns true
1880     private boolean preSetReg(int reg) {
1881         regField(reg); // just to check for validity
1882         preSetRegStack[preSetRegStackPos] = reg;
1883         preSetRegStackPos++;
1884         if(doLocal(reg)) {
1885             return false;
1886         } else {
1887             a(InstructionConstants.ALOAD_0);
1888             return true;
1889         }
1890     }
1891     
1892     private InstructionHandle setReg() {
1893         if(preSetRegStackPos==0) throw new RuntimeException("didn't do preSetReg");
1894         preSetRegStackPos--;
1895         int reg = preSetRegStack[preSetRegStackPos];
1896         InstructionHandle h;
1897         if(doLocal(reg)) {
1898             h = a(InstructionFactory.createStore(Type.INT,getLocalForReg(reg)));
1899             regLocalWriteCount[reg]++;
1900         } else {
1901             h = a(fac.createFieldAccess(fullClassName,regField(reg),Type.INT, PUTFIELD));
1902         }
1903         return h;
1904     }
1905     
1906     private InstructionHandle preSetPC() { return a(InstructionConstants.ALOAD_0); }
1907     private InstructionHandle setPC() { return a(fac.createFieldAccess(fullClassName,"pc",Type.INT, PUTFIELD)); }
1908     
1909     //unused - private InstructionHandle pushFloat(int reg) throws CompilationException { return pushDouble(reg,false); }
1910     //unused - private InstructionHandle pushDouble(int reg) throws CompilationException { return pushDouble(reg,true); }
1911     private InstructionHandle pushDouble(int reg, boolean d) throws Exn {
1912         if(reg < F || reg >= F+32) throw new IllegalArgumentException(""+reg);
1913         InstructionHandle h;
1914         if(d) {
1915             if(reg == F+31) throw new Exn("Tried to use a double in f31");
1916             h = pushReg(reg+1);
1917             a(InstructionConstants.I2L);
1918             pushConst(32);
1919             a(InstructionConstants.LSHL);
1920             pushReg(reg);
1921             a(InstructionConstants.I2L);
1922             pushConst(0xffffffffL);
1923             a(InstructionConstants.LAND);
1924             a(InstructionConstants.LOR);
1925             //p("invokestatic java/lang/Double/longBitsToDouble(J)D");
1926             a(fac.createInvoke("java.lang.Double","longBitsToDouble",Type.DOUBLE,new Type[]{Type.LONG},INVOKESTATIC));
1927         } else {
1928             h = pushReg(reg);
1929             a(fac.createInvoke("java.lang.Float","intBitsToFloat",Type.FLOAT,new Type[]{Type.INT},INVOKESTATIC));
1930         }
1931         return h;
1932     }
1933     
1934     private void preSetFloat(int reg) { preSetDouble(reg,false); }
1935     private void preSetDouble(int reg) { preSetDouble(reg,true); }
1936     private void preSetDouble(int reg, boolean d) { preSetReg(reg); }
1937     
1938     private InstructionHandle setFloat() throws Exn { return setDouble(false); }
1939     private InstructionHandle setDouble() throws Exn { return setDouble(true); }
1940     private InstructionHandle setDouble(boolean d) throws Exn {
1941         int reg = preSetRegStack[preSetRegStackPos-1];
1942         if(reg < F || reg >= F+32) throw new IllegalArgumentException(""+reg);
1943         //p("invokestatic java/lang/Double/doubleToLongBits(D)J");
1944         InstructionHandle h;
1945         if(d) {
1946             if(reg == F+31) throw new Exn("Tried to use a double in f31");
1947             h = a(fac.createInvoke("java.lang.Double","doubleToLongBits",Type.LONG,new Type[]{Type.DOUBLE},INVOKESTATIC));
1948             a(InstructionConstants.DUP2);
1949             pushConst(32);
1950             a(InstructionConstants.LUSHR);
1951             a(InstructionConstants.L2I);
1952             if(preSetReg(reg+1))
1953                 a(InstructionConstants.SWAP);
1954             setReg();
1955             a(InstructionConstants.L2I);
1956             setReg(); // preSetReg was already done for this by preSetDouble
1957         } else {
1958             h = a(fac.createInvoke("java.lang.Float","floatToRawIntBits",Type.INT,new Type[]{Type.FLOAT},INVOKESTATIC));
1959             setReg();   
1960         }
1961         return h;
1962     }
1963         
1964     private Hashtable intCache = new Hashtable();
1965     
1966     private InstructionHandle pushConst(int n) {
1967         if(n >= -1 && n <= 5) {
1968             switch(n) {
1969                 case -1: return a(InstructionConstants.ICONST_M1);
1970                 case 0: return a(InstructionConstants.ICONST_0);
1971                 case 1: return a(InstructionConstants.ICONST_1);
1972                 case 2: return a(InstructionConstants.ICONST_2);
1973                 case 3: return a(InstructionConstants.ICONST_3);
1974                 case 4: return a(InstructionConstants.ICONST_4);
1975                 case 5: return a(InstructionConstants.ICONST_5);
1976                 default: return null;
1977             }
1978         } else if(n >= -128 && n <= 127) {
1979             return a(new BIPUSH((byte) n));
1980         } else if(n >= -32768 && n <= 32767) {
1981             return a(new SIPUSH((short) n));
1982         } else {
1983             return a(new PUSH(cp,n));
1984         }
1985     }
1986     
1987     private InstructionHandle pushConst(long l) { return a(new PUSH(cp,l)); }
1988     private InstructionHandle pushConst(float f) { return a(new PUSH(cp,f)); }
1989     private InstructionHandle pushConst(double d) { return a(new PUSH(cp,d)); }
1990     
1991     private void pushTmp() { a(InstructionConstants.ILOAD_1); }
1992     private void setTmp() { a(InstructionConstants.ISTORE_1); }
1993     
1994     private void addiu(int reg, int offset) {
1995         if(reg != R+0 && offset != 0) {
1996             pushReg(reg);
1997             pushConst(offset);
1998             a(InstructionConstants.IADD);
1999         } else if(reg != R+0) {
2000             pushReg(reg);
2001         } else {
2002             pushConst(offset);
2003         }        
2004     }
2005     private int memWriteStage;
2006     private void preMemWrite1() {
2007         if(memWriteStage!=0) throw new Error("pending preMemWrite1/2");
2008         memWriteStage=1;
2009         if(onePage)
2010             a(InstructionConstants.ALOAD_2);
2011         else if(fastMem)
2012             a(InstructionFactory.createLoad(Type.OBJECT,3));
2013         else
2014             a(InstructionConstants.ALOAD_0);
2015     }
2016     
2017     private void preMemWrite2(int reg, int offset) {
2018         addiu(reg,offset);
2019         preMemWrite2();
2020     }
2021     
2022     private void preMemWrite2() { preMemWrite2(false); }
2023     private void preMemWrite2(boolean addrInTmp) {
2024         if(memWriteStage!=1) throw new Error("pending preMemWrite2 or no preMemWrite1");
2025         memWriteStage=2;
2026         
2027         if(nullPointerCheck) {
2028             a(InstructionConstants.DUP);
2029             a(InstructionConstants.ALOAD_0);
2030             a(InstructionConstants.SWAP);
2031             a(fac.createInvoke(fullClassName,"nullPointerCheck",Type.VOID,new Type[]{Type.INT},INVOKEVIRTUAL));
2032         }
2033         
2034         if(onePage) {
2035             a(InstructionConstants.ICONST_2);
2036             a(InstructionConstants.IUSHR);
2037         } else if(fastMem) {
2038             if(!addrInTmp)
2039                 a(InstructionConstants.DUP_X1);
2040             pushConst(pageShift);
2041             a(InstructionConstants.IUSHR);
2042             a(InstructionConstants.AALOAD);
2043             if(addrInTmp)
2044                 pushTmp();
2045             else
2046                 a(InstructionConstants.SWAP);
2047             a(InstructionConstants.ICONST_2);
2048             a(InstructionConstants.IUSHR);
2049             pushConst((pageSize>>2)-1);
2050             a(InstructionConstants.IAND);            
2051         }
2052     }
2053     
2054     // pops an address and value off the stack, sets *addr to value
2055     private void memWrite() {
2056         if(memWriteStage!=2) throw new Error("didn't do preMemWrite1 or preMemWrite2");
2057         memWriteStage=0;
2058                 
2059         if(onePage) {
2060             a(InstructionConstants.IASTORE);
2061         } else if(fastMem) {
2062             a(InstructionConstants.IASTORE);
2063         } else {
2064             a(fac.createInvoke(fullClassName,"unsafeMemWrite",Type.VOID,new Type[]{Type.INT,Type.INT},INVOKEVIRTUAL));
2065         }
2066         
2067     }
2068     
2069     // reads the word at r[reg]+offset
2070     private void memRead(int reg, int offset) {
2071         preMemRead();
2072         addiu(reg,offset);
2073         memRead();
2074     }
2075     
2076     private boolean didPreMemRead;
2077     private boolean preMemReadDoPreWrite;
2078     
2079     private void preMemRead() { preMemRead(false); }
2080     private void preMemRead(boolean preWrite) {
2081         if(didPreMemRead) throw new Error("pending preMemRead");
2082         didPreMemRead = true;
2083         preMemReadDoPreWrite = preWrite;
2084         if(onePage)
2085             a(InstructionConstants.ALOAD_2);
2086         else if(fastMem)
2087             a(InstructionFactory.createLoad(Type.OBJECT,preWrite ? 3 : 2));
2088         else
2089             a(InstructionConstants.ALOAD_0);
2090     }
2091     // memRead pops an address off the stack, reads the value at that addr, and pushed the value
2092     // preMemRead MUST be called BEFORE the addresses is pushed
2093     private void memRead() { memRead(false); }
2094     
2095     private void memRead(boolean addrInTmp) {
2096         if(!didPreMemRead) throw new Error("didn't do preMemRead");
2097         didPreMemRead = false;
2098         if(preMemReadDoPreWrite)
2099             memWriteStage=2; 
2100             
2101         if(nullPointerCheck) {
2102             a(InstructionConstants.DUP);
2103             a(InstructionConstants.ALOAD_0);
2104             a(InstructionConstants.SWAP);
2105             a(fac.createInvoke(fullClassName,"nullPointerCheck",Type.VOID,new Type[]{Type.INT},INVOKEVIRTUAL));
2106         }
2107         
2108         if(onePage) {
2109             // p(target + "= page[(" + addr + ")>>>2];");
2110             a(InstructionConstants.ICONST_2);
2111             a(InstructionConstants.IUSHR);
2112             if(preMemReadDoPreWrite)
2113                 a(InstructionConstants.DUP2);
2114             a(InstructionConstants.IALOAD);
2115         } else if(fastMem) {
2116             //p(target  + " = readPages[("+addr+")>>>"+pageShift+"][(("+addr+")>>>2)&"+toHex((pageSize>>2)-1)+"];");
2117             
2118             if(!addrInTmp)
2119                 a(InstructionConstants.DUP_X1);
2120             pushConst(pageShift);
2121             a(InstructionConstants.IUSHR);
2122             a(InstructionConstants.AALOAD);
2123             if(addrInTmp)
2124                 pushTmp();
2125             else
2126                 a(InstructionConstants.SWAP);
2127             a(InstructionConstants.ICONST_2);
2128             a(InstructionConstants.IUSHR);
2129             pushConst((pageSize>>2)-1);
2130             a(InstructionConstants.IAND);
2131             if(preMemReadDoPreWrite)
2132                 a(InstructionConstants.DUP2);
2133             a(InstructionConstants.IALOAD);
2134             
2135         } else {
2136             if(preMemReadDoPreWrite)
2137                 a(InstructionConstants.DUP2);
2138             a(fac.createInvoke(fullClassName,"unsafeMemWrite",Type.INT,new Type[]{Type.INT},INVOKEVIRTUAL));
2139         }
2140     }
2141     
2142     
2143     // This might come in handy for something else
2144     /*private boolean touchesReg(int insn, int reg) {
2145         if((reg < R+0 || reg >= R+32) && reg != FCSR) throw new IllegalArgumentException(""+reg);
2146         if(reg == R+0) return false; // r0 is never modified
2147         int op = (insn >>> 26) & 0xff;                 // bits 26-31
2148         int subcode = insn & 0x3f;                     // bits 0-5 
2149         int rd = (insn >>> 11) & 0x1f;                 // bits 11-15
2150         int rt = (insn >>> 16) & 0x1f;                 // bits 16-20 
2151         int rs = (insn >>> 21) & 0x1f;                 // bits 21-25
2152         
2153         switch(op) {
2154         case 0:
2155             if(subcode >= 0 && subcode <= 7) return reg == R+rd; // Shift ops
2156             if(subcode >= 32 && subcode <= 43) return reg == R+rd; // Other math ops 
2157             if(subcode >= 24 && subcode <= 27) return reg == HI || reg == LO; // MULT/DIV
2158             break;
2159         case 13: return false; // BREAK
2160         case 17:
2161             switch(rs) {
2162                 case 0: return reg == R+rt; // MFC.1
2163                 case 2: return reg == R+rt; // CFC.1
2164                 case 4: return false; // MTC.1
2165                 case 6: return false; // CTC.1
2166                 case 16: // Single 
2167                 case 17: // Double
2168                     if(subcode == 50 || subcode == 60 || subcode == 62) return reg == FCSR;
2169                     return false; // everything else just touches f0-f31
2170                 case 20: return false; // Integer - just touches f0-f31
2171             }
2172             break;
2173         default:
2174             if(op >= 8 && op <= 15) return reg == R+rt; // XXXI instructions
2175             if(op >= 40 && op <= 46) return false; // Memory WRITE ops
2176             if(op == 49) return reg == F+rt; // LWC1
2177             if(op == 57) return false; // SWC1
2178             break;
2179         }
2180         warn.println("Unknown instruction in touchesReg()- assuming it modifies all regs " + op + " " + subcode);
2181         new Exception().fillInStackTrace().printStackTrace(warn);
2182         return true;
2183     }*/
2184 }