X-Git-Url: http://git.megacz.com/?p=nestedvm.git;a=blobdiff_plain;f=src%2Forg%2Fibex%2Fnestedvm%2FClassFileCompiler.java;h=86954454f0d78c7096e47f2cd000ebf739c442f4;hp=d1ea2bd40775e36680799ae65f304e045647a77c;hb=c690989b7973d1a2e5aed45afe51f782f064a127;hpb=d05879bd0fed14f6f11ceb2f0772a995424e96b8 diff --git a/src/org/ibex/nestedvm/ClassFileCompiler.java b/src/org/ibex/nestedvm/ClassFileCompiler.java index d1ea2bd..8695445 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: Use BCEL to do 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,70 +36,113 @@ 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.Class me; - private ClassGen cg; - private MethodGen clinit; - private MethodGen init; - private Type.Object me; - private Type.Object superClass; + private ClassFile cg; + 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 = Type.fromClass(fullClassName); + } public void setWarnWriter(PrintStream warn) { this.warn = warn; } protected void _go() throws Exn, IOException { - if(lessConstants) throw new Exn("ClassFileCompiler doesn't support -o lessconstants"); + try { + __go(); + } catch(ClassFile.Exn e) { + 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); - cg = new ClassGen(me,superClass,ACC_PUBLIC|ACC_FINAL|ACC_SUPER); + Type.Class superClass = Type.fromClass(runtimeClass); + cg = new ClassFile(me,superClass,PUBLIC|FINAL|SUPER); if(source != null) cg.setSourceFile(source); // Fields - cg.addField("pc",Type.INT,ACC_PRIVATE); - cg.addField("hi",Type.INT,ACC_PRIVATE); - 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); - - clinit = cg.addMethod("",Type.VOID,Type.NO_ARGS,ACC_PRIVATE|ACC_STATIC); - - init = cg.addMethod("",Type.VOID,Type.NO_ARGS,ACC_PUBLIC); + cg.addField("pc",Type.INT,PRIVATE); + cg.addField("hi",Type.INT,PRIVATE); + cg.addField("lo",Type.INT,PRIVATE); + cg.addField("fcsr",Type.INT,PRIVATE); + for(int i=1;i<32;i++) cg.addField("r" + i,Type.INT,PRIVATE); + for(int i=0;i<32;i++) cg.addField("f" + i,singleFloat ? Type.FLOAT : Type.INT,PRIVATE); + + // + clinit = cg.addMethod("",Type.VOID,Type.NO_ARGS,PRIVATE|STATIC); + + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.UnixRuntime. + + // + init = cg.addMethod("",Type.VOID,Type.NO_ARGS,PUBLIC); init.add(ALOAD_0); init.add(LDC,pageSize); init.add(LDC,totalPages); - init.add(INVOKESPECIAL,new MethodRef(me,"",Type.VOID,new Type[]{Type.INT,Type.INT})); + init.add(INVOKESPECIAL,me.method("",Type.VOID,new Type[]{Type.INT,Type.INT})); init.add(RETURN); - init = cg.addMethod("",Type.VOID,new Type[]{Type.INT,Type.INT},ACC_PUBLIC); + // (Z) + init = cg.addMethod("",Type.VOID,new Type[]{Type.BOOLEAN},PUBLIC); + init.add(ALOAD_0); + init.add(LDC,pageSize); + init.add(LDC,totalPages); + init.add(ILOAD_1); + init.add(INVOKESPECIAL,me.method("",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},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,me.method("",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},PUBLIC); + init.add(ALOAD_0); + init.add(ILOAD_1); + init.add(ILOAD_2); + init.add(ILOAD_3); + init.add(INVOKESPECIAL,superClass.method("",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN})); if(onePage) { - cg.addField("page",Type.arrayType(Type.INT),ACC_PRIVATE|ACC_FINAL); + cg.addField("page",Type.INT.makeArray(),PRIVATE|FINAL); init.add(ALOAD_0); init.add(DUP); - init.add(GETFIELD,new FieldRef(me,"readPages",Type.arrayType(Type.INT,2))); + init.add(GETFIELD,me.field("readPages",Type.INT.makeArray(2))); init.add(LDC,0); init.add(AALOAD); - init.add(PUTFIELD,new FieldRef(me,"page",Type.arrayType(Type.INT))); + init.add(PUTFIELD,me.field("page",Type.INT.makeArray())); } if(supportCall) - cg.addField("symbols",new Type.Object(hashClass),ACC_PRIVATE|ACC_STATIC|ACC_FINAL); + cg.addField("symbols",Type.fromClass(hashClass),PRIVATE|STATIC|FINAL); int highestAddr = 0; @@ -123,12 +169,12 @@ public class ClassFileCompiler extends Compiler implements CGConst { // Finish clinit if(supportCall) { - Type.Object hash = new Type.Object(hashClass); + Type.Class hash = Type.fromClass(hashClass); clinit.add(NEW,hash); clinit.add(DUP); clinit.add(DUP); - clinit.add(INVOKESPECIAL,new MethodRef(hash,"",Type.VOID,Type.NO_ARGS)); - clinit.add(PUTSTATIC,new FieldRef(me,"symbols",hash)); + clinit.add(INVOKESPECIAL,hash.method("",Type.VOID,Type.NO_ARGS)); + clinit.add(PUTSTATIC,me.field("symbols",hash)); ELF.Symbol[] symbols = elf.getSymtab().symbols; for(int i=0;i",Type.VOID,new Type[]{Type.INT})); - clinit.add(INVOKEVIRTUAL,new MethodRef(hash,"put",Type.OBJECT,new Type[]{Type.OBJECT,Type.OBJECT})); + clinit.add(INVOKESPECIAL,Type.INTEGER_OBJECT.method("",Type.VOID,new Type[]{Type.INT})); + clinit.add(INVOKEVIRTUAL,hash.method("put",Type.OBJECT,new Type[]{Type.OBJECT,Type.OBJECT})); clinit.add(POP); } } @@ -151,63 +197,54 @@ public class ClassFileCompiler extends Compiler implements CGConst { ELF.SHeader text = elf.sectionWithName(".text"); // Trampoline - MethodGen tramp = cg.addMethod("trampoline",Type.VOID,Type.NO_ARGS,ACC_PRIVATE); + MethodGen tramp = cg.addMethod("trampoline",Type.VOID,Type.NO_ARGS,PRIVATE); int start = tramp.size(); tramp.add(ALOAD_0); - tramp.add(GETFIELD,new FieldRef(me,"state",Type.INT)); - tramp.add(LDC,Runtime.RUNNING); + tramp.add(GETFIELD,me.field("state",Type.INT)); + tramp.add(IFEQ,tramp.size()+2); + tramp.add(RETURN); - int stateCheck = tramp.add(IF_ICMPNE); tramp.add(ALOAD_0); tramp.add(ALOAD_0); - tramp.add(GETFIELD,new FieldRef(me,"pc",Type.INT)); + tramp.add(GETFIELD,me.field("pc",Type.INT)); tramp.add(LDC,methodShift); tramp.add(IUSHR); int beg = text.addr >>> methodShift; int end = ((text.addr + text.size + maxBytesPerMethod - 1) >>> methodShift); - MethodGen.TSI tsi = new MethodGen.TSI(beg,end-1); + MethodGen.Switch.Table tsi = new MethodGen.Switch.Table(beg,end-1); tramp.add(TABLESWITCH,tsi); for(int n=beg;n",Type.VOID,new Type[]{Type.STRING})); + tramp.add(INVOKESPECIAL,Type.STRINGBUFFER.method("",Type.VOID,new Type[]{Type.STRING})); tramp.add(ALOAD_0); - tramp.add(GETFIELD, new FieldRef(me,"r2",Type.INT)); - tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.INT})); + tramp.add(GETFIELD, me.field("r2",Type.INT)); + tramp.add(INVOKEVIRTUAL,Type.STRINGBUFFER.method("append",Type.STRINGBUFFER,new Type[]{Type.INT})); tramp.add(LDC," pc: "); - tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.STRING})); + tramp.add(INVOKEVIRTUAL,Type.STRINGBUFFER.method("append",Type.STRINGBUFFER,new Type[]{Type.STRING})); tramp.add(ALOAD_0); - tramp.add(GETFIELD, new FieldRef(me,"pc",Type.INT)); - tramp.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.INT})); + tramp.add(GETFIELD, me.field("pc",Type.INT)); + tramp.add(INVOKEVIRTUAL,Type.STRINGBUFFER.method("append",Type.STRINGBUFFER,new Type[]{Type.INT})); 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)); - tramp.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"",Type.VOID,new Type[]{Type.STRING})); + tramp.add(INVOKEVIRTUAL,Type.STRINGBUFFER.method("append",Type.STRINGBUFFER,new Type[]{Type.STRING})); + tramp.add(INVOKEVIRTUAL,Type.STRINGBUFFER.method("toString",Type.STRING,Type.NO_ARGS)); + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime$ExecutionException. + tramp.add(INVOKESPECIAL,Type.fromClass("org.ibex.nestedvm.Runtime$ExecutionException").method("",Type.VOID,new Type[]{Type.STRING})); tramp.add(ATHROW); - tramp.setArg(stateCheck,tramp.size()); - tramp.add(RETURN); - - 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); addConstReturnMethod("heapStart",highestAddr); @@ -218,15 +255,15 @@ public class ClassFileCompiler extends Compiler implements CGConst { } if(supportCall) { - Type.Object hashClassType = new Type.Object(hashClass); - MethodGen ls = cg.addMethod("lookupSymbol",Type.INT,new Type[]{Type.STRING},ACC_PROTECTED); - ls.add(GETSTATIC,new FieldRef(me,"symbols",hashClassType)); + Type.Class hashClassType = Type.fromClass(hashClass); + MethodGen ls = cg.addMethod("lookupSymbol",Type.INT,new Type[]{Type.STRING},PROTECTED); + ls.add(GETSTATIC,me.field("symbols",hashClassType)); ls.add(ALOAD_1); - ls.add(INVOKEVIRTUAL,new MethodRef(hashClassType,"get",Type.OBJECT,new Type[]{Type.OBJECT})); + ls.add(INVOKEVIRTUAL,hashClassType.method("get",Type.OBJECT,new Type[]{Type.OBJECT})); ls.add(DUP); int b = ls.add(IFNULL); ls.add(CHECKCAST,Type.INTEGER_OBJECT); - ls.add(INVOKEVIRTUAL,new MethodRef(Type.INTEGER_OBJECT,"intValue",Type.INT,Type.NO_ARGS)); + ls.add(INVOKEVIRTUAL,Type.INTEGER_OBJECT.method("intValue",Type.INT,Type.NO_ARGS)); ls.add(IRETURN); ls.setArg(b,ls.size()); ls.add(POP); @@ -234,14 +271,16 @@ public class ClassFileCompiler extends Compiler implements CGConst { ls.add(IRETURN); } - 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); + // 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.Class cpuStateType = Type.fromClass("org.ibex.nestedvm.Runtime$CPUState"); + MethodGen setCPUState = cg.addMethod("setCPUState",Type.VOID,new Type[]{cpuStateType},PROTECTED); + MethodGen getCPUState = cg.addMethod("getCPUState",Type.VOID,new Type[]{cpuStateType},PROTECTED); setCPUState.add(ALOAD_1); getCPUState.add(ALOAD_1); - setCPUState.add(GETFIELD,new FieldRef(cpuStateType,"r",Type.arrayType(Type.INT))); - getCPUState.add(GETFIELD,new FieldRef(cpuStateType,"r",Type.arrayType(Type.INT))); + setCPUState.add(GETFIELD,cpuStateType.field("r",Type.INT.makeArray())); + getCPUState.add(GETFIELD,cpuStateType.field("r",Type.INT.makeArray())); setCPUState.add(ASTORE_2); getCPUState.add(ASTORE_2); @@ -250,19 +289,19 @@ public class ClassFileCompiler extends Compiler implements CGConst { setCPUState.add(ALOAD_2); setCPUState.add(LDC,i); setCPUState.add(IALOAD); - setCPUState.add(PUTFIELD,new FieldRef(me,"r"+i,Type.INT)); + setCPUState.add(PUTFIELD,me.field("r"+i,Type.INT)); getCPUState.add(ALOAD_2); getCPUState.add(LDC,i); getCPUState.add(ALOAD_0); - getCPUState.add(GETFIELD,new FieldRef(me,"r"+i,Type.INT)); + getCPUState.add(GETFIELD,me.field("r"+i,Type.INT)); getCPUState.add(IASTORE); } setCPUState.add(ALOAD_1); getCPUState.add(ALOAD_1); - setCPUState.add(GETFIELD,new FieldRef(cpuStateType,"f",Type.arrayType(Type.INT))); - getCPUState.add(GETFIELD,new FieldRef(cpuStateType,"f",Type.arrayType(Type.INT))); + setCPUState.add(GETFIELD,cpuStateType.field("f",Type.INT.makeArray())); + getCPUState.add(GETFIELD,cpuStateType.field("f",Type.INT.makeArray())); setCPUState.add(ASTORE_2); getCPUState.add(ASTORE_2); @@ -271,12 +310,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,Type.FLOAT_OBJECT.method("intBitsToFloat",Type.FLOAT,new Type[]{Type.INT})); + setCPUState.add(PUTFIELD,me.field("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,me.field("f"+i,singleFloat ? Type.FLOAT: Type.INT)); + if(singleFloat) getCPUState.add(INVOKESTATIC,Type.FLOAT_OBJECT.method("floatToIntBits",Type.INT,new Type[]{Type.FLOAT})); getCPUState.add(IASTORE); } @@ -284,56 +325,64 @@ public class ClassFileCompiler extends Compiler implements CGConst { for(int i=0;i",Type.VOID,new Type[]{new Type.Object("java.lang.RuntimeException")})); + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime$FaultException. + execute.add(INVOKESPECIAL,Type.fromClass("org.ibex.nestedvm.Runtime$FaultException").method("",Type.VOID,new Type[]{Type.fromClass("java.lang.RuntimeException")})); execute.add(ATHROW); - execute.addExceptionHandler(tryStart,tryEnd,catchInsn,new Type.Object("java.lang.RuntimeException")); - execute.addThrow(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException")); + execute.addExceptionHandler(tryStart,tryEnd,catchInsn,Type.fromClass("java.lang.RuntimeException")); + execute.addThrow(Type.fromClass("org.ibex.nestedvm.Runtime$ExecutionException")); - MethodGen main = cg.addMethod("main",Type.VOID,new Type[]{Type.arrayType(Type.STRING)},ACC_STATIC|ACC_PUBLIC); + MethodGen main = cg.addMethod("main",Type.VOID,new Type[]{Type.STRING.makeArray()},STATIC|PUBLIC); main.add(NEW,me); main.add(DUP); - main.add(INVOKESPECIAL,new MethodRef(me,"",Type.VOID,Type.NO_ARGS)); + main.add(INVOKESPECIAL,me.method("",Type.VOID,Type.NO_ARGS)); main.add(LDC,fullClassName); main.add(ALOAD_0); if(unixRuntime) { - Type.Object ur = new Type.Object("org.ibex.nestedvm.UnixRuntime"); - main.add(INVOKESTATIC,new MethodRef(ur,"runAndExec",Type.INT,new Type[]{ur,Type.STRING,Type.arrayType(Type.STRING)})); + Type.Class ur = Type.fromClass("org.ibex.nestedvm.UnixRuntime"); + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.runAndExec + main.add(INVOKESTATIC,ur.method("runAndExec",Type.INT,new Type[]{ur,Type.STRING,Type.STRING.makeArray()})); } else { - main.add(INVOKEVIRTUAL,new MethodRef(me,"run",Type.INT,new Type[]{Type.STRING,Type.arrayType(Type.STRING)})); + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.run + main.add(INVOKEVIRTUAL,me.method("run",Type.INT,new Type[]{Type.STRING,Type.STRING.makeArray()})); } - main.add(INVOKESTATIC,new MethodRef(new Type.Object("java.lang.System"),"exit",Type.VOID,new Type[]{Type.INT})); + main.add(INVOKESTATIC,Type.fromClass("java.lang.System").method("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) { - MethodGen m = cg.addMethod(name,Type.INT,Type.NO_ARGS,ACC_PROTECTED); + MethodGen m = cg.addMethod(name,Type.INT,Type.NO_ARGS,PROTECTED); m.add(LDC,val); m.add(IRETURN); } @@ -356,18 +405,19 @@ public class ClassFileCompiler extends Compiler implements CGConst { sb.append((char) ((l>>>(7*(7-j)))&0x7f)); } String fieldname = "_data" + (++initDataCount); - cg.addField(fieldname,Type.arrayType(Type.INT),ACC_PRIVATE|ACC_STATIC|ACC_FINAL); + cg.addField(fieldname,Type.INT.makeArray(),PRIVATE|STATIC|FINAL); clinit.add(LDC,sb.toString()); clinit.add(LDC,segSize/4); - 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))); - + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.decodeData + clinit.add(INVOKESTATIC,Type.fromClass("org.ibex.nestedvm.Runtime").method("decodeData",Type.INT.makeArray(),new Type[]{Type.STRING,Type.INT})); + clinit.add(PUTSTATIC,me.field(fieldname,Type.INT.makeArray())); init.add(ALOAD_0); - init.add(GETSTATIC,new FieldRef(me,fieldname,Type.arrayType(Type.INT))); + init.add(GETSTATIC,me.field(fieldname,Type.INT.makeArray())); init.add(LDC,addr); init.add(LDC,readOnly ? 1 : 0); - init.add(INVOKEVIRTUAL,new MethodRef(me,"initPages",Type.VOID,new Type[]{Type.arrayType(Type.INT),Type.INT,Type.BOOLEAN})); + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.initPages + init.add(INVOKEVIRTUAL,me.method("initPages",Type.VOID,new Type[]{Type.INT.makeArray(),Type.INT,Type.BOOLEAN})); addr += segSize; size -= segSize; @@ -383,14 +433,13 @@ public class ClassFileCompiler extends Compiler implements CGConst { init.add(ALOAD_0); init.add(LDC,addr); init.add(LDC,count); - init.add(INVOKEVIRTUAL,new MethodRef(me,"clearPages",Type.VOID,new Type[]{Type.INT,Type.INT})); + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.clearPages + init.add(INVOKEVIRTUAL,me.method("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) @@ -399,6 +448,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; @@ -406,46 +459,53 @@ 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) { startOfMethod = first & methodMask; endOfMethod = startOfMethod + maxBytesPerMethod; - mg = cg.addMethod("run_" + toHex(startOfMethod),Type.VOID,Type.NO_ARGS,ACC_PRIVATE|ACC_FINAL); + mg = cg.addMethod("run_" + toHex(startOfMethod),Type.VOID,Type.NO_ARGS,PRIVATE|FINAL); if(onePage) { mg.add(ALOAD_0); - mg.add(GETFIELD,new FieldRef(me,"page",Type.arrayType(Type.INT))); + mg.add(GETFIELD,me.field("page",Type.INT.makeArray())); mg.add(ASTORE_2); } else { mg.add(ALOAD_0); - mg.add(GETFIELD,new FieldRef(me,"readPages",Type.arrayType(Type.INT,2))); + mg.add(GETFIELD,me.field("readPages",Type.INT.makeArray(2))); mg.add(ASTORE_2); mg.add(ALOAD_0); - mg.add(GETFIELD,new FieldRef(me,"writePages",Type.arrayType(Type.INT,2))); + mg.add(GETFIELD,me.field("writePages",Type.INT.makeArray(2))); mg.add(ASTORE_3); } @@ -463,7 +523,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { } } - MethodGen.LSI lsi = new MethodGen.LSI(n); + MethodGen.Switch.Lookup lsi = new MethodGen.Switch.Lookup(n); System.arraycopy(buf,0,lsi.vals,0,n); System.arraycopy(targetBuf,0,lsi.targets,0,n); lsi.setDefaultTarget(defaultTarget = new MethodGen.PhantomTarget()); @@ -471,11 +531,11 @@ public class ClassFileCompiler extends Compiler implements CGConst { fixupRegsStart(); mg.add(ALOAD_0); - mg.add(GETFIELD,new FieldRef(me,"pc",Type.INT)); + mg.add(GETFIELD,me.field("pc",Type.INT)); mg.add(LOOKUPSWITCH,lsi); } - private void endMethod(int firstAddrOfNext) { + private void endMethod(int firstAddrOfNext,boolean unreachable) { if(startOfMethod == 0) return; if(!unreachable) { @@ -495,23 +555,23 @@ public class ClassFileCompiler extends Compiler implements CGConst { defaultTarget.setTarget(mg.size()); if(debugCompiler) { - mg.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException")); + mg.add(NEW,Type.fromClass("org.ibex.nestedvm.Runtime$ExecutionException")); mg.add(DUP); mg.add(NEW,Type.STRINGBUFFER); mg.add(DUP); mg.add(LDC,"Jumped to invalid address: "); - mg.add(INVOKESPECIAL,new MethodRef(Type.STRINGBUFFER,"",Type.VOID,new Type[]{Type.STRING})); + mg.add(INVOKESPECIAL,Type.STRINGBUFFER.method("",Type.VOID,new Type[]{Type.STRING})); mg.add(ALOAD_0); - mg.add(GETFIELD,new FieldRef(me,"pc",Type.INT)); - mg.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"append",Type.STRINGBUFFER,new Type[]{Type.INT})); - mg.add(INVOKEVIRTUAL,new MethodRef(Type.STRINGBUFFER,"toString",Type.STRING,Type.NO_ARGS)); - mg.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"",Type.VOID,new Type[]{Type.STRING})); + mg.add(GETFIELD,me.field("pc",Type.INT)); + mg.add(INVOKEVIRTUAL,Type.STRINGBUFFER.method("append",Type.STRINGBUFFER,new Type[]{Type.INT})); + mg.add(INVOKEVIRTUAL,Type.STRINGBUFFER.method("toString",Type.STRING,Type.NO_ARGS)); + mg.add(INVOKESPECIAL,Type.fromClass("org.ibex.nestedvm.Runtime$ExecutionException").method("",Type.VOID,new Type[]{Type.STRING})); mg.add(ATHROW); } else { - mg.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException")); + mg.add(NEW,Type.fromClass("org.ibex.nestedvm.Runtime$ExecutionException")); mg.add(DUP); mg.add(LDC,"Jumped to invalid address"); - mg.add(INVOKESPECIAL,new MethodRef(new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"),"",Type.VOID,new Type[]{Type.STRING})); + mg.add(INVOKESPECIAL,Type.fromClass("org.ibex.nestedvm.Runtime$ExecutionException").method("",Type.VOID,new Type[]{Type.STRING})); mg.add(ATHROW); } @@ -522,6 +582,21 @@ public class ClassFileCompiler extends Compiler implements CGConst { private void leaveMethod() { mg.add(GOTO,returnTarget); } + + private void link(int mypc) { + preSetReg(R+RA); + if(lessConstants){ + int ref = (mypc+8 + 32768) & ~65535; + int diff = (mypc+8) - ref; + if(diff < -32768 || diff > 32767) throw new Error("should never happen " + diff); + mg.add(LDC,ref); + mg.add(LDC,diff); + mg.add(IADD); + } else { + mg.add(LDC,mypc+8); + } + setReg(); + } private void branch(int pc, int target) { if((pc&methodMask) == (target&methodMask)) { @@ -535,7 +610,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]); @@ -544,7 +619,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) { @@ -552,17 +627,19 @@ 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 int b = mg.add(GOTO); + insnTargets[(pc+4-startOfMethod)/4].setTarget(mg.size()); emitInstruction(-1,nextInsn,01); // delay slot mg.setArg(b,mg.size()); - return true; + return SKIP_NEXT; } } @@ -570,10 +647,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 @@ -584,12 +663,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; @@ -646,26 +725,25 @@ 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"); emitInstruction(-1,nextInsn,-1); + link(pc); preSetPC(); pushRegWZ(R+rs); setPC(); - - preSetReg(R+RA); - mg.add(LDC,pc+8); - setReg(); leaveMethod(); - unreachable = true; + ret |= UNREACHABLE; break; case 12: // SYSCALL preSetPC(); mg.add(LDC,pc); setPC(); + // FEATURE: This is actually broken, but it happens to work for our code + // a func could theoretically jump back to here from a future point restoreChangedRegs(); preSetReg(R+V0); @@ -677,14 +755,13 @@ public class ClassFileCompiler extends Compiler implements CGConst { pushRegZ(R+A3); pushRegZ(R+T0); pushRegZ(R+T1); - 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})); + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.syscall + mg.add(INVOKEVIRTUAL,me.method("syscall",Type.INT,new Type[]{Type.INT,Type.INT,Type.INT,Type.INT,Type.INT,Type.INT,Type.INT})); setReg(); mg.add(ALOAD_0); - mg.add(GETFIELD,new FieldRef(me,"state",Type.INT)); - // FEATURE: Set Runtime.RUNNING to 0 and just use IFEQ here - mg.add(LDC,Runtime.RUNNING); - b1 = mg.add(IF_ICMPEQ); + mg.add(GETFIELD,me.field("state",Type.INT)); + b1 = mg.add(IFEQ); preSetPC(); mg.add(LDC,pc+4); setPC(); @@ -692,12 +769,12 @@ public class ClassFileCompiler extends Compiler implements CGConst { mg.setArg(b1,mg.size()); break; case 13: // BREAK - mg.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException")); + mg.add(NEW,Type.fromClass("org.ibex.nestedvm.Runtime$ExecutionException")); mg.add(DUP); 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(INVOKESPECIAL,Type.fromClass("org.ibex.nestedvm.Runtime$ExecutionException").method("",Type.VOID,new Type[]{Type.STRING})); mg.add(ATHROW); - unreachable = true; + ret |= UNREACHABLE; break; case 16: // MFHI preSetReg(R+rd); @@ -948,9 +1025,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { pushRegWZ(R+rs); b1 = mg.add(IFGE); emitInstruction(-1,nextInsn,-1); - preSetReg(R+RA); - mg.add(LDC,pc+8); - setReg(); + link(pc); branch(pc,pc+branchTarget*4+4); mg.setArg(b1,mg.size()); break; @@ -962,12 +1037,10 @@ public class ClassFileCompiler extends Compiler implements CGConst { b1 = mg.add(IFLT); } emitInstruction(-1,nextInsn,-1); - preSetReg(R+RA); - mg.add(LDC,pc+8); - setReg(); + 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); @@ -978,18 +1051,16 @@ 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 if(pc == -1) throw new Exn("pc modifying insn in delay slot"); int target = (pc&0xf0000000)|(jumpTarget << 2); emitInstruction(-1,nextInsn,-1); - preSetReg(R+RA); - mg.add(LDC,pc+8); - setReg(); + link(pc); branch(pc, target); - unreachable = true; + ret |= UNREACHABLE; break; } case 4: // BEQ @@ -997,7 +1068,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); @@ -1027,9 +1098,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); @@ -1108,10 +1185,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 @@ -1186,13 +1261,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); @@ -1213,7 +1287,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { setDouble(); break; case 36: { // CVT.W.D - MethodGen.TSI tsi = new MethodGen.TSI(0,3); + MethodGen.Switch.Table tsi = new MethodGen.Switch.Table(0,3); preSetReg(F+fd); pushDouble(F+fs,d); pushReg(FCSR); @@ -1224,7 +1298,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { // Round towards plus infinity tsi.setTarget(2,mg.size()); if(!d) mg.add(F2D); // Ugh.. java.lang.Math doesn't have a float ceil/floor - mg.add(INVOKESTATIC,new MethodRef("java.lang.Math","ceil",Type.DOUBLE,new Type[]{Type.DOUBLE})); + mg.add(INVOKESTATIC,Type.fromClass("java.lang.Math").method("ceil",Type.DOUBLE,new Type[]{Type.DOUBLE})); if(!d) mg.add(D2F); b1 = mg.add(GOTO); @@ -1237,7 +1311,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { // Round towards minus infinity tsi.setTarget(3,mg.size()); if(!d) mg.add(F2D); - mg.add(INVOKESTATIC,new MethodRef("java.lang.Math","floor",Type.DOUBLE,new Type[]{Type.DOUBLE})); + mg.add(INVOKESTATIC,Type.fromClass("java.lang.Math").method("floor",Type.DOUBLE,new Type[]{Type.DOUBLE})); if(!d) mg.add(D2F); tsi.setTarget(1,mg.size()); @@ -1460,7 +1534,6 @@ public class ClassFileCompiler extends Compiler implements CGConst { addiu(R+rs,signedImmediate); setTmp(); // addr - // FEATURE: DO the preMemRead(true) thing for the rest of the S* instructions preMemRead(true); pushTmp(); memRead(true); @@ -1500,19 +1573,13 @@ public class ClassFileCompiler extends Compiler implements CGConst { break; } case 41: { // SH - preMemWrite1(); - addiu(R+rs,signedImmediate); + setTmp(); - mg.add(DUP); - setTmp(); // addr - - preMemWrite2(true); - - preMemRead(); + preMemRead(true); pushTmp(); memRead(true); - + mg.add(LDC,0xffff); pushTmp(); @@ -1546,15 +1613,10 @@ public class ClassFileCompiler extends Compiler implements CGConst { break; } case 42: { // SWL - preMemWrite1(); - addiu(R+rs,signedImmediate); - mg.add(DUP); - setTmp(); // addr - - preMemWrite2(true); + setTmp(); - preMemRead(); + preMemRead(true); pushTmp(); memRead(true); @@ -1591,15 +1653,10 @@ public class ClassFileCompiler extends Compiler implements CGConst { memWrite(); break; case 46: { // SWR - preMemWrite1(); - addiu(R+rs,signedImmediate); - mg.add(DUP); - setTmp(); // addr - - preMemWrite2(true); + setTmp(); - preMemRead(); + preMemRead(true); pushTmp(); memRead(true); @@ -1663,7 +1720,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 @@ -1674,26 +1731,42 @@ 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; - - // FEATURE: Clean this up + 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 boolean doLocal(int reg) { + return reg == R+2 || reg == R+3 || reg == R+4 || reg == R+29; + } 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 int loadsStart; 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,me.field(regField[i],Type.INT)); } } } - 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; - } - 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,me.field(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!"); @@ -1756,7 +1807,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { } private int pushRegZ(int reg) { - if(reg == R+0) return mg.add(LDC,0); + if(reg == R+0) return mg.add(ICONST_0); else return pushReg(reg); } @@ -1764,12 +1815,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,me.field(regField[reg],Type.FLOAT)); + mg.add(INVOKESTATIC,Type.FLOAT_OBJECT.method("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,me.field(regField[reg],Type.INT)); } return h; } @@ -1779,7 +1832,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)) { @@ -1797,24 +1849,28 @@ 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,Type.FLOAT_OBJECT.method("intBitsToFloat",Type.FLOAT,new Type[]{Type.INT})); + mg.add(PUTFIELD,me.field(regField[reg],Type.FLOAT)); } else { - mg.add(PUTFIELD,new FieldRef(me,regField(reg),Type.INT)); + mg.add(PUTFIELD,me.field(regField[reg],Type.INT)); } return h; } private int preSetPC() { return mg.add(ALOAD_0); } private int setPC() { - return mg.add(PUTFIELD,new FieldRef(me,"pc",Type.INT)); + return mg.add(PUTFIELD,me.field("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); @@ -1825,10 +1881,13 @@ public class ClassFileCompiler extends Compiler implements CGConst { mg.add(LDC,FFFFFFFF); mg.add(LAND); mg.add(LOR); - mg.add(INVOKESTATIC,new MethodRef(Type.DOUBLE_OBJECT,"longBitsToDouble",Type.DOUBLE,new Type[]{Type.LONG})); + mg.add(INVOKESTATIC,Type.DOUBLE_OBJECT.method("longBitsToDouble",Type.DOUBLE,new Type[]{Type.LONG})); + } else if(singleFloat) { + mg.add(ALOAD_0); + mg.add(GETFIELD,me.field(regField[reg],Type.FLOAT)); } else { pushReg(reg); - mg.add(INVOKESTATIC,new MethodRef("java.lang.Float","intToFloatBits",Type.FLOAT,new Type[]{Type.INT})); + mg.add(INVOKESTATIC,Type.fromClass("java.lang.Float").method("intBitsToFloat",Type.FLOAT,new Type[]{Type.INT})); } return h; } @@ -1844,8 +1903,9 @@ 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(INVOKESTATIC,Type.DOUBLE_OBJECT.method("doubleToLongBits",Type.LONG,new Type[]{Type.DOUBLE})); mg.add(DUP2); mg.add(LDC,32); mg.add(LUSHR); @@ -1855,9 +1915,13 @@ 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,me.field(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})); + mg.add(INVOKESTATIC,Type.FLOAT_OBJECT.method("floatToRawIntBits",Type.INT,new Type[]{Type.FLOAT})); setReg(); } return h; @@ -1903,7 +1967,8 @@ public class ClassFileCompiler extends Compiler implements CGConst { mg.add(DUP); mg.add(ALOAD_0); mg.add(SWAP); - mg.add(INVOKEVIRTUAL,new MethodRef(me,"nullPointerCheck",Type.VOID,new Type[]{Type.INT})); + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.nullPointerCheck + mg.add(INVOKEVIRTUAL,me.method("nullPointerCheck",Type.VOID,new Type[]{Type.INT})); } if(onePage) { @@ -1936,7 +2001,8 @@ public class ClassFileCompiler extends Compiler implements CGConst { } else if(fastMem) { mg.add(IASTORE); } else { - mg.add(INVOKEVIRTUAL,new MethodRef(me,"unsafeMemWrite",Type.VOID,new Type[]{Type.INT,Type.INT})); + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.unsafeMemWrite + mg.add(INVOKEVIRTUAL,me.method("unsafeMemWrite",Type.VOID,new Type[]{Type.INT,Type.INT})); } } @@ -1977,7 +2043,7 @@ public class ClassFileCompiler extends Compiler implements CGConst { mg.add(DUP); mg.add(ALOAD_0); mg.add(SWAP); - mg.add(INVOKEVIRTUAL,new MethodRef(me,"nullPointerCheck",Type.VOID,new Type[]{Type.INT})); + mg.add(INVOKEVIRTUAL,me.method("nullPointerCheck",Type.VOID,new Type[]{Type.INT})); } if(onePage) { @@ -2007,7 +2073,8 @@ public class ClassFileCompiler extends Compiler implements CGConst { } else { if(preMemReadDoPreWrite) mg.add(DUP2); - mg.add(INVOKEVIRTUAL,new MethodRef(me,"unsafeMemRead",Type.INT,new Type[]{Type.INT})); + // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime.unsafeMemRead + mg.add(INVOKEVIRTUAL,me.method("unsafeMemRead",Type.INT,new Type[]{Type.INT})); } }