+// 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.*;
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
*/
-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.instance(fullClassName).asClass();
+ }
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.instance(runtimeClass).asClass();
+ 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("<clinit>",Type.VOID,Type.NO_ARGS,ACC_PRIVATE|ACC_STATIC);
-
- init = cg.addMethod("<init>",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>
+ clinit = cg.addMethod("<clinit>",Type.VOID,Type.NO_ARGS,PRIVATE|STATIC);
+
+ // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.UnixRuntime.<init>
+
+ // <init>
+ init = cg.addMethod("<init>",Type.VOID,Type.NO_ARGS,PUBLIC);
init.add(ALOAD_0);
init.add(LDC,pageSize);
init.add(LDC,totalPages);
- init.add(INVOKESPECIAL,new MethodRef(me,"<init>",Type.VOID,new Type[]{Type.INT,Type.INT}));
+ init.add(INVOKESPECIAL,me.method("<init>",Type.VOID,new Type[]{Type.INT,Type.INT}));
init.add(RETURN);
- init = cg.addMethod("<init>",Type.VOID,new Type[]{Type.INT,Type.INT},ACC_PUBLIC);
+ // <init>(Z)
+ init = cg.addMethod("<init>",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("<init>",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN}));
+ init.add(RETURN);
+
+ // <init>(II)
+ init = cg.addMethod("<init>",Type.VOID,new Type[]{Type.INT,Type.INT},PUBLIC);
+ init.add(ALOAD_0);
+ init.add(ILOAD_1);
+ init.add(ILOAD_2);
+ init.add(ICONST_0);
+ init.add(INVOKESPECIAL,me.method("<init>",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN}));
+ init.add(RETURN);
+
+ // <init>(IIZ)
+ init = cg.addMethod("<init>",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(INVOKESPECIAL,new MethodRef(superClass,"<init>",Type.VOID,new Type[]{Type.INT,Type.INT}));
+ init.add(ILOAD_3);
+ init.add(INVOKESPECIAL,superClass.method("<init>",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.instance(hashClass),PRIVATE|STATIC|FINAL);
int highestAddr = 0;
// Finish clinit
if(supportCall) {
- Type.Object hash = new Type.Object(hashClass);
+ Type.Class hash = Type.instance(hashClass).asClass();
clinit.add(NEW,hash);
clinit.add(DUP);
clinit.add(DUP);
- clinit.add(INVOKESPECIAL,new MethodRef(hash,"<init>",Type.VOID,Type.NO_ARGS));
- clinit.add(PUTSTATIC,new FieldRef(me,"symbols",hash));
+ clinit.add(INVOKESPECIAL,hash.method("<init>",Type.VOID,Type.NO_ARGS));
+ clinit.add(PUTSTATIC,me.field("symbols",hash));
ELF.Symbol[] symbols = elf.getSymtab().symbols;
for(int i=0;i<symbols.length;i++) {
ELF.Symbol s = symbols[i];
clinit.add(NEW,Type.INTEGER_OBJECT);
clinit.add(DUP);
clinit.add(LDC,s.addr);
- clinit.add(INVOKESPECIAL,new MethodRef(Type.INTEGER_OBJECT,"<init>",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("<init>",Type.VOID,new Type[]{Type.INT}));
+ clinit.add(INVOKEVIRTUAL,hash.method("put",Type.OBJECT,new Type[]{Type.OBJECT,Type.OBJECT}));
clinit.add(POP);
}
}
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));
- int stateCheck = tramp.add(IFNE);
+ tramp.add(GETFIELD,me.field("state",Type.INT));
+ tramp.add(IFEQ,tramp.size()+2);
+ tramp.add(RETURN);
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<end;n++) {
tsi.setTargetForVal(n,tramp.size());
- tramp.add(INVOKESPECIAL,new MethodRef(me,"run_"+toHex(n<<methodShift),Type.VOID,Type.NO_ARGS));
+ tramp.add(INVOKESPECIAL,me.method("run_"+toHex(n<<methodShift),Type.VOID,Type.NO_ARGS));
tramp.add(GOTO,start);
}
tsi.setDefaultTarget(tramp.size());
tramp.add(POP);
- tramp.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
+ tramp.add(NEW,Type.instance("org.ibex.nestedvm.Runtime$ExecutionException"));
tramp.add(DUP);
tramp.add(NEW, Type.STRINGBUFFER);
tramp.add(DUP);
tramp.add(LDC,"Jumped to invalid address in trampoline (r2: ");
- tramp.add(INVOKESPECIAL,new MethodRef(Type.STRINGBUFFER,"<init>",Type.VOID,new Type[]{Type.STRING}));
+ tramp.add(INVOKESPECIAL,Type.STRINGBUFFER.method("<init>",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"),"<init>",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.<init>
+ tramp.add(INVOKESPECIAL,Type.instance("org.ibex.nestedvm.Runtime$ExecutionException").asClass().method("<init>",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);
}
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.instance(hashClass).asClass();
+ 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);
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.instance("org.ibex.nestedvm.Runtime$CPUState").asClass();
+ 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);
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);
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);
}
for(int i=0;i<each.length;i++) {
setCPUState.add(ALOAD_0);
setCPUState.add(ALOAD_1);
- setCPUState.add(GETFIELD,new FieldRef(cpuStateType,each[i],Type.INT));
- setCPUState.add(PUTFIELD,new FieldRef(me,each[i],Type.INT));
+ setCPUState.add(GETFIELD,cpuStateType.field(each[i],Type.INT));
+ setCPUState.add(PUTFIELD,me.field(each[i],Type.INT));
getCPUState.add(ALOAD_1);
getCPUState.add(ALOAD_0);
- getCPUState.add(GETFIELD,new FieldRef(me,each[i],Type.INT));
- getCPUState.add(PUTFIELD,new FieldRef(cpuStateType,each[i],Type.INT));
+ getCPUState.add(GETFIELD,me.field(each[i],Type.INT));
+ getCPUState.add(PUTFIELD,cpuStateType.field(each[i],Type.INT));
}
setCPUState.add(RETURN);
getCPUState.add(RETURN);
- MethodGen execute = cg.addMethod("_execute",Type.VOID,Type.NO_ARGS,ACC_PROTECTED);
+ MethodGen execute = cg.addMethod("_execute",Type.VOID,Type.NO_ARGS,PROTECTED);
int tryStart = execute.size();
execute.add(ALOAD_0);
- execute.add(INVOKESPECIAL,new MethodRef(me,"trampoline",Type.VOID,Type.NO_ARGS));
+ execute.add(INVOKESPECIAL,me.method("trampoline",Type.VOID,Type.NO_ARGS));
int tryEnd = execute.size();
execute.add(RETURN);
int catchInsn = execute.size();
execute.add(ASTORE_1);
- execute.add(NEW, new Type.Object("org.ibex.nestedvm.Runtime$FaultException"));
+ execute.add(NEW, Type.instance("org.ibex.nestedvm.Runtime$FaultException"));
execute.add(DUP);
execute.add(ALOAD_1);
- execute.add(INVOKESPECIAL,new MethodRef("org.ibex.nestedvm.Runtime$FaultException","<init>",Type.VOID,new Type[]{new Type.Object("java.lang.RuntimeException")}));
+ // GCCLASS_HINT: org.ibex.nestedvm.RuntimeCompiler.compile org.ibex.nestedvm.Runtime$FaultException.<init>
+ execute.add(INVOKESPECIAL,Type.instance("org.ibex.nestedvm.Runtime$FaultException").asClass().method("<init>",Type.VOID,new Type[]{Type.instance("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.instance("java.lang.RuntimeException").asClass());
+ execute.addThrow(Type.instance("org.ibex.nestedvm.Runtime$ExecutionException").asClass());
- 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,"<init>",Type.VOID,Type.NO_ARGS));
+ main.add(INVOKESPECIAL,me.method("<init>",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.instance("org.ibex.nestedvm.UnixRuntime").asClass();
+ // 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.instance("java.lang.System").asClass().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);
}
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.instance("org.ibex.nestedvm.Runtime").asClass().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;
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)
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;
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<count;i++,addr+=4) {
insn = skipNext ? dis.readInt() : nextInsn;
nextInsn = (i == count-1) ? -1 : dis.readInt();
- if(addr >= 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);
}
}
}
- 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());
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) {
defaultTarget.setTarget(mg.size());
if(debugCompiler) {
- mg.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
+ mg.add(NEW,Type.instance("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,"<init>",Type.VOID,new Type[]{Type.STRING}));
+ mg.add(INVOKESPECIAL,Type.STRINGBUFFER.method("<init>",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"),"<init>",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.instance("org.ibex.nestedvm.Runtime$ExecutionException").asClass().method("<init>",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.instance("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"),"<init>",Type.VOID,new Type[]{Type.STRING}));
+ mg.add(INVOKESPECIAL,Type.instance("org.ibex.nestedvm.Runtime$ExecutionException").asClass().method("<init>",Type.VOID,new Type[]{Type.STRING}));
mg.add(ATHROW);
}
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)) {
}
// 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]);
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) {
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
emitInstruction(-1,nextInsn,01); // delay slot
mg.setArg(b,mg.size());
- return true;
+ return SKIP_NEXT;
}
}
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
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;
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();
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));
+ mg.add(GETFIELD,me.field("state",Type.INT));
b1 = mg.add(IFEQ);
preSetPC();
mg.add(LDC,pc+4);
mg.setArg(b1,mg.size());
break;
case 13: // BREAK
- mg.add(NEW,new Type.Object("org.ibex.nestedvm.Runtime$ExecutionException"));
+ mg.add(NEW,Type.instance("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"),"<init>",Type.VOID,new Type[]{Type.STRING}));
+ mg.add(INVOKESPECIAL,Type.instance("org.ibex.nestedvm.Runtime$ExecutionException").asClass().method("<init>",Type.VOID,new Type[]{Type.STRING}));
mg.add(ATHROW);
- unreachable = true;
+ ret |= UNREACHABLE;
break;
case 16: // MFHI
preSetReg(R+rd);
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;
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);
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
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);
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);
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
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);
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);
// 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.instance("java.lang.Math").asClass().method("ceil",Type.DOUBLE,new Type[]{Type.DOUBLE}));
if(!d) mg.add(D2F);
b1 = mg.add(GOTO);
// 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.instance("java.lang.Math").asClass().method("floor",Type.DOUBLE,new Type[]{Type.DOUBLE}));
if(!d) mg.add(D2F);
tsi.setTarget(1,mg.size());
addiu(R+rs,signedImmediate);
setTmp(); // addr
- // FEATURE: DO the preMemRead(true) thing for the rest of the S* instructions
preMemRead(true);
pushTmp();
memRead(true);
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();
break;
}
case 42: { // SWL
- preMemWrite1();
-
addiu(R+rs,signedImmediate);
- mg.add(DUP);
- setTmp(); // addr
-
- preMemWrite2(true);
+ setTmp();
- preMemRead();
+ preMemRead(true);
pushTmp();
memRead(true);
memWrite();
break;
case 46: { // SWR
- preMemWrite1();
-
addiu(R+rs,signedImmediate);
- mg.add(DUP);
- setTmp(); // addr
-
- preMemWrite2(true);
+ setTmp();
- preMemRead();
+ preMemRead(true);
pushTmp();
memRead(true);
default:
throw new Exn("Invalid Instruction: " + op + " at " + toHex(pc));
}
- return false;
+ return ret;
}
// Helper functions for emitText
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;
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<REG_COUNT;i++)
- regLocalMapping[i] = regLocalReadCount[i] = regLocalWriteCount[i] = 0;
- nextAvailLocal = 0;
+ for(int i=0;i<REG_COUNT;i++) {
+ regLocalMapping[i] = 0;
+ regLocalWritten[i] = false;
+ }
+ nextAvailLocal = onePage ? 4 : 5;
loadsStart = mg.size();
for(int i=0;i<MAX_LOCALS*LOAD_LENGTH;i++)
mg.add(NOP);
for(int i=0;i<REG_COUNT;i++) {
if(regLocalMapping[i] == 0) continue;
mg.set(p++,ALOAD_0);
- mg.set(p++,GETFIELD,new FieldRef(me,regField(i),Type.INT));
+ mg.set(p++,GETFIELD,me.field(regField[i],Type.INT));
mg.set(p++,ISTORE,regLocalMapping[i]);
- if(regLocalWriteCount[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 void restoreChangedRegs() {
for(int i=0;i<REG_COUNT;i++) {
- if(regLocalWriteCount[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!");
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;
}
// 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)) {
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);
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.instance("java.lang.Float").asClass().method("intBitsToFloat",Type.FLOAT,new Type[]{Type.INT}));
}
return h;
}
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);
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;
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) {
} 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}));
}
}
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) {
} 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}));
}
}