X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Forg%2Fibex%2Fnestedvm%2FClassFileCompiler.java;h=6e67c80cd64b0739a49405410b11f4fd39fd7037;hb=b5282b0a1a8ca5212c75623610be6d0483fd35bd;hp=0572ea13453879adeade0e7309d56cc74fccbdf7;hpb=f138e115bc00194fdcf6800bbe63ebb2ae95525a;p=nestedvm.git diff --git a/src/org/ibex/nestedvm/ClassFileCompiler.java b/src/org/ibex/nestedvm/ClassFileCompiler.java index 0572ea1..6e67c80 100644 --- a/src/org/ibex/nestedvm/ClassFileCompiler.java +++ b/src/org/ibex/nestedvm/ClassFileCompiler.java @@ -1,3 +1,7 @@ +// Copyright 2000-2005 the Contributors, as shown in the revision logs. +// Licensed under the Apache Public Source License 2.0 ("the License"). +// You may not use this file except in compliance with the License. + package org.ibex.nestedvm; import java.io.*; @@ -5,9 +9,8 @@ import java.io.*; import org.ibex.nestedvm.util.*; import org.ibex.classgen.*; -// FEATURE: Use IINC where possible -// FEATURE: Some kind of peephole optimization -// FEATURE: Special mode to support single-precision only - regs are floats not ints +// FEATURE: Eliminate unnecessary use of SWAP +// FEATURE: Put regs in low (<=3) local vars, small classfile size /* FEATURE: Span large binaries across several classfiles * We should be able to do this with no performance penalty @@ -33,22 +36,34 @@ import org.ibex.classgen.*; */ -public class ClassFileCompiler extends Compiler implements CGConst { +public class ClassFileCompiler extends Compiler implements CGConst { + private static final boolean OPTIMIZE_CP = true; + /** The stream to write the compiled output to */ private OutputStream os; + private File outDir; private PrintStream warn = System.err; + + private final Type.Object me; private ClassGen cg; - private MethodGen clinit; - private MethodGen init; - private Type.Object me; - private Type.Object superClass; + private MethodGen clinit, init; public ClassFileCompiler(String path, String className, OutputStream os) throws IOException { this(new Seekable.File(path),className,os); } public ClassFileCompiler(Seekable binary, String className, OutputStream os) throws IOException { - super(binary,className); + this(binary,className); + if(os == null) throw new NullPointerException(); this.os = os; } + public ClassFileCompiler(Seekable binary, String className, File outDir) throws IOException { + this(binary,className); + if(outDir == null) throw new NullPointerException(); + this.outDir = outDir; + } + private ClassFileCompiler(Seekable binary, String className) throws IOException { + super(binary,className); + me = new Type.Object(fullClassName); + } public void setWarnWriter(PrintStream warn) { this.warn = warn; } @@ -56,17 +71,16 @@ public class ClassFileCompiler extends Compiler implements CGConst { try { __go(); } catch(ClassGen.Exn e) { - e.printStackTrace(); + e.printStackTrace(warn); throw new Exn("Class generation exception: " + e.toString()); } } - + private void __go() throws Exn, IOException { if(!pruneCases) throw new Exn("-o prunecases MUST be enabled for ClassFileCompiler"); // Class - me = new Type.Object(fullClassName); - superClass = new Type.Object(runtimeClass); + Type.Object superClass = new Type.Object(runtimeClass); cg = new ClassGen(me,superClass,ACC_PUBLIC|ACC_FINAL|ACC_SUPER); if(source != null) cg.setSourceFile(source); @@ -76,10 +90,14 @@ public class ClassFileCompiler extends Compiler implements CGConst { cg.addField("lo",Type.INT,ACC_PRIVATE); cg.addField("fcsr",Type.INT,ACC_PRIVATE); for(int i=1;i<32;i++) cg.addField("r" + i,Type.INT,ACC_PRIVATE); - for(int i=0;i<32;i++) cg.addField("f" + i,Type.INT,ACC_PRIVATE); - + for(int i=0;i<32;i++) cg.addField("f" + i,singleFloat ? Type.FLOAT : Type.INT,ACC_PRIVATE); + + // clinit = cg.addMethod("",Type.VOID,Type.NO_ARGS,ACC_PRIVATE|ACC_STATIC); - + + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.UnixRuntime. + + // init = cg.addMethod("",Type.VOID,Type.NO_ARGS,ACC_PUBLIC); init.add(ALOAD_0); init.add(LDC,pageSize); @@ -87,11 +105,31 @@ public class ClassFileCompiler extends Compiler implements CGConst { init.add(INVOKESPECIAL,new MethodRef(me,"",Type.VOID,new Type[]{Type.INT,Type.INT})); init.add(RETURN); + // (Z) + init = cg.addMethod("",Type.VOID,new Type[]{Type.BOOLEAN},ACC_PUBLIC); + init.add(ALOAD_0); + init.add(LDC,pageSize); + init.add(LDC,totalPages); + init.add(ILOAD_1); + init.add(INVOKESPECIAL,new MethodRef(me,"",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN})); + init.add(RETURN); + + // (II) init = cg.addMethod("",Type.VOID,new Type[]{Type.INT,Type.INT},ACC_PUBLIC); init.add(ALOAD_0); init.add(ILOAD_1); init.add(ILOAD_2); - init.add(INVOKESPECIAL,new MethodRef(superClass,"",Type.VOID,new Type[]{Type.INT,Type.INT})); + init.add(ICONST_0); + init.add(INVOKESPECIAL,new MethodRef(me,"",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN})); + init.add(RETURN); + + // (IIZ) + init = cg.addMethod("",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN},ACC_PUBLIC); + init.add(ALOAD_0); + init.add(ILOAD_1); + init.add(ILOAD_2); + init.add(ILOAD_3); + init.add(INVOKESPECIAL,new MethodRef(superClass,"",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN})); if(onePage) { cg.addField("page",Type.arrayType(Type.INT),ACC_PRIVATE|ACC_FINAL); @@ -203,15 +241,19 @@ public class ClassFileCompiler extends Compiler implements CGConst { tramp.add(LDC,")"); tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.STRING})); tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"toString",Type.STRING,Type.NO_ARGS)); + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime$ExecutionException. tramp.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"",Type.VOID,new Type[]{Type.STRING})); tramp.add(ATHROW); + + if(false) { try { tramp.finish(); } catch(ClassGen.Exn e) { e.printStackTrace(warn); throw new Exn("Generation of the trampoline method failed. Try increasing maxInsnPerMethod"); } + } addConstReturnMethod("gp",gp.addr); addConstReturnMethod("entryPoint",elf.header.entry); @@ -239,6 +281,8 @@ public class ClassFileCompiler extends Compiler implements CGConst { ls.add(IRETURN); } + // Kind of a hack, referencing dup() gets us all the fields for free + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime$CPUState.dup Type.Object cpuStateType = new Type.Object("org.ibex.nestedvm.Runtime$CPUState"); MethodGen setCPUState = cg.addMethod("setCPUState",Type.VOID,new Type[]{cpuStateType},ACC_PROTECTED); MethodGen getCPUState = cg.addMethod("getCPUState",Type.VOID,new Type[]{cpuStateType},ACC_PROTECTED); @@ -276,12 +320,14 @@ public class ClassFileCompiler extends Compiler implements CGConst { setCPUState.add(ALOAD_2); setCPUState.add(LDC,i); setCPUState.add(IALOAD); - setCPUState.add(PUTFIELD,new FieldRef(me,"f"+i,Type.INT)); + if(singleFloat) setCPUState.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"intBitsToFloat",Type.FLOAT,new Type[]{Type.INT})); + setCPUState.add(PUTFIELD,new FieldRef(me,"f"+i,singleFloat ? Type.FLOAT : Type.INT)); getCPUState.add(ALOAD_2); getCPUState.add(LDC,i); getCPUState.add(ALOAD_0); - getCPUState.add(GETFIELD,new FieldRef(me,"f"+i,Type.INT)); + getCPUState.add(GETFIELD,new FieldRef(me,"f"+i,singleFloat ? Type.FLOAT: Type.INT)); + if(singleFloat) getCPUState.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"floatToIntBits",Type.INT,new Type[]{Type.FLOAT})); getCPUState.add(IASTORE); } @@ -313,6 +359,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { execute.add(NEW, new Type.Object("org.ibex.nestedvm.Runtime$FaultException")); execute.add(DUP); execute.add(ALOAD_1); + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime$FaultException. execute.add(INVOKESPECIAL,new MethodRef("org.ibex.nestedvm.Runtime$FaultException","",Type.VOID,new Type[]{new Type.Object("java.lang.RuntimeException")})); execute.add(ATHROW); @@ -327,14 +374,21 @@ public class ClassFileCompiler extends Compiler implements CGConst { main.add(ALOAD_0); if(unixRuntime) { Type.Object ur = new Type.Object("org.ibex.nestedvm.UnixRuntime"); + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.runAndExec main.add(INVOKESTATIC,new MethodRef(ur,"runAndExec",Type.INT,new Type[]{ur,Type.STRING,Type.arrayType(Type.STRING)})); } else { + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.run main.add(INVOKEVIRTUAL,new MethodRef(me,"run",Type.INT,new Type[]{Type.STRING,Type.arrayType(Type.STRING)})); } main.add(INVOKESTATIC,new MethodRef(new Type.Object("java.lang.System"),"exit",Type.VOID,new Type[]{Type.INT})); main.add(RETURN); - cg.dump(os); + if(outDir != null) { + if(!outDir.isDirectory()) throw new IOException("" + outDir + " isn't a directory"); + cg.dump(outDir); + } else { + cg.dump(os); + } } private void addConstReturnMethod(String name, int val) { @@ -365,13 +419,14 @@ public class ClassFileCompiler extends Compiler implements CGConst { clinit.add(LDC,sb.toString()); clinit.add(LDC,segSize/4); + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.decodeData clinit.add(INVOKESTATIC,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime"),"decodeData",Type.arrayType(Type.INT),new Type[]{Type.STRING,Type.INT})); clinit.add(PUTSTATIC,new FieldRef(me,fieldname,Type.arrayType(Type.INT))); - init.add(ALOAD_0); init.add(GETSTATIC,new FieldRef(me,fieldname,Type.arrayType(Type.INT))); init.add(LDC,addr); init.add(LDC,readOnly ? 1 : 0); + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.initPages init.add(INVOKEVIRTUAL,new MethodRef(me,"initPages",Type.VOID,new Type[]{Type.arrayType(Type.INT),Type.INT,Type.BOOLEAN})); addr += segSize; @@ -388,14 +443,13 @@ public class ClassFileCompiler extends Compiler implements CGConst { init.add(ALOAD_0); init.add(LDC,addr); init.add(LDC,count); + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.clearPages init.add(INVOKEVIRTUAL,new MethodRef(me,"clearPages",Type.VOID,new Type[]{Type.INT,Type.INT})); } // Method state info - private boolean textDone; // a text segment was already processed private int startOfMethod = 0; // the start of this method (not necessarily the first instruction) private int endOfMethod = 0; // the maximum end of this method (could end before it is full) - private boolean unreachable = false; // is the current pc is reachable private MethodGen.PhantomTarget returnTarget; // where to jump when exiting the method private MethodGen.PhantomTarget defaultTarget; // the default switch target (throws exn) @@ -404,6 +458,10 @@ public class ClassFileCompiler extends Compiler implements CGConst { private boolean jumpable(int addr) { return jumpableAddresses.get(new Integer(addr)) != null; } + private static final int UNREACHABLE = 1; + private static final int SKIP_NEXT = 2; + + private boolean textDone; // a text segment was already processed private void emitText(int addr, DataInputStream dis, int size) throws Exn,IOException { if(textDone) throw new Exn("Multiple text segments"); textDone = true; @@ -411,29 +469,36 @@ public class ClassFileCompiler extends Compiler implements CGConst { if((addr&3)!=0 || (size&3)!=0) throw new Exn("Section on weird boundaries"); int count = size/4; int insn,nextInsn=-1; + boolean skipNext = true; + boolean unreachable = false; for(int i=0;i= endOfMethod) { endMethod(addr); startMethod(addr); } - if(insnTargets[(addr-startOfMethod)/4] != null) { - insnTargets[(addr-startOfMethod)/4].setTarget(mg.size()); + if(addr >= endOfMethod) { endMethod(addr,unreachable); startMethod(addr); } + if(insnTargets[i%maxInsnPerMethod] != null) { + insnTargets[i%maxInsnPerMethod].setTarget(mg.size()); unreachable = false; } else if(unreachable) { continue; } try { - skipNext = emitInstruction(addr,insn,nextInsn); + int ret = emitInstruction(addr,insn,nextInsn); + unreachable = (ret & UNREACHABLE) != 0; + skipNext = (ret & SKIP_NEXT) != 0; + } catch(Exn e) { + e.printStackTrace(warn); + warn.println("Exception at " + toHex(addr)); + throw e; } catch(RuntimeException e) { warn.println("Exception at " + toHex(addr)); throw e; } if(skipNext) { addr+=4; i++; } } - endMethod(0); + endMethod(0,unreachable); dis.close(); - mg.finish(); } private void startMethod(int first) { @@ -480,7 +545,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { mg.add(LOOKUPSWITCH,lsi); } - private void endMethod(int firstAddrOfNext) { + private void endMethod(int firstAddrOfNext,boolean unreachable) { if(startOfMethod == 0) return; if(!unreachable) { @@ -555,7 +620,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { } // This assumes everything needed by ifInsn is already on the stack - private boolean doIfInstruction(byte op, int pc, int target, int nextInsn) throws Exn { + private int doIfInstruction(byte op, int pc, int target, int nextInsn) throws Exn { emitInstruction(-1,nextInsn,-1); // delay slot if((target&methodMask) == (pc&methodMask)) { mg.add(op,insnTargets[(target-startOfMethod)/4]); @@ -564,7 +629,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { branch(pc,target); mg.setArg(h,mg.size()); } - if(!jumpable(pc+4)) return true; // done - skip it + if(!jumpable(pc+4)) return SKIP_NEXT; // done - skip it //System.err.println("Delay slot is jumpable - This code is untested + " + toHex(nextInsn)); if(pc+4==endOfMethod) { @@ -572,8 +637,9 @@ public class ClassFileCompiler extends Compiler implements CGConst { jumpableAddresses.put(new Integer(pc+8),Boolean.TRUE); // make the 2nd insn of the next method jumpable branch(pc,pc+8); // jump over it //System.err.println("delay slot: " + toHex(pc+8)); */ - unreachable = true; - return false; // we still need to output it + //unreachable = true; + //return false; // we still need to output it + return UNREACHABLE; } else { //System.err.println("jumped over delay slot: " + toHex(pc+4)); // add another copy and jump over @@ -583,7 +649,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { emitInstruction(-1,nextInsn,01); // delay slot mg.setArg(b,mg.size()); - return true; + return SKIP_NEXT; } } @@ -591,10 +657,12 @@ public class ClassFileCompiler extends Compiler implements CGConst { private static final Double POINT_5_D = new Double(0.5f); private static final Long FFFFFFFF = new Long(0xffffffffL); - private boolean emitInstruction(int pc, int insn, int nextInsn) throws Exn { + private int emitInstruction(int pc, int insn, int nextInsn) throws Exn { MethodGen mg = this.mg; // smaller bytecode if(insn == -1) throw new Exn("insn is -1"); + int ret = 0; + int op = (insn >>> 26) & 0xff; // bits 26-31 int rs = (insn >>> 21) & 0x1f; // bits 21-25 int rt = (insn >>> 16) & 0x1f; // bits 16-20 @@ -605,12 +673,12 @@ public class ClassFileCompiler extends Compiler implements CGConst { int fd = (insn >>> 6) & 0x1f; int subcode = insn & 0x3f; // bits 0-5 int breakCode = (insn >>> 6) & 0xfffff; // bits 6-20 - + int jumpTarget = (insn & 0x03ffffff); // bits 0-25 int unsignedImmediate = insn & 0xffff; int signedImmediate = (insn << 16) >> 16; int branchTarget = signedImmediate; - + // temporaries int b1,b2; @@ -667,7 +735,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { pushRegWZ(R+rs); setPC(); leaveMethod(); - unreachable = true; + ret |= UNREACHABLE; break; case 9: // JALR if(pc == -1) throw new Exn("pc modifying insn in delay slot"); @@ -677,7 +745,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { pushRegWZ(R+rs); setPC(); leaveMethod(); - unreachable = true; + ret |= UNREACHABLE; break; case 12: // SYSCALL preSetPC(); @@ -697,6 +765,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { pushRegZ(R+A3); pushRegZ(R+T0); pushRegZ(R+T1); + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.syscall 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})); setReg(); @@ -715,7 +784,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { mg.add(LDC,"BREAK Code " + toHex(breakCode)); mg.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"",Type.VOID,new Type[]{Type.STRING})); mg.add(ATHROW); - unreachable = true; + ret |= UNREACHABLE; break; case 16: // MFHI preSetReg(R+rd); @@ -981,7 +1050,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { link(pc); branch(pc,pc+branchTarget*4+4); if(b1 != -1) mg.setArg(b1,mg.size()); - if(b1 == -1) unreachable = true; + if(b1 == -1) ret |= UNREACHABLE; break; default: throw new Exn("Illegal Instruction 1/" + rt); @@ -992,7 +1061,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { if(pc == -1) throw new Exn("pc modifying insn in delay slot"); emitInstruction(-1,nextInsn,-1); branch(pc,(pc&0xf0000000)|(jumpTarget << 2)); - unreachable = true; + ret |= UNREACHABLE; break; } case 3: { // JAL @@ -1001,7 +1070,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { emitInstruction(-1,nextInsn,-1); link(pc); branch(pc, target); - unreachable = true; + ret |= UNREACHABLE; break; } case 4: // BEQ @@ -1009,7 +1078,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { if(rs == rt) { emitInstruction(-1,nextInsn,-1); branch(pc,pc+branchTarget*4+4); - unreachable = true; + ret |= UNREACHABLE; } else if(rs == 0 || rt == 0) { pushReg(rt == 0 ? R+rs : R+rt); return doIfInstruction(IFEQ,pc,pc+branchTarget*4+4,nextInsn); @@ -1039,9 +1108,15 @@ public class ClassFileCompiler extends Compiler implements CGConst { case 8: // ADDI throw new Exn("ADDI (add immediate with oveflow trap) not suported"); case 9: // ADDIU - preSetReg(R+rt); - addiu(rs,signedImmediate); - setReg(); + if(rs != 0 && signedImmediate != 0 && rs == rt && doLocal(rt) && signedImmediate >= -32768 && signedImmediate <= 32767) { + // HACK: This should be a little cleaner + regLocalWritten[rt] = true; + mg.add(IINC, new MethodGen.Pair(getLocalForReg(rt),signedImmediate)); + } else { + preSetReg(R+rt); + addiu(rs,signedImmediate); + setReg(); + } break; case 10: // SLTI preSetReg(R+rt); @@ -1120,10 +1195,8 @@ public class ClassFileCompiler extends Compiler implements CGConst { break; case 4: // MTC.1 preSetReg(F+rd); - if(rt != 0) - pushReg(R+rt); - else - mg.add(LDC,0); + if(rt != 0) pushReg(R+rt); + else mg.add(ICONST_0); setReg(); break; case 6: // CTC.1 @@ -1198,13 +1271,12 @@ public class ClassFileCompiler extends Compiler implements CGConst { preSetReg(F+fd); pushReg(F+fs); setReg(); - + if(d) { preSetReg(F+fd+1); pushReg(F+fs+1); setReg(); } - break; case 7: // NEG.X preSetDouble(F+fd,d); @@ -1658,7 +1730,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { default: throw new Exn("Invalid Instruction: " + op + " at " + toHex(pc)); } - return false; + return ret; } // Helper functions for emitText @@ -1669,14 +1741,25 @@ public class ClassFileCompiler extends Compiler implements CGConst { private static final int LO = 65; private static final int FCSR = 66; private static final int REG_COUNT=67; - + private static final String[] regField = { + "r0","r1","r2","r3","r4","r5","r6","r7", + "r8","r9","r10","r11","r12","r13","r14","r15", + "r16","r17","r18","r19","r20","r21","r22","r23", + "r24","r25","r26","r27","r28","r29","r30","r31", + "f0","f1","f2","f3","f4","f5","f6","f7", + "f8","f9","f10","f11","f12","f13","f14","f15", + "f16","f17","f18","f19","f20","f21","f22","f23", + "f24","f25","f26","f27","f28","f29","f30","f31", + "hi","lo","fcsr" + }; + private static final int MAX_LOCALS = 4; // doLocal can return true for this many regs + private static final int LOAD_LENGTH = 3; // number of instructions needed to load a field to a reg + + // Local register state info private int[] regLocalMapping = new int[REG_COUNT]; - private int[] regLocalReadCount = new int[REG_COUNT]; - private int[] regLocalWriteCount = new int[REG_COUNT]; - private int nextAvailLocal; + private boolean[] regLocalWritten = new boolean[REG_COUNT]; + private int nextAvailLocal; private int loadsStart; - private static final int MAX_LOCALS = 4; - private static final int LOAD_LENGTH = 3; private boolean doLocal(int reg) { return reg == R+2 || reg == R+3 || reg == R+4 || reg == R+29; @@ -1684,15 +1767,16 @@ public class ClassFileCompiler extends Compiler implements CGConst { private int getLocalForReg(int reg) { if(regLocalMapping[reg] != 0) return regLocalMapping[reg]; - if(nextAvailLocal == 0) nextAvailLocal = onePage ? 3 : 4; regLocalMapping[reg] = nextAvailLocal++; return regLocalMapping[reg]; } private void fixupRegsStart() { - for(int i=0;i 0) { + if(regLocalWritten[i]) { mg.add(ALOAD_0); mg.add(ILOAD,regLocalMapping[i]); - mg.add(PUTFIELD,new FieldRef(me,regField(i),Type.INT)); + mg.add(PUTFIELD,new FieldRef(me,regField[i],Type.INT)); } } } private void restoreChangedRegs() { for(int i=0;i 0) { + if(regLocalWritten[i]) { mg.add(ALOAD_0); mg.add(ILOAD,regLocalMapping[i]); - mg.add(PUTFIELD,new FieldRef(me,regField(i),Type.INT)); + mg.add(PUTFIELD,new FieldRef(me,regField[i],Type.INT)); } } } - - private static final String[] regField = { - "r0","r1","r2","r3","r4","r5","r6","r7", - "r8","r9","r10","r11","r12","r13","r14","r15", - "r16","r17","r18","r19","r20","r21","r22","r23", - "r24","r25","r26","r27","r28","r29","r30","r31", - - "f0","f1","f2","f3","f4","f5","f6","f7", - "f8","f9","f10","f11","f12","f13","f14","f15", - "f16","f17","f18","f19","f20","f21","f22","f23", - "f24","f25","f26","f27","f28","f29","f30","f31", - "hi","lo","fcsr" - }; - - private static String regField(int reg) { return regField[reg]; } - private int pushRegWZ(int reg) { if(reg == R+0) { warn.println("Warning: Pushing r0!"); @@ -1757,12 +1825,14 @@ public class ClassFileCompiler extends Compiler implements CGConst { private int pushReg(int reg) { int h = mg.size(); if(doLocal(reg)) { - regLocalReadCount[reg]++; mg.add(ILOAD,getLocalForReg(reg)); - + } else if(reg >= F+0 && reg <= F+31 && singleFloat) { + mg.add(ALOAD_0); + mg.add(GETFIELD,new FieldRef(me,regField[reg],Type.FLOAT)); + mg.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"floatToIntBits",Type.INT,new Type[]{Type.FLOAT})); } else { mg.add(ALOAD_0); - mg.add(GETFIELD,new FieldRef(me,regField(reg),Type.INT)); + mg.add(GETFIELD,new FieldRef(me,regField[reg],Type.INT)); } return h; } @@ -1772,7 +1842,6 @@ public class ClassFileCompiler extends Compiler implements CGConst { // This can push ONE or ZERO words to the stack. If it pushed one it returns true private boolean preSetReg(int reg) { - regField(reg); // just to check for validity preSetRegStack[preSetRegStackPos] = reg; preSetRegStackPos++; if(doLocal(reg)) { @@ -1790,9 +1859,12 @@ public class ClassFileCompiler extends Compiler implements CGConst { int h = mg.size(); if(doLocal(reg)) { mg.add(ISTORE,getLocalForReg(reg)); - regLocalWriteCount[reg]++; + regLocalWritten[reg] = true; + } else if(reg >= F+0 && reg <= F+31 && singleFloat) { + mg.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"intBitsToFloat",Type.FLOAT,new Type[]{Type.INT})); + mg.add(PUTFIELD,new FieldRef(me,regField[reg],Type.FLOAT)); } else { - mg.add(PUTFIELD,new FieldRef(me,regField(reg),Type.INT)); + mg.add(PUTFIELD,new FieldRef(me,regField[reg],Type.INT)); } return h; } @@ -1802,12 +1874,13 @@ public class ClassFileCompiler extends Compiler implements CGConst { return mg.add(PUTFIELD,new FieldRef(me,"pc",Type.INT)); } - //unused - private InstructionHandle pushFloat(int reg) throws CompilationException { return pushDouble(reg,false); } //unused - private InstructionHandle pushDouble(int reg) throws CompilationException { return pushDouble(reg,true); } + private int pushFloat(int reg) throws Exn { return pushDouble(reg,false); } private int pushDouble(int reg, boolean d) throws Exn { if(reg < F || reg >= F+32) throw new IllegalArgumentException(""+reg); int h = mg.size(); if(d) { + if(singleFloat) throw new Exn("Double operations not supported when singleFloat is enabled"); if(reg == F+31) throw new Exn("Tried to use a double in f31"); pushReg(reg+1); mg.add(I2L); @@ -1819,6 +1892,9 @@ public class ClassFileCompiler extends Compiler implements CGConst { mg.add(LAND); mg.add(LOR); mg.add(INVOKESTATIC,new MethodRef(Type.DOUBLE_OBJECT,"longBitsToDouble",Type.DOUBLE,new Type[]{Type.LONG})); + } else if(singleFloat) { + mg.add(ALOAD_0); + mg.add(GETFIELD,new FieldRef(me,regField[reg],Type.FLOAT)); } else { pushReg(reg); mg.add(INVOKESTATIC,new MethodRef("java.lang.Float","intBitsToFloat",Type.FLOAT,new Type[]{Type.INT})); @@ -1837,6 +1913,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { if(reg < F || reg >= F+32) throw new IllegalArgumentException(""+reg); int h = mg.size(); if(d) { + if(singleFloat) throw new Exn("Double operations not supported when singleFloat is enabled"); if(reg == F+31) throw new Exn("Tried to use a double in f31"); mg.add(INVOKESTATIC,new MethodRef(Type.DOUBLE_OBJECT,"doubleToLongBits",Type.LONG,new Type[]{Type.DOUBLE})); mg.add(DUP2); @@ -1848,6 +1925,10 @@ public class ClassFileCompiler extends Compiler implements CGConst { setReg(); mg.add(L2I); setReg(); // preSetReg was already done for this by preSetDouble + } else if(singleFloat) { + // HACK: Clean this up + preSetRegStackPos--; + mg.add(PUTFIELD,new FieldRef(me,regField[reg],Type.FLOAT)); } else { //h = a(fac.createInvoke("java.lang.Float","floatToRawIntBits",Type.INT,new Type[]{Type.FLOAT},INVOKESTATIC)); mg.add(INVOKESTATIC,new MethodRef(Type.FLOAT_OBJECT,"floatToRawIntBits",Type.INT,new Type[]{Type.FLOAT})); @@ -1896,6 +1977,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { mg.add(DUP); mg.add(ALOAD_0); mg.add(SWAP); + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.nullPointerCheck mg.add(INVOKEVIRTUAL,new MethodRef(me,"nullPointerCheck",Type.VOID,new Type[]{Type.INT})); } @@ -1929,6 +2011,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { } else if(fastMem) { mg.add(IASTORE); } else { + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.unsafeMemWrite mg.add(INVOKEVIRTUAL,new MethodRef(me,"unsafeMemWrite",Type.VOID,new Type[]{Type.INT,Type.INT})); } @@ -2000,6 +2083,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { } else { if(preMemReadDoPreWrite) mg.add(DUP2); + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.unsafeMemRead mg.add(INVOKEVIRTUAL,new MethodRef(me,"unsafeMemRead",Type.INT,new Type[]{Type.INT})); } }