1 // Copyright 2000-2005 the Contributors, as shown in the revision logs.
2 // Licensed under the Apache Public Source License 2.0 ("the License").
3 // You may not use this file except in compliance with the License.
5 package org.ibex.nestedvm;
9 import org.ibex.nestedvm.util.*;
10 import org.ibex.classgen.*;
12 // FEATURE: Eliminate unnecessary use of SWAP
13 // FEATURE: Put regs in low (<=3) local vars, small classfile size
15 /* FEATURE: Span large binaries across several classfiles
16 * We should be able to do this with no performance penalty
17 * Every method in the inner classes is static and takes the main class as an arg
18 * This makes them look just like methods in the main class because arg1 gets loaded into
22 /* FEATURE: smarter with local regs
23 * Be even smarter with the use of local registers. We need to only load fields into
24 * local regs when they are actually used and only write to fields if the regs could have
25 * changed. This should allow us to put more regs in local vars. Right now putting all used
26 * regs local vars makes code like this slower.
28 * void work(int a, int b) {
35 * Because all the regs used in "real work" are loaded/restored even for fast path
39 public class ClassFileCompiler extends Compiler implements CGConst {
40 private static final boolean OPTIMIZE_CP = true;
42 /** The stream to write the compiled output to */
43 private OutputStream os;
45 private PrintStream warn = System.err;
47 private final Type.Object me;
50 private MethodGen clinit, init;
52 public ClassFileCompiler(String path, String className, OutputStream os) throws IOException { this(new Seekable.File(path),className,os); }
53 public ClassFileCompiler(Seekable binary, String className, OutputStream os) throws IOException {
54 this(binary,className);
55 if(os == null) throw new NullPointerException();
58 public ClassFileCompiler(Seekable binary, String className, File outDir) throws IOException {
59 this(binary,className);
60 if(outDir == null) throw new NullPointerException();
63 private ClassFileCompiler(Seekable binary, String className) throws IOException {
64 super(binary,className);
65 me = new Type.Object(fullClassName);
68 public void setWarnWriter(PrintStream warn) { this.warn = warn; }
70 protected void _go() throws Exn, IOException {
73 } catch(ClassGen.Exn e) {
74 e.printStackTrace(warn);
75 throw new Exn("Class generation exception: " + e.toString());
79 private void __go() throws Exn, IOException {
80 if(!pruneCases) throw new Exn("-o prunecases MUST be enabled for ClassFileCompiler");
83 Type.Object superClass = new Type.Object(runtimeClass);
84 cg = new ClassGen(me,superClass,ACC_PUBLIC|ACC_FINAL|ACC_SUPER);
85 if(source != null) cg.setSourceFile(source);
88 cg.addField("pc",Type.INT,ACC_PRIVATE);
89 cg.addField("hi",Type.INT,ACC_PRIVATE);
90 cg.addField("lo",Type.INT,ACC_PRIVATE);
91 cg.addField("fcsr",Type.INT,ACC_PRIVATE);
92 for(int i=1;i<32;i++) cg.addField("r" + i,Type.INT,ACC_PRIVATE);
93 for(int i=0;i<32;i++) cg.addField("f" + i,singleFloat ? Type.FLOAT : Type.INT,ACC_PRIVATE);
96 clinit = cg.addMethod("<clinit>",Type.VOID,Type.NO_ARGS,ACC_PRIVATE|ACC_STATIC);
98 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.UnixRuntime.<init>
101 init = cg.addMethod("<init>",Type.VOID,Type.NO_ARGS,ACC_PUBLIC);
103 init.add(LDC,pageSize);
104 init.add(LDC,totalPages);
105 init.add(INVOKESPECIAL,new MethodRef(me,"<init>",Type.VOID,new Type[]{Type.INT,Type.INT}));
109 init = cg.addMethod("<init>",Type.VOID,new Type[]{Type.BOOLEAN},ACC_PUBLIC);
111 init.add(LDC,pageSize);
112 init.add(LDC,totalPages);
114 init.add(INVOKESPECIAL,new MethodRef(me,"<init>",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN}));
118 init = cg.addMethod("<init>",Type.VOID,new Type[]{Type.INT,Type.INT},ACC_PUBLIC);
123 init.add(INVOKESPECIAL,new MethodRef(me,"<init>",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN}));
127 init = cg.addMethod("<init>",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN},ACC_PUBLIC);
132 init.add(INVOKESPECIAL,new MethodRef(superClass,"<init>",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN}));
135 cg.addField("page",Type.arrayType(Type.INT),ACC_PRIVATE|ACC_FINAL);
138 init.add(GETFIELD,new FieldRef(me,"readPages",Type.arrayType(Type.INT,2)));
141 init.add(PUTFIELD,new FieldRef(me,"page",Type.arrayType(Type.INT)));
145 cg.addField("symbols",new Type.Object(hashClass),ACC_PRIVATE|ACC_STATIC|ACC_FINAL);
149 for(int i=0;i<elf.sheaders.length;i++) {
150 ELF.SHeader sheader = elf.sheaders[i];
151 String name = sheader.name;
152 // if this section doesn't get loaded into our address space don't worry about it
153 if(sheader.addr == 0x0) continue;
155 highestAddr = Math.max(highestAddr, sheader.addr + sheader.size);
157 if(name.equals(".text"))
158 emitText(sheader.addr, new DataInputStream(sheader.getInputStream()),sheader.size);
159 else if(name.equals(".data") || name.equals(".sdata") || name.equals(".rodata") || name.equals(".ctors") || name.equals(".dtors"))
160 emitData(sheader.addr, new DataInputStream(sheader.getInputStream()), sheader.size,name.equals(".rodata"));
161 else if(name.equals(".bss") || name.equals(".sbss"))
162 emitBSS(sheader.addr,sheader.size);
164 throw new Exn("Unknown segment: " + name);
172 Type.Object hash = new Type.Object(hashClass);
173 clinit.add(NEW,hash);
176 clinit.add(INVOKESPECIAL,new MethodRef(hash,"<init>",Type.VOID,Type.NO_ARGS));
177 clinit.add(PUTSTATIC,new FieldRef(me,"symbols",hash));
178 ELF.Symbol[] symbols = elf.getSymtab().symbols;
179 for(int i=0;i<symbols.length;i++) {
180 ELF.Symbol s = symbols[i];
181 if(s.type == ELF.Symbol.STT_FUNC && s.binding == ELF.Symbol.STB_GLOBAL && (s.name.equals("_call_helper") || !s.name.startsWith("_"))) {
183 clinit.add(LDC,s.name);
184 clinit.add(NEW,Type.INTEGER_OBJECT);
186 clinit.add(LDC,s.addr);
187 clinit.add(INVOKESPECIAL,new MethodRef(Type.INTEGER_OBJECT,"<init>",Type.VOID,new Type[]{Type.INT}));
188 clinit.add(INVOKEVIRTUAL,new MethodRef(hash,"put",Type.OBJECT,new Type[]{Type.OBJECT,Type.OBJECT}));
197 ELF.SHeader text = elf.sectionWithName(".text");
200 MethodGen tramp = cg.addMethod("trampoline",Type.VOID,Type.NO_ARGS,ACC_PRIVATE);
202 int start = tramp.size();
204 tramp.add(GETFIELD,new FieldRef(me,"state",Type.INT));
205 tramp.add(IFEQ,tramp.size()+2);
210 tramp.add(GETFIELD,new FieldRef(me,"pc",Type.INT));
211 tramp.add(LDC,methodShift);
214 int beg = text.addr >>> methodShift;
215 int end = ((text.addr + text.size + maxBytesPerMethod - 1) >>> methodShift);
217 MethodGen.TSI tsi = new MethodGen.TSI(beg,end-1);
218 tramp.add(TABLESWITCH,tsi);
219 for(int n=beg;n<end;n++) {
220 tsi.setTargetForVal(n,tramp.size());
221 tramp.add(INVOKESPECIAL,new MethodRef(me,"run_"+toHex(n<<methodShift),Type.VOID,Type.NO_ARGS));
222 tramp.add(GOTO,start);
224 tsi.setDefaultTarget(tramp.size());
227 tramp.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
229 tramp.add(NEW, Type.STRINGBUFFER);
231 tramp.add(LDC,"Jumped to invalid address in trampoline (r2: ");
232 tramp.add(INVOKESPECIAL,new MethodRef(Type.STRINGBUFFER,"<init>",Type.VOID,new Type[]{Type.STRING}));
234 tramp.add(GETFIELD, new FieldRef(me,"r2",Type.INT));
235 tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.INT}));
236 tramp.add(LDC," pc: ");
237 tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.STRING}));
239 tramp.add(GETFIELD, new FieldRef(me,"pc",Type.INT));
240 tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.INT}));
242 tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.STRING}));
243 tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"toString",Type.STRING,Type.NO_ARGS));
244 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime$ExecutionException.<init>
245 tramp.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"<init>",Type.VOID,new Type[]{Type.STRING}));
252 } catch(ClassGen.Exn e) {
253 e.printStackTrace(warn);
254 throw new Exn("Generation of the trampoline method failed. Try increasing maxInsnPerMethod");
258 addConstReturnMethod("gp",gp.addr);
259 addConstReturnMethod("entryPoint",elf.header.entry);
260 addConstReturnMethod("heapStart",highestAddr);
262 if(userInfo != null) {
263 addConstReturnMethod("userInfoBase",userInfo.addr);
264 addConstReturnMethod("userInfoSize",userInfo.size);
268 Type.Object hashClassType = new Type.Object(hashClass);
269 MethodGen ls = cg.addMethod("lookupSymbol",Type.INT,new Type[]{Type.STRING},ACC_PROTECTED);
270 ls.add(GETSTATIC,new FieldRef(me,"symbols",hashClassType));
272 ls.add(INVOKEVIRTUAL,new MethodRef(hashClassType,"get",Type.OBJECT,new Type[]{Type.OBJECT}));
274 int b = ls.add(IFNULL);
275 ls.add(CHECKCAST,Type.INTEGER_OBJECT);
276 ls.add(INVOKEVIRTUAL,new MethodRef(Type.INTEGER_OBJECT,"intValue",Type.INT,Type.NO_ARGS));
278 ls.setArg(b,ls.size());
284 // Kind of a hack, referencing dup() gets us all the fields for free
285 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime$CPUState.dup
286 Type.Object cpuStateType = new Type.Object("org.ibex.nestedvm.Runtime$CPUState");
287 MethodGen setCPUState = cg.addMethod("setCPUState",Type.VOID,new Type[]{cpuStateType},ACC_PROTECTED);
288 MethodGen getCPUState = cg.addMethod("getCPUState",Type.VOID,new Type[]{cpuStateType},ACC_PROTECTED);
290 setCPUState.add(ALOAD_1);
291 getCPUState.add(ALOAD_1);
292 setCPUState.add(GETFIELD,new FieldRef(cpuStateType,"r",Type.arrayType(Type.INT)));
293 getCPUState.add(GETFIELD,new FieldRef(cpuStateType,"r",Type.arrayType(Type.INT)));
294 setCPUState.add(ASTORE_2);
295 getCPUState.add(ASTORE_2);
297 for(int i=1;i<32;i++) {
298 setCPUState.add(ALOAD_0);
299 setCPUState.add(ALOAD_2);
300 setCPUState.add(LDC,i);
301 setCPUState.add(IALOAD);
302 setCPUState.add(PUTFIELD,new FieldRef(me,"r"+i,Type.INT));
304 getCPUState.add(ALOAD_2);
305 getCPUState.add(LDC,i);
306 getCPUState.add(ALOAD_0);
307 getCPUState.add(GETFIELD,new FieldRef(me,"r"+i,Type.INT));
308 getCPUState.add(IASTORE);
311 setCPUState.add(ALOAD_1);
312 getCPUState.add(ALOAD_1);
313 setCPUState.add(GETFIELD,new FieldRef(cpuStateType,"f",Type.arrayType(Type.INT)));
314 getCPUState.add(GETFIELD,new FieldRef(cpuStateType,"f",Type.arrayType(Type.INT)));
315 setCPUState.add(ASTORE_2);
316 getCPUState.add(ASTORE_2);
318 for(int i=0;i<32;i++) {
319 setCPUState.add(ALOAD_0);
320 setCPUState.add(ALOAD_2);
321 setCPUState.add(LDC,i);
322 setCPUState.add(IALOAD);
323 if(singleFloat) setCPUState.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"intBitsToFloat",Type.FLOAT,new Type[]{Type.INT}));
324 setCPUState.add(PUTFIELD,new FieldRef(me,"f"+i,singleFloat ? Type.FLOAT : Type.INT));
326 getCPUState.add(ALOAD_2);
327 getCPUState.add(LDC,i);
328 getCPUState.add(ALOAD_0);
329 getCPUState.add(GETFIELD,new FieldRef(me,"f"+i,singleFloat ? Type.FLOAT: Type.INT));
330 if(singleFloat) getCPUState.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"floatToIntBits",Type.INT,new Type[]{Type.FLOAT}));
331 getCPUState.add(IASTORE);
334 String[] each = new String[] { "hi","lo","fcsr","pc" };
335 for(int i=0;i<each.length;i++) {
336 setCPUState.add(ALOAD_0);
337 setCPUState.add(ALOAD_1);
338 setCPUState.add(GETFIELD,new FieldRef(cpuStateType,each[i],Type.INT));
339 setCPUState.add(PUTFIELD,new FieldRef(me,each[i],Type.INT));
341 getCPUState.add(ALOAD_1);
342 getCPUState.add(ALOAD_0);
343 getCPUState.add(GETFIELD,new FieldRef(me,each[i],Type.INT));
344 getCPUState.add(PUTFIELD,new FieldRef(cpuStateType,each[i],Type.INT));
346 setCPUState.add(RETURN);
347 getCPUState.add(RETURN);
350 MethodGen execute = cg.addMethod("_execute",Type.VOID,Type.NO_ARGS,ACC_PROTECTED);
351 int tryStart = execute.size();
352 execute.add(ALOAD_0);
353 execute.add(INVOKESPECIAL,new MethodRef(me,"trampoline",Type.VOID,Type.NO_ARGS));
354 int tryEnd = execute.size();
357 int catchInsn = execute.size();
358 execute.add(ASTORE_1);
359 execute.add(NEW, new Type.Object("org.ibex.nestedvm.Runtime$FaultException"));
361 execute.add(ALOAD_1);
362 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime$FaultException.<init>
363 execute.add(INVOKESPECIAL,new MethodRef("org.ibex.nestedvm.Runtime$FaultException","<init>",Type.VOID,new Type[]{new Type.Object("java.lang.RuntimeException")}));
366 execute.addExceptionHandler(tryStart,tryEnd,catchInsn,new Type.Object("java.lang.RuntimeException"));
367 execute.addThrow(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
369 MethodGen main = cg.addMethod("main",Type.VOID,new Type[]{Type.arrayType(Type.STRING)},ACC_STATIC|ACC_PUBLIC);
372 main.add(INVOKESPECIAL,new MethodRef(me,"<init>",Type.VOID,Type.NO_ARGS));
373 main.add(LDC,fullClassName);
376 Type.Object ur = new Type.Object("org.ibex.nestedvm.UnixRuntime");
377 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.runAndExec
378 main.add(INVOKESTATIC,new MethodRef(ur,"runAndExec",Type.INT,new Type[]{ur,Type.STRING,Type.arrayType(Type.STRING)}));
380 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.run
381 main.add(INVOKEVIRTUAL,new MethodRef(me,"run",Type.INT,new Type[]{Type.STRING,Type.arrayType(Type.STRING)}));
383 main.add(INVOKESTATIC,new MethodRef(new Type.Object("java.lang.System"),"exit",Type.VOID,new Type[]{Type.INT}));
387 if(!outDir.isDirectory()) throw new IOException("" + outDir + " isn't a directory");
394 private void addConstReturnMethod(String name, int val) {
395 MethodGen m = cg.addMethod(name,Type.INT,Type.NO_ARGS,ACC_PROTECTED);
400 private static int initDataCount;
401 private void emitData(int addr, DataInputStream dis, int size, boolean readOnly) throws Exn,IOException {
402 if((addr&3)!=0 || (size&3)!=0) throw new Exn("Data section on weird boundaries");
403 int last = addr + size;
405 int segSize = Math.min(size,28000); // must be a multiple of 56
406 StringBuffer sb = new StringBuffer();
407 for(int i=0;i<segSize;i+=7) {
409 for(int j=0;j<7;j++) {
411 byte b = (i+j < size) ? dis.readByte() : 1;
415 sb.append((char) ((l>>>(7*(7-j)))&0x7f));
417 String fieldname = "_data" + (++initDataCount);
418 cg.addField(fieldname,Type.arrayType(Type.INT),ACC_PRIVATE|ACC_STATIC|ACC_FINAL);
420 clinit.add(LDC,sb.toString());
421 clinit.add(LDC,segSize/4);
422 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.decodeData
423 clinit.add(INVOKESTATIC,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime"),"decodeData",Type.arrayType(Type.INT),new Type[]{Type.STRING,Type.INT}));
424 clinit.add(PUTSTATIC,new FieldRef(me,fieldname,Type.arrayType(Type.INT)));
426 init.add(GETSTATIC,new FieldRef(me,fieldname,Type.arrayType(Type.INT)));
428 init.add(LDC,readOnly ? 1 : 0);
429 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.initPages
430 init.add(INVOKEVIRTUAL,new MethodRef(me,"initPages",Type.VOID,new Type[]{Type.arrayType(Type.INT),Type.INT,Type.BOOLEAN}));
438 private void emitBSS(int addr, int size) throws Exn {
439 if((addr&3)!=0) throw new Exn("BSS section on weird boundaries");
446 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.clearPages
447 init.add(INVOKEVIRTUAL,new MethodRef(me,"clearPages",Type.VOID,new Type[]{Type.INT,Type.INT}));
451 private int startOfMethod = 0; // the start of this method (not necessarily the first instruction)
452 private int endOfMethod = 0; // the maximum end of this method (could end before it is full)
454 private MethodGen.PhantomTarget returnTarget; // where to jump when exiting the method
455 private MethodGen.PhantomTarget defaultTarget; // the default switch target (throws exn)
456 private MethodGen.PhantomTarget[] insnTargets; // the targets for each jumpable instruction
457 private MethodGen mg; // the method itself
459 private boolean jumpable(int addr) { return jumpableAddresses.get(new Integer(addr)) != null; }
461 private static final int UNREACHABLE = 1;
462 private static final int SKIP_NEXT = 2;
464 private boolean textDone; // a text segment was already processed
465 private void emitText(int addr, DataInputStream dis, int size) throws Exn,IOException {
466 if(textDone) throw new Exn("Multiple text segments");
469 if((addr&3)!=0 || (size&3)!=0) throw new Exn("Section on weird boundaries");
471 int insn,nextInsn=-1;
473 boolean skipNext = true;
474 boolean unreachable = false;
476 for(int i=0;i<count;i++,addr+=4) {
477 insn = skipNext ? dis.readInt() : nextInsn;
478 nextInsn = (i == count-1) ? -1 : dis.readInt();
479 if(addr >= endOfMethod) { endMethod(addr,unreachable); startMethod(addr); }
480 if(insnTargets[i%maxInsnPerMethod] != null) {
481 insnTargets[i%maxInsnPerMethod].setTarget(mg.size());
483 } else if(unreachable) {
487 int ret = emitInstruction(addr,insn,nextInsn);
488 unreachable = (ret & UNREACHABLE) != 0;
489 skipNext = (ret & SKIP_NEXT) != 0;
491 e.printStackTrace(warn);
492 warn.println("Exception at " + toHex(addr));
494 } catch(RuntimeException e) {
495 warn.println("Exception at " + toHex(addr));
498 if(skipNext) { addr+=4; i++; }
500 endMethod(0,unreachable);
504 private void startMethod(int first) {
505 startOfMethod = first & methodMask;
506 endOfMethod = startOfMethod + maxBytesPerMethod;
508 mg = cg.addMethod("run_" + toHex(startOfMethod),Type.VOID,Type.NO_ARGS,ACC_PRIVATE|ACC_FINAL);
511 mg.add(GETFIELD,new FieldRef(me,"page",Type.arrayType(Type.INT)));
515 mg.add(GETFIELD,new FieldRef(me,"readPages",Type.arrayType(Type.INT,2)));
518 mg.add(GETFIELD,new FieldRef(me,"writePages",Type.arrayType(Type.INT,2)));
522 returnTarget = new MethodGen.PhantomTarget();
523 insnTargets = new MethodGen.PhantomTarget[maxBytesPerMethod/4];
525 int[] buf = new int[maxBytesPerMethod/4];
526 Object[] targetBuf = new Object[maxBytesPerMethod/4];
528 for(int addr=first;addr<endOfMethod;addr+=4) {
530 targetBuf[n] = insnTargets[(addr-startOfMethod)/4] = new MethodGen.PhantomTarget();
536 MethodGen.LSI lsi = new MethodGen.LSI(n);
537 System.arraycopy(buf,0,lsi.vals,0,n);
538 System.arraycopy(targetBuf,0,lsi.targets,0,n);
539 lsi.setDefaultTarget(defaultTarget = new MethodGen.PhantomTarget());
544 mg.add(GETFIELD,new FieldRef(me,"pc",Type.INT));
545 mg.add(LOOKUPSWITCH,lsi);
548 private void endMethod(int firstAddrOfNext,boolean unreachable) {
549 if(startOfMethod == 0) return;
553 mg.add(LDC,firstAddrOfNext);
555 // mark the start of the next method as jumpable
556 jumpableAddresses.put(new Integer(firstAddrOfNext),Boolean.TRUE);
559 returnTarget.setTarget(mg.size());
565 defaultTarget.setTarget(mg.size());
568 mg.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
570 mg.add(NEW,Type.STRINGBUFFER);
572 mg.add(LDC,"Jumped to invalid address: ");
573 mg.add(INVOKESPECIAL,new MethodRef(Type.STRINGBUFFER,"<init>",Type.VOID,new Type[]{Type.STRING}));
575 mg.add(GETFIELD,new FieldRef(me,"pc",Type.INT));
576 mg.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.INT}));
577 mg.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"toString",Type.STRING,Type.NO_ARGS));
578 mg.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"<init>",Type.VOID,new Type[]{Type.STRING}));
581 mg.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
583 mg.add(LDC,"Jumped to invalid address");
584 mg.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"<init>",Type.VOID,new Type[]{Type.STRING}));
588 endOfMethod = startOfMethod = 0;
592 private void leaveMethod() {
593 mg.add(GOTO,returnTarget);
596 private void link(int mypc) {
599 int ref = (mypc+8 + 32768) & ~65535;
600 int diff = (mypc+8) - ref;
601 if(diff < -32768 || diff > 32767) throw new Error("should never happen " + diff);
611 private void branch(int pc, int target) {
612 if((pc&methodMask) == (target&methodMask)) {
613 mg.add(GOTO,insnTargets[(target-startOfMethod)/4]);
622 // This assumes everything needed by ifInsn is already on the stack
623 private int doIfInstruction(byte op, int pc, int target, int nextInsn) throws Exn {
624 emitInstruction(-1,nextInsn,-1); // delay slot
625 if((target&methodMask) == (pc&methodMask)) {
626 mg.add(op,insnTargets[(target-startOfMethod)/4]);
628 int h = mg.add(MethodGen.negate(op));
630 mg.setArg(h,mg.size());
632 if(!jumpable(pc+4)) return SKIP_NEXT; // done - skip it
634 //System.err.println("Delay slot is jumpable - This code is untested + " + toHex(nextInsn));
635 if(pc+4==endOfMethod) {
636 // the delay slot is at the start of the next method
637 jumpableAddresses.put(new Integer(pc+8),Boolean.TRUE); // make the 2nd insn of the next method jumpable
638 branch(pc,pc+8); // jump over it
639 //System.err.println("delay slot: " + toHex(pc+8)); */
640 //unreachable = true;
641 //return false; // we still need to output it
644 //System.err.println("jumped over delay slot: " + toHex(pc+4));
645 // add another copy and jump over
647 int b = mg.add(GOTO);
648 insnTargets[(pc+4-startOfMethod)/4].setTarget(mg.size());
649 emitInstruction(-1,nextInsn,01); // delay slot
650 mg.setArg(b,mg.size());
656 private static final Float POINT_5_F = new Float(0.5f);
657 private static final Double POINT_5_D = new Double(0.5f);
658 private static final Long FFFFFFFF = new Long(0xffffffffL);
660 private int emitInstruction(int pc, int insn, int nextInsn) throws Exn {
661 MethodGen mg = this.mg; // smaller bytecode
662 if(insn == -1) throw new Exn("insn is -1");
666 int op = (insn >>> 26) & 0xff; // bits 26-31
667 int rs = (insn >>> 21) & 0x1f; // bits 21-25
668 int rt = (insn >>> 16) & 0x1f; // bits 16-20
669 int ft = (insn >>> 16) & 0x1f;
670 int rd = (insn >>> 11) & 0x1f; // bits 11-15
671 int fs = (insn >>> 11) & 0x1f;
672 int shamt = (insn >>> 6) & 0x1f; // bits 6-10
673 int fd = (insn >>> 6) & 0x1f;
674 int subcode = insn & 0x3f; // bits 0-5
675 int breakCode = (insn >>> 6) & 0xfffff; // bits 6-20
677 int jumpTarget = (insn & 0x03ffffff); // bits 0-25
678 int unsignedImmediate = insn & 0xffff;
679 int signedImmediate = (insn << 16) >> 16;
680 int branchTarget = signedImmediate;
732 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
733 emitInstruction(-1,nextInsn,-1);
741 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
742 emitInstruction(-1,nextInsn,-1);
755 // FEATURE: This is actually broken, but it happens to work for our code
756 // a func could theoretically jump back to here from a future point
757 restoreChangedRegs();
768 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.syscall
769 mg.add(INVOKEVIRTUAL,new MethodRef(me,"syscall",Type.INT,new Type[]{Type.INT,Type.INT,Type.INT,Type.INT,Type.INT,Type.INT,Type.INT}));
773 mg.add(GETFIELD,new FieldRef(me,"state",Type.INT));
779 mg.setArg(b1,mg.size());
782 mg.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
784 mg.add(LDC,"BREAK Code " + toHex(breakCode));
785 mg.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"<init>",Type.VOID,new Type[]{Type.STRING}));
819 mg.add(SWAP); //a(InstructionConstants.SWAP);
826 mg.add(SWAP); //a(InstructionConstants.SWAP);
833 mg.add(LDC,FFFFFFFF);
837 mg.add(LDC,FFFFFFFF);
879 mg.add(LDC,FFFFFFFF);
884 mg.add(LDC,FFFFFFFF);
901 mg.setArg(b1,mg.size());
906 throw new Exn("ADD (add with oveflow trap) not suported");
909 if(rt != 0 && rs != 0) {
921 throw new Exn("SUB (add with oveflow trap) not suported");
924 if(rt != 0 && rs != 0) {
959 if(rs != 0 || rt != 0) {
960 if(rs != 0 && rt != 0) {
981 b1 = mg.add(IF_ICMPLT);
984 mg.setArg(b1,mg.add(ICONST_1));
985 mg.setArg(b2,mg.size());
997 mg.add(LDC,FFFFFFFF);
1001 mg.add(LDC,FFFFFFFF);
1011 mg.setArg(b1,mg.add(ICONST_1));
1012 mg.setArg(b2,mg.size());
1019 throw new Exn("Illegal instruction 0/" + subcode);
1026 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1028 return doIfInstruction(IFLT,pc,pc+branchTarget*4+4,nextInsn);
1030 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1032 return doIfInstruction(IFGE,pc,pc+branchTarget*4+4,nextInsn);
1034 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1037 emitInstruction(-1,nextInsn,-1);
1039 branch(pc,pc+branchTarget*4+4);
1040 mg.setArg(b1,mg.size());
1043 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1045 if(rs != 0) { // r0 is always >= 0
1049 emitInstruction(-1,nextInsn,-1);
1051 branch(pc,pc+branchTarget*4+4);
1052 if(b1 != -1) mg.setArg(b1,mg.size());
1053 if(b1 == -1) ret |= UNREACHABLE;
1056 throw new Exn("Illegal Instruction 1/" + rt);
1061 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1062 emitInstruction(-1,nextInsn,-1);
1063 branch(pc,(pc&0xf0000000)|(jumpTarget << 2));
1068 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1069 int target = (pc&0xf0000000)|(jumpTarget << 2);
1070 emitInstruction(-1,nextInsn,-1);
1077 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1079 emitInstruction(-1,nextInsn,-1);
1080 branch(pc,pc+branchTarget*4+4);
1082 } else if(rs == 0 || rt == 0) {
1083 pushReg(rt == 0 ? R+rs : R+rt);
1084 return doIfInstruction(IFEQ,pc,pc+branchTarget*4+4,nextInsn);
1088 return doIfInstruction(IF_ICMPEQ,pc,pc+branchTarget*4+4,nextInsn);
1092 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1095 return doIfInstruction(IFNE,pc,pc+branchTarget*4+4,nextInsn);
1098 return doIfInstruction(IF_ICMPNE,pc,pc+branchTarget*4+4,nextInsn);
1101 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1103 return doIfInstruction(IFLE,pc,pc+branchTarget*4+4,nextInsn);
1105 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1107 return doIfInstruction(IFGT,pc,pc+branchTarget*4+4,nextInsn);
1109 throw new Exn("ADDI (add immediate with oveflow trap) not suported");
1111 if(rs != 0 && signedImmediate != 0 && rs == rt && doLocal(rt) && signedImmediate >= -32768 && signedImmediate <= 32767) {
1112 // HACK: This should be a little cleaner
1113 regLocalWritten[rt] = true;
1114 mg.add(IINC, new MethodGen.Pair(getLocalForReg(rt),signedImmediate));
1117 addiu(rs,signedImmediate);
1124 mg.add(LDC,signedImmediate);
1125 b1 = mg.add(IF_ICMPLT);
1128 mg.setArg(b1,mg.add(ICONST_1));
1129 mg.setArg(b2,mg.size());
1136 mg.add(LDC,FFFFFFFF);
1138 // Yes, this is correct, you have to sign extend the immediate then do an UNSIGNED comparison
1139 mg.add(LDC,new Long(signedImmediate&0xffffffffL));
1145 mg.setArg(b1,mg.add(ICONST_1));
1146 mg.setArg(b2,mg.size());
1152 mg.add(LDC,unsignedImmediate);
1158 if(rs != 0 && unsignedImmediate != 0) {
1160 mg.add(LDC,unsignedImmediate);
1165 mg.add(LDC,unsignedImmediate);
1172 mg.add(LDC,unsignedImmediate);
1178 mg.add(LDC,unsignedImmediate << 16);
1182 throw new Exn("TLB/Exception support not implemented");
1191 if(fs != 31) throw new Exn("FCR " + fs + " unavailable");
1198 if(rt != 0) pushReg(R+rt);
1199 else mg.add(ICONST_0);
1203 if(fs != 31) throw new Exn("FCR " + fs + " unavailable");
1208 case 8: {// BC1F, BC1T
1210 mg.add(LDC,0x800000);
1212 return doIfInstruction(((insn>>>16)&1) == 0 ? IFEQ : IFNE,pc,pc+branchTarget*4+4,nextInsn);
1216 { // Single/Double math
1217 boolean d = rs == 17;
1220 preSetDouble(F+fd,d);
1223 mg.add(d ? DADD : FADD);
1227 preSetDouble(F+fd,d);
1230 mg.add(d ? DSUB : FSUB);
1234 preSetDouble(F+fd,d);
1237 mg.add(d ? DMUL : FMUL);
1241 preSetDouble(F+fd,d);
1244 mg.add(d ? DDIV : FDIV);
1248 preSetDouble(F+fd,d);
1249 // NOTE: We can't use fneg/dneg here since they'll turn +0.0 into -0.0
1252 mg.add(d ? DUP2 : DUP);
1253 mg.add(d ? DCONST_0 : FCONST_0);
1254 mg.add(d ? DCMPG : FCMPG);
1257 mg.add(d ? DCONST_0 : FCONST_0);
1264 mg.add(d ? DSUB : FSUB);
1266 mg.setArg(b1,mg.size());
1282 preSetDouble(F+fd,d);
1284 mg.add(d ? DNEG : FNEG);
1299 case 36: { // CVT.W.D
1300 MethodGen.TSI tsi = new MethodGen.TSI(0,3);
1306 mg.add(TABLESWITCH,tsi);
1308 // Round towards plus infinity
1309 tsi.setTarget(2,mg.size());
1310 if(!d) mg.add(F2D); // Ugh.. java.lang.Math doesn't have a float ceil/floor
1311 mg.add(INVOKESTATIC,new MethodRef("java.lang.Math","ceil",Type.DOUBLE,new Type[]{Type.DOUBLE}));
1316 tsi.setTarget(0,mg.size());
1317 mg.add(LDC,d ? (Object)POINT_5_D : (Object)POINT_5_F);
1318 mg.add(d ? DADD : FADD);
1321 // Round towards minus infinity
1322 tsi.setTarget(3,mg.size());
1324 mg.add(INVOKESTATIC,new MethodRef("java.lang.Math","floor",Type.DOUBLE,new Type[]{Type.DOUBLE}));
1327 tsi.setTarget(1,mg.size());
1328 tsi.setDefaultTarget(mg.size());
1329 mg.setArg(b1,mg.size());
1331 mg.add(d ? D2I : F2I);
1341 mg.add(LDC,~0x800000);
1345 mg.add(d ? DCMPG : FCMPG);
1347 case 50: b1 = mg.add(IFNE); break;
1348 case 60: b1 = mg.add(IFGE); break;
1349 case 62: b1 = mg.add(IFGT); break;
1352 mg.add(LDC,0x800000);
1354 mg.setArg(b1,mg.size());
1357 default: throw new Exn("Invalid Instruction 17/" + rs + "/" + subcode);
1361 case 20: { // Integer
1375 default: throw new Exn("Invalid Instruction 17/" + rs + "/" + subcode);
1380 throw new Exn("Invalid Instruction 17/" + rs);
1385 throw new Exn("coprocessor 2 and 3 instructions not available");
1388 addiu(R+rs,signedImmediate);
1408 addiu(R+rs,signedImmediate);
1428 addiu(R+rs,signedImmediate);
1432 mg.add(LDC,0x00ffffff);
1463 memRead(R+rs,signedImmediate);
1468 addiu(R+rs,signedImmediate);
1489 addiu(R+rs,signedImmediate);
1504 // chars are unsigend so this works
1511 addiu(R+rs,signedImmediate);
1515 mg.add(LDC,0xffffff00);
1544 addiu(R+rs,signedImmediate);
1551 mg.add(LDC,0xff000000);
1586 addiu(R+rs,signedImmediate);
1626 addiu(R+rs,signedImmediate);
1633 mg.add(LDC,0xffffff00);
1661 preMemWrite2(R+rs,signedImmediate);
1666 addiu(R+rs,signedImmediate);
1673 mg.add(LDC,0x00ffffff);
1698 // This need to be atomic if we ever support threads (see SWC0/SC)
1701 memRead(R+rs,signedImmediate);
1707 memRead(R+rs,signedImmediate);
1711 /* This needs to fail (set rt to 0) if the memory location was modified
1712 * between the LL and SC if we ever support threads.
1717 preMemWrite2(R+rs,signedImmediate);
1726 preMemWrite2(R+rs,signedImmediate);
1731 throw new Exn("Invalid Instruction: " + op + " at " + toHex(pc));
1736 // Helper functions for emitText
1738 private static final int R = 0;
1739 private static final int F = 32;
1740 private static final int HI = 64;
1741 private static final int LO = 65;
1742 private static final int FCSR = 66;
1743 private static final int REG_COUNT=67;
1744 private static final String[] regField = {
1745 "r0","r1","r2","r3","r4","r5","r6","r7",
1746 "r8","r9","r10","r11","r12","r13","r14","r15",
1747 "r16","r17","r18","r19","r20","r21","r22","r23",
1748 "r24","r25","r26","r27","r28","r29","r30","r31",
1749 "f0","f1","f2","f3","f4","f5","f6","f7",
1750 "f8","f9","f10","f11","f12","f13","f14","f15",
1751 "f16","f17","f18","f19","f20","f21","f22","f23",
1752 "f24","f25","f26","f27","f28","f29","f30","f31",
1755 private static final int MAX_LOCALS = 4; // doLocal can return true for this many regs
1756 private static final int LOAD_LENGTH = 3; // number of instructions needed to load a field to a reg
1758 // Local register state info
1759 private int[] regLocalMapping = new int[REG_COUNT];
1760 private boolean[] regLocalWritten = new boolean[REG_COUNT];
1761 private int nextAvailLocal;
1762 private int loadsStart;
1764 private boolean doLocal(int reg) {
1765 return reg == R+2 || reg == R+3 || reg == R+4 || reg == R+29;
1768 private int getLocalForReg(int reg) {
1769 if(regLocalMapping[reg] != 0) return regLocalMapping[reg];
1770 regLocalMapping[reg] = nextAvailLocal++;
1771 return regLocalMapping[reg];
1774 private void fixupRegsStart() {
1775 for(int i=0;i<REG_COUNT;i++) {
1776 regLocalMapping[i] = 0;
1777 regLocalWritten[i] = false;
1779 nextAvailLocal = onePage ? 4 : 5;
1780 loadsStart = mg.size();
1781 for(int i=0;i<MAX_LOCALS*LOAD_LENGTH;i++)
1785 private void fixupRegsEnd() {
1787 for(int i=0;i<REG_COUNT;i++) {
1788 if(regLocalMapping[i] == 0) continue;
1789 mg.set(p++,ALOAD_0);
1790 mg.set(p++,GETFIELD,new FieldRef(me,regField[i],Type.INT));
1791 mg.set(p++,ISTORE,regLocalMapping[i]);
1793 if(regLocalWritten[i]) {
1795 mg.add(ILOAD,regLocalMapping[i]);
1796 mg.add(PUTFIELD,new FieldRef(me,regField[i],Type.INT));
1801 private void restoreChangedRegs() {
1802 for(int i=0;i<REG_COUNT;i++) {
1803 if(regLocalWritten[i]) {
1805 mg.add(ILOAD,regLocalMapping[i]);
1806 mg.add(PUTFIELD,new FieldRef(me,regField[i],Type.INT));
1811 private int pushRegWZ(int reg) {
1813 warn.println("Warning: Pushing r0!");
1814 new Exception().printStackTrace(warn);
1816 return pushRegZ(reg);
1819 private int pushRegZ(int reg) {
1820 if(reg == R+0) return mg.add(ICONST_0);
1821 else return pushReg(reg);
1825 private int pushReg(int reg) {
1828 mg.add(ILOAD,getLocalForReg(reg));
1829 } else if(reg >= F+0 && reg <= F+31 && singleFloat) {
1831 mg.add(GETFIELD,new FieldRef(me,regField[reg],Type.FLOAT));
1832 mg.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"floatToIntBits",Type.INT,new Type[]{Type.FLOAT}));
1835 mg.add(GETFIELD,new FieldRef(me,regField[reg],Type.INT));
1840 private int preSetRegStackPos;
1841 private int[] preSetRegStack = new int[8];
1843 // This can push ONE or ZERO words to the stack. If it pushed one it returns true
1844 private boolean preSetReg(int reg) {
1845 preSetRegStack[preSetRegStackPos] = reg;
1846 preSetRegStackPos++;
1855 private int setReg() {
1856 if(preSetRegStackPos==0) throw new RuntimeException("didn't do preSetReg");
1857 preSetRegStackPos--;
1858 int reg = preSetRegStack[preSetRegStackPos];
1861 mg.add(ISTORE,getLocalForReg(reg));
1862 regLocalWritten[reg] = true;
1863 } else if(reg >= F+0 && reg <= F+31 && singleFloat) {
1864 mg.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"intBitsToFloat",Type.FLOAT,new Type[]{Type.INT}));
1865 mg.add(PUTFIELD,new FieldRef(me,regField[reg],Type.FLOAT));
1867 mg.add(PUTFIELD,new FieldRef(me,regField[reg],Type.INT));
1872 private int preSetPC() { return mg.add(ALOAD_0); }
1873 private int setPC() {
1874 return mg.add(PUTFIELD,new FieldRef(me,"pc",Type.INT));
1877 //unused - private InstructionHandle pushDouble(int reg) throws CompilationException { return pushDouble(reg,true); }
1878 private int pushFloat(int reg) throws Exn { return pushDouble(reg,false); }
1879 private int pushDouble(int reg, boolean d) throws Exn {
1880 if(reg < F || reg >= F+32) throw new IllegalArgumentException(""+reg);
1883 if(singleFloat) throw new Exn("Double operations not supported when singleFloat is enabled");
1884 if(reg == F+31) throw new Exn("Tried to use a double in f31");
1891 mg.add(LDC,FFFFFFFF);
1894 mg.add(INVOKESTATIC,new MethodRef(Type.DOUBLE_OBJECT,"longBitsToDouble",Type.DOUBLE,new Type[]{Type.LONG}));
1895 } else if(singleFloat) {
1897 mg.add(GETFIELD,new FieldRef(me,regField[reg],Type.FLOAT));
1900 mg.add(INVOKESTATIC,new MethodRef("java.lang.Float","intBitsToFloat",Type.FLOAT,new Type[]{Type.INT}));
1905 private void preSetFloat(int reg) { preSetDouble(reg,false); }
1906 private void preSetDouble(int reg) { preSetDouble(reg,true); }
1907 private void preSetDouble(int reg, boolean d) { preSetReg(reg); }
1909 private int setFloat() throws Exn { return setDouble(false); }
1910 private int setDouble() throws Exn { return setDouble(true); }
1911 private int setDouble(boolean d) throws Exn {
1912 int reg = preSetRegStack[preSetRegStackPos-1];
1913 if(reg < F || reg >= F+32) throw new IllegalArgumentException(""+reg);
1916 if(singleFloat) throw new Exn("Double operations not supported when singleFloat is enabled");
1917 if(reg == F+31) throw new Exn("Tried to use a double in f31");
1918 mg.add(INVOKESTATIC,new MethodRef(Type.DOUBLE_OBJECT,"doubleToLongBits",Type.LONG,new Type[]{Type.DOUBLE}));
1923 if(preSetReg(reg+1))
1927 setReg(); // preSetReg was already done for this by preSetDouble
1928 } else if(singleFloat) {
1929 // HACK: Clean this up
1930 preSetRegStackPos--;
1931 mg.add(PUTFIELD,new FieldRef(me,regField[reg],Type.FLOAT));
1933 //h = a(fac.createInvoke("java.lang.Float","floatToRawIntBits",Type.INT,new Type[]{Type.FLOAT},INVOKESTATIC));
1934 mg.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"floatToRawIntBits",Type.INT,new Type[]{Type.FLOAT}));
1940 private void pushTmp() { mg.add(ILOAD_1); }
1941 private void setTmp() { mg.add(ISTORE_1); }
1943 private void addiu(int reg, int offset) {
1944 if(reg != R+0 && offset != 0) {
1948 } else if(reg != R+0) {
1954 private int memWriteStage;
1955 private void preMemWrite1() {
1956 if(memWriteStage!=0) throw new Error("pending preMemWrite1/2");
1966 private void preMemWrite2(int reg, int offset) {
1971 private void preMemWrite2() { preMemWrite2(false); }
1972 private void preMemWrite2(boolean addrInTmp) {
1973 if(memWriteStage!=1) throw new Error("pending preMemWrite2 or no preMemWrite1");
1976 if(nullPointerCheck) {
1980 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.nullPointerCheck
1981 mg.add(INVOKEVIRTUAL,new MethodRef(me,"nullPointerCheck",Type.VOID,new Type[]{Type.INT}));
1987 } else if(fastMem) {
1990 mg.add(LDC,pageShift);
1999 mg.add(LDC,(pageSize>>2)-1);
2004 // pops an address and value off the stack, sets *addr to value
2005 private void memWrite() {
2006 if(memWriteStage!=2) throw new Error("didn't do preMemWrite1 or preMemWrite2");
2011 } else if(fastMem) {
2014 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.unsafeMemWrite
2015 mg.add(INVOKEVIRTUAL,new MethodRef(me,"unsafeMemWrite",Type.VOID,new Type[]{Type.INT,Type.INT}));
2020 // reads the word at r[reg]+offset
2021 private void memRead(int reg, int offset) {
2027 private boolean didPreMemRead;
2028 private boolean preMemReadDoPreWrite;
2030 private void preMemRead() { preMemRead(false); }
2031 private void preMemRead(boolean preWrite) {
2032 if(didPreMemRead) throw new Error("pending preMemRead");
2033 didPreMemRead = true;
2034 preMemReadDoPreWrite = preWrite;
2038 mg.add(ALOAD,preWrite ? 3 : 2);
2042 // memRead pops an address off the stack, reads the value at that addr, and pushed the value
2043 // preMemRead MUST be called BEFORE the addresses is pushed
2044 private void memRead() { memRead(false); }
2046 private void memRead(boolean addrInTmp) {
2047 if(!didPreMemRead) throw new Error("didn't do preMemRead");
2048 didPreMemRead = false;
2049 if(preMemReadDoPreWrite)
2052 if(nullPointerCheck) {
2056 mg.add(INVOKEVIRTUAL,new MethodRef(me,"nullPointerCheck",Type.VOID,new Type[]{Type.INT}));
2062 if(preMemReadDoPreWrite)
2065 } else if(fastMem) {
2068 mg.add(LDC,pageShift);
2077 mg.add(LDC,(pageSize>>2)-1);
2079 if(preMemReadDoPreWrite)
2084 if(preMemReadDoPreWrite)
2086 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.unsafeMemRead
2087 mg.add(INVOKEVIRTUAL,new MethodRef(me,"unsafeMemRead",Type.INT,new Type[]{Type.INT}));
2092 // This might come in handy for something else
2093 /*private boolean touchesReg(int insn, int reg) {
2094 if((reg < R+0 || reg >= R+32) && reg != FCSR) throw new IllegalArgumentException(""+reg);
2095 if(reg == R+0) return false; // r0 is never modified
2096 int op = (insn >>> 26) & 0xff; // bits 26-31
2097 int subcode = insn & 0x3f; // bits 0-5
2098 int rd = (insn >>> 11) & 0x1f; // bits 11-15
2099 int rt = (insn >>> 16) & 0x1f; // bits 16-20
2100 int rs = (insn >>> 21) & 0x1f; // bits 21-25
2104 if(subcode >= 0 && subcode <= 7) return reg == R+rd; // Shift ops
2105 if(subcode >= 32 && subcode <= 43) return reg == R+rd; // Other math ops
2106 if(subcode >= 24 && subcode <= 27) return reg == HI || reg == LO; // MULT/DIV
2108 case 13: return false; // BREAK
2111 case 0: return reg == R+rt; // MFC.1
2112 case 2: return reg == R+rt; // CFC.1
2113 case 4: return false; // MTC.1
2114 case 6: return false; // CTC.1
2117 if(subcode == 50 || subcode == 60 || subcode == 62) return reg == FCSR;
2118 return false; // everything else just touches f0-f31
2119 case 20: return false; // Integer - just touches f0-f31
2123 if(op >= 8 && op <= 15) return reg == R+rt; // XXXI instructions
2124 if(op >= 40 && op <= 46) return false; // Memory WRITE ops
2125 if(op == 49) return reg == F+rt; // LWC1
2126 if(op == 57) return false; // SWC1
2129 warn.println("Unknown instruction in touchesReg()- assuming it modifies all regs " + op + " " + subcode);
2130 new Exception().fillInStackTrace().printStackTrace(warn);