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