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