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