1 package org.ibex.nestedvm;
4 import org.ibex.nestedvm.util.*;
6 import org.apache.bcel.generic.*;
8 // FEATURE: Use BCEL to do peephole optimization
9 // FEATURE: Special mode to support single-precision only - regs are floats not ints
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
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.
24 * void work(int a, int b) {
31 * Because all the regs used in "real work" are loaded/restored even for fast path
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;
41 private ConstantPoolGen cp;
42 private InstructionList clinitExtras = new InstructionList();
43 private InstructionList initExtras = new InstructionList();
44 private InstructionFactory fac;
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); }
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 */ }
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);
69 public ClassFileCompiler(String path, String className, OutputStream os) throws IOException { this(new Seekable.File(path),className,os); }
70 public ClassFileCompiler(Seekable binary, String className, OutputStream os) throws IOException {
71 super(binary,className);
75 public void setWarnWriter(PrintStream warn) { this.warn = warn; }
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");
82 cl = new ClassGen(fullClassName,runtimeClass,source,ACC_SUPER|ACC_PUBLIC|ACC_FINAL,null);
83 cp = cl.getConstantPool();
84 fac = new InstructionFactory(cl,cp);
87 cl.addField(new FieldGen(ACC_PRIVATE,Type.INT,"pc",cp).getField());
89 cl.addField(new FieldGen(ACC_PRIVATE,Type.INT,"r"+i,cp).getField());
91 cl.addField(new FieldGen(ACC_PRIVATE,Type.INT,"f"+i,cp).getField());
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());
98 cl.addField(new FieldGen(ACC_PRIVATE|ACC_FINAL,new ArrayType(Type.INT,1),"page",cp).getField());
100 selectList(initExtras);
101 a(InstructionConstants.ALOAD_0);
102 a(InstructionConstants.DUP);
103 a(fac.createFieldAccess(fullClassName,"readPages",new ArrayType(Type.INT, 2), GETFIELD));
105 a(InstructionConstants.AALOAD);
106 a(fac.createFieldAccess(fullClassName,"page",new ArrayType(Type.INT,1), PUTFIELD));
110 cl.addField(new FieldGen(ACC_PRIVATE|ACC_STATIC|ACC_FINAL,Type.getType("L"+hashClass.replace('.','/')+";"),"symbols",cp).getField());
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;
120 highestAddr = Math.max(highestAddr, sheader.addr + sheader.size);
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);
129 throw new Exn("Unknown segment: " + name);
132 ELF.SHeader text = elf.sectionWithName(".text");
135 MethodGen tramp = newMethod(ACC_PRIVATE,Type.VOID, Type.NO_ARGS, "trampoline");
136 tramp.addException("org.ibex.nestedvm.Runtime$ExecutionException");
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);
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);
150 int beg = text.addr >>> methodShift;
151 int end = ((text.addr + text.size) >>> methodShift);
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);
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);
164 ts.setTarget(a(InstructionConstants.POP)); // default case
165 a(fac.createNew("org.ibex.nestedvm.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));
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.ibex.nestedvm.Runtime$ExecutionException","<init>",Type.VOID,new Type[]{Type.STRING},INVOKESPECIAL));
183 a(InstructionConstants.ATHROW);
185 stateCheck.setTarget(a(InstructionConstants.RETURN));
188 tramp.setMaxLocals();
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");
196 addConstReturnMethod("gp",gp.addr);
197 addConstReturnMethod("entryPoint",elf.header.entry);
198 addConstReturnMethod("heapStart",highestAddr);
200 if(userInfo != null) {
201 addConstReturnMethod("userInfoBase",userInfo.addr);
202 addConstReturnMethod("userInfoSize",userInfo.size);
205 // FEATURE: Allow specification of memory size at runtime (numpages)
207 MethodGen init = newMethod(ACC_PUBLIC,Type.VOID, Type.NO_ARGS, "<init>");
209 a(InstructionConstants.ALOAD_0);
211 pushConst(totalPages);
212 a(fac.createInvoke(runtimeClass,"<init>",Type.VOID,new Type[]{Type.INT,Type.INT},INVOKESPECIAL));
216 a(InstructionConstants.RETURN);
220 cl.addMethod(init.getMethod());
223 MethodGen clinit = newMethod(ACC_PRIVATE|ACC_STATIC,Type.VOID, Type.NO_ARGS, "<clinit>");
224 selectMethod(clinit);
228 a(fac.createNew(hashClass));
229 a(InstructionConstants.DUP);
230 a(InstructionConstants.DUP);
231 a(fac.createInvoke(hashClass,"<init>",Type.VOID,Type.NO_ARGS,INVOKESPECIAL));
232 a(fac.createFieldAccess(fullClassName,"symbols",Type.getType("L"+hashClass.replace('.','/')+";"), PUTSTATIC));
233 ELF.Symbol[] symbols = elf.getSymtab().symbols;
234 for(int i=0;i<symbols.length;i++) {
235 ELF.Symbol s = symbols[i];
236 if(s.type == ELF.Symbol.STT_FUNC && s.binding == ELF.Symbol.STB_GLOBAL && (s.name.equals("_call_helper") || !s.name.startsWith("_"))) {
237 a(InstructionConstants.DUP);
238 a(new PUSH(cp,s.name));
239 a(fac.createNew("java.lang.Integer"));
240 a(InstructionConstants.DUP);
241 a(new PUSH(cp,s.addr));
242 a(fac.createInvoke("java.lang.Integer","<init>",Type.VOID,new Type[]{Type.INT},INVOKESPECIAL));
243 a(fac.createInvoke(hashClass,"put",Type.OBJECT,new Type[]{Type.OBJECT,Type.OBJECT},INVOKEVIRTUAL));
244 a(InstructionConstants.POP);
247 a(InstructionConstants.POP);
250 a(InstructionConstants.RETURN);
251 clinit.setMaxLocals();
252 clinit.setMaxStack();
253 cl.addMethod(clinit.getMethod());
256 MethodGen lookupSymbol = newMethod(ACC_PROTECTED,Type.INT,new Type[]{Type.STRING},"lookupSymbol");
257 selectMethod(lookupSymbol);
258 a(fac.createFieldAccess(fullClassName,"symbols",Type.getType("L"+hashClass.replace('.','/')+";"), GETSTATIC));
259 a(InstructionConstants.ALOAD_1);
260 a(fac.createInvoke(hashClass,"get",Type.OBJECT,new Type[]{Type.OBJECT},INVOKEVIRTUAL));
261 a(InstructionConstants.DUP);
262 BranchHandle bh = a(InstructionFactory.createBranchInstruction(IFNULL,null));
263 a(fac.createCheckCast(new ObjectType("java.lang.Integer")));
264 a(fac.createInvoke("java.lang.Integer","intValue",Type.INT,Type.NO_ARGS,INVOKEVIRTUAL));
265 a(InstructionConstants.IRETURN);
266 bh.setTarget(a(InstructionConstants.ICONST_M1));
267 a(InstructionConstants.IRETURN);
268 lookupSymbol.setMaxLocals();
269 lookupSymbol.setMaxStack();
270 cl.addMethod(lookupSymbol.getMethod());
273 MethodGen setCPUState = newMethod(ACC_PROTECTED,Type.VOID,new Type[]{Type.getType("Lorg/ibex/nestedvm/Runtime$CPUState;")},"setCPUState");
274 selectMethod(setCPUState);
275 a(InstructionConstants.ALOAD_1);
276 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","r",new ArrayType(Type.INT,1),GETFIELD));
277 a(InstructionConstants.ASTORE_2);
278 for(int i=1;i<32;i++) {
279 a(InstructionConstants.ALOAD_0);
280 a(InstructionConstants.ALOAD_2);
282 a(InstructionConstants.IALOAD);
283 a(fac.createFieldAccess(fullClassName,"r"+i,Type.INT, PUTFIELD));
285 a(InstructionConstants.ALOAD_1);
286 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","f",new ArrayType(Type.INT,1),GETFIELD));
287 a(InstructionConstants.ASTORE_2);
288 for(int i=0;i<32;i++) {
289 a(InstructionConstants.ALOAD_0);
290 a(InstructionConstants.ALOAD_2);
292 a(InstructionConstants.IALOAD);
293 a(fac.createFieldAccess(fullClassName,"f"+i,Type.INT, PUTFIELD));
295 a(InstructionConstants.ALOAD_0);
296 a(InstructionConstants.ALOAD_1);
297 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","hi",Type.INT,GETFIELD));
298 a(fac.createFieldAccess(fullClassName,"hi",Type.INT, PUTFIELD));
299 a(InstructionConstants.ALOAD_0);
300 a(InstructionConstants.ALOAD_1);
301 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","lo",Type.INT,GETFIELD));
302 a(fac.createFieldAccess(fullClassName,"lo",Type.INT, PUTFIELD));
303 a(InstructionConstants.ALOAD_0);
304 a(InstructionConstants.ALOAD_1);
305 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","fcsr",Type.INT,GETFIELD));
306 a(fac.createFieldAccess(fullClassName,"fcsr",Type.INT, PUTFIELD));
307 a(InstructionConstants.ALOAD_0);
308 a(InstructionConstants.ALOAD_1);
309 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","pc",Type.INT,GETFIELD));
310 a(fac.createFieldAccess(fullClassName,"pc",Type.INT, PUTFIELD));
312 a(InstructionConstants.RETURN);
313 setCPUState.setMaxLocals();
314 setCPUState.setMaxStack();
315 cl.addMethod(setCPUState.getMethod());
317 MethodGen getCPUState = newMethod(ACC_PROTECTED,Type.VOID,new Type[]{Type.getType("Lorg/ibex/nestedvm/Runtime$CPUState;")},"getCPUState");
318 selectMethod(getCPUState);
319 a(InstructionConstants.ALOAD_1);
320 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","r",new ArrayType(Type.INT,1),GETFIELD));
321 a(InstructionConstants.ASTORE_2);
322 for(int i=1;i<32;i++) {
323 a(InstructionConstants.ALOAD_2);
325 a(InstructionConstants.ALOAD_0);
326 a(fac.createFieldAccess(fullClassName,"r"+i,Type.INT, GETFIELD));
327 a(InstructionConstants.IASTORE);
330 a(InstructionConstants.ALOAD_1);
331 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","f",new ArrayType(Type.INT,1),GETFIELD));
332 a(InstructionConstants.ASTORE_2);
333 for(int i=0;i<32;i++) {
334 a(InstructionConstants.ALOAD_2);
336 a(InstructionConstants.ALOAD_0);
337 a(fac.createFieldAccess(fullClassName,"f"+i,Type.INT, GETFIELD));
338 a(InstructionConstants.IASTORE);
340 a(InstructionConstants.ALOAD_1);
341 a(InstructionConstants.ALOAD_0);
342 a(fac.createFieldAccess(fullClassName,"hi",Type.INT, GETFIELD));
343 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","hi",Type.INT,PUTFIELD));
344 a(InstructionConstants.ALOAD_1);
345 a(InstructionConstants.ALOAD_0);
346 a(fac.createFieldAccess(fullClassName,"lo",Type.INT, GETFIELD));
347 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","lo",Type.INT,PUTFIELD));
348 a(InstructionConstants.ALOAD_1);
349 a(InstructionConstants.ALOAD_0);
350 a(fac.createFieldAccess(fullClassName,"fcsr",Type.INT, GETFIELD));
351 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","fcsr",Type.INT,PUTFIELD));
352 a(InstructionConstants.ALOAD_1);
353 a(InstructionConstants.ALOAD_0);
354 a(fac.createFieldAccess(fullClassName,"pc",Type.INT, GETFIELD));
355 a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","pc",Type.INT,PUTFIELD));
357 a(InstructionConstants.RETURN);
358 getCPUState.setMaxLocals();
359 getCPUState.setMaxStack();
360 cl.addMethod(getCPUState.getMethod());
363 MethodGen execute = newMethod(ACC_PROTECTED,Type.VOID,Type.NO_ARGS,"_execute");
364 selectMethod(execute);
365 InstructionHandle tryStart = a(InstructionConstants.ALOAD_0);
366 InstructionHandle tryEnd = a(fac.createInvoke(fullClassName,"trampoline",Type.VOID,Type.NO_ARGS,INVOKESPECIAL));
367 a(InstructionConstants.RETURN);
369 InstructionHandle catchInsn = a(InstructionConstants.ASTORE_1);
370 a(fac.createNew("org.ibex.nestedvm.Runtime$FaultException"));
371 a(InstructionConstants.DUP);
372 a(InstructionConstants.ALOAD_1);
373 a(fac.createInvoke("org.ibex.nestedvm.Runtime$FaultException","<init>",Type.VOID,new Type[]{new ObjectType("java.lang.RuntimeException")},INVOKESPECIAL));
374 a(InstructionConstants.ATHROW);
376 execute.addExceptionHandler(tryStart,tryEnd,catchInsn,new ObjectType("java.lang.RuntimeException"));
377 execute.setMaxLocals();
378 execute.setMaxStack();
379 cl.addMethod(execute.getMethod());
382 MethodGen main = newMethod(ACC_STATIC|ACC_PUBLIC,Type.VOID,new Type[]{new ArrayType(Type.STRING,1)},"main");
384 a(fac.createNew(fullClassName));
385 a(InstructionConstants.DUP);
386 a(fac.createInvoke(fullClassName,"<init>",Type.VOID,Type.NO_ARGS,INVOKESPECIAL));
387 a(new PUSH(cp,fullClassName));
388 a(InstructionConstants.ALOAD_0);
390 a(fac.createInvoke("org.ibex.nestedvm.UnixRuntime","runAndExec",Type.INT,
391 new Type[]{Type.getType("Lorg/ibex/nestedvm/UnixRuntime;"),Type.STRING,new ArrayType(Type.STRING,1)},
394 a(fac.createInvoke(fullClassName,"run",Type.INT,new Type[]{Type.STRING,new ArrayType(Type.STRING,1)},INVOKEVIRTUAL));
395 a(fac.createInvoke("java.lang.System","exit",Type.VOID,new Type[]{Type.INT},INVOKESTATIC));
396 a(InstructionConstants.RETURN);
399 cl.addMethod(main.getMethod());
402 System.out.println("Constant Pool Size: " + cp.getSize());
403 cl.getJavaClass().dump(os);
406 private void addConstReturnMethod(String name, int val) {
407 MethodGen method = newMethod(ACC_PROTECTED,Type.INT, Type.NO_ARGS,name);
408 selectMethod(method);
410 a(InstructionConstants.IRETURN);
411 method.setMaxLocals();
412 method.setMaxStack();
413 cl.addMethod(method.getMethod());
416 private static int initDataCount;
417 private void emitData(int addr, DataInputStream dis, int size, boolean readOnly) throws Exn,IOException {
418 if((addr&3)!=0 || (size&3)!=0) throw new Exn("Data section on weird boundaries");
419 int last = addr + size;
421 int segSize = Math.min(size,28000); // must be a multiple of 56
422 StringBuffer sb = new StringBuffer();
423 for(int i=0;i<segSize;i+=7) {
425 for(int j=0;j<7;j++) {
427 byte b = (i+j < size) ? dis.readByte() : 1;
431 sb.append((char) ((l>>>(7*(7-j)))&0x7f));
433 String fieldname = "_data" + (++initDataCount);
434 cl.addField(new FieldGen(ACC_PRIVATE|ACC_STATIC|ACC_FINAL,new ArrayType(Type.INT,1),fieldname,cp).getField());
436 selectList(clinitExtras);
437 a(new PUSH(cp,sb.toString()));
438 a(new PUSH(cp,segSize/4));
439 a(fac.createInvoke("org.ibex.nestedvm.Runtime","decodeData",new ArrayType(Type.INT,1),new Type[]{Type.STRING,Type.INT},INVOKESTATIC));
440 a(fac.createPutStatic(fullClassName,fieldname,new ArrayType(Type.INT,1)));
442 selectList(initExtras);
443 a(InstructionConstants.ALOAD_0);
444 a(fac.createGetStatic(fullClassName,fieldname,new ArrayType(Type.INT,1)));
445 a(new PUSH(cp,addr));
446 a(new PUSH(cp,readOnly));
447 a(fac.createInvoke(fullClassName,"initPages",Type.VOID,new Type[]{new ArrayType(Type.INT,1),Type.INT,Type.BOOLEAN},INVOKEVIRTUAL));
455 private void emitBSS(int addr, int size) throws Exn {
456 if((addr&3)!=0) throw new Exn("BSS section on weird boundaries");
459 selectList(initExtras);
460 a(InstructionConstants.ALOAD_0);
461 a(new PUSH(cp,addr));
462 a(new PUSH(cp,count));
463 a(fac.createInvoke(fullClassName,"clearPages",Type.VOID,new Type[]{Type.INT,Type.INT},INVOKEVIRTUAL));
467 private boolean textDone;
468 private int startOfMethod = 0;
469 private int endOfMethod = 0;
470 private boolean unreachable = false;
471 private InstructionHandle[] jumpHandles;
472 private InstructionHandle defaultHandle;
473 private InstructionHandle returnHandle;
474 private InstructionHandle realStart;
475 private MethodGen curMethod;
477 private boolean jumpable(int addr) { return jumpableAddresses.contains(new Integer(addr)); }
479 private void emitText(int addr, DataInputStream dis, int size) throws Exn,IOException {
480 if(textDone) throw new Exn("Multiple text segments");
483 if((addr&3)!=0 || (size&3)!=0) throw new Exn("Section on weird boundaries");
485 int insn,nextInsn=-1;
486 boolean skipNext = true;
488 for(int i=0;i<count;i++,addr+=4) {
489 insn = skipNext ? dis.readInt() : nextInsn;
490 nextInsn = (i == count-1) ? -1 : dis.readInt();
491 if(addr >= endOfMethod) { endMethod(addr); startMethod(addr); }
492 if(jumpHandles[(addr-startOfMethod)/4] != null) {
493 // Move the fake jump target to the current location
494 insnList.move(jumpHandles[(addr-startOfMethod)/4],insnList.getEnd());
496 } else if(unreachable) {
500 skipNext = emitInstruction(addr,insn,nextInsn);
501 } catch(RuntimeException e) {
502 warn.println("Exception at " + toHex(addr));
505 if(skipNext) { addr+=4; i++; }
511 private void startMethod(int first) {
512 startOfMethod = first & methodMask;
513 endOfMethod = startOfMethod + maxBytesPerMethod;
514 curMethod = newMethod(ACC_PRIVATE,Type.VOID,Type.NO_ARGS,"run_" + toHex(startOfMethod));
515 selectMethod(curMethod);
517 int[] buf = new int[maxBytesPerMethod/4];
518 jumpHandles = new InstructionHandle[maxBytesPerMethod/4];
520 for(int addr=first;addr<endOfMethod;addr+=4) {
523 // append NOPs for GOTO jumps (these will be moved to the correct location later)
524 jumpHandles[(addr-startOfMethod)/4] = a(InstructionConstants.NOP);
528 // append NOP for default case (throw exn) (this will be moved later)
529 defaultHandle = a(InstructionConstants.NOP);
530 returnHandle = a(InstructionConstants.NOP);
532 int[] matches = new int[n];
533 System.arraycopy(buf,0,matches,0,n);
534 InstructionHandle[] targets = new InstructionHandle[n];
535 for(int i=0;i<matches.length;i++)
536 targets[i] = jumpHandles[(matches[i]-startOfMethod)/4];
539 // First instruction of the actual method - everything above this should be removed
540 // before we get to the end
541 realStart = a(InstructionConstants.NOP);
544 a(InstructionConstants.ALOAD_0);
545 a(fac.createFieldAccess(fullClassName,"page",new ArrayType(Type.INT,1), GETFIELD));
546 a(InstructionConstants.ASTORE_2);
548 a(InstructionConstants.ALOAD_0);
549 a(fac.createFieldAccess(fullClassName,"readPages",new ArrayType(Type.INT,2), GETFIELD));
550 a(InstructionConstants.ASTORE_2);
551 a(InstructionConstants.ALOAD_0);
552 a(fac.createFieldAccess(fullClassName,"writePages",new ArrayType(Type.INT,2), GETFIELD));
553 a(InstructionFactory.createStore(Type.OBJECT,3));
556 LOOKUPSWITCH initialSwitch = new LOOKUPSWITCH(matches,targets,defaultHandle);
557 a(InstructionConstants.ALOAD_0);
558 a(fac.createFieldAccess(fullClassName,"pc",Type.INT, GETFIELD));
562 private void endMethod(int firstAddrOfNext) {
563 if(startOfMethod == 0) return;
567 pushConst(firstAddrOfNext);
569 // mark the start of the next method as jumpable
570 jumpableAddresses.add(new Integer(firstAddrOfNext));
573 insnList.move(returnHandle,insnList.getEnd());
575 a(InstructionConstants.RETURN);
577 // move the default jump target (lookupswitch) to before the throw
578 insnList.move(defaultHandle,insnList.getEnd());
580 a(fac.createNew("org.ibex.nestedvm.Runtime$ExecutionException"));
581 a(InstructionConstants.DUP);
582 a(fac.createNew("java.lang.StringBuffer"));
583 a(InstructionConstants.DUP);
584 a(new PUSH(cp,"Jumped to invalid address: "));
585 a(fac.createInvoke("java.lang.StringBuffer","<init>",Type.VOID,new Type[]{Type.STRING},INVOKESPECIAL));
586 a(InstructionConstants.ALOAD_0);
587 a(fac.createFieldAccess(fullClassName,"pc",Type.INT, GETFIELD));
588 a(fac.createInvoke("java.lang.StringBuffer","append",Type.STRINGBUFFER,new Type[]{Type.INT},INVOKEVIRTUAL));
589 a(fac.createInvoke("java.lang.StringBuffer","toString",Type.STRING,Type.NO_ARGS,INVOKEVIRTUAL));
590 a(fac.createInvoke("org.ibex.nestedvm.Runtime$ExecutionException","<init>",Type.VOID,new Type[]{Type.STRING},INVOKESPECIAL));
591 a(InstructionConstants.ATHROW);
593 a(fac.createNew("org.ibex.nestedvm.Runtime$ExecutionException"));
594 a(InstructionConstants.DUP);
595 a(new PUSH(cp,"Jumped to invalid address"));
596 a(fac.createInvoke("org.ibex.nestedvm.Runtime$ExecutionException","<init>",Type.VOID,new Type[]{Type.STRING},INVOKESPECIAL));
597 a(InstructionConstants.ATHROW);
600 if(insnList.getStart() != realStart) {
601 System.err.println(insnList);
602 throw new Error("A jumpHandle wasn't moved into place");
605 curMethod.removeNOPs();
606 curMethod.setMaxLocals();
607 curMethod.setMaxStack();
609 cl.addMethod(curMethod.getMethod());
611 endOfMethod = startOfMethod = 0;
615 private void leaveMethod() {
616 a(InstructionFactory.createBranchInstruction(GOTO,returnHandle));
619 private void branch(int pc, int target) {
620 if((pc&methodMask) == (target&methodMask)) {
621 a(InstructionFactory.createBranchInstruction(GOTO,jumpHandles[(target-startOfMethod)/4]));
630 // This assumes everything needed by ifInsn is already on the stack
631 private boolean doIfInstruction(short op, int pc, int target, int nextInsn) throws Exn {
632 emitInstruction(-1,nextInsn,-1); // delay slot
634 IfInstruction ifInsn = (IfInstruction) InstructionFactory.createBranchInstruction(op,null);
635 if((target&methodMask) == (pc&methodMask)) {
637 h.setTarget(jumpHandles[(target-startOfMethod)/4]);
639 h = a(ifInsn.negate());
641 h.setTarget(a(InstructionConstants.NOP));
643 if(!jumpable(pc+4)) return true; // done - skip it
645 //System.err.println("Delay slot is jumpable - This code is untested + " + toHex(nextInsn));
646 if(pc+4==endOfMethod) {
647 // the delay slot is at the start of the next method
648 jumpableAddresses.add(new Integer(pc+8)); // make the 2nd insn of the next method jumpable
649 branch(pc,pc+8); // jump over it
650 //System.err.println("delay slot: " + toHex(pc+8));
652 return false; // we still need to output it
654 //System.err.println("jumped over delay slot: " + toHex(pc+4));
655 // add another copy and jump over
656 h = a(InstructionFactory.createBranchInstruction(GOTO,null));
657 insnList.move(jumpHandles[(pc+4-startOfMethod)/4],insnList.getEnd());
658 emitInstruction(-1,nextInsn,-1); // delay slot
659 h.setTarget(a(InstructionConstants.NOP));
664 private boolean emitInstruction(int pc, int insn, int nextInsn) throws Exn {
665 if(insn == -1) throw new Exn("insn is -1");
667 int op = (insn >>> 26) & 0xff; // bits 26-31
668 int rs = (insn >>> 21) & 0x1f; // bits 21-25
669 int rt = (insn >>> 16) & 0x1f; // bits 16-20
670 int ft = (insn >>> 16) & 0x1f;
671 int rd = (insn >>> 11) & 0x1f; // bits 11-15
672 int fs = (insn >>> 11) & 0x1f;
673 int shamt = (insn >>> 6) & 0x1f; // bits 6-10
674 int fd = (insn >>> 6) & 0x1f;
675 int subcode = insn & 0x3f; // bits 0-5
676 int breakCode = (insn >>> 6) & 0xfffff; // bits 6-20
678 int jumpTarget = (insn & 0x03ffffff); // bits 0-25
679 int unsignedImmediate = insn & 0xffff;
680 int signedImmediate = (insn << 16) >> 16;
681 int branchTarget = signedImmediate;
694 a(InstructionConstants.ISHL);
701 a(InstructionConstants.IUSHR);
708 a(InstructionConstants.ISHR);
715 a(InstructionConstants.ISHL);
722 a(InstructionConstants.IUSHR);
729 a(InstructionConstants.ISHR);
733 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
734 emitInstruction(-1,nextInsn,-1);
742 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
743 emitInstruction(-1,nextInsn,-1);
759 restoreChangedRegs();
762 a(InstructionConstants.ALOAD_0);
768 a(fac.createInvoke(fullClassName,"syscall",Type.INT,new Type[]{Type.INT,Type.INT,Type.INT,Type.INT,Type.INT},INVOKEVIRTUAL));
771 a(InstructionConstants.ALOAD_0);
772 a(fac.createFieldAccess(fullClassName,"state",Type.INT, GETFIELD));
773 pushConst(Runtime.RUNNING);
774 b1 = a(InstructionFactory.createBranchInstruction(IF_ICMPEQ,null));
779 b1.setTarget(a(InstructionConstants.NOP));
783 a(fac.createNew("org.ibex.nestedvm.Runtime$ExecutionException"));
784 a(InstructionConstants.DUP);
785 a(new PUSH(cp,"BREAK Code " + toHex(breakCode)));
786 a(fac.createInvoke("org.ibex.nestedvm.Runtime$ExecutionException","<init>",Type.VOID,new Type[]{Type.STRING},INVOKESPECIAL));
787 a(InstructionConstants.ATHROW);
812 a(InstructionConstants.I2L);
814 a(InstructionConstants.I2L);
815 a(InstructionConstants.LMUL);
816 a(InstructionConstants.DUP2);
818 a(InstructionConstants.L2I);
820 a(InstructionConstants.SWAP);
824 a(InstructionConstants.LUSHR);
825 a(InstructionConstants.L2I);
827 a(InstructionConstants.SWAP);
833 a(InstructionConstants.I2L);
834 pushConst(0xffffffffL);
835 a(InstructionConstants.LAND);
837 a(InstructionConstants.I2L);
838 pushConst(0xffffffffL);
839 a(InstructionConstants.LAND);
840 a(InstructionConstants.LMUL);
841 a(InstructionConstants.DUP2);
843 a(InstructionConstants.L2I);
845 a(InstructionConstants.SWAP);
849 a(InstructionConstants.LUSHR);
850 a(InstructionConstants.L2I);
852 a(InstructionConstants.SWAP);
859 a(InstructionConstants.DUP2);
861 a(InstructionConstants.IDIV);
863 a(InstructionConstants.SWAP);
866 a(InstructionConstants.IREM);
868 a(InstructionConstants.SWAP);
874 a(InstructionConstants.DUP);
876 b1 = a(InstructionFactory.createBranchInstruction(IFEQ,null));
879 a(InstructionConstants.I2L);
880 pushConst(0xffffffffL);
881 a(InstructionConstants.LAND);
882 a(InstructionConstants.DUP2);
884 a(InstructionConstants.I2L);
885 pushConst(0xffffffffL);
887 a(InstructionConstants.LAND);
888 a(InstructionConstants.DUP2_X2);
889 a(InstructionConstants.LDIV);
891 a(InstructionConstants.L2I);
893 a(InstructionConstants.SWAP);
896 a(InstructionConstants.LREM);
897 a(InstructionConstants.L2I);
899 a(InstructionConstants.SWAP);
902 b1.setTarget(a(InstructionConstants.NOP));
907 throw new Exn("ADD (add with oveflow trap) not suported");
910 if(rt != 0 && rs != 0) {
913 a(InstructionConstants.IADD);
922 throw new Exn("SUB (add with oveflow trap) not suported");
925 if(rt != 0 && rs != 0) {
928 a(InstructionConstants.ISUB);
931 a(InstructionConstants.INEG);
941 a(InstructionConstants.IAND);
948 a(InstructionConstants.IOR);
955 a(InstructionConstants.IXOR);
960 if(rs != 0 || rt != 0) {
961 if(rs != 0 && rt != 0) {
964 a(InstructionConstants.IOR);
970 a(InstructionConstants.ICONST_M1);
971 a(InstructionConstants.IXOR);
982 b1 = a(InstructionFactory.createBranchInstruction(IF_ICMPLT,null));
983 a(InstructionConstants.ICONST_0);
984 b2 = a(InstructionFactory.createBranchInstruction(GOTO,null));
985 b1.setTarget(a(InstructionConstants.ICONST_1));
986 b2.setTarget(a(InstructionConstants.NOP));
997 a(InstructionConstants.I2L);
998 pushConst(0xffffffffL);
999 a(InstructionConstants.LAND);
1001 a(InstructionConstants.I2L);
1002 pushConst(0xffffffffL);
1003 a(InstructionConstants.LAND);
1004 a(InstructionConstants.LCMP);
1005 b1 = a(InstructionFactory.createBranchInstruction(IFLT,null));
1008 b1 = a(InstructionFactory.createBranchInstruction(IFNE,null));
1010 a(InstructionConstants.ICONST_0);
1011 b2 = a(InstructionFactory.createBranchInstruction(GOTO,null));
1012 b1.setTarget(a(InstructionConstants.ICONST_1));
1013 b2.setTarget(a(InstructionConstants.NOP));
1020 throw new RuntimeException("Illegal instruction 0/" + subcode);
1027 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1029 return doIfInstruction(IFLT,pc,pc+branchTarget*4+4,nextInsn);
1031 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1033 return doIfInstruction(IFGE,pc,pc+branchTarget*4+4,nextInsn);
1035 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1037 b1 = a(InstructionFactory.createBranchInstruction(IFGE,null));
1038 emitInstruction(-1,nextInsn,-1);
1042 branch(pc,pc+branchTarget*4+4);
1043 b1.setTarget(a(InstructionConstants.NOP));
1046 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1048 if(rs != 0) { // r0 is always >= 0
1050 b1 = a(InstructionFactory.createBranchInstruction(IFLT,null));
1052 emitInstruction(-1,nextInsn,-1);
1056 branch(pc,pc+branchTarget*4+4);
1057 if(b1 != null) b1.setTarget(a(InstructionConstants.NOP));
1058 if(b1 == null) unreachable = true;
1061 throw new RuntimeException("Illegal Instruction 1/" + rt);
1066 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1067 emitInstruction(-1,nextInsn,-1);
1068 branch(pc,(pc&0xf0000000)|(jumpTarget << 2));
1073 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1074 int target = (pc&0xf0000000)|(jumpTarget << 2);
1075 emitInstruction(-1,nextInsn,-1);
1076 // FIXME: Have a memcpy syscall and just override memcpy in libnestedvm
1077 if(optimizedMemcpy && (target == memcpy || target == memset)) {
1078 a(InstructionConstants.ALOAD_0);
1082 a(fac.createInvoke(fullClassName,target==memcpy ? "memcpy" : "memset", Type.VOID, new Type[]{Type.INT,Type.INT,Type.INT},INVOKEVIRTUAL));
1097 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1099 emitInstruction(-1,nextInsn,-1);
1100 branch(pc,pc+branchTarget*4+4);
1102 } else if(rs == 0 || rt == 0) {
1103 pushReg(rt == 0 ? R+rs : R+rt);
1104 return doIfInstruction(IFEQ,pc,pc+branchTarget*4+4,nextInsn);
1108 return doIfInstruction(IF_ICMPEQ,pc,pc+branchTarget*4+4,nextInsn);
1112 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1115 return doIfInstruction(IFNE,pc,pc+branchTarget*4+4,nextInsn);
1118 return doIfInstruction(IF_ICMPNE,pc,pc+branchTarget*4+4,nextInsn);
1121 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1123 return doIfInstruction(IFLE,pc,pc+branchTarget*4+4,nextInsn);
1125 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1127 return doIfInstruction(IFGT,pc,pc+branchTarget*4+4,nextInsn);
1129 throw new Exn("ADDI (add immediate with oveflow trap) not suported");
1132 addiu(rs,signedImmediate);
1138 pushConst(signedImmediate);
1139 b1 = a(InstructionFactory.createBranchInstruction(IF_ICMPLT,null));
1140 a(InstructionConstants.ICONST_0);
1141 b2 = a(InstructionFactory.createBranchInstruction(GOTO,null));
1142 b1.setTarget(a(InstructionConstants.ICONST_1));
1143 b2.setTarget(a(InstructionConstants.NOP));
1149 a(InstructionConstants.I2L);
1150 pushConst(0xffffffffL);
1151 a(InstructionConstants.LAND);
1152 pushConst((long)unsignedImmediate);
1153 a(InstructionConstants.LCMP);
1155 b1 = a(InstructionFactory.createBranchInstruction(IFLT,null));
1156 a(InstructionConstants.ICONST_0);
1157 b2 = a(InstructionFactory.createBranchInstruction(GOTO,null));
1158 b1.setTarget(a(InstructionConstants.ICONST_1));
1159 b2.setTarget(a(InstructionConstants.NOP));
1166 pushConst(unsignedImmediate);
1167 a(InstructionConstants.IAND);
1172 if(rs != 0 && unsignedImmediate != 0) {
1174 pushConst(unsignedImmediate);
1175 a(InstructionConstants.IOR);
1179 pushConst(unsignedImmediate);
1186 pushConst(unsignedImmediate);
1187 a(InstructionConstants.IXOR);
1192 pushConst(unsignedImmediate << 16);
1196 throw new Exn("TLB/Exception support not implemented");
1205 if(fs != 31) throw new Exn("FCR " + fs + " unavailable");
1219 if(fs != 31) throw new Exn("FCR " + fs + " unavailable");
1224 case 8: {// BC1F, BC1T
1226 pushConst(0x800000);
1227 a(InstructionConstants.IAND);
1228 return doIfInstruction(((insn>>>16)&1) == 0 ? IFEQ : IFNE,pc,pc+branchTarget*4+4,nextInsn);
1232 { // Single/Double math
1233 boolean d = rs == 17;
1236 preSetDouble(F+fd,d);
1239 a(d ? InstructionConstants.DADD : InstructionConstants.FADD);
1243 preSetDouble(F+fd,d);
1246 a(d ? InstructionConstants.DSUB : InstructionConstants.FSUB);
1250 preSetDouble(F+fd,d);
1253 a(d ? InstructionConstants.DMUL : InstructionConstants.FMUL);
1257 preSetDouble(F+fd,d);
1260 a(d ? InstructionConstants.DDIV : InstructionConstants.FDIV);
1264 preSetDouble(F+fd,d);
1265 // NOTE: We can't use fneg/dneg here since they'll turn +0.0 into -0.0
1268 a(d ? InstructionConstants.DUP2 : InstructionConstants.DUP);
1269 a(d ? InstructionConstants.DCONST_0 : InstructionConstants.FCONST_0);
1270 a(d ? InstructionConstants.DCMPG : InstructionConstants.FCMPG);
1272 b1 = a(InstructionFactory.createBranchInstruction(IFGT,null));
1273 a(d ? InstructionConstants.DCONST_0 : InstructionConstants.FCONST_0);
1275 a(InstructionConstants.DUP2_X2);
1276 a(InstructionConstants.POP2);
1278 a(InstructionConstants.POP);
1280 a(InstructionConstants.DSUB);
1282 b1.setTarget(setDouble(d));
1296 preSetDouble(F+fd,d);
1298 a(d ? InstructionConstants.DNEG : InstructionConstants.FNEG);
1304 if(d) a(InstructionConstants.D2F);
1310 if(!d) a(InstructionConstants.F2D);
1313 case 36: { // CVT.W.D
1314 int[] matches = new int[4];
1315 for(int i=0;i<4;i++) matches[i] = i;
1317 TABLESWITCH ts = new TABLESWITCH(matches,new InstructionHandle[4], null);
1322 a(InstructionConstants.ICONST_3);
1323 a(InstructionConstants.IAND);
1326 // Round towards plus infinity
1327 ts.setTarget(2,a(InstructionConstants.NOP));
1328 if(!d) a(InstructionConstants.F2D); // Ugh.. java.lang.Math doesn't have a float ceil/floor
1329 a(fac.createInvoke("java.lang.Math","ceil",Type.DOUBLE,new Type[]{Type.DOUBLE},INVOKESTATIC));
1330 if(!d) a(InstructionConstants.D2F);
1331 b1 = a(InstructionFactory.createBranchInstruction(GOTO,null));
1334 ts.setTarget(0,d ? pushConst(0.5d) : pushConst(0.5f));
1335 a(d ? InstructionConstants.DADD : InstructionConstants.FADD);
1338 // Round towards minus infinity
1339 ts.setTarget(3,a(InstructionConstants.NOP));
1340 if(!d) a(InstructionConstants.F2D);
1341 a(fac.createInvoke("java.lang.Math","floor",Type.DOUBLE,new Type[]{Type.DOUBLE},INVOKESTATIC));
1342 if(!d) a(InstructionConstants.D2F);
1344 InstructionHandle h = a(d ? InstructionConstants.D2I : InstructionConstants.F2I);
1358 pushConst(~0x800000);
1359 a(InstructionConstants.IAND);
1362 a(d ? InstructionConstants.DCMPG : InstructionConstants.FCMPG);
1364 case 50: b1 = a(InstructionFactory.createBranchInstruction(IFEQ,null)); break;
1365 case 60: b1 = a(InstructionFactory.createBranchInstruction(IFLT,null)); break;
1366 case 62: b1 = a(InstructionFactory.createBranchInstruction(IFLE,null)); break;
1370 pushConst(0x000000);
1371 b2 = a(InstructionFactory.createBranchInstruction(GOTO,null));
1372 b1.setTarget(pushConst(0x800000));
1373 b2.setTarget(a(InstructionConstants.IOR));
1376 default: throw new Exn("Invalid Instruction 17/" + rs + "/" + subcode);
1380 case 20: { // Integer
1385 a(InstructionConstants.I2F);
1391 a(InstructionConstants.I2D);
1394 default: throw new Exn("Invalid Instruction 17/" + rs + "/" + subcode);
1399 throw new Exn("Invalid Instruction 17/" + rs);
1404 throw new Exn("coprocessor 2 and 3 instructions not available");
1407 addiu(R+rs,signedImmediate);
1414 a(InstructionConstants.ICONST_M1);
1415 a(InstructionConstants.IXOR);
1416 a(InstructionConstants.ICONST_3);
1417 a(InstructionConstants.IAND);
1418 a(InstructionConstants.ICONST_3);
1419 a(InstructionConstants.ISHL);
1420 a(InstructionConstants.IUSHR);
1421 a(InstructionConstants.I2B);
1427 addiu(R+rs,signedImmediate);
1434 a(InstructionConstants.ICONST_M1);
1435 a(InstructionConstants.IXOR);
1436 a(InstructionConstants.ICONST_2);
1437 a(InstructionConstants.IAND);
1438 a(InstructionConstants.ICONST_3);
1439 a(InstructionConstants.ISHL);
1440 a(InstructionConstants.IUSHR);
1441 a(InstructionConstants.I2S);
1447 addiu(R+rs,signedImmediate);
1451 pushConst(0x00ffffff);
1454 a(InstructionConstants.ICONST_M1);
1455 a(InstructionConstants.IXOR);
1456 a(InstructionConstants.ICONST_3);
1457 a(InstructionConstants.IAND);
1458 a(InstructionConstants.ICONST_3);
1459 a(InstructionConstants.ISHL);
1460 a(InstructionConstants.IUSHR);
1461 a(InstructionConstants.IAND);
1468 a(InstructionConstants.ICONST_3);
1469 a(InstructionConstants.IAND);
1470 a(InstructionConstants.ICONST_3);
1471 a(InstructionConstants.ISHL);
1472 a(InstructionConstants.ISHL);
1473 a(InstructionConstants.IOR);
1482 memRead(R+rs,signedImmediate);
1487 addiu(R+rs,signedImmediate);
1494 a(InstructionConstants.ICONST_M1);
1495 a(InstructionConstants.IXOR);
1496 a(InstructionConstants.ICONST_3);
1497 a(InstructionConstants.IAND);
1498 a(InstructionConstants.ICONST_3);
1499 a(InstructionConstants.ISHL);
1500 a(InstructionConstants.IUSHR);
1502 a(InstructionConstants.IAND);
1508 addiu(R+rs,signedImmediate);
1515 a(InstructionConstants.ICONST_M1);
1516 a(InstructionConstants.IXOR);
1517 a(InstructionConstants.ICONST_2);
1518 a(InstructionConstants.IAND);
1519 a(InstructionConstants.ICONST_3);
1520 a(InstructionConstants.ISHL);
1521 a(InstructionConstants.IUSHR);
1523 // chars are unsigend so this works
1524 a(InstructionConstants.I2C);
1530 addiu(R+rs,signedImmediate);
1534 pushConst(0xffffff00);
1537 a(InstructionConstants.ICONST_3);
1538 a(InstructionConstants.IAND);
1539 a(InstructionConstants.ICONST_3);
1540 a(InstructionConstants.ISHL);
1541 a(InstructionConstants.ISHL);
1542 a(InstructionConstants.IAND);
1549 a(InstructionConstants.ICONST_M1);
1550 a(InstructionConstants.IXOR);
1551 a(InstructionConstants.ICONST_3);
1552 a(InstructionConstants.IAND);
1553 a(InstructionConstants.ICONST_3);
1554 a(InstructionConstants.ISHL);
1555 a(InstructionConstants.IUSHR);
1556 a(InstructionConstants.IOR);
1563 addiu(R+rs,signedImmediate);
1566 // FEATURE: DO the preMemRead(true) thing for the rest of the S* instructions
1571 pushConst(0xff000000);
1574 a(InstructionConstants.ICONST_3);
1575 a(InstructionConstants.IAND);
1576 a(InstructionConstants.ICONST_3);
1577 a(InstructionConstants.ISHL);
1578 a(InstructionConstants.IUSHR);
1579 a(InstructionConstants.ICONST_M1);
1580 a(InstructionConstants.IXOR);
1581 a(InstructionConstants.IAND);
1586 a(InstructionConstants.IAND);
1592 a(InstructionConstants.ICONST_M1);
1593 a(InstructionConstants.IXOR);
1594 a(InstructionConstants.ICONST_3);
1595 a(InstructionConstants.IAND);
1596 a(InstructionConstants.ICONST_3);
1597 a(InstructionConstants.ISHL);
1598 a(InstructionConstants.ISHL);
1599 a(InstructionConstants.IOR);
1608 addiu(R+rs,signedImmediate);
1610 a(InstructionConstants.DUP);
1622 a(InstructionConstants.ICONST_2);
1623 a(InstructionConstants.IAND);
1624 a(InstructionConstants.ICONST_3);
1625 a(InstructionConstants.ISHL);
1626 a(InstructionConstants.ISHL);
1627 a(InstructionConstants.IAND);
1632 a(InstructionConstants.IAND);
1638 a(InstructionConstants.ICONST_M1);
1639 a(InstructionConstants.IXOR);
1640 a(InstructionConstants.ICONST_2);
1641 a(InstructionConstants.IAND);
1642 a(InstructionConstants.ICONST_3);
1643 a(InstructionConstants.ISHL);
1644 a(InstructionConstants.ISHL);
1645 a(InstructionConstants.IOR);
1654 addiu(R+rs,signedImmediate);
1655 a(InstructionConstants.DUP);
1664 pushConst(0xffffff00);
1667 a(InstructionConstants.ICONST_M1);
1668 a(InstructionConstants.IXOR);
1669 a(InstructionConstants.ICONST_3);
1670 a(InstructionConstants.IAND);
1671 a(InstructionConstants.ICONST_3);
1672 a(InstructionConstants.ISHL);
1673 a(InstructionConstants.ISHL);
1674 a(InstructionConstants.IAND);
1679 a(InstructionConstants.ICONST_3);
1680 a(InstructionConstants.IAND);
1681 a(InstructionConstants.ICONST_3);
1682 a(InstructionConstants.ISHL);
1683 a(InstructionConstants.IUSHR);
1684 a(InstructionConstants.IOR);
1692 preMemWrite2(R+rs,signedImmediate);
1699 addiu(R+rs,signedImmediate);
1700 a(InstructionConstants.DUP);
1709 pushConst(0x00ffffff);
1712 a(InstructionConstants.ICONST_3);
1713 a(InstructionConstants.IAND);
1714 a(InstructionConstants.ICONST_3);
1715 a(InstructionConstants.ISHL);
1716 a(InstructionConstants.IUSHR);
1717 a(InstructionConstants.IAND);
1722 a(InstructionConstants.ICONST_M1);
1723 a(InstructionConstants.IXOR);
1724 a(InstructionConstants.ICONST_3);
1725 a(InstructionConstants.IAND);
1726 a(InstructionConstants.ICONST_3);
1727 a(InstructionConstants.ISHL);
1728 a(InstructionConstants.ISHL);
1729 a(InstructionConstants.IOR);
1734 // This need to be atomic if we ever support threads (see SWC0/SC)
1737 memRead(R+rs,signedImmediate);
1743 memRead(R+rs,signedImmediate);
1747 /* This needs to fail (set rt to 0) if the memory location was modified
1748 * between the LL and SC if we every support threads.
1753 preMemWrite2(R+rs,signedImmediate);
1762 preMemWrite2(R+rs,signedImmediate);
1767 throw new Exn("Invalid Instruction: " + op + " at " + toHex(pc));
1772 // Helper functions for emitText
1774 private static final int R = 0;
1775 private static final int F = 32;
1776 private static final int HI = 64;
1777 private static final int LO = 65;
1778 private static final int FCSR = 66;
1779 private static final int REG_COUNT=67;
1781 private int[] regLocalMapping = new int[REG_COUNT];
1782 private int[] regLocalReadCount = new int[REG_COUNT];
1783 private int[] regLocalWriteCount = new int[REG_COUNT];
1784 private int nextAvailLocal;
1786 private int getLocalForReg(int reg) {
1787 if(regLocalMapping[reg] != 0) return regLocalMapping[reg];
1788 if(nextAvailLocal == 0) nextAvailLocal = onePage ? 3 : 4;
1789 regLocalMapping[reg] = nextAvailLocal++;
1790 return regLocalMapping[reg];
1793 private void fixupRegs() {
1794 InstructionHandle prev = realStart;
1795 for(int i=0;i<REG_COUNT;i++) {
1796 if(regLocalMapping[i] == 0) continue;
1798 prev = insnList.append(prev,InstructionConstants.ALOAD_0);
1799 prev = insnList.append(prev,fac.createFieldAccess(fullClassName,regField(i),Type.INT, GETFIELD));
1800 prev = insnList.append(prev,InstructionFactory.createStore(Type.INT,regLocalMapping[i]));
1802 if(regLocalWriteCount[i] > 0) {
1803 a(InstructionConstants.ALOAD_0);
1804 a(InstructionFactory.createLoad(Type.INT,regLocalMapping[i]));
1805 a(fac.createFieldAccess(fullClassName,regField(i),Type.INT, PUTFIELD));
1808 regLocalMapping[i] = regLocalReadCount[i] = regLocalWriteCount[i] = 0;
1813 private void restoreChangedRegs() {
1814 for(int i=0;i<REG_COUNT;i++) {
1815 if(regLocalWriteCount[i] > 0) {
1816 a(InstructionConstants.ALOAD_0);
1817 a(InstructionFactory.createLoad(Type.INT,regLocalMapping[i]));
1818 a(fac.createFieldAccess(fullClassName,regField(i),Type.INT, PUTFIELD));
1823 private String regField(int reg) {
1826 case HI: field = "hi"; break;
1827 case LO: field = "lo"; break;
1828 case FCSR: field = "fcsr"; break;
1830 if(reg > R && reg < R+32) field="r"+(reg-R);
1831 else if(reg >= F && reg < F+32) field="f"+(reg-F);
1832 else throw new IllegalArgumentException(""+reg);
1837 private boolean doLocal(int reg) {
1839 return reg == R+2 || reg == R+3 || reg == R+4 || reg == R+29;
1842 private InstructionHandle pushRegWZ(int reg) {
1844 warn.println("Warning: Pushing r0!");
1845 new Exception().printStackTrace(warn);
1847 return pushRegZ(reg);
1850 private InstructionHandle pushRegZ(int reg) {
1851 if(reg == R+0) return pushConst(0);
1852 else return pushReg(reg);
1856 private InstructionHandle pushReg(int reg) {
1857 InstructionHandle h;
1859 regLocalReadCount[reg]++;
1860 h = a(InstructionFactory.createLoad(Type.INT,getLocalForReg(reg)));
1862 h = a(InstructionConstants.ALOAD_0);
1863 a(fac.createFieldAccess(fullClassName,regField(reg),Type.INT, GETFIELD));
1868 private int preSetRegStackPos;
1869 private int[] preSetRegStack = new int[8];
1871 // This can push ONE or ZERO words to the stack. If it pushed one it returns true
1872 private boolean preSetReg(int reg) {
1873 regField(reg); // just to check for validity
1874 preSetRegStack[preSetRegStackPos] = reg;
1875 preSetRegStackPos++;
1879 a(InstructionConstants.ALOAD_0);
1884 private InstructionHandle setReg() {
1885 if(preSetRegStackPos==0) throw new RuntimeException("didn't do preSetReg");
1886 preSetRegStackPos--;
1887 int reg = preSetRegStack[preSetRegStackPos];
1888 InstructionHandle h;
1890 h = a(InstructionFactory.createStore(Type.INT,getLocalForReg(reg)));
1891 regLocalWriteCount[reg]++;
1893 h = a(fac.createFieldAccess(fullClassName,regField(reg),Type.INT, PUTFIELD));
1898 private InstructionHandle preSetPC() { return a(InstructionConstants.ALOAD_0); }
1899 private InstructionHandle setPC() { return a(fac.createFieldAccess(fullClassName,"pc",Type.INT, PUTFIELD)); }
1901 //unused - private InstructionHandle pushFloat(int reg) throws CompilationException { return pushDouble(reg,false); }
1902 //unused - private InstructionHandle pushDouble(int reg) throws CompilationException { return pushDouble(reg,true); }
1903 private InstructionHandle pushDouble(int reg, boolean d) throws Exn {
1904 if(reg < F || reg >= F+32) throw new IllegalArgumentException(""+reg);
1905 InstructionHandle h;
1907 if(reg == F+31) throw new Exn("Tried to use a double in f31");
1909 a(InstructionConstants.I2L);
1911 a(InstructionConstants.LSHL);
1913 a(InstructionConstants.I2L);
1914 pushConst(0xffffffffL);
1915 a(InstructionConstants.LAND);
1916 a(InstructionConstants.LOR);
1917 //p("invokestatic java/lang/Double/longBitsToDouble(J)D");
1918 a(fac.createInvoke("java.lang.Double","longBitsToDouble",Type.DOUBLE,new Type[]{Type.LONG},INVOKESTATIC));
1921 a(fac.createInvoke("java.lang.Float","intBitsToFloat",Type.FLOAT,new Type[]{Type.INT},INVOKESTATIC));
1926 private void preSetFloat(int reg) { preSetDouble(reg,false); }
1927 private void preSetDouble(int reg) { preSetDouble(reg,true); }
1928 private void preSetDouble(int reg, boolean d) { preSetReg(reg); }
1930 private InstructionHandle setFloat() throws Exn { return setDouble(false); }
1931 private InstructionHandle setDouble() throws Exn { return setDouble(true); }
1932 private InstructionHandle setDouble(boolean d) throws Exn {
1933 int reg = preSetRegStack[preSetRegStackPos-1];
1934 if(reg < F || reg >= F+32) throw new IllegalArgumentException(""+reg);
1935 //p("invokestatic java/lang/Double/doubleToLongBits(D)J");
1936 InstructionHandle h;
1938 if(reg == F+31) throw new Exn("Tried to use a double in f31");
1939 h = a(fac.createInvoke("java.lang.Double","doubleToLongBits",Type.LONG,new Type[]{Type.DOUBLE},INVOKESTATIC));
1940 a(InstructionConstants.DUP2);
1942 a(InstructionConstants.LUSHR);
1943 a(InstructionConstants.L2I);
1944 if(preSetReg(reg+1))
1945 a(InstructionConstants.SWAP);
1947 a(InstructionConstants.L2I);
1948 setReg(); // preSetReg was already done for this by preSetDouble
1950 h = a(fac.createInvoke("java.lang.Float","floatToRawIntBits",Type.INT,new Type[]{Type.FLOAT},INVOKESTATIC));
1956 private InstructionHandle pushConst(int n) {
1957 if(n >= 0 && n <= 5) {
1959 case 0: return a(InstructionConstants.ICONST_0);
1960 case 1: return a(InstructionConstants.ICONST_1);
1961 case 2: return a(InstructionConstants.ICONST_2);
1962 case 3: return a(InstructionConstants.ICONST_3);
1963 case 4: return a(InstructionConstants.ICONST_4);
1964 case 5: return a(InstructionConstants.ICONST_5);
1965 default: return null;
1967 } else if(n == -1) {
1968 return a(InstructionConstants.ICONST_M1);
1969 } else if(n >= -128 && n <= 127) {
1970 return a(new BIPUSH((byte) n));
1971 } else if(n >= -32768 && n <= 32767) {
1972 return a(new SIPUSH((short) n));
1974 return a(new PUSH(cp,n));
1978 private InstructionHandle pushConst(long l) { return a(new PUSH(cp,l)); }
1979 private InstructionHandle pushConst(float f) { return a(new PUSH(cp,f)); }
1980 private InstructionHandle pushConst(double d) { return a(new PUSH(cp,d)); }
1982 private void pushTmp() { a(InstructionConstants.ILOAD_1); }
1983 private void setTmp() { a(InstructionConstants.ISTORE_1); }
1985 private void addiu(int reg, int offset) {
1986 if(reg != R+0 && offset != 0) {
1989 a(InstructionConstants.IADD);
1990 } else if(reg != R+0) {
1996 private int memWriteStage;
1997 private void preMemWrite1() {
1998 if(memWriteStage!=0) throw new Error("pending preMemWrite1/2");
2001 a(InstructionConstants.ALOAD_2);
2003 a(InstructionFactory.createLoad(Type.OBJECT,3));
2005 a(InstructionConstants.ALOAD_0);
2008 private void preMemWrite2(int reg, int offset) {
2013 private void preMemWrite2() { preMemWrite2(false); }
2014 private void preMemWrite2(boolean addrInTmp) {
2015 if(memWriteStage!=1) throw new Error("pending preMemWrite2 or no preMemWrite1");
2018 if(nullPointerCheck) {
2019 a(InstructionConstants.DUP);
2020 a(InstructionConstants.ALOAD_0);
2021 a(InstructionConstants.SWAP);
2022 a(fac.createInvoke(fullClassName,"nullPointerCheck",Type.VOID,new Type[]{Type.INT},INVOKEVIRTUAL));
2026 a(InstructionConstants.ICONST_2);
2027 a(InstructionConstants.IUSHR);
2028 } else if(fastMem) {
2030 a(InstructionConstants.DUP_X1);
2031 pushConst(pageShift);
2032 a(InstructionConstants.IUSHR);
2033 a(InstructionConstants.AALOAD);
2037 a(InstructionConstants.SWAP);
2038 a(InstructionConstants.ICONST_2);
2039 a(InstructionConstants.IUSHR);
2040 pushConst((pageSize>>2)-1);
2041 a(InstructionConstants.IAND);
2045 // pops an address and value off the stack, sets *addr to value
2046 private void memWrite() {
2047 if(memWriteStage!=2) throw new Error("didn't do preMemWrite1 or preMemWrite2");
2051 a(InstructionConstants.IASTORE);
2052 } else if(fastMem) {
2053 a(InstructionConstants.IASTORE);
2055 a(fac.createInvoke(fullClassName,"unsafeMemWrite",Type.VOID,new Type[]{Type.INT,Type.INT},INVOKEVIRTUAL));
2060 // reads the word at r[reg]+offset
2061 private void memRead(int reg, int offset) {
2067 private boolean didPreMemRead;
2068 private boolean preMemReadDoPreWrite;
2070 private void preMemRead() { preMemRead(false); }
2071 private void preMemRead(boolean preWrite) {
2072 if(didPreMemRead) throw new Error("pending preMemRead");
2073 didPreMemRead = true;
2074 preMemReadDoPreWrite = preWrite;
2076 a(InstructionConstants.ALOAD_2);
2078 a(InstructionFactory.createLoad(Type.OBJECT,preWrite ? 3 : 2));
2080 a(InstructionConstants.ALOAD_0);
2082 // memRead pops an address off the stack, reads the value at that addr, and pushed the value
2083 // preMemRead MUST be called BEFORE the addresses is pushed
2084 private void memRead() { memRead(false); }
2086 private void memRead(boolean addrInTmp) {
2087 if(!didPreMemRead) throw new Error("didn't do preMemRead");
2088 didPreMemRead = false;
2089 if(preMemReadDoPreWrite)
2092 if(nullPointerCheck) {
2093 a(InstructionConstants.DUP);
2094 a(InstructionConstants.ALOAD_0);
2095 a(InstructionConstants.SWAP);
2096 a(fac.createInvoke(fullClassName,"nullPointerCheck",Type.VOID,new Type[]{Type.INT},INVOKEVIRTUAL));
2100 // p(target + "= page[(" + addr + ")>>>2];");
2101 a(InstructionConstants.ICONST_2);
2102 a(InstructionConstants.IUSHR);
2103 if(preMemReadDoPreWrite)
2104 a(InstructionConstants.DUP2);
2105 a(InstructionConstants.IALOAD);
2106 } else if(fastMem) {
2107 //p(target + " = readPages[("+addr+")>>>"+pageShift+"][(("+addr+")>>>2)&"+toHex((pageSize>>2)-1)+"];");
2110 a(InstructionConstants.DUP_X1);
2111 pushConst(pageShift);
2112 a(InstructionConstants.IUSHR);
2113 a(InstructionConstants.AALOAD);
2117 a(InstructionConstants.SWAP);
2118 a(InstructionConstants.ICONST_2);
2119 a(InstructionConstants.IUSHR);
2120 pushConst((pageSize>>2)-1);
2121 a(InstructionConstants.IAND);
2122 if(preMemReadDoPreWrite)
2123 a(InstructionConstants.DUP2);
2124 a(InstructionConstants.IALOAD);
2127 if(preMemReadDoPreWrite)
2128 a(InstructionConstants.DUP2);
2129 a(fac.createInvoke(fullClassName,"unsafeMemWrite",Type.INT,new Type[]{Type.INT},INVOKEVIRTUAL));
2134 // This might come in handy for something else
2135 /*private boolean touchesReg(int insn, int reg) {
2136 if((reg < R+0 || reg >= R+32) && reg != FCSR) throw new IllegalArgumentException(""+reg);
2137 if(reg == R+0) return false; // r0 is never modified
2138 int op = (insn >>> 26) & 0xff; // bits 26-31
2139 int subcode = insn & 0x3f; // bits 0-5
2140 int rd = (insn >>> 11) & 0x1f; // bits 11-15
2141 int rt = (insn >>> 16) & 0x1f; // bits 16-20
2142 int rs = (insn >>> 21) & 0x1f; // bits 21-25
2146 if(subcode >= 0 && subcode <= 7) return reg == R+rd; // Shift ops
2147 if(subcode >= 32 && subcode <= 43) return reg == R+rd; // Other math ops
2148 if(subcode >= 24 && subcode <= 27) return reg == HI || reg == LO; // MULT/DIV
2150 case 13: return false; // BREAK
2153 case 0: return reg == R+rt; // MFC.1
2154 case 2: return reg == R+rt; // CFC.1
2155 case 4: return false; // MTC.1
2156 case 6: return false; // CTC.1
2159 if(subcode == 50 || subcode == 60 || subcode == 62) return reg == FCSR;
2160 return false; // everything else just touches f0-f31
2161 case 20: return false; // Integer - just touches f0-f31
2165 if(op >= 8 && op <= 15) return reg == R+rt; // XXXI instructions
2166 if(op >= 40 && op <= 46) return false; // Memory WRITE ops
2167 if(op == 49) return reg == F+rt; // LWC1
2168 if(op == 57) return false; // SWC1
2171 warn.println("Unknown instruction in touchesReg()- assuming it modifies all regs " + op + " " + subcode);
2172 new Exception().fillInStackTrace().printStackTrace(warn);