1 package org.ibex.nestedvm;
4 import java.util.Hashtable;
6 import org.ibex.nestedvm.util.*;
8 import org.apache.bcel.generic.*;
10 // FEATURE: Use IINC where possible
11 // FEATURE: Use BCEL to do peephole optimization
12 // FEATURE: Special mode to support single-precision only - regs are floats not ints
14 /* FEATURE: Span large binaries across several classfiles
15 * We should be able to do this with no performance penalty
16 * Every method in the inner classes is static and takes the main class as an arg
17 * This makes them look just like methods in the main class because arg1 gets loaded into
21 /* FEATURE: smarter with local regs
22 * Be even smarter with the use of local registers. We need to only load fields into
23 * local regs when they are actually used and only write to fields if the regs could have
24 * changed. This should allow us to put more regs in local vars. Right now putting all used
25 * regs local vars makes code like this slower.
27 * void work(int a, int b) {
34 * Because all the regs used in "real work" are loaded/restored even for fast path
38 public class ClassFileCompiler extends Compiler implements org.apache.bcel.Constants {
39 /** The stream to write the compiled output to */
40 private OutputStream os;
41 private PrintStream warn = System.err;
44 private ConstantPoolGen cp;
45 private InstructionList clinitExtras = new InstructionList();
46 private InstructionList initExtras = new InstructionList();
47 private InstructionFactory fac;
49 // Handy wrappers around the BCEL functions
50 private InstructionList insnList;
51 private void selectMethod(MethodGen m) { insnList = m.getInstructionList(); }
52 private void selectList(InstructionList l) { insnList = l; }
53 private InstructionHandle a(Instruction i) { return insnList.append(i); }
54 private BranchHandle a(BranchInstruction i) { return insnList.append(i); }
55 private InstructionHandle a(InstructionList l) { return insnList.append(l); }
56 private InstructionHandle a(CompoundInstruction c) { return insnList.append(c); }
58 // This works around a bug in InstructionList
59 // FEATURE: fix this in bcel, send them a patch, etc
60 private static class FixedInstructionList extends InstructionList {
61 public void move(InstructionHandle start, InstructionHandle end, InstructionHandle target) {
62 InstructionHandle extra = target != null && target == getEnd() ? append(InstructionConstants.NOP) : null;
63 super.move(start,end,target);
64 if(extra != null) try { delete(extra); } catch (TargetLostException e) { /* won't happen */ }
68 private MethodGen newMethod(int flags, Type ret, Type[] args, String name) {
69 return new MethodGen(flags,ret,args,null,name,fullClassName,new FixedInstructionList(),cp);
72 public ClassFileCompiler(String path, String className, OutputStream os) throws IOException { this(new Seekable.File(path),className,os); }
73 public ClassFileCompiler(Seekable binary, String className, OutputStream os) throws IOException {
74 super(binary,className);
78 public void setWarnWriter(PrintStream warn) { this.warn = warn; }
80 protected void _go() throws Exn, IOException {
81 if(lessConstants) throw new Exn("ClassFileCompiler doesn't support -o lessconstants");
82 if(!pruneCases) throw new Exn("-o prunecases MUST be enabled for ClassFileCompiler");
85 cl = new ClassGen(fullClassName,runtimeClass,source,ACC_SUPER|ACC_PUBLIC|ACC_FINAL,null);
86 cp = cl.getConstantPool();
87 fac = new InstructionFactory(cl,cp);
90 cl.addField(new FieldGen(ACC_PRIVATE,Type.INT,"pc",cp).getField());
92 cl.addField(new FieldGen(ACC_PRIVATE,Type.INT,"r"+i,cp).getField());
94 cl.addField(new FieldGen(ACC_PRIVATE,Type.INT,"f"+i,cp).getField());
96 cl.addField(new FieldGen(ACC_PRIVATE,Type.INT,"hi",cp).getField());
97 cl.addField(new FieldGen(ACC_PRIVATE,Type.INT,"lo",cp).getField());
98 cl.addField(new FieldGen(ACC_PRIVATE,Type.INT,"fcsr",cp).getField());
101 cl.addField(new FieldGen(ACC_PRIVATE|ACC_FINAL,new ArrayType(Type.INT,1),"page",cp).getField());
103 selectList(initExtras);
104 a(InstructionConstants.ALOAD_0);
105 a(InstructionConstants.DUP);
106 a(fac.createFieldAccess(fullClassName,"readPages",new ArrayType(Type.INT, 2), GETFIELD));
108 a(InstructionConstants.AALOAD);
109 a(fac.createFieldAccess(fullClassName,"page",new ArrayType(Type.INT,1), PUTFIELD));
113 cl.addField(new FieldGen(ACC_PRIVATE|ACC_STATIC|ACC_FINAL,Type.getType("L"+hashClass.replace('.','/')+";"),"symbols",cp).getField());
117 for(int i=0;i<elf.sheaders.length;i++) {
118 ELF.SHeader sheader = elf.sheaders[i];
119 String name = sheader.name;
120 // if this section doesn't get loaded into our address space don't worry about it
121 if(sheader.addr == 0x0) continue;
123 highestAddr = Math.max(highestAddr, sheader.addr + sheader.size);
125 if(name.equals(".text"))
126 emitText(sheader.addr, new DataInputStream(sheader.getInputStream()),sheader.size);
127 else if(name.equals(".data") || name.equals(".sdata") || name.equals(".rodata") || name.equals(".ctors") || name.equals(".dtors"))
128 emitData(sheader.addr, new DataInputStream(sheader.getInputStream()), sheader.size,name.equals(".rodata"));
129 else if(name.equals(".bss") || name.equals(".sbss"))
130 emitBSS(sheader.addr,sheader.size);
132 throw new Exn("Unknown segment: " + name);
135 ELF.SHeader text = elf.sectionWithName(".text");
138 MethodGen tramp = newMethod(ACC_PRIVATE,Type.VOID, Type.NO_ARGS, "trampoline");
139 tramp.addException("org.ibex.nestedvm.Runtime$ExecutionException");
142 InstructionHandle start = a(InstructionConstants.ALOAD_0);
143 a(fac.createFieldAccess(fullClassName,"state",Type.INT, GETFIELD));
144 pushConst(Runtime.RUNNING);
145 BranchInstruction stateCheck = InstructionFactory.createBranchInstruction(IF_ICMPNE,null);
147 a(InstructionConstants.ALOAD_0);
148 a(InstructionConstants.ALOAD_0);
149 a(fac.createFieldAccess(fullClassName,"pc",Type.INT, GETFIELD));
150 pushConst(methodShift);
151 a(InstructionConstants.IUSHR);
153 int beg = text.addr >>> methodShift;
154 int end = ((text.addr + text.size + maxBytesPerMethod - 1) >>> methodShift);
156 // This data is redundant but BCEL wants it
157 int[] matches = new int[end-beg];
158 for(int i=beg;i<end;i++) matches[i-beg] = i;
159 TABLESWITCH ts = new TABLESWITCH(matches,new InstructionHandle[matches.length],null);
161 for(int n=beg;n<end;n++){
162 InstructionHandle h = a(fac.createInvoke(fullClassName,"run_"+toHex(n<<methodShift),Type.VOID,Type.NO_ARGS,INVOKESPECIAL));
163 a(InstructionFactory.createBranchInstruction(GOTO,start));
164 ts.setTarget(n-beg,h);
167 ts.setTarget(a(InstructionConstants.POP)); // default case
168 a(fac.createNew("org.ibex.nestedvm.Runtime$ExecutionException"));
169 a(InstructionConstants.DUP);
170 a(fac.createNew("java.lang.StringBuffer"));
171 a(InstructionConstants.DUP);
172 a(new PUSH(cp,"Jumped to invalid address in trampoline (r2: "));
173 a(fac.createInvoke("java.lang.StringBuffer","<init>",Type.VOID,new Type[]{Type.STRING},INVOKESPECIAL));
174 a(InstructionConstants.ALOAD_0);
175 a(fac.createFieldAccess(fullClassName,"r2",Type.INT, GETFIELD));
176 a(fac.createInvoke("java.lang.StringBuffer","append",Type.STRINGBUFFER,new Type[]{Type.INT},INVOKEVIRTUAL));
177 a(new PUSH(cp," pc:"));
178 a(fac.createInvoke("java.lang.StringBuffer","append",Type.STRINGBUFFER,new Type[]{Type.STRING},INVOKEVIRTUAL));
179 a(InstructionConstants.ALOAD_0);
180 a(fac.createFieldAccess(fullClassName,"pc",Type.INT, GETFIELD));
181 a(fac.createInvoke("java.lang.StringBuffer","append",Type.STRINGBUFFER,new Type[]{Type.INT},INVOKEVIRTUAL));
183 a(fac.createInvoke("java.lang.StringBuffer","append",Type.STRINGBUFFER,new Type[]{Type.CHAR},INVOKEVIRTUAL));
184 a(fac.createInvoke("java.lang.StringBuffer","toString",Type.STRING,Type.NO_ARGS,INVOKEVIRTUAL));
185 a(fac.createInvoke("org.ibex.nestedvm.Runtime$ExecutionException","<init>",Type.VOID,new Type[]{Type.STRING},INVOKESPECIAL));
186 a(InstructionConstants.ATHROW);
188 stateCheck.setTarget(a(InstructionConstants.RETURN));
191 tramp.setMaxLocals();
193 cl.addMethod(tramp.getMethod());
194 } catch(ClassGenException e) {
195 e.printStackTrace(warn);
196 throw new Exn("Generation of the trampoline method failed. Try increasing maxInsnPerMethod");
199 addConstReturnMethod("gp",gp.addr);
200 addConstReturnMethod("entryPoint",elf.header.entry);
201 addConstReturnMethod("heapStart",highestAddr);
203 if(userInfo != null) {
204 addConstReturnMethod("userInfoBase",userInfo.addr);
205 addConstReturnMethod("userInfoSize",userInfo.size);
208 // FEATURE: Allow specification of memory size at runtime (numpages)
210 MethodGen init = newMethod(ACC_PUBLIC,Type.VOID, Type.NO_ARGS, "<init>");
212 a(InstructionConstants.ALOAD_0);
214 pushConst(totalPages);
215 a(fac.createInvoke(runtimeClass,"<init>",Type.VOID,new Type[]{Type.INT,Type.INT},INVOKESPECIAL));
219 a(InstructionConstants.RETURN);
223 cl.addMethod(init.getMethod());
226 MethodGen clinit = newMethod(ACC_PRIVATE|ACC_STATIC,Type.VOID, Type.NO_ARGS, "<clinit>");
227 selectMethod(clinit);
231 a(fac.createNew(hashClass));
232 a(InstructionConstants.DUP);
233 a(InstructionConstants.DUP);
234 a(fac.createInvoke(hashClass,"<init>",Type.VOID,Type.NO_ARGS,INVOKESPECIAL));
235 a(fac.createFieldAccess(fullClassName,"symbols",Type.getType("L"+hashClass.replace('.','/')+";"), PUTSTATIC));
236 ELF.Symbol[] symbols = elf.getSymtab().symbols;
237 for(int i=0;i<symbols.length;i++) {
238 ELF.Symbol s = symbols[i];
239 if(s.type == ELF.Symbol.STT_FUNC && s.binding == ELF.Symbol.STB_GLOBAL && (s.name.equals("_call_helper") || !s.name.startsWith("_"))) {
240 a(InstructionConstants.DUP);
241 a(new PUSH(cp,s.name));
242 a(fac.createNew("java.lang.Integer"));
243 a(InstructionConstants.DUP);
244 a(new PUSH(cp,s.addr));
245 a(fac.createInvoke("java.lang.Integer","<init>",Type.VOID,new Type[]{Type.INT},INVOKESPECIAL));
246 a(fac.createInvoke(hashClass,"put",Type.OBJECT,new Type[]{Type.OBJECT,Type.OBJECT},INVOKEVIRTUAL));
247 a(InstructionConstants.POP);
250 a(InstructionConstants.POP);
253 a(InstructionConstants.RETURN);
254 clinit.setMaxLocals();
255 clinit.setMaxStack();
256 cl.addMethod(clinit.getMethod());
259 MethodGen lookupSymbol = newMethod(ACC_PROTECTED,Type.INT,new Type[]{Type.STRING},"lookupSymbol");
260 selectMethod(lookupSymbol);
261 a(fac.createFieldAccess(fullClassName,"symbols",Type.getType("L"+hashClass.replace('.','/')+";"), GETSTATIC));
262 a(InstructionConstants.ALOAD_1);
263 a(fac.createInvoke(hashClass,"get",Type.OBJECT,new Type[]{Type.OBJECT},INVOKEVIRTUAL));
264 a(InstructionConstants.DUP);
265 BranchHandle bh = a(InstructionFactory.createBranchInstruction(IFNULL,null));
266 a(fac.createCheckCast(new ObjectType("java.lang.Integer")));
267 a(fac.createInvoke("java.lang.Integer","intValue",Type.INT,Type.NO_ARGS,INVOKEVIRTUAL));
268 a(InstructionConstants.IRETURN);
269 bh.setTarget(a(InstructionConstants.POP));
270 a(InstructionConstants.ICONST_M1);
271 a(InstructionConstants.IRETURN);
272 lookupSymbol.setMaxLocals();
273 lookupSymbol.setMaxStack();
274 cl.addMethod(lookupSymbol.getMethod());
277 MethodGen setCPUState = newMethod(ACC_PROTECTED,Type.VOID,new Type[]{Type.getType("Lorg/ibex/nestedvm/Runtime$CPUState;")},"setCPUState");
278 selectMethod(setCPUState);
279 a(InstructionConstants.ALOAD_1);
280 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","r",new ArrayType(Type.INT,1),GETFIELD));
281 a(InstructionConstants.ASTORE_2);
282 for(int i=1;i<32;i++) {
283 a(InstructionConstants.ALOAD_0);
284 a(InstructionConstants.ALOAD_2);
286 a(InstructionConstants.IALOAD);
287 a(fac.createFieldAccess(fullClassName,"r"+i,Type.INT, PUTFIELD));
289 a(InstructionConstants.ALOAD_1);
290 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","f",new ArrayType(Type.INT,1),GETFIELD));
291 a(InstructionConstants.ASTORE_2);
292 for(int i=0;i<32;i++) {
293 a(InstructionConstants.ALOAD_0);
294 a(InstructionConstants.ALOAD_2);
296 a(InstructionConstants.IALOAD);
297 a(fac.createFieldAccess(fullClassName,"f"+i,Type.INT, PUTFIELD));
299 a(InstructionConstants.ALOAD_0);
300 a(InstructionConstants.ALOAD_1);
301 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","hi",Type.INT,GETFIELD));
302 a(fac.createFieldAccess(fullClassName,"hi",Type.INT, PUTFIELD));
303 a(InstructionConstants.ALOAD_0);
304 a(InstructionConstants.ALOAD_1);
305 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","lo",Type.INT,GETFIELD));
306 a(fac.createFieldAccess(fullClassName,"lo",Type.INT, PUTFIELD));
307 a(InstructionConstants.ALOAD_0);
308 a(InstructionConstants.ALOAD_1);
309 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","fcsr",Type.INT,GETFIELD));
310 a(fac.createFieldAccess(fullClassName,"fcsr",Type.INT, PUTFIELD));
311 a(InstructionConstants.ALOAD_0);
312 a(InstructionConstants.ALOAD_1);
313 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","pc",Type.INT,GETFIELD));
314 a(fac.createFieldAccess(fullClassName,"pc",Type.INT, PUTFIELD));
316 a(InstructionConstants.RETURN);
317 setCPUState.setMaxLocals();
318 setCPUState.setMaxStack();
319 cl.addMethod(setCPUState.getMethod());
321 MethodGen getCPUState = newMethod(ACC_PROTECTED,Type.VOID,new Type[]{Type.getType("Lorg/ibex/nestedvm/Runtime$CPUState;")},"getCPUState");
322 selectMethod(getCPUState);
323 a(InstructionConstants.ALOAD_1);
324 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","r",new ArrayType(Type.INT,1),GETFIELD));
325 a(InstructionConstants.ASTORE_2);
326 for(int i=1;i<32;i++) {
327 a(InstructionConstants.ALOAD_2);
329 a(InstructionConstants.ALOAD_0);
330 a(fac.createFieldAccess(fullClassName,"r"+i,Type.INT, GETFIELD));
331 a(InstructionConstants.IASTORE);
334 a(InstructionConstants.ALOAD_1);
335 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","f",new ArrayType(Type.INT,1),GETFIELD));
336 a(InstructionConstants.ASTORE_2);
337 for(int i=0;i<32;i++) {
338 a(InstructionConstants.ALOAD_2);
340 a(InstructionConstants.ALOAD_0);
341 a(fac.createFieldAccess(fullClassName,"f"+i,Type.INT, GETFIELD));
342 a(InstructionConstants.IASTORE);
344 a(InstructionConstants.ALOAD_1);
345 a(InstructionConstants.ALOAD_0);
346 a(fac.createFieldAccess(fullClassName,"hi",Type.INT, GETFIELD));
347 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","hi",Type.INT,PUTFIELD));
348 a(InstructionConstants.ALOAD_1);
349 a(InstructionConstants.ALOAD_0);
350 a(fac.createFieldAccess(fullClassName,"lo",Type.INT, GETFIELD));
351 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","lo",Type.INT,PUTFIELD));
352 a(InstructionConstants.ALOAD_1);
353 a(InstructionConstants.ALOAD_0);
354 a(fac.createFieldAccess(fullClassName,"fcsr",Type.INT, GETFIELD));
355 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","fcsr",Type.INT,PUTFIELD));
356 a(InstructionConstants.ALOAD_1);
357 a(InstructionConstants.ALOAD_0);
358 a(fac.createFieldAccess(fullClassName,"pc",Type.INT, GETFIELD));
359 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","pc",Type.INT,PUTFIELD));
361 a(InstructionConstants.RETURN);
362 getCPUState.setMaxLocals();
363 getCPUState.setMaxStack();
364 cl.addMethod(getCPUState.getMethod());
367 MethodGen execute = newMethod(ACC_PROTECTED,Type.VOID,Type.NO_ARGS,"_execute");
368 selectMethod(execute);
369 InstructionHandle tryStart = a(InstructionConstants.ALOAD_0);
370 InstructionHandle tryEnd = a(fac.createInvoke(fullClassName,"trampoline",Type.VOID,Type.NO_ARGS,INVOKESPECIAL));
371 a(InstructionConstants.RETURN);
373 InstructionHandle catchInsn = a(InstructionConstants.ASTORE_1);
374 a(fac.createNew("org.ibex.nestedvm.Runtime$FaultException"));
375 a(InstructionConstants.DUP);
376 a(InstructionConstants.ALOAD_1);
377 a(fac.createInvoke("org.ibex.nestedvm.Runtime$FaultException","<init>",Type.VOID,new Type[]{new ObjectType("java.lang.RuntimeException")},INVOKESPECIAL));
378 a(InstructionConstants.ATHROW);
380 execute.addExceptionHandler(tryStart,tryEnd,catchInsn,new ObjectType("java.lang.RuntimeException"));
381 execute.setMaxLocals();
382 execute.setMaxStack();
383 cl.addMethod(execute.getMethod());
386 MethodGen main = newMethod(ACC_STATIC|ACC_PUBLIC,Type.VOID,new Type[]{new ArrayType(Type.STRING,1)},"main");
388 a(fac.createNew(fullClassName));
389 a(InstructionConstants.DUP);
390 a(fac.createInvoke(fullClassName,"<init>",Type.VOID,Type.NO_ARGS,INVOKESPECIAL));
391 a(new PUSH(cp,fullClassName));
392 a(InstructionConstants.ALOAD_0);
394 a(fac.createInvoke("org.ibex.nestedvm.UnixRuntime","runAndExec",Type.INT,
395 new Type[]{Type.getType("Lorg/ibex/nestedvm/UnixRuntime;"),Type.STRING,new ArrayType(Type.STRING,1)},
398 a(fac.createInvoke(fullClassName,"run",Type.INT,new Type[]{Type.STRING,new ArrayType(Type.STRING,1)},INVOKEVIRTUAL));
399 a(fac.createInvoke("java.lang.System","exit",Type.VOID,new Type[]{Type.INT},INVOKESTATIC));
400 a(InstructionConstants.RETURN);
403 cl.addMethod(main.getMethod());
406 System.out.println("Constant Pool Size: " + cp.getSize());
407 cl.getJavaClass().dump(os);
410 private void addConstReturnMethod(String name, int val) {
411 MethodGen method = newMethod(ACC_PROTECTED,Type.INT, Type.NO_ARGS,name);
412 selectMethod(method);
414 a(InstructionConstants.IRETURN);
415 method.setMaxLocals();
416 method.setMaxStack();
417 cl.addMethod(method.getMethod());
420 private static int initDataCount;
421 private void emitData(int addr, DataInputStream dis, int size, boolean readOnly) throws Exn,IOException {
422 if((addr&3)!=0 || (size&3)!=0) throw new Exn("Data section on weird boundaries");
423 int last = addr + size;
425 int segSize = Math.min(size,28000); // must be a multiple of 56
426 StringBuffer sb = new StringBuffer();
427 for(int i=0;i<segSize;i+=7) {
429 for(int j=0;j<7;j++) {
431 byte b = (i+j < size) ? dis.readByte() : 1;
435 sb.append((char) ((l>>>(7*(7-j)))&0x7f));
437 String fieldname = "_data" + (++initDataCount);
438 cl.addField(new FieldGen(ACC_PRIVATE|ACC_STATIC|ACC_FINAL,new ArrayType(Type.INT,1),fieldname,cp).getField());
440 selectList(clinitExtras);
441 a(new PUSH(cp,sb.toString()));
442 a(new PUSH(cp,segSize/4));
443 a(fac.createInvoke("org.ibex.nestedvm.Runtime","decodeData",new ArrayType(Type.INT,1),new Type[]{Type.STRING,Type.INT},INVOKESTATIC));
444 a(fac.createPutStatic(fullClassName,fieldname,new ArrayType(Type.INT,1)));
446 selectList(initExtras);
447 a(InstructionConstants.ALOAD_0);
448 a(fac.createGetStatic(fullClassName,fieldname,new ArrayType(Type.INT,1)));
449 a(new PUSH(cp,addr));
450 a(new PUSH(cp,readOnly));
451 a(fac.createInvoke(fullClassName,"initPages",Type.VOID,new Type[]{new ArrayType(Type.INT,1),Type.INT,Type.BOOLEAN},INVOKEVIRTUAL));
459 private void emitBSS(int addr, int size) throws Exn {
460 if((addr&3)!=0) throw new Exn("BSS section on weird boundaries");
463 selectList(initExtras);
464 a(InstructionConstants.ALOAD_0);
465 a(new PUSH(cp,addr));
466 a(new PUSH(cp,count));
467 a(fac.createInvoke(fullClassName,"clearPages",Type.VOID,new Type[]{Type.INT,Type.INT},INVOKEVIRTUAL));
471 private boolean textDone;
472 private int startOfMethod = 0;
473 private int endOfMethod = 0;
474 private boolean unreachable = false;
475 private InstructionHandle[] jumpHandles;
476 private InstructionHandle defaultHandle;
477 private InstructionHandle returnHandle;
478 private InstructionHandle realStart;
479 private MethodGen curMethod;
481 private boolean jumpable(int addr) { return jumpableAddresses.get(new Integer(addr)) != null; }
483 private void emitText(int addr, DataInputStream dis, int size) throws Exn,IOException {
484 if(textDone) throw new Exn("Multiple text segments");
487 if((addr&3)!=0 || (size&3)!=0) throw new Exn("Section on weird boundaries");
489 int insn,nextInsn=-1;
490 boolean skipNext = true;
492 for(int i=0;i<count;i++,addr+=4) {
493 insn = skipNext ? dis.readInt() : nextInsn;
494 nextInsn = (i == count-1) ? -1 : dis.readInt();
495 if(addr >= endOfMethod) { endMethod(addr); startMethod(addr); }
496 if(jumpHandles[(addr-startOfMethod)/4] != null) {
497 // Move the fake jump target to the current location
498 insnList.move(jumpHandles[(addr-startOfMethod)/4],insnList.getEnd());
500 } else if(unreachable) {
504 skipNext = emitInstruction(addr,insn,nextInsn);
505 } catch(RuntimeException e) {
506 warn.println("Exception at " + toHex(addr));
509 if(skipNext) { addr+=4; i++; }
515 private void startMethod(int first) {
516 startOfMethod = first & methodMask;
517 endOfMethod = startOfMethod + maxBytesPerMethod;
518 curMethod = newMethod(ACC_PRIVATE,Type.VOID,Type.NO_ARGS,"run_" + toHex(startOfMethod));
519 selectMethod(curMethod);
521 int[] buf = new int[maxBytesPerMethod/4];
522 jumpHandles = new InstructionHandle[maxBytesPerMethod/4];
524 for(int addr=first;addr<endOfMethod;addr+=4) {
527 // append NOPs for GOTO jumps (these will be moved to the correct location later)
528 jumpHandles[(addr-startOfMethod)/4] = a(InstructionConstants.NOP);
532 // append NOP for default case (throw exn) (this will be moved later)
533 defaultHandle = a(InstructionConstants.NOP);
534 returnHandle = a(InstructionConstants.NOP);
536 int[] matches = new int[n];
537 System.arraycopy(buf,0,matches,0,n);
538 InstructionHandle[] targets = new InstructionHandle[n];
539 for(int i=0;i<matches.length;i++)
540 targets[i] = jumpHandles[(matches[i]-startOfMethod)/4];
543 // First instruction of the actual method - everything above this should be removed
544 // before we get to the end
545 realStart = a(InstructionConstants.NOP);
548 a(InstructionConstants.ALOAD_0);
549 a(fac.createFieldAccess(fullClassName,"page",new ArrayType(Type.INT,1), GETFIELD));
550 a(InstructionConstants.ASTORE_2);
552 a(InstructionConstants.ALOAD_0);
553 a(fac.createFieldAccess(fullClassName,"readPages",new ArrayType(Type.INT,2), GETFIELD));
554 a(InstructionConstants.ASTORE_2);
555 a(InstructionConstants.ALOAD_0);
556 a(fac.createFieldAccess(fullClassName,"writePages",new ArrayType(Type.INT,2), GETFIELD));
557 a(InstructionFactory.createStore(Type.OBJECT,3));
560 LOOKUPSWITCH initialSwitch = new LOOKUPSWITCH(matches,targets,defaultHandle);
561 a(InstructionConstants.ALOAD_0);
562 a(fac.createFieldAccess(fullClassName,"pc",Type.INT, GETFIELD));
566 private void endMethod(int firstAddrOfNext) {
567 if(startOfMethod == 0) return;
571 pushConst(firstAddrOfNext);
573 // mark the start of the next method as jumpable
574 jumpableAddresses.put(new Integer(firstAddrOfNext),Boolean.TRUE);
577 insnList.move(returnHandle,insnList.getEnd());
579 a(InstructionConstants.RETURN);
581 // move the default jump target (lookupswitch) to before the throw
582 insnList.move(defaultHandle,insnList.getEnd());
584 a(fac.createNew("org.ibex.nestedvm.Runtime$ExecutionException"));
585 a(InstructionConstants.DUP);
586 a(fac.createNew("java.lang.StringBuffer"));
587 a(InstructionConstants.DUP);
588 a(new PUSH(cp,"Jumped to invalid address: "));
589 a(fac.createInvoke("java.lang.StringBuffer","<init>",Type.VOID,new Type[]{Type.STRING},INVOKESPECIAL));
590 a(InstructionConstants.ALOAD_0);
591 a(fac.createFieldAccess(fullClassName,"pc",Type.INT, GETFIELD));
592 a(fac.createInvoke("java.lang.StringBuffer","append",Type.STRINGBUFFER,new Type[]{Type.INT},INVOKEVIRTUAL));
593 a(fac.createInvoke("java.lang.StringBuffer","toString",Type.STRING,Type.NO_ARGS,INVOKEVIRTUAL));
594 a(fac.createInvoke("org.ibex.nestedvm.Runtime$ExecutionException","<init>",Type.VOID,new Type[]{Type.STRING},INVOKESPECIAL));
595 a(InstructionConstants.ATHROW);
597 a(fac.createNew("org.ibex.nestedvm.Runtime$ExecutionException"));
598 a(InstructionConstants.DUP);
599 a(new PUSH(cp,"Jumped to invalid address"));
600 a(fac.createInvoke("org.ibex.nestedvm.Runtime$ExecutionException","<init>",Type.VOID,new Type[]{Type.STRING},INVOKESPECIAL));
601 a(InstructionConstants.ATHROW);
604 if(insnList.getStart() != realStart) {
605 System.err.println(insnList);
606 throw new Error("A jumpHandle wasn't moved into place");
609 curMethod.removeNOPs();
610 curMethod.setMaxLocals();
611 curMethod.setMaxStack();
613 cl.addMethod(curMethod.getMethod());
615 endOfMethod = startOfMethod = 0;
619 private void leaveMethod() {
620 a(InstructionFactory.createBranchInstruction(GOTO,returnHandle));
623 private void branch(int pc, int target) {
624 if((pc&methodMask) == (target&methodMask)) {
625 a(InstructionFactory.createBranchInstruction(GOTO,jumpHandles[(target-startOfMethod)/4]));
634 // This assumes everything needed by ifInsn is already on the stack
635 private boolean doIfInstruction(short op, int pc, int target, int nextInsn) throws Exn {
636 emitInstruction(-1,nextInsn,-1); // delay slot
638 IfInstruction ifInsn = (IfInstruction) InstructionFactory.createBranchInstruction(op,null);
639 if((target&methodMask) == (pc&methodMask)) {
641 h.setTarget(jumpHandles[(target-startOfMethod)/4]);
643 h = a(ifInsn.negate());
645 h.setTarget(a(InstructionConstants.NOP));
647 if(!jumpable(pc+4)) return true; // done - skip it
649 //System.err.println("Delay slot is jumpable - This code is untested + " + toHex(nextInsn));
650 if(pc+4==endOfMethod) {
651 // the delay slot is at the start of the next method
652 jumpableAddresses.put(new Integer(pc+8),Boolean.TRUE); // make the 2nd insn of the next method jumpable
653 branch(pc,pc+8); // jump over it
654 //System.err.println("delay slot: " + toHex(pc+8));
656 return false; // we still need to output it
658 //System.err.println("jumped over delay slot: " + toHex(pc+4));
659 // add another copy and jump over
660 h = a(InstructionFactory.createBranchInstruction(GOTO,null));
661 insnList.move(jumpHandles[(pc+4-startOfMethod)/4],insnList.getEnd());
662 emitInstruction(-1,nextInsn,-1); // delay slot
663 h.setTarget(a(InstructionConstants.NOP));
668 private boolean emitInstruction(int pc, int insn, int nextInsn) throws Exn {
669 if(insn == -1) throw new Exn("insn is -1");
671 int op = (insn >>> 26) & 0xff; // bits 26-31
672 int rs = (insn >>> 21) & 0x1f; // bits 21-25
673 int rt = (insn >>> 16) & 0x1f; // bits 16-20
674 int ft = (insn >>> 16) & 0x1f;
675 int rd = (insn >>> 11) & 0x1f; // bits 11-15
676 int fs = (insn >>> 11) & 0x1f;
677 int shamt = (insn >>> 6) & 0x1f; // bits 6-10
678 int fd = (insn >>> 6) & 0x1f;
679 int subcode = insn & 0x3f; // bits 0-5
680 int breakCode = (insn >>> 6) & 0xfffff; // bits 6-20
682 int jumpTarget = (insn & 0x03ffffff); // bits 0-25
683 int unsignedImmediate = insn & 0xffff;
684 int signedImmediate = (insn << 16) >> 16;
685 int branchTarget = signedImmediate;
698 a(InstructionConstants.ISHL);
705 a(InstructionConstants.IUSHR);
712 a(InstructionConstants.ISHR);
719 a(InstructionConstants.ISHL);
726 a(InstructionConstants.IUSHR);
733 a(InstructionConstants.ISHR);
737 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
738 emitInstruction(-1,nextInsn,-1);
746 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
747 emitInstruction(-1,nextInsn,-1);
763 restoreChangedRegs();
766 a(InstructionConstants.ALOAD_0);
774 a(fac.createInvoke(fullClassName,"syscall",Type.INT,new Type[]{Type.INT,Type.INT,Type.INT,Type.INT,Type.INT,Type.INT,Type.INT},INVOKEVIRTUAL));
777 a(InstructionConstants.ALOAD_0);
778 a(fac.createFieldAccess(fullClassName,"state",Type.INT, GETFIELD));
779 pushConst(Runtime.RUNNING);
780 b1 = a(InstructionFactory.createBranchInstruction(IF_ICMPEQ,null));
785 b1.setTarget(a(InstructionConstants.NOP));
789 a(fac.createNew("org.ibex.nestedvm.Runtime$ExecutionException"));
790 a(InstructionConstants.DUP);
791 a(new PUSH(cp,"BREAK Code " + toHex(breakCode)));
792 a(fac.createInvoke("org.ibex.nestedvm.Runtime$ExecutionException","<init>",Type.VOID,new Type[]{Type.STRING},INVOKESPECIAL));
793 a(InstructionConstants.ATHROW);
818 a(InstructionConstants.I2L);
820 a(InstructionConstants.I2L);
821 a(InstructionConstants.LMUL);
822 a(InstructionConstants.DUP2);
824 a(InstructionConstants.L2I);
826 a(InstructionConstants.SWAP);
830 a(InstructionConstants.LUSHR);
831 a(InstructionConstants.L2I);
833 a(InstructionConstants.SWAP);
839 a(InstructionConstants.I2L);
840 pushConst(0xffffffffL);
841 a(InstructionConstants.LAND);
843 a(InstructionConstants.I2L);
844 pushConst(0xffffffffL);
845 a(InstructionConstants.LAND);
846 a(InstructionConstants.LMUL);
847 a(InstructionConstants.DUP2);
849 a(InstructionConstants.L2I);
851 a(InstructionConstants.SWAP);
855 a(InstructionConstants.LUSHR);
856 a(InstructionConstants.L2I);
858 a(InstructionConstants.SWAP);
865 a(InstructionConstants.DUP2);
867 a(InstructionConstants.IDIV);
869 a(InstructionConstants.SWAP);
872 a(InstructionConstants.IREM);
874 a(InstructionConstants.SWAP);
880 a(InstructionConstants.DUP);
882 b1 = a(InstructionFactory.createBranchInstruction(IFEQ,null));
885 a(InstructionConstants.I2L);
886 pushConst(0xffffffffL);
887 a(InstructionConstants.LAND);
888 a(InstructionConstants.DUP2);
890 a(InstructionConstants.I2L);
891 pushConst(0xffffffffL);
893 a(InstructionConstants.LAND);
894 a(InstructionConstants.DUP2_X2);
895 a(InstructionConstants.LDIV);
897 a(InstructionConstants.L2I);
899 a(InstructionConstants.SWAP);
902 a(InstructionConstants.LREM);
903 a(InstructionConstants.L2I);
905 a(InstructionConstants.SWAP);
908 b1.setTarget(a(InstructionConstants.NOP));
913 throw new Exn("ADD (add with oveflow trap) not suported");
916 if(rt != 0 && rs != 0) {
919 a(InstructionConstants.IADD);
928 throw new Exn("SUB (add with oveflow trap) not suported");
931 if(rt != 0 && rs != 0) {
934 a(InstructionConstants.ISUB);
937 a(InstructionConstants.INEG);
947 a(InstructionConstants.IAND);
954 a(InstructionConstants.IOR);
961 a(InstructionConstants.IXOR);
966 if(rs != 0 || rt != 0) {
967 if(rs != 0 && rt != 0) {
970 a(InstructionConstants.IOR);
976 a(InstructionConstants.ICONST_M1);
977 a(InstructionConstants.IXOR);
988 b1 = a(InstructionFactory.createBranchInstruction(IF_ICMPLT,null));
989 a(InstructionConstants.ICONST_0);
990 b2 = a(InstructionFactory.createBranchInstruction(GOTO,null));
991 b1.setTarget(a(InstructionConstants.ICONST_1));
992 b2.setTarget(a(InstructionConstants.NOP));
1003 a(InstructionConstants.I2L);
1004 pushConst(0xffffffffL);
1005 a(InstructionConstants.LAND);
1007 a(InstructionConstants.I2L);
1008 pushConst(0xffffffffL);
1009 a(InstructionConstants.LAND);
1010 a(InstructionConstants.LCMP);
1011 b1 = a(InstructionFactory.createBranchInstruction(IFLT,null));
1014 b1 = a(InstructionFactory.createBranchInstruction(IFNE,null));
1016 a(InstructionConstants.ICONST_0);
1017 b2 = a(InstructionFactory.createBranchInstruction(GOTO,null));
1018 b1.setTarget(a(InstructionConstants.ICONST_1));
1019 b2.setTarget(a(InstructionConstants.NOP));
1026 throw new Exn("Illegal instruction 0/" + subcode);
1033 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1035 return doIfInstruction(IFLT,pc,pc+branchTarget*4+4,nextInsn);
1037 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1039 return doIfInstruction(IFGE,pc,pc+branchTarget*4+4,nextInsn);
1041 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1043 b1 = a(InstructionFactory.createBranchInstruction(IFGE,null));
1044 emitInstruction(-1,nextInsn,-1);
1048 branch(pc,pc+branchTarget*4+4);
1049 b1.setTarget(a(InstructionConstants.NOP));
1052 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1054 if(rs != 0) { // r0 is always >= 0
1056 b1 = a(InstructionFactory.createBranchInstruction(IFLT,null));
1058 emitInstruction(-1,nextInsn,-1);
1062 branch(pc,pc+branchTarget*4+4);
1063 if(b1 != null) b1.setTarget(a(InstructionConstants.NOP));
1064 if(b1 == null) unreachable = true;
1067 throw new Exn("Illegal Instruction 1/" + rt);
1072 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1073 emitInstruction(-1,nextInsn,-1);
1074 branch(pc,(pc&0xf0000000)|(jumpTarget << 2));
1079 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1080 int target = (pc&0xf0000000)|(jumpTarget << 2);
1081 emitInstruction(-1,nextInsn,-1);
1090 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1092 emitInstruction(-1,nextInsn,-1);
1093 branch(pc,pc+branchTarget*4+4);
1095 } else if(rs == 0 || rt == 0) {
1096 pushReg(rt == 0 ? R+rs : R+rt);
1097 return doIfInstruction(IFEQ,pc,pc+branchTarget*4+4,nextInsn);
1101 return doIfInstruction(IF_ICMPEQ,pc,pc+branchTarget*4+4,nextInsn);
1105 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1108 return doIfInstruction(IFNE,pc,pc+branchTarget*4+4,nextInsn);
1111 return doIfInstruction(IF_ICMPNE,pc,pc+branchTarget*4+4,nextInsn);
1114 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1116 return doIfInstruction(IFLE,pc,pc+branchTarget*4+4,nextInsn);
1118 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1120 return doIfInstruction(IFGT,pc,pc+branchTarget*4+4,nextInsn);
1122 throw new Exn("ADDI (add immediate with oveflow trap) not suported");
1125 addiu(rs,signedImmediate);
1131 pushConst(signedImmediate);
1132 b1 = a(InstructionFactory.createBranchInstruction(IF_ICMPLT,null));
1133 a(InstructionConstants.ICONST_0);
1134 b2 = a(InstructionFactory.createBranchInstruction(GOTO,null));
1135 b1.setTarget(a(InstructionConstants.ICONST_1));
1136 b2.setTarget(a(InstructionConstants.NOP));
1142 a(InstructionConstants.I2L);
1143 pushConst(0xffffffffL);
1144 a(InstructionConstants.LAND);
1145 // Yes, this is correct, you have to sign extend the immediate then do an UNSIGNED comparison
1146 pushConst(signedImmediate&0xffffffffL);
1147 a(InstructionConstants.LCMP);
1149 b1 = a(InstructionFactory.createBranchInstruction(IFLT,null));
1150 a(InstructionConstants.ICONST_0);
1151 b2 = a(InstructionFactory.createBranchInstruction(GOTO,null));
1152 b1.setTarget(a(InstructionConstants.ICONST_1));
1153 b2.setTarget(a(InstructionConstants.NOP));
1160 pushConst(unsignedImmediate);
1161 a(InstructionConstants.IAND);
1166 if(rs != 0 && unsignedImmediate != 0) {
1168 pushConst(unsignedImmediate);
1169 a(InstructionConstants.IOR);
1173 pushConst(unsignedImmediate);
1180 pushConst(unsignedImmediate);
1181 a(InstructionConstants.IXOR);
1186 pushConst(unsignedImmediate << 16);
1190 throw new Exn("TLB/Exception support not implemented");
1199 if(fs != 31) throw new Exn("FCR " + fs + " unavailable");
1213 if(fs != 31) throw new Exn("FCR " + fs + " unavailable");
1218 case 8: {// BC1F, BC1T
1220 pushConst(0x800000);
1221 a(InstructionConstants.IAND);
1222 return doIfInstruction(((insn>>>16)&1) == 0 ? IFEQ : IFNE,pc,pc+branchTarget*4+4,nextInsn);
1226 { // Single/Double math
1227 boolean d = rs == 17;
1230 preSetDouble(F+fd,d);
1233 a(d ? InstructionConstants.DADD : InstructionConstants.FADD);
1237 preSetDouble(F+fd,d);
1240 a(d ? InstructionConstants.DSUB : InstructionConstants.FSUB);
1244 preSetDouble(F+fd,d);
1247 a(d ? InstructionConstants.DMUL : InstructionConstants.FMUL);
1251 preSetDouble(F+fd,d);
1254 a(d ? InstructionConstants.DDIV : InstructionConstants.FDIV);
1258 preSetDouble(F+fd,d);
1259 // NOTE: We can't use fneg/dneg here since they'll turn +0.0 into -0.0
1262 a(d ? InstructionConstants.DUP2 : InstructionConstants.DUP);
1263 a(d ? InstructionConstants.DCONST_0 : InstructionConstants.FCONST_0);
1264 a(d ? InstructionConstants.DCMPG : InstructionConstants.FCMPG);
1266 b1 = a(InstructionFactory.createBranchInstruction(IFGT,null));
1267 a(d ? InstructionConstants.DCONST_0 : InstructionConstants.FCONST_0);
1268 a(d ? InstructionConstants.DSUB : InstructionConstants.FSUB);
1270 b1.setTarget(setDouble(d));
1286 preSetDouble(F+fd,d);
1288 a(d ? InstructionConstants.DNEG : InstructionConstants.FNEG);
1294 if(d) a(InstructionConstants.D2F);
1300 if(!d) a(InstructionConstants.F2D);
1303 case 36: { // CVT.W.D
1304 int[] matches = new int[4];
1305 for(int i=0;i<4;i++) matches[i] = i;
1307 TABLESWITCH ts = new TABLESWITCH(matches,new InstructionHandle[4], null);
1312 a(InstructionConstants.ICONST_3);
1313 a(InstructionConstants.IAND);
1316 // Round towards plus infinity
1317 ts.setTarget(2,a(InstructionConstants.NOP));
1318 if(!d) a(InstructionConstants.F2D); // Ugh.. java.lang.Math doesn't have a float ceil/floor
1319 a(fac.createInvoke("java.lang.Math","ceil",Type.DOUBLE,new Type[]{Type.DOUBLE},INVOKESTATIC));
1320 if(!d) a(InstructionConstants.D2F);
1321 b1 = a(InstructionFactory.createBranchInstruction(GOTO,null));
1324 ts.setTarget(0,d ? pushConst(0.5d) : pushConst(0.5f));
1325 a(d ? InstructionConstants.DADD : InstructionConstants.FADD);
1328 // Round towards minus infinity
1329 ts.setTarget(3,a(InstructionConstants.NOP));
1330 if(!d) a(InstructionConstants.F2D);
1331 a(fac.createInvoke("java.lang.Math","floor",Type.DOUBLE,new Type[]{Type.DOUBLE},INVOKESTATIC));
1332 if(!d) a(InstructionConstants.D2F);
1334 InstructionHandle h = a(d ? InstructionConstants.D2I : InstructionConstants.F2I);
1348 pushConst(~0x800000);
1349 a(InstructionConstants.IAND);
1352 a(d ? InstructionConstants.DCMPG : InstructionConstants.FCMPG);
1354 case 50: b1 = a(InstructionFactory.createBranchInstruction(IFEQ,null)); break;
1355 case 60: b1 = a(InstructionFactory.createBranchInstruction(IFLT,null)); break;
1356 case 62: b1 = a(InstructionFactory.createBranchInstruction(IFLE,null)); break;
1359 // FIXME: We probably don't need to pushConst(0x00000)
1360 pushConst(0x000000);
1361 b2 = a(InstructionFactory.createBranchInstruction(GOTO,null));
1362 b1.setTarget(pushConst(0x800000));
1363 b2.setTarget(a(InstructionConstants.IOR));
1366 default: throw new Exn("Invalid Instruction 17/" + rs + "/" + subcode);
1370 case 20: { // Integer
1375 a(InstructionConstants.I2F);
1381 a(InstructionConstants.I2D);
1384 default: throw new Exn("Invalid Instruction 17/" + rs + "/" + subcode);
1389 throw new Exn("Invalid Instruction 17/" + rs);
1394 throw new Exn("coprocessor 2 and 3 instructions not available");
1397 addiu(R+rs,signedImmediate);
1404 a(InstructionConstants.ICONST_M1);
1405 a(InstructionConstants.IXOR);
1406 a(InstructionConstants.ICONST_3);
1407 a(InstructionConstants.IAND);
1408 a(InstructionConstants.ICONST_3);
1409 a(InstructionConstants.ISHL);
1410 a(InstructionConstants.IUSHR);
1411 a(InstructionConstants.I2B);
1417 addiu(R+rs,signedImmediate);
1424 a(InstructionConstants.ICONST_M1);
1425 a(InstructionConstants.IXOR);
1426 a(InstructionConstants.ICONST_2);
1427 a(InstructionConstants.IAND);
1428 a(InstructionConstants.ICONST_3);
1429 a(InstructionConstants.ISHL);
1430 a(InstructionConstants.IUSHR);
1431 a(InstructionConstants.I2S);
1437 addiu(R+rs,signedImmediate);
1441 pushConst(0x00ffffff);
1444 a(InstructionConstants.ICONST_M1);
1445 a(InstructionConstants.IXOR);
1446 a(InstructionConstants.ICONST_3);
1447 a(InstructionConstants.IAND);
1448 a(InstructionConstants.ICONST_3);
1449 a(InstructionConstants.ISHL);
1450 a(InstructionConstants.IUSHR);
1451 a(InstructionConstants.IAND);
1458 a(InstructionConstants.ICONST_3);
1459 a(InstructionConstants.IAND);
1460 a(InstructionConstants.ICONST_3);
1461 a(InstructionConstants.ISHL);
1462 a(InstructionConstants.ISHL);
1463 a(InstructionConstants.IOR);
1472 memRead(R+rs,signedImmediate);
1477 addiu(R+rs,signedImmediate);
1484 a(InstructionConstants.ICONST_M1);
1485 a(InstructionConstants.IXOR);
1486 a(InstructionConstants.ICONST_3);
1487 a(InstructionConstants.IAND);
1488 a(InstructionConstants.ICONST_3);
1489 a(InstructionConstants.ISHL);
1490 a(InstructionConstants.IUSHR);
1492 a(InstructionConstants.IAND);
1498 addiu(R+rs,signedImmediate);
1505 a(InstructionConstants.ICONST_M1);
1506 a(InstructionConstants.IXOR);
1507 a(InstructionConstants.ICONST_2);
1508 a(InstructionConstants.IAND);
1509 a(InstructionConstants.ICONST_3);
1510 a(InstructionConstants.ISHL);
1511 a(InstructionConstants.IUSHR);
1513 // chars are unsigend so this works
1514 a(InstructionConstants.I2C);
1520 addiu(R+rs,signedImmediate);
1524 pushConst(0xffffff00);
1527 a(InstructionConstants.ICONST_3);
1528 a(InstructionConstants.IAND);
1529 a(InstructionConstants.ICONST_3);
1530 a(InstructionConstants.ISHL);
1531 a(InstructionConstants.ISHL);
1532 a(InstructionConstants.IAND);
1539 a(InstructionConstants.ICONST_M1);
1540 a(InstructionConstants.IXOR);
1541 a(InstructionConstants.ICONST_3);
1542 a(InstructionConstants.IAND);
1543 a(InstructionConstants.ICONST_3);
1544 a(InstructionConstants.ISHL);
1545 a(InstructionConstants.IUSHR);
1546 a(InstructionConstants.IOR);
1553 addiu(R+rs,signedImmediate);
1556 // FEATURE: DO the preMemRead(true) thing for the rest of the S* instructions
1561 pushConst(0xff000000);
1564 a(InstructionConstants.ICONST_3);
1565 a(InstructionConstants.IAND);
1566 a(InstructionConstants.ICONST_3);
1567 a(InstructionConstants.ISHL);
1568 a(InstructionConstants.IUSHR);
1569 a(InstructionConstants.ICONST_M1);
1570 a(InstructionConstants.IXOR);
1571 a(InstructionConstants.IAND);
1576 a(InstructionConstants.IAND);
1582 a(InstructionConstants.ICONST_M1);
1583 a(InstructionConstants.IXOR);
1584 a(InstructionConstants.ICONST_3);
1585 a(InstructionConstants.IAND);
1586 a(InstructionConstants.ICONST_3);
1587 a(InstructionConstants.ISHL);
1588 a(InstructionConstants.ISHL);
1589 a(InstructionConstants.IOR);
1598 addiu(R+rs,signedImmediate);
1600 a(InstructionConstants.DUP);
1612 a(InstructionConstants.ICONST_2);
1613 a(InstructionConstants.IAND);
1614 a(InstructionConstants.ICONST_3);
1615 a(InstructionConstants.ISHL);
1616 a(InstructionConstants.ISHL);
1617 a(InstructionConstants.IAND);
1622 a(InstructionConstants.IAND);
1628 a(InstructionConstants.ICONST_M1);
1629 a(InstructionConstants.IXOR);
1630 a(InstructionConstants.ICONST_2);
1631 a(InstructionConstants.IAND);
1632 a(InstructionConstants.ICONST_3);
1633 a(InstructionConstants.ISHL);
1634 a(InstructionConstants.ISHL);
1635 a(InstructionConstants.IOR);
1644 addiu(R+rs,signedImmediate);
1645 a(InstructionConstants.DUP);
1654 pushConst(0xffffff00);
1657 a(InstructionConstants.ICONST_M1);
1658 a(InstructionConstants.IXOR);
1659 a(InstructionConstants.ICONST_3);
1660 a(InstructionConstants.IAND);
1661 a(InstructionConstants.ICONST_3);
1662 a(InstructionConstants.ISHL);
1663 a(InstructionConstants.ISHL);
1664 a(InstructionConstants.IAND);
1669 a(InstructionConstants.ICONST_3);
1670 a(InstructionConstants.IAND);
1671 a(InstructionConstants.ICONST_3);
1672 a(InstructionConstants.ISHL);
1673 a(InstructionConstants.IUSHR);
1674 a(InstructionConstants.IOR);
1682 preMemWrite2(R+rs,signedImmediate);
1689 addiu(R+rs,signedImmediate);
1690 a(InstructionConstants.DUP);
1699 pushConst(0x00ffffff);
1702 a(InstructionConstants.ICONST_3);
1703 a(InstructionConstants.IAND);
1704 a(InstructionConstants.ICONST_3);
1705 a(InstructionConstants.ISHL);
1706 a(InstructionConstants.IUSHR);
1707 a(InstructionConstants.IAND);
1712 a(InstructionConstants.ICONST_M1);
1713 a(InstructionConstants.IXOR);
1714 a(InstructionConstants.ICONST_3);
1715 a(InstructionConstants.IAND);
1716 a(InstructionConstants.ICONST_3);
1717 a(InstructionConstants.ISHL);
1718 a(InstructionConstants.ISHL);
1719 a(InstructionConstants.IOR);
1724 // This need to be atomic if we ever support threads (see SWC0/SC)
1727 memRead(R+rs,signedImmediate);
1733 memRead(R+rs,signedImmediate);
1737 /* This needs to fail (set rt to 0) if the memory location was modified
1738 * between the LL and SC if we every support threads.
1743 preMemWrite2(R+rs,signedImmediate);
1752 preMemWrite2(R+rs,signedImmediate);
1757 throw new Exn("Invalid Instruction: " + op + " at " + toHex(pc));
1762 // Helper functions for emitText
1764 private static final int R = 0;
1765 private static final int F = 32;
1766 private static final int HI = 64;
1767 private static final int LO = 65;
1768 private static final int FCSR = 66;
1769 private static final int REG_COUNT=67;
1771 private int[] regLocalMapping = new int[REG_COUNT];
1772 private int[] regLocalReadCount = new int[REG_COUNT];
1773 private int[] regLocalWriteCount = new int[REG_COUNT];
1774 private int nextAvailLocal;
1776 private int getLocalForReg(int reg) {
1777 if(regLocalMapping[reg] != 0) return regLocalMapping[reg];
1778 if(nextAvailLocal == 0) nextAvailLocal = onePage ? 3 : 4;
1779 regLocalMapping[reg] = nextAvailLocal++;
1780 return regLocalMapping[reg];
1783 private void fixupRegs() {
1784 InstructionHandle prev = realStart;
1785 for(int i=0;i<REG_COUNT;i++) {
1786 if(regLocalMapping[i] == 0) continue;
1788 prev = insnList.append(prev,InstructionConstants.ALOAD_0);
1789 prev = insnList.append(prev,fac.createFieldAccess(fullClassName,regField(i),Type.INT, GETFIELD));
1790 prev = insnList.append(prev,InstructionFactory.createStore(Type.INT,regLocalMapping[i]));
1792 if(regLocalWriteCount[i] > 0) {
1793 a(InstructionConstants.ALOAD_0);
1794 a(InstructionFactory.createLoad(Type.INT,regLocalMapping[i]));
1795 a(fac.createFieldAccess(fullClassName,regField(i),Type.INT, PUTFIELD));
1798 regLocalMapping[i] = regLocalReadCount[i] = regLocalWriteCount[i] = 0;
1803 private void restoreChangedRegs() {
1804 for(int i=0;i<REG_COUNT;i++) {
1805 if(regLocalWriteCount[i] > 0) {
1806 a(InstructionConstants.ALOAD_0);
1807 a(InstructionFactory.createLoad(Type.INT,regLocalMapping[i]));
1808 a(fac.createFieldAccess(fullClassName,regField(i),Type.INT, PUTFIELD));
1813 private static final String[] regField = {
1814 "r0","r1","r2","r3","r4","r5","r6","r7",
1815 "r8","r9","r10","r11","r12","r13","r14","r15",
1816 "r16","r17","r18","r19","r20","r21","r22","r23",
1817 "r24","r25","r26","r27","r28","r29","r30","r31",
1819 "f0","f1","f2","f3","f4","f5","f6","f7",
1820 "f8","f9","f10","f11","f12","f13","f14","f15",
1821 "f16","f17","f18","f19","f20","f21","f22","f23",
1822 "f24","f25","f26","f27","f28","f29","f30","f31",
1827 private static String regField(int reg) {
1828 return regField[reg];
1832 case HI: field = "hi"; break;
1833 case LO: field = "lo"; break;
1834 case FCSR: field = "fcsr"; break;
1836 if(reg > R && reg < R+32) regFieldR[reg-R];
1837 else if(reg >= F && reg < F+32) return regFieldF[
1838 else throw new IllegalArgumentException(""+reg);
1843 private boolean doLocal(int reg) {
1845 return reg == R+2 || reg == R+3 || reg == R+4 || reg == R+29;
1848 private InstructionHandle pushRegWZ(int reg) {
1850 warn.println("Warning: Pushing r0!");
1851 new Exception().printStackTrace(warn);
1853 return pushRegZ(reg);
1856 private InstructionHandle pushRegZ(int reg) {
1857 if(reg == R+0) return pushConst(0);
1858 else return pushReg(reg);
1862 private InstructionHandle pushReg(int reg) {
1863 InstructionHandle h;
1865 regLocalReadCount[reg]++;
1866 h = a(InstructionFactory.createLoad(Type.INT,getLocalForReg(reg)));
1868 h = a(InstructionConstants.ALOAD_0);
1869 a(fac.createFieldAccess(fullClassName,regField(reg),Type.INT, GETFIELD));
1874 private int preSetRegStackPos;
1875 private int[] preSetRegStack = new int[8];
1877 // This can push ONE or ZERO words to the stack. If it pushed one it returns true
1878 private boolean preSetReg(int reg) {
1879 regField(reg); // just to check for validity
1880 preSetRegStack[preSetRegStackPos] = reg;
1881 preSetRegStackPos++;
1885 a(InstructionConstants.ALOAD_0);
1890 private InstructionHandle setReg() {
1891 if(preSetRegStackPos==0) throw new RuntimeException("didn't do preSetReg");
1892 preSetRegStackPos--;
1893 int reg = preSetRegStack[preSetRegStackPos];
1894 InstructionHandle h;
1896 h = a(InstructionFactory.createStore(Type.INT,getLocalForReg(reg)));
1897 regLocalWriteCount[reg]++;
1899 h = a(fac.createFieldAccess(fullClassName,regField(reg),Type.INT, PUTFIELD));
1904 private InstructionHandle preSetPC() { return a(InstructionConstants.ALOAD_0); }
1905 private InstructionHandle setPC() { return a(fac.createFieldAccess(fullClassName,"pc",Type.INT, PUTFIELD)); }
1907 //unused - private InstructionHandle pushFloat(int reg) throws CompilationException { return pushDouble(reg,false); }
1908 //unused - private InstructionHandle pushDouble(int reg) throws CompilationException { return pushDouble(reg,true); }
1909 private InstructionHandle pushDouble(int reg, boolean d) throws Exn {
1910 if(reg < F || reg >= F+32) throw new IllegalArgumentException(""+reg);
1911 InstructionHandle h;
1913 if(reg == F+31) throw new Exn("Tried to use a double in f31");
1915 a(InstructionConstants.I2L);
1917 a(InstructionConstants.LSHL);
1919 a(InstructionConstants.I2L);
1920 pushConst(0xffffffffL);
1921 a(InstructionConstants.LAND);
1922 a(InstructionConstants.LOR);
1923 //p("invokestatic java/lang/Double/longBitsToDouble(J)D");
1924 a(fac.createInvoke("java.lang.Double","longBitsToDouble",Type.DOUBLE,new Type[]{Type.LONG},INVOKESTATIC));
1927 a(fac.createInvoke("java.lang.Float","intBitsToFloat",Type.FLOAT,new Type[]{Type.INT},INVOKESTATIC));
1932 private void preSetFloat(int reg) { preSetDouble(reg,false); }
1933 private void preSetDouble(int reg) { preSetDouble(reg,true); }
1934 private void preSetDouble(int reg, boolean d) { preSetReg(reg); }
1936 private InstructionHandle setFloat() throws Exn { return setDouble(false); }
1937 private InstructionHandle setDouble() throws Exn { return setDouble(true); }
1938 private InstructionHandle setDouble(boolean d) throws Exn {
1939 int reg = preSetRegStack[preSetRegStackPos-1];
1940 if(reg < F || reg >= F+32) throw new IllegalArgumentException(""+reg);
1941 //p("invokestatic java/lang/Double/doubleToLongBits(D)J");
1942 InstructionHandle h;
1944 if(reg == F+31) throw new Exn("Tried to use a double in f31");
1945 h = a(fac.createInvoke("java.lang.Double","doubleToLongBits",Type.LONG,new Type[]{Type.DOUBLE},INVOKESTATIC));
1946 a(InstructionConstants.DUP2);
1948 a(InstructionConstants.LUSHR);
1949 a(InstructionConstants.L2I);
1950 if(preSetReg(reg+1))
1951 a(InstructionConstants.SWAP);
1953 a(InstructionConstants.L2I);
1954 setReg(); // preSetReg was already done for this by preSetDouble
1956 h = a(fac.createInvoke("java.lang.Float","floatToRawIntBits",Type.INT,new Type[]{Type.FLOAT},INVOKESTATIC));
1962 private Hashtable intCache = new Hashtable();
1964 private InstructionHandle pushConst(int n) {
1965 if(n >= -1 && n <= 5) {
1967 case -1: return a(InstructionConstants.ICONST_M1);
1968 case 0: return a(InstructionConstants.ICONST_0);
1969 case 1: return a(InstructionConstants.ICONST_1);
1970 case 2: return a(InstructionConstants.ICONST_2);
1971 case 3: return a(InstructionConstants.ICONST_3);
1972 case 4: return a(InstructionConstants.ICONST_4);
1973 case 5: return a(InstructionConstants.ICONST_5);
1974 default: return null;
1976 } else if(n >= -128 && n <= 127) {
1977 return a(new BIPUSH((byte) n));
1978 } else if(n >= -32768 && n <= 32767) {
1979 return a(new SIPUSH((short) n));
1981 return a(new PUSH(cp,n));
1985 private InstructionHandle pushConst(long l) { return a(new PUSH(cp,l)); }
1986 private InstructionHandle pushConst(float f) { return a(new PUSH(cp,f)); }
1987 private InstructionHandle pushConst(double d) { return a(new PUSH(cp,d)); }
1989 private void pushTmp() { a(InstructionConstants.ILOAD_1); }
1990 private void setTmp() { a(InstructionConstants.ISTORE_1); }
1992 private void addiu(int reg, int offset) {
1993 if(reg != R+0 && offset != 0) {
1996 a(InstructionConstants.IADD);
1997 } else if(reg != R+0) {
2003 private int memWriteStage;
2004 private void preMemWrite1() {
2005 if(memWriteStage!=0) throw new Error("pending preMemWrite1/2");
2008 a(InstructionConstants.ALOAD_2);
2010 a(InstructionFactory.createLoad(Type.OBJECT,3));
2012 a(InstructionConstants.ALOAD_0);
2015 private void preMemWrite2(int reg, int offset) {
2020 private void preMemWrite2() { preMemWrite2(false); }
2021 private void preMemWrite2(boolean addrInTmp) {
2022 if(memWriteStage!=1) throw new Error("pending preMemWrite2 or no preMemWrite1");
2025 if(nullPointerCheck) {
2026 a(InstructionConstants.DUP);
2027 a(InstructionConstants.ALOAD_0);
2028 a(InstructionConstants.SWAP);
2029 a(fac.createInvoke(fullClassName,"nullPointerCheck",Type.VOID,new Type[]{Type.INT},INVOKEVIRTUAL));
2033 a(InstructionConstants.ICONST_2);
2034 a(InstructionConstants.IUSHR);
2035 } else if(fastMem) {
2037 a(InstructionConstants.DUP_X1);
2038 pushConst(pageShift);
2039 a(InstructionConstants.IUSHR);
2040 a(InstructionConstants.AALOAD);
2044 a(InstructionConstants.SWAP);
2045 a(InstructionConstants.ICONST_2);
2046 a(InstructionConstants.IUSHR);
2047 pushConst((pageSize>>2)-1);
2048 a(InstructionConstants.IAND);
2052 // pops an address and value off the stack, sets *addr to value
2053 private void memWrite() {
2054 if(memWriteStage!=2) throw new Error("didn't do preMemWrite1 or preMemWrite2");
2058 a(InstructionConstants.IASTORE);
2059 } else if(fastMem) {
2060 a(InstructionConstants.IASTORE);
2062 a(fac.createInvoke(fullClassName,"unsafeMemWrite",Type.VOID,new Type[]{Type.INT,Type.INT},INVOKEVIRTUAL));
2067 // reads the word at r[reg]+offset
2068 private void memRead(int reg, int offset) {
2074 private boolean didPreMemRead;
2075 private boolean preMemReadDoPreWrite;
2077 private void preMemRead() { preMemRead(false); }
2078 private void preMemRead(boolean preWrite) {
2079 if(didPreMemRead) throw new Error("pending preMemRead");
2080 didPreMemRead = true;
2081 preMemReadDoPreWrite = preWrite;
2083 a(InstructionConstants.ALOAD_2);
2085 a(InstructionFactory.createLoad(Type.OBJECT,preWrite ? 3 : 2));
2087 a(InstructionConstants.ALOAD_0);
2089 // memRead pops an address off the stack, reads the value at that addr, and pushed the value
2090 // preMemRead MUST be called BEFORE the addresses is pushed
2091 private void memRead() { memRead(false); }
2093 private void memRead(boolean addrInTmp) {
2094 if(!didPreMemRead) throw new Error("didn't do preMemRead");
2095 didPreMemRead = false;
2096 if(preMemReadDoPreWrite)
2099 if(nullPointerCheck) {
2100 a(InstructionConstants.DUP);
2101 a(InstructionConstants.ALOAD_0);
2102 a(InstructionConstants.SWAP);
2103 a(fac.createInvoke(fullClassName,"nullPointerCheck",Type.VOID,new Type[]{Type.INT},INVOKEVIRTUAL));
2107 // p(target + "= page[(" + addr + ")>>>2];");
2108 a(InstructionConstants.ICONST_2);
2109 a(InstructionConstants.IUSHR);
2110 if(preMemReadDoPreWrite)
2111 a(InstructionConstants.DUP2);
2112 a(InstructionConstants.IALOAD);
2113 } else if(fastMem) {
2114 //p(target + " = readPages[("+addr+")>>>"+pageShift+"][(("+addr+")>>>2)&"+toHex((pageSize>>2)-1)+"];");
2117 a(InstructionConstants.DUP_X1);
2118 pushConst(pageShift);
2119 a(InstructionConstants.IUSHR);
2120 a(InstructionConstants.AALOAD);
2124 a(InstructionConstants.SWAP);
2125 a(InstructionConstants.ICONST_2);
2126 a(InstructionConstants.IUSHR);
2127 pushConst((pageSize>>2)-1);
2128 a(InstructionConstants.IAND);
2129 if(preMemReadDoPreWrite)
2130 a(InstructionConstants.DUP2);
2131 a(InstructionConstants.IALOAD);
2134 if(preMemReadDoPreWrite)
2135 a(InstructionConstants.DUP2);
2136 a(fac.createInvoke(fullClassName,"unsafeMemWrite",Type.INT,new Type[]{Type.INT},INVOKEVIRTUAL));
2141 // This might come in handy for something else
2142 /*private boolean touchesReg(int insn, int reg) {
2143 if((reg < R+0 || reg >= R+32) && reg != FCSR) throw new IllegalArgumentException(""+reg);
2144 if(reg == R+0) return false; // r0 is never modified
2145 int op = (insn >>> 26) & 0xff; // bits 26-31
2146 int subcode = insn & 0x3f; // bits 0-5
2147 int rd = (insn >>> 11) & 0x1f; // bits 11-15
2148 int rt = (insn >>> 16) & 0x1f; // bits 16-20
2149 int rs = (insn >>> 21) & 0x1f; // bits 21-25
2153 if(subcode >= 0 && subcode <= 7) return reg == R+rd; // Shift ops
2154 if(subcode >= 32 && subcode <= 43) return reg == R+rd; // Other math ops
2155 if(subcode >= 24 && subcode <= 27) return reg == HI || reg == LO; // MULT/DIV
2157 case 13: return false; // BREAK
2160 case 0: return reg == R+rt; // MFC.1
2161 case 2: return reg == R+rt; // CFC.1
2162 case 4: return false; // MTC.1
2163 case 6: return false; // CTC.1
2166 if(subcode == 50 || subcode == 60 || subcode == 62) return reg == FCSR;
2167 return false; // everything else just touches f0-f31
2168 case 20: return false; // Integer - just touches f0-f31
2172 if(op >= 8 && op <= 15) return reg == R+rt; // XXXI instructions
2173 if(op >= 40 && op <= 46) return false; // Memory WRITE ops
2174 if(op == 49) return reg == F+rt; // LWC1
2175 if(op == 57) return false; // SWC1
2178 warn.println("Unknown instruction in touchesReg()- assuming it modifies all regs " + op + " " + subcode);
2179 new Exception().fillInStackTrace().printStackTrace(warn);