1 package org.ibex.nestedvm;
5 import org.ibex.nestedvm.util.*;
6 import org.ibex.classgen.*;
8 // FEATURE: Eliminate unnecessary use of SWAP
9 // FEATURE: Put regs in low (<=3) local vars, small classfile size
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 CGConst {
36 private static final boolean OPTIMIZE_CP = true;
38 /** The stream to write the compiled output to */
39 private OutputStream os;
41 private PrintStream warn = System.err;
43 private final Type.Object me;
46 private MethodGen clinit, init;
48 public ClassFileCompiler(String path, String className, OutputStream os) throws IOException { this(new Seekable.File(path),className,os); }
49 public ClassFileCompiler(Seekable binary, String className, OutputStream os) throws IOException {
50 this(binary,className);
51 if(os == null) throw new NullPointerException();
54 public ClassFileCompiler(Seekable binary, String className, File outDir) throws IOException {
55 this(binary,className);
56 if(outDir == null) throw new NullPointerException();
59 private ClassFileCompiler(Seekable binary, String className) throws IOException {
60 super(binary,className);
61 me = new Type.Object(fullClassName);
64 public void setWarnWriter(PrintStream warn) { this.warn = warn; }
66 protected void _go() throws Exn, IOException {
69 } catch(ClassGen.Exn e) {
70 e.printStackTrace(warn);
71 throw new Exn("Class generation exception: " + e.toString());
75 private void __go() throws Exn, IOException {
76 if(!pruneCases) throw new Exn("-o prunecases MUST be enabled for ClassFileCompiler");
79 Type.Object superClass = new Type.Object(runtimeClass);
80 cg = new ClassGen(me,superClass,ACC_PUBLIC|ACC_FINAL|ACC_SUPER);
81 if(source != null) cg.setSourceFile(source);
84 cg.addField("pc",Type.INT,ACC_PRIVATE);
85 cg.addField("hi",Type.INT,ACC_PRIVATE);
86 cg.addField("lo",Type.INT,ACC_PRIVATE);
87 cg.addField("fcsr",Type.INT,ACC_PRIVATE);
88 for(int i=1;i<32;i++) cg.addField("r" + i,Type.INT,ACC_PRIVATE);
89 for(int i=0;i<32;i++) cg.addField("f" + i,singleFloat ? Type.FLOAT : Type.INT,ACC_PRIVATE);
92 clinit = cg.addMethod("<clinit>",Type.VOID,Type.NO_ARGS,ACC_PRIVATE|ACC_STATIC);
94 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.UnixRuntime.<init>
97 init = cg.addMethod("<init>",Type.VOID,Type.NO_ARGS,ACC_PUBLIC);
99 init.add(LDC,pageSize);
100 init.add(LDC,totalPages);
101 init.add(INVOKESPECIAL,new MethodRef(me,"<init>",Type.VOID,new Type[]{Type.INT,Type.INT}));
105 init = cg.addMethod("<init>",Type.VOID,new Type[]{Type.BOOLEAN},ACC_PUBLIC);
107 init.add(LDC,pageSize);
108 init.add(LDC,totalPages);
110 init.add(INVOKESPECIAL,new MethodRef(me,"<init>",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN}));
114 init = cg.addMethod("<init>",Type.VOID,new Type[]{Type.INT,Type.INT},ACC_PUBLIC);
119 init.add(INVOKESPECIAL,new MethodRef(me,"<init>",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN}));
123 init = cg.addMethod("<init>",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN},ACC_PUBLIC);
128 init.add(INVOKESPECIAL,new MethodRef(superClass,"<init>",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN}));
131 cg.addField("page",Type.arrayType(Type.INT),ACC_PRIVATE|ACC_FINAL);
134 init.add(GETFIELD,new FieldRef(me,"readPages",Type.arrayType(Type.INT,2)));
137 init.add(PUTFIELD,new FieldRef(me,"page",Type.arrayType(Type.INT)));
141 cg.addField("symbols",new Type.Object(hashClass),ACC_PRIVATE|ACC_STATIC|ACC_FINAL);
145 for(int i=0;i<elf.sheaders.length;i++) {
146 ELF.SHeader sheader = elf.sheaders[i];
147 String name = sheader.name;
148 // if this section doesn't get loaded into our address space don't worry about it
149 if(sheader.addr == 0x0) continue;
151 highestAddr = Math.max(highestAddr, sheader.addr + sheader.size);
153 if(name.equals(".text"))
154 emitText(sheader.addr, new DataInputStream(sheader.getInputStream()),sheader.size);
155 else if(name.equals(".data") || name.equals(".sdata") || name.equals(".rodata") || name.equals(".ctors") || name.equals(".dtors"))
156 emitData(sheader.addr, new DataInputStream(sheader.getInputStream()), sheader.size,name.equals(".rodata"));
157 else if(name.equals(".bss") || name.equals(".sbss"))
158 emitBSS(sheader.addr,sheader.size);
160 throw new Exn("Unknown segment: " + name);
168 Type.Object hash = new Type.Object(hashClass);
169 clinit.add(NEW,hash);
172 clinit.add(INVOKESPECIAL,new MethodRef(hash,"<init>",Type.VOID,Type.NO_ARGS));
173 clinit.add(PUTSTATIC,new FieldRef(me,"symbols",hash));
174 ELF.Symbol[] symbols = elf.getSymtab().symbols;
175 for(int i=0;i<symbols.length;i++) {
176 ELF.Symbol s = symbols[i];
177 if(s.type == ELF.Symbol.STT_FUNC && s.binding == ELF.Symbol.STB_GLOBAL && (s.name.equals("_call_helper") || !s.name.startsWith("_"))) {
179 clinit.add(LDC,s.name);
180 clinit.add(NEW,Type.INTEGER_OBJECT);
182 clinit.add(LDC,s.addr);
183 clinit.add(INVOKESPECIAL,new MethodRef(Type.INTEGER_OBJECT,"<init>",Type.VOID,new Type[]{Type.INT}));
184 clinit.add(INVOKEVIRTUAL,new MethodRef(hash,"put",Type.OBJECT,new Type[]{Type.OBJECT,Type.OBJECT}));
193 ELF.SHeader text = elf.sectionWithName(".text");
196 MethodGen tramp = cg.addMethod("trampoline",Type.VOID,Type.NO_ARGS,ACC_PRIVATE);
198 int start = tramp.size();
200 tramp.add(GETFIELD,new FieldRef(me,"state",Type.INT));
201 tramp.add(IFEQ,tramp.size()+2);
206 tramp.add(GETFIELD,new FieldRef(me,"pc",Type.INT));
207 tramp.add(LDC,methodShift);
210 int beg = text.addr >>> methodShift;
211 int end = ((text.addr + text.size + maxBytesPerMethod - 1) >>> methodShift);
213 MethodGen.TSI tsi = new MethodGen.TSI(beg,end-1);
214 tramp.add(TABLESWITCH,tsi);
215 for(int n=beg;n<end;n++) {
216 tsi.setTargetForVal(n,tramp.size());
217 tramp.add(INVOKESPECIAL,new MethodRef(me,"run_"+toHex(n<<methodShift),Type.VOID,Type.NO_ARGS));
218 tramp.add(GOTO,start);
220 tsi.setDefaultTarget(tramp.size());
223 tramp.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
225 tramp.add(NEW, Type.STRINGBUFFER);
227 tramp.add(LDC,"Jumped to invalid address in trampoline (r2: ");
228 tramp.add(INVOKESPECIAL,new MethodRef(Type.STRINGBUFFER,"<init>",Type.VOID,new Type[]{Type.STRING}));
230 tramp.add(GETFIELD, new FieldRef(me,"r2",Type.INT));
231 tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.INT}));
232 tramp.add(LDC," pc: ");
233 tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.STRING}));
235 tramp.add(GETFIELD, new FieldRef(me,"pc",Type.INT));
236 tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.INT}));
238 tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.STRING}));
239 tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"toString",Type.STRING,Type.NO_ARGS));
240 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime$ExecutionException.<init>
241 tramp.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"<init>",Type.VOID,new Type[]{Type.STRING}));
248 } catch(ClassGen.Exn e) {
249 e.printStackTrace(warn);
250 throw new Exn("Generation of the trampoline method failed. Try increasing maxInsnPerMethod");
254 addConstReturnMethod("gp",gp.addr);
255 addConstReturnMethod("entryPoint",elf.header.entry);
256 addConstReturnMethod("heapStart",highestAddr);
258 if(userInfo != null) {
259 addConstReturnMethod("userInfoBase",userInfo.addr);
260 addConstReturnMethod("userInfoSize",userInfo.size);
264 Type.Object hashClassType = new Type.Object(hashClass);
265 MethodGen ls = cg.addMethod("lookupSymbol",Type.INT,new Type[]{Type.STRING},ACC_PROTECTED);
266 ls.add(GETSTATIC,new FieldRef(me,"symbols",hashClassType));
268 ls.add(INVOKEVIRTUAL,new MethodRef(hashClassType,"get",Type.OBJECT,new Type[]{Type.OBJECT}));
270 int b = ls.add(IFNULL);
271 ls.add(CHECKCAST,Type.INTEGER_OBJECT);
272 ls.add(INVOKEVIRTUAL,new MethodRef(Type.INTEGER_OBJECT,"intValue",Type.INT,Type.NO_ARGS));
274 ls.setArg(b,ls.size());
280 // Kind of a hack, referencing dup() gets us all the fields for free
281 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime$CPUState.dup
282 Type.Object cpuStateType = new Type.Object("org.ibex.nestedvm.Runtime$CPUState");
283 MethodGen setCPUState = cg.addMethod("setCPUState",Type.VOID,new Type[]{cpuStateType},ACC_PROTECTED);
284 MethodGen getCPUState = cg.addMethod("getCPUState",Type.VOID,new Type[]{cpuStateType},ACC_PROTECTED);
286 setCPUState.add(ALOAD_1);
287 getCPUState.add(ALOAD_1);
288 setCPUState.add(GETFIELD,new FieldRef(cpuStateType,"r",Type.arrayType(Type.INT)));
289 getCPUState.add(GETFIELD,new FieldRef(cpuStateType,"r",Type.arrayType(Type.INT)));
290 setCPUState.add(ASTORE_2);
291 getCPUState.add(ASTORE_2);
293 for(int i=1;i<32;i++) {
294 setCPUState.add(ALOAD_0);
295 setCPUState.add(ALOAD_2);
296 setCPUState.add(LDC,i);
297 setCPUState.add(IALOAD);
298 setCPUState.add(PUTFIELD,new FieldRef(me,"r"+i,Type.INT));
300 getCPUState.add(ALOAD_2);
301 getCPUState.add(LDC,i);
302 getCPUState.add(ALOAD_0);
303 getCPUState.add(GETFIELD,new FieldRef(me,"r"+i,Type.INT));
304 getCPUState.add(IASTORE);
307 setCPUState.add(ALOAD_1);
308 getCPUState.add(ALOAD_1);
309 setCPUState.add(GETFIELD,new FieldRef(cpuStateType,"f",Type.arrayType(Type.INT)));
310 getCPUState.add(GETFIELD,new FieldRef(cpuStateType,"f",Type.arrayType(Type.INT)));
311 setCPUState.add(ASTORE_2);
312 getCPUState.add(ASTORE_2);
314 for(int i=0;i<32;i++) {
315 setCPUState.add(ALOAD_0);
316 setCPUState.add(ALOAD_2);
317 setCPUState.add(LDC,i);
318 setCPUState.add(IALOAD);
319 if(singleFloat) setCPUState.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"intBitsToFloat",Type.FLOAT,new Type[]{Type.INT}));
320 setCPUState.add(PUTFIELD,new FieldRef(me,"f"+i,singleFloat ? Type.FLOAT : Type.INT));
322 getCPUState.add(ALOAD_2);
323 getCPUState.add(LDC,i);
324 getCPUState.add(ALOAD_0);
325 getCPUState.add(GETFIELD,new FieldRef(me,"f"+i,singleFloat ? Type.FLOAT: Type.INT));
326 if(singleFloat) getCPUState.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"floatToIntBits",Type.INT,new Type[]{Type.FLOAT}));
327 getCPUState.add(IASTORE);
330 String[] each = new String[] { "hi","lo","fcsr","pc" };
331 for(int i=0;i<each.length;i++) {
332 setCPUState.add(ALOAD_0);
333 setCPUState.add(ALOAD_1);
334 setCPUState.add(GETFIELD,new FieldRef(cpuStateType,each[i],Type.INT));
335 setCPUState.add(PUTFIELD,new FieldRef(me,each[i],Type.INT));
337 getCPUState.add(ALOAD_1);
338 getCPUState.add(ALOAD_0);
339 getCPUState.add(GETFIELD,new FieldRef(me,each[i],Type.INT));
340 getCPUState.add(PUTFIELD,new FieldRef(cpuStateType,each[i],Type.INT));
342 setCPUState.add(RETURN);
343 getCPUState.add(RETURN);
346 MethodGen execute = cg.addMethod("_execute",Type.VOID,Type.NO_ARGS,ACC_PROTECTED);
347 int tryStart = execute.size();
348 execute.add(ALOAD_0);
349 execute.add(INVOKESPECIAL,new MethodRef(me,"trampoline",Type.VOID,Type.NO_ARGS));
350 int tryEnd = execute.size();
353 int catchInsn = execute.size();
354 execute.add(ASTORE_1);
355 execute.add(NEW, new Type.Object("org.ibex.nestedvm.Runtime$FaultException"));
357 execute.add(ALOAD_1);
358 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime$FaultException.<init>
359 execute.add(INVOKESPECIAL,new MethodRef("org.ibex.nestedvm.Runtime$FaultException","<init>",Type.VOID,new Type[]{new Type.Object("java.lang.RuntimeException")}));
362 execute.addExceptionHandler(tryStart,tryEnd,catchInsn,new Type.Object("java.lang.RuntimeException"));
363 execute.addThrow(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
365 MethodGen main = cg.addMethod("main",Type.VOID,new Type[]{Type.arrayType(Type.STRING)},ACC_STATIC|ACC_PUBLIC);
368 main.add(INVOKESPECIAL,new MethodRef(me,"<init>",Type.VOID,Type.NO_ARGS));
369 main.add(LDC,fullClassName);
372 Type.Object ur = new Type.Object("org.ibex.nestedvm.UnixRuntime");
373 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.runAndExec
374 main.add(INVOKESTATIC,new MethodRef(ur,"runAndExec",Type.INT,new Type[]{ur,Type.STRING,Type.arrayType(Type.STRING)}));
376 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.run
377 main.add(INVOKEVIRTUAL,new MethodRef(me,"run",Type.INT,new Type[]{Type.STRING,Type.arrayType(Type.STRING)}));
379 main.add(INVOKESTATIC,new MethodRef(new Type.Object("java.lang.System"),"exit",Type.VOID,new Type[]{Type.INT}));
383 if(!outDir.isDirectory()) throw new IOException("" + outDir + " isn't a directory");
390 private void addConstReturnMethod(String name, int val) {
391 MethodGen m = cg.addMethod(name,Type.INT,Type.NO_ARGS,ACC_PROTECTED);
396 private static int initDataCount;
397 private void emitData(int addr, DataInputStream dis, int size, boolean readOnly) throws Exn,IOException {
398 if((addr&3)!=0 || (size&3)!=0) throw new Exn("Data section on weird boundaries");
399 int last = addr + size;
401 int segSize = Math.min(size,28000); // must be a multiple of 56
402 StringBuffer sb = new StringBuffer();
403 for(int i=0;i<segSize;i+=7) {
405 for(int j=0;j<7;j++) {
407 byte b = (i+j < size) ? dis.readByte() : 1;
411 sb.append((char) ((l>>>(7*(7-j)))&0x7f));
413 String fieldname = "_data" + (++initDataCount);
414 cg.addField(fieldname,Type.arrayType(Type.INT),ACC_PRIVATE|ACC_STATIC|ACC_FINAL);
416 clinit.add(LDC,sb.toString());
417 clinit.add(LDC,segSize/4);
418 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.decodeData
419 clinit.add(INVOKESTATIC,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime"),"decodeData",Type.arrayType(Type.INT),new Type[]{Type.STRING,Type.INT}));
420 clinit.add(PUTSTATIC,new FieldRef(me,fieldname,Type.arrayType(Type.INT)));
422 init.add(GETSTATIC,new FieldRef(me,fieldname,Type.arrayType(Type.INT)));
424 init.add(LDC,readOnly ? 1 : 0);
425 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.initPages
426 init.add(INVOKEVIRTUAL,new MethodRef(me,"initPages",Type.VOID,new Type[]{Type.arrayType(Type.INT),Type.INT,Type.BOOLEAN}));
434 private void emitBSS(int addr, int size) throws Exn {
435 if((addr&3)!=0) throw new Exn("BSS section on weird boundaries");
442 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.clearPages
443 init.add(INVOKEVIRTUAL,new MethodRef(me,"clearPages",Type.VOID,new Type[]{Type.INT,Type.INT}));
447 private int startOfMethod = 0; // the start of this method (not necessarily the first instruction)
448 private int endOfMethod = 0; // the maximum end of this method (could end before it is full)
450 private MethodGen.PhantomTarget returnTarget; // where to jump when exiting the method
451 private MethodGen.PhantomTarget defaultTarget; // the default switch target (throws exn)
452 private MethodGen.PhantomTarget[] insnTargets; // the targets for each jumpable instruction
453 private MethodGen mg; // the method itself
455 private boolean jumpable(int addr) { return jumpableAddresses.get(new Integer(addr)) != null; }
457 private static final int UNREACHABLE = 1;
458 private static final int SKIP_NEXT = 2;
460 private boolean textDone; // a text segment was already processed
461 private void emitText(int addr, DataInputStream dis, int size) throws Exn,IOException {
462 if(textDone) throw new Exn("Multiple text segments");
465 if((addr&3)!=0 || (size&3)!=0) throw new Exn("Section on weird boundaries");
467 int insn,nextInsn=-1;
469 boolean skipNext = true;
470 boolean unreachable = false;
472 for(int i=0;i<count;i++,addr+=4) {
473 insn = skipNext ? dis.readInt() : nextInsn;
474 nextInsn = (i == count-1) ? -1 : dis.readInt();
475 if(addr >= endOfMethod) { endMethod(addr,unreachable); startMethod(addr); }
476 if(insnTargets[i%maxInsnPerMethod] != null) {
477 insnTargets[i%maxInsnPerMethod].setTarget(mg.size());
479 } else if(unreachable) {
483 int ret = emitInstruction(addr,insn,nextInsn);
484 unreachable = (ret & UNREACHABLE) != 0;
485 skipNext = (ret & SKIP_NEXT) != 0;
487 e.printStackTrace(warn);
488 warn.println("Exception at " + toHex(addr));
490 } catch(RuntimeException e) {
491 warn.println("Exception at " + toHex(addr));
494 if(skipNext) { addr+=4; i++; }
496 endMethod(0,unreachable);
500 private void startMethod(int first) {
501 startOfMethod = first & methodMask;
502 endOfMethod = startOfMethod + maxBytesPerMethod;
504 mg = cg.addMethod("run_" + toHex(startOfMethod),Type.VOID,Type.NO_ARGS,ACC_PRIVATE|ACC_FINAL);
507 mg.add(GETFIELD,new FieldRef(me,"page",Type.arrayType(Type.INT)));
511 mg.add(GETFIELD,new FieldRef(me,"readPages",Type.arrayType(Type.INT,2)));
514 mg.add(GETFIELD,new FieldRef(me,"writePages",Type.arrayType(Type.INT,2)));
518 returnTarget = new MethodGen.PhantomTarget();
519 insnTargets = new MethodGen.PhantomTarget[maxBytesPerMethod/4];
521 int[] buf = new int[maxBytesPerMethod/4];
522 Object[] targetBuf = new Object[maxBytesPerMethod/4];
524 for(int addr=first;addr<endOfMethod;addr+=4) {
526 targetBuf[n] = insnTargets[(addr-startOfMethod)/4] = new MethodGen.PhantomTarget();
532 MethodGen.LSI lsi = new MethodGen.LSI(n);
533 System.arraycopy(buf,0,lsi.vals,0,n);
534 System.arraycopy(targetBuf,0,lsi.targets,0,n);
535 lsi.setDefaultTarget(defaultTarget = new MethodGen.PhantomTarget());
540 mg.add(GETFIELD,new FieldRef(me,"pc",Type.INT));
541 mg.add(LOOKUPSWITCH,lsi);
544 private void endMethod(int firstAddrOfNext,boolean unreachable) {
545 if(startOfMethod == 0) return;
549 mg.add(LDC,firstAddrOfNext);
551 // mark the start of the next method as jumpable
552 jumpableAddresses.put(new Integer(firstAddrOfNext),Boolean.TRUE);
555 returnTarget.setTarget(mg.size());
561 defaultTarget.setTarget(mg.size());
564 mg.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
566 mg.add(NEW,Type.STRINGBUFFER);
568 mg.add(LDC,"Jumped to invalid address: ");
569 mg.add(INVOKESPECIAL,new MethodRef(Type.STRINGBUFFER,"<init>",Type.VOID,new Type[]{Type.STRING}));
571 mg.add(GETFIELD,new FieldRef(me,"pc",Type.INT));
572 mg.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.INT}));
573 mg.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"toString",Type.STRING,Type.NO_ARGS));
574 mg.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"<init>",Type.VOID,new Type[]{Type.STRING}));
577 mg.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
579 mg.add(LDC,"Jumped to invalid address");
580 mg.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"<init>",Type.VOID,new Type[]{Type.STRING}));
584 endOfMethod = startOfMethod = 0;
588 private void leaveMethod() {
589 mg.add(GOTO,returnTarget);
592 private void link(int mypc) {
595 int ref = (mypc+8 + 32768) & ~65535;
596 int diff = (mypc+8) - ref;
597 if(diff < -32768 || diff > 32767) throw new Error("should never happen " + diff);
607 private void branch(int pc, int target) {
608 if((pc&methodMask) == (target&methodMask)) {
609 mg.add(GOTO,insnTargets[(target-startOfMethod)/4]);
618 // This assumes everything needed by ifInsn is already on the stack
619 private int doIfInstruction(byte op, int pc, int target, int nextInsn) throws Exn {
620 emitInstruction(-1,nextInsn,-1); // delay slot
621 if((target&methodMask) == (pc&methodMask)) {
622 mg.add(op,insnTargets[(target-startOfMethod)/4]);
624 int h = mg.add(MethodGen.negate(op));
626 mg.setArg(h,mg.size());
628 if(!jumpable(pc+4)) return SKIP_NEXT; // done - skip it
630 //System.err.println("Delay slot is jumpable - This code is untested + " + toHex(nextInsn));
631 if(pc+4==endOfMethod) {
632 // the delay slot is at the start of the next method
633 jumpableAddresses.put(new Integer(pc+8),Boolean.TRUE); // make the 2nd insn of the next method jumpable
634 branch(pc,pc+8); // jump over it
635 //System.err.println("delay slot: " + toHex(pc+8)); */
636 //unreachable = true;
637 //return false; // we still need to output it
640 //System.err.println("jumped over delay slot: " + toHex(pc+4));
641 // add another copy and jump over
643 int b = mg.add(GOTO);
644 insnTargets[(pc+4-startOfMethod)/4].setTarget(mg.size());
645 emitInstruction(-1,nextInsn,01); // delay slot
646 mg.setArg(b,mg.size());
652 private static final Float POINT_5_F = new Float(0.5f);
653 private static final Double POINT_5_D = new Double(0.5f);
654 private static final Long FFFFFFFF = new Long(0xffffffffL);
656 private int emitInstruction(int pc, int insn, int nextInsn) throws Exn {
657 MethodGen mg = this.mg; // smaller bytecode
658 if(insn == -1) throw new Exn("insn is -1");
662 int op = (insn >>> 26) & 0xff; // bits 26-31
663 int rs = (insn >>> 21) & 0x1f; // bits 21-25
664 int rt = (insn >>> 16) & 0x1f; // bits 16-20
665 int ft = (insn >>> 16) & 0x1f;
666 int rd = (insn >>> 11) & 0x1f; // bits 11-15
667 int fs = (insn >>> 11) & 0x1f;
668 int shamt = (insn >>> 6) & 0x1f; // bits 6-10
669 int fd = (insn >>> 6) & 0x1f;
670 int subcode = insn & 0x3f; // bits 0-5
671 int breakCode = (insn >>> 6) & 0xfffff; // bits 6-20
673 int jumpTarget = (insn & 0x03ffffff); // bits 0-25
674 int unsignedImmediate = insn & 0xffff;
675 int signedImmediate = (insn << 16) >> 16;
676 int branchTarget = signedImmediate;
728 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
729 emitInstruction(-1,nextInsn,-1);
737 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
738 emitInstruction(-1,nextInsn,-1);
751 // FEATURE: This is actually broken, but it happens to work for our code
752 // a func could theoretically jump back to here from a future point
753 restoreChangedRegs();
764 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.syscall
765 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}));
769 mg.add(GETFIELD,new FieldRef(me,"state",Type.INT));
775 mg.setArg(b1,mg.size());
778 mg.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
780 mg.add(LDC,"BREAK Code " + toHex(breakCode));
781 mg.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"<init>",Type.VOID,new Type[]{Type.STRING}));
815 mg.add(SWAP); //a(InstructionConstants.SWAP);
822 mg.add(SWAP); //a(InstructionConstants.SWAP);
829 mg.add(LDC,FFFFFFFF);
833 mg.add(LDC,FFFFFFFF);
875 mg.add(LDC,FFFFFFFF);
880 mg.add(LDC,FFFFFFFF);
897 mg.setArg(b1,mg.size());
902 throw new Exn("ADD (add with oveflow trap) not suported");
905 if(rt != 0 && rs != 0) {
917 throw new Exn("SUB (add with oveflow trap) not suported");
920 if(rt != 0 && rs != 0) {
955 if(rs != 0 || rt != 0) {
956 if(rs != 0 && rt != 0) {
977 b1 = mg.add(IF_ICMPLT);
980 mg.setArg(b1,mg.add(ICONST_1));
981 mg.setArg(b2,mg.size());
993 mg.add(LDC,FFFFFFFF);
997 mg.add(LDC,FFFFFFFF);
1007 mg.setArg(b1,mg.add(ICONST_1));
1008 mg.setArg(b2,mg.size());
1015 throw new Exn("Illegal instruction 0/" + subcode);
1022 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1024 return doIfInstruction(IFLT,pc,pc+branchTarget*4+4,nextInsn);
1026 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1028 return doIfInstruction(IFGE,pc,pc+branchTarget*4+4,nextInsn);
1030 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1033 emitInstruction(-1,nextInsn,-1);
1035 branch(pc,pc+branchTarget*4+4);
1036 mg.setArg(b1,mg.size());
1039 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1041 if(rs != 0) { // r0 is always >= 0
1045 emitInstruction(-1,nextInsn,-1);
1047 branch(pc,pc+branchTarget*4+4);
1048 if(b1 != -1) mg.setArg(b1,mg.size());
1049 if(b1 == -1) ret |= UNREACHABLE;
1052 throw new Exn("Illegal Instruction 1/" + rt);
1057 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1058 emitInstruction(-1,nextInsn,-1);
1059 branch(pc,(pc&0xf0000000)|(jumpTarget << 2));
1064 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1065 int target = (pc&0xf0000000)|(jumpTarget << 2);
1066 emitInstruction(-1,nextInsn,-1);
1073 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1075 emitInstruction(-1,nextInsn,-1);
1076 branch(pc,pc+branchTarget*4+4);
1078 } else if(rs == 0 || rt == 0) {
1079 pushReg(rt == 0 ? R+rs : R+rt);
1080 return doIfInstruction(IFEQ,pc,pc+branchTarget*4+4,nextInsn);
1084 return doIfInstruction(IF_ICMPEQ,pc,pc+branchTarget*4+4,nextInsn);
1088 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1091 return doIfInstruction(IFNE,pc,pc+branchTarget*4+4,nextInsn);
1094 return doIfInstruction(IF_ICMPNE,pc,pc+branchTarget*4+4,nextInsn);
1097 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1099 return doIfInstruction(IFLE,pc,pc+branchTarget*4+4,nextInsn);
1101 if(pc == -1) throw new Exn("pc modifying insn in delay slot");
1103 return doIfInstruction(IFGT,pc,pc+branchTarget*4+4,nextInsn);
1105 throw new Exn("ADDI (add immediate with oveflow trap) not suported");
1107 if(rs != 0 && signedImmediate != 0 && rs == rt && doLocal(rt) && signedImmediate >= -32768 && signedImmediate <= 32767) {
1108 // HACK: This should be a little cleaner
1109 regLocalWritten[rt] = true;
1110 mg.add(IINC, new MethodGen.Pair(getLocalForReg(rt),signedImmediate));
1113 addiu(rs,signedImmediate);
1120 mg.add(LDC,signedImmediate);
1121 b1 = mg.add(IF_ICMPLT);
1124 mg.setArg(b1,mg.add(ICONST_1));
1125 mg.setArg(b2,mg.size());
1132 mg.add(LDC,FFFFFFFF);
1134 // Yes, this is correct, you have to sign extend the immediate then do an UNSIGNED comparison
1135 mg.add(LDC,new Long(signedImmediate&0xffffffffL));
1141 mg.setArg(b1,mg.add(ICONST_1));
1142 mg.setArg(b2,mg.size());
1148 mg.add(LDC,unsignedImmediate);
1154 if(rs != 0 && unsignedImmediate != 0) {
1156 mg.add(LDC,unsignedImmediate);
1161 mg.add(LDC,unsignedImmediate);
1168 mg.add(LDC,unsignedImmediate);
1174 mg.add(LDC,unsignedImmediate << 16);
1178 throw new Exn("TLB/Exception support not implemented");
1187 if(fs != 31) throw new Exn("FCR " + fs + " unavailable");
1194 if(rt != 0) pushReg(R+rt);
1195 else mg.add(ICONST_0);
1199 if(fs != 31) throw new Exn("FCR " + fs + " unavailable");
1204 case 8: {// BC1F, BC1T
1206 mg.add(LDC,0x800000);
1208 return doIfInstruction(((insn>>>16)&1) == 0 ? IFEQ : IFNE,pc,pc+branchTarget*4+4,nextInsn);
1212 { // Single/Double math
1213 boolean d = rs == 17;
1216 preSetDouble(F+fd,d);
1219 mg.add(d ? DADD : FADD);
1223 preSetDouble(F+fd,d);
1226 mg.add(d ? DSUB : FSUB);
1230 preSetDouble(F+fd,d);
1233 mg.add(d ? DMUL : FMUL);
1237 preSetDouble(F+fd,d);
1240 mg.add(d ? DDIV : FDIV);
1244 preSetDouble(F+fd,d);
1245 // NOTE: We can't use fneg/dneg here since they'll turn +0.0 into -0.0
1248 mg.add(d ? DUP2 : DUP);
1249 mg.add(d ? DCONST_0 : FCONST_0);
1250 mg.add(d ? DCMPG : FCMPG);
1253 mg.add(d ? DCONST_0 : FCONST_0);
1260 mg.add(d ? DSUB : FSUB);
1262 mg.setArg(b1,mg.size());
1278 preSetDouble(F+fd,d);
1280 mg.add(d ? DNEG : FNEG);
1295 case 36: { // CVT.W.D
1296 MethodGen.TSI tsi = new MethodGen.TSI(0,3);
1302 mg.add(TABLESWITCH,tsi);
1304 // Round towards plus infinity
1305 tsi.setTarget(2,mg.size());
1306 if(!d) mg.add(F2D); // Ugh.. java.lang.Math doesn't have a float ceil/floor
1307 mg.add(INVOKESTATIC,new MethodRef("java.lang.Math","ceil",Type.DOUBLE,new Type[]{Type.DOUBLE}));
1312 tsi.setTarget(0,mg.size());
1313 mg.add(LDC,d ? (Object)POINT_5_D : (Object)POINT_5_F);
1314 mg.add(d ? DADD : FADD);
1317 // Round towards minus infinity
1318 tsi.setTarget(3,mg.size());
1320 mg.add(INVOKESTATIC,new MethodRef("java.lang.Math","floor",Type.DOUBLE,new Type[]{Type.DOUBLE}));
1323 tsi.setTarget(1,mg.size());
1324 tsi.setDefaultTarget(mg.size());
1325 mg.setArg(b1,mg.size());
1327 mg.add(d ? D2I : F2I);
1337 mg.add(LDC,~0x800000);
1341 mg.add(d ? DCMPG : FCMPG);
1343 case 50: b1 = mg.add(IFNE); break;
1344 case 60: b1 = mg.add(IFGE); break;
1345 case 62: b1 = mg.add(IFGT); break;
1348 mg.add(LDC,0x800000);
1350 mg.setArg(b1,mg.size());
1353 default: throw new Exn("Invalid Instruction 17/" + rs + "/" + subcode);
1357 case 20: { // Integer
1371 default: throw new Exn("Invalid Instruction 17/" + rs + "/" + subcode);
1376 throw new Exn("Invalid Instruction 17/" + rs);
1381 throw new Exn("coprocessor 2 and 3 instructions not available");
1384 addiu(R+rs,signedImmediate);
1404 addiu(R+rs,signedImmediate);
1424 addiu(R+rs,signedImmediate);
1428 mg.add(LDC,0x00ffffff);
1459 memRead(R+rs,signedImmediate);
1464 addiu(R+rs,signedImmediate);
1485 addiu(R+rs,signedImmediate);
1500 // chars are unsigend so this works
1507 addiu(R+rs,signedImmediate);
1511 mg.add(LDC,0xffffff00);
1540 addiu(R+rs,signedImmediate);
1547 mg.add(LDC,0xff000000);
1582 addiu(R+rs,signedImmediate);
1622 addiu(R+rs,signedImmediate);
1629 mg.add(LDC,0xffffff00);
1657 preMemWrite2(R+rs,signedImmediate);
1662 addiu(R+rs,signedImmediate);
1669 mg.add(LDC,0x00ffffff);
1694 // This need to be atomic if we ever support threads (see SWC0/SC)
1697 memRead(R+rs,signedImmediate);
1703 memRead(R+rs,signedImmediate);
1707 /* This needs to fail (set rt to 0) if the memory location was modified
1708 * between the LL and SC if we ever support threads.
1713 preMemWrite2(R+rs,signedImmediate);
1722 preMemWrite2(R+rs,signedImmediate);
1727 throw new Exn("Invalid Instruction: " + op + " at " + toHex(pc));
1732 // Helper functions for emitText
1734 private static final int R = 0;
1735 private static final int F = 32;
1736 private static final int HI = 64;
1737 private static final int LO = 65;
1738 private static final int FCSR = 66;
1739 private static final int REG_COUNT=67;
1740 private static final String[] regField = {
1741 "r0","r1","r2","r3","r4","r5","r6","r7",
1742 "r8","r9","r10","r11","r12","r13","r14","r15",
1743 "r16","r17","r18","r19","r20","r21","r22","r23",
1744 "r24","r25","r26","r27","r28","r29","r30","r31",
1745 "f0","f1","f2","f3","f4","f5","f6","f7",
1746 "f8","f9","f10","f11","f12","f13","f14","f15",
1747 "f16","f17","f18","f19","f20","f21","f22","f23",
1748 "f24","f25","f26","f27","f28","f29","f30","f31",
1751 private static final int MAX_LOCALS = 4; // doLocal can return true for this many regs
1752 private static final int LOAD_LENGTH = 3; // number of instructions needed to load a field to a reg
1754 // Local register state info
1755 private int[] regLocalMapping = new int[REG_COUNT];
1756 private boolean[] regLocalWritten = new boolean[REG_COUNT];
1757 private int nextAvailLocal;
1758 private int loadsStart;
1760 private boolean doLocal(int reg) {
1761 return reg == R+2 || reg == R+3 || reg == R+4 || reg == R+29;
1764 private int getLocalForReg(int reg) {
1765 if(regLocalMapping[reg] != 0) return regLocalMapping[reg];
1766 regLocalMapping[reg] = nextAvailLocal++;
1767 return regLocalMapping[reg];
1770 private void fixupRegsStart() {
1771 for(int i=0;i<REG_COUNT;i++) {
1772 regLocalMapping[i] = 0;
1773 regLocalWritten[i] = false;
1775 nextAvailLocal = onePage ? 4 : 5;
1776 loadsStart = mg.size();
1777 for(int i=0;i<MAX_LOCALS*LOAD_LENGTH;i++)
1781 private void fixupRegsEnd() {
1783 for(int i=0;i<REG_COUNT;i++) {
1784 if(regLocalMapping[i] == 0) continue;
1785 mg.set(p++,ALOAD_0);
1786 mg.set(p++,GETFIELD,new FieldRef(me,regField[i],Type.INT));
1787 mg.set(p++,ISTORE,regLocalMapping[i]);
1789 if(regLocalWritten[i]) {
1791 mg.add(ILOAD,regLocalMapping[i]);
1792 mg.add(PUTFIELD,new FieldRef(me,regField[i],Type.INT));
1797 private void restoreChangedRegs() {
1798 for(int i=0;i<REG_COUNT;i++) {
1799 if(regLocalWritten[i]) {
1801 mg.add(ILOAD,regLocalMapping[i]);
1802 mg.add(PUTFIELD,new FieldRef(me,regField[i],Type.INT));
1807 private int pushRegWZ(int reg) {
1809 warn.println("Warning: Pushing r0!");
1810 new Exception().printStackTrace(warn);
1812 return pushRegZ(reg);
1815 private int pushRegZ(int reg) {
1816 if(reg == R+0) return mg.add(ICONST_0);
1817 else return pushReg(reg);
1821 private int pushReg(int reg) {
1824 mg.add(ILOAD,getLocalForReg(reg));
1825 } else if(reg >= F+0 && reg <= F+31 && singleFloat) {
1827 mg.add(GETFIELD,new FieldRef(me,regField[reg],Type.FLOAT));
1828 mg.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"floatToIntBits",Type.INT,new Type[]{Type.FLOAT}));
1831 mg.add(GETFIELD,new FieldRef(me,regField[reg],Type.INT));
1836 private int preSetRegStackPos;
1837 private int[] preSetRegStack = new int[8];
1839 // This can push ONE or ZERO words to the stack. If it pushed one it returns true
1840 private boolean preSetReg(int reg) {
1841 preSetRegStack[preSetRegStackPos] = reg;
1842 preSetRegStackPos++;
1851 private int setReg() {
1852 if(preSetRegStackPos==0) throw new RuntimeException("didn't do preSetReg");
1853 preSetRegStackPos--;
1854 int reg = preSetRegStack[preSetRegStackPos];
1857 mg.add(ISTORE,getLocalForReg(reg));
1858 regLocalWritten[reg] = true;
1859 } else if(reg >= F+0 && reg <= F+31 && singleFloat) {
1860 mg.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"intBitsToFloat",Type.FLOAT,new Type[]{Type.INT}));
1861 mg.add(PUTFIELD,new FieldRef(me,regField[reg],Type.FLOAT));
1863 mg.add(PUTFIELD,new FieldRef(me,regField[reg],Type.INT));
1868 private int preSetPC() { return mg.add(ALOAD_0); }
1869 private int setPC() {
1870 return mg.add(PUTFIELD,new FieldRef(me,"pc",Type.INT));
1873 //unused - private InstructionHandle pushDouble(int reg) throws CompilationException { return pushDouble(reg,true); }
1874 private int pushFloat(int reg) throws Exn { return pushDouble(reg,false); }
1875 private int pushDouble(int reg, boolean d) throws Exn {
1876 if(reg < F || reg >= F+32) throw new IllegalArgumentException(""+reg);
1879 if(singleFloat) throw new Exn("Double operations not supported when singleFloat is enabled");
1880 if(reg == F+31) throw new Exn("Tried to use a double in f31");
1887 mg.add(LDC,FFFFFFFF);
1890 mg.add(INVOKESTATIC,new MethodRef(Type.DOUBLE_OBJECT,"longBitsToDouble",Type.DOUBLE,new Type[]{Type.LONG}));
1891 } else if(singleFloat) {
1893 mg.add(GETFIELD,new FieldRef(me,regField[reg],Type.FLOAT));
1896 mg.add(INVOKESTATIC,new MethodRef("java.lang.Float","intBitsToFloat",Type.FLOAT,new Type[]{Type.INT}));
1901 private void preSetFloat(int reg) { preSetDouble(reg,false); }
1902 private void preSetDouble(int reg) { preSetDouble(reg,true); }
1903 private void preSetDouble(int reg, boolean d) { preSetReg(reg); }
1905 private int setFloat() throws Exn { return setDouble(false); }
1906 private int setDouble() throws Exn { return setDouble(true); }
1907 private int setDouble(boolean d) throws Exn {
1908 int reg = preSetRegStack[preSetRegStackPos-1];
1909 if(reg < F || reg >= F+32) throw new IllegalArgumentException(""+reg);
1912 if(singleFloat) throw new Exn("Double operations not supported when singleFloat is enabled");
1913 if(reg == F+31) throw new Exn("Tried to use a double in f31");
1914 mg.add(INVOKESTATIC,new MethodRef(Type.DOUBLE_OBJECT,"doubleToLongBits",Type.LONG,new Type[]{Type.DOUBLE}));
1919 if(preSetReg(reg+1))
1923 setReg(); // preSetReg was already done for this by preSetDouble
1924 } else if(singleFloat) {
1925 // HACK: Clean this up
1926 preSetRegStackPos--;
1927 mg.add(PUTFIELD,new FieldRef(me,regField[reg],Type.FLOAT));
1929 //h = a(fac.createInvoke("java.lang.Float","floatToRawIntBits",Type.INT,new Type[]{Type.FLOAT},INVOKESTATIC));
1930 mg.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"floatToRawIntBits",Type.INT,new Type[]{Type.FLOAT}));
1936 private void pushTmp() { mg.add(ILOAD_1); }
1937 private void setTmp() { mg.add(ISTORE_1); }
1939 private void addiu(int reg, int offset) {
1940 if(reg != R+0 && offset != 0) {
1944 } else if(reg != R+0) {
1950 private int memWriteStage;
1951 private void preMemWrite1() {
1952 if(memWriteStage!=0) throw new Error("pending preMemWrite1/2");
1962 private void preMemWrite2(int reg, int offset) {
1967 private void preMemWrite2() { preMemWrite2(false); }
1968 private void preMemWrite2(boolean addrInTmp) {
1969 if(memWriteStage!=1) throw new Error("pending preMemWrite2 or no preMemWrite1");
1972 if(nullPointerCheck) {
1976 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.nullPointerCheck
1977 mg.add(INVOKEVIRTUAL,new MethodRef(me,"nullPointerCheck",Type.VOID,new Type[]{Type.INT}));
1983 } else if(fastMem) {
1986 mg.add(LDC,pageShift);
1995 mg.add(LDC,(pageSize>>2)-1);
2000 // pops an address and value off the stack, sets *addr to value
2001 private void memWrite() {
2002 if(memWriteStage!=2) throw new Error("didn't do preMemWrite1 or preMemWrite2");
2007 } else if(fastMem) {
2010 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.unsafeMemWrite
2011 mg.add(INVOKEVIRTUAL,new MethodRef(me,"unsafeMemWrite",Type.VOID,new Type[]{Type.INT,Type.INT}));
2016 // reads the word at r[reg]+offset
2017 private void memRead(int reg, int offset) {
2023 private boolean didPreMemRead;
2024 private boolean preMemReadDoPreWrite;
2026 private void preMemRead() { preMemRead(false); }
2027 private void preMemRead(boolean preWrite) {
2028 if(didPreMemRead) throw new Error("pending preMemRead");
2029 didPreMemRead = true;
2030 preMemReadDoPreWrite = preWrite;
2034 mg.add(ALOAD,preWrite ? 3 : 2);
2038 // memRead pops an address off the stack, reads the value at that addr, and pushed the value
2039 // preMemRead MUST be called BEFORE the addresses is pushed
2040 private void memRead() { memRead(false); }
2042 private void memRead(boolean addrInTmp) {
2043 if(!didPreMemRead) throw new Error("didn't do preMemRead");
2044 didPreMemRead = false;
2045 if(preMemReadDoPreWrite)
2048 if(nullPointerCheck) {
2052 mg.add(INVOKEVIRTUAL,new MethodRef(me,"nullPointerCheck",Type.VOID,new Type[]{Type.INT}));
2058 if(preMemReadDoPreWrite)
2061 } else if(fastMem) {
2064 mg.add(LDC,pageShift);
2073 mg.add(LDC,(pageSize>>2)-1);
2075 if(preMemReadDoPreWrite)
2080 if(preMemReadDoPreWrite)
2082 // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.unsafeMemRead
2083 mg.add(INVOKEVIRTUAL,new MethodRef(me,"unsafeMemRead",Type.INT,new Type[]{Type.INT}));
2088 // This might come in handy for something else
2089 /*private boolean touchesReg(int insn, int reg) {
2090 if((reg < R+0 || reg >= R+32) && reg != FCSR) throw new IllegalArgumentException(""+reg);
2091 if(reg == R+0) return false; // r0 is never modified
2092 int op = (insn >>> 26) & 0xff; // bits 26-31
2093 int subcode = insn & 0x3f; // bits 0-5
2094 int rd = (insn >>> 11) & 0x1f; // bits 11-15
2095 int rt = (insn >>> 16) & 0x1f; // bits 16-20
2096 int rs = (insn >>> 21) & 0x1f; // bits 21-25
2100 if(subcode >= 0 && subcode <= 7) return reg == R+rd; // Shift ops
2101 if(subcode >= 32 && subcode <= 43) return reg == R+rd; // Other math ops
2102 if(subcode >= 24 && subcode <= 27) return reg == HI || reg == LO; // MULT/DIV
2104 case 13: return false; // BREAK
2107 case 0: return reg == R+rt; // MFC.1
2108 case 2: return reg == R+rt; // CFC.1
2109 case 4: return false; // MTC.1
2110 case 6: return false; // CTC.1
2113 if(subcode == 50 || subcode == 60 || subcode == 62) return reg == FCSR;
2114 return false; // everything else just touches f0-f31
2115 case 20: return false; // Integer - just touches f0-f31
2119 if(op >= 8 && op <= 15) return reg == R+rt; // XXXI instructions
2120 if(op >= 40 && op <= 46) return false; // Memory WRITE ops
2121 if(op == 49) return reg == F+rt; // LWC1
2122 if(op == 57) return false; // SWC1
2125 warn.println("Unknown instruction in touchesReg()- assuming it modifies all regs " + op + " " + subcode);
2126 new Exception().fillInStackTrace().printStackTrace(warn);