package org.ibex.nestedvm;
import java.io.*;
+import java.util.Hashtable;
+
import org.ibex.nestedvm.util.*;
import org.apache.bcel.generic.*;
+// 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
// Handy wrappers around the BCEL functions
private InstructionList insnList;
- private void selectMethod(MethodGen m) { insnList = m.getInstructionList(); }
+ private void selectMethod(MethodGen m) { insnList = m.getInstructionList(); }
private void selectList(InstructionList l) { insnList = l; }
private InstructionHandle a(Instruction i) { return insnList.append(i); }
private BranchHandle a(BranchInstruction i) { return insnList.append(i); }
if(!pruneCases) throw new Exn("-o prunecases MUST be enabled for ClassFileCompiler");
// Class
- cl = new ClassGen(fullClassName,runtimeClass,source,ACC_SUPER|ACC_PUBLIC,null);
+ cl = new ClassGen(fullClassName,runtimeClass,source,ACC_SUPER|ACC_PUBLIC|ACC_FINAL,null);
cp = cl.getConstantPool();
fac = new InstructionFactory(cl,cp);
a(InstructionConstants.IUSHR);
int beg = text.addr >>> methodShift;
- int end = ((text.addr + text.size) >>> methodShift);
+ int end = ((text.addr + text.size + maxBytesPerMethod - 1) >>> methodShift);
// This data is redundant but BCEL wants it
int[] matches = new int[end-beg];
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(userInfo != null) {
+ addConstReturnMethod("userInfoBase",userInfo.addr);
+ addConstReturnMethod("userInfoSize",userInfo.size);
+ }
+
+ // FEATURE: Allow specification of memory size at runtime (numpages)
+ // Constructor
MethodGen init = newMethod(ACC_PUBLIC,Type.VOID, Type.NO_ARGS, "<init>");
selectMethod(init);
- // Constructor
a(InstructionConstants.ALOAD_0);
pushConst(pageSize);
pushConst(totalPages);
- pushConst(fastMem ? 0 : 1);
- a(fac.createInvoke(runtimeClass,"<init>",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN},INVOKESPECIAL));
- a(InstructionConstants.ALOAD_0);
- pushConst(gp.addr);
- a(fac.createFieldAccess(fullClassName,"gp",Type.INT, PUTFIELD));
+ a(fac.createInvoke(runtimeClass,"<init>",Type.VOID,new Type[]{Type.INT,Type.INT},INVOKESPECIAL));
- a(InstructionConstants.ALOAD_0);
- pushConst(elf.header.entry);
- a(fac.createFieldAccess(fullClassName,"entryPoint",Type.INT, PUTFIELD));
-
- a(InstructionConstants.ALOAD_0);
- pushConst(onePage ? ((highestAddr+4095)&~4095) : ((highestAddr+pageSize-1)&~(pageSize-1)));
- a(fac.createFieldAccess(fullClassName,"brkAddr",Type.INT, PUTFIELD));
-
- if(userInfo != null) {
- a(InstructionConstants.ALOAD_0);
- pushConst(userInfo.addr);
- a(fac.createFieldAccess(fullClassName,"userInfoBase",Type.INT, PUTFIELD));
- a(InstructionConstants.ALOAD_0);
- pushConst(userInfo.size);
- a(fac.createFieldAccess(fullClassName,"userInfoSize",Type.INT, PUTFIELD));
- }
a(initExtras);
- a(InstructionConstants.ALOAD_0);
- pushConst(Runtime.INITIALIZED);
- a(fac.createFieldAccess(fullClassName,"state",Type.INT, PUTFIELD));
+
a(InstructionConstants.RETURN);
+
init.setMaxLocals();
init.setMaxStack();
cl.addMethod(init.getMethod());
+
MethodGen clinit = newMethod(ACC_PRIVATE|ACC_STATIC,Type.VOID, Type.NO_ARGS, "<clinit>");
selectMethod(clinit);
a(clinitExtras);
a(fac.createCheckCast(new ObjectType("java.lang.Integer")));
a(fac.createInvoke("java.lang.Integer","intValue",Type.INT,Type.NO_ARGS,INVOKEVIRTUAL));
a(InstructionConstants.IRETURN);
- bh.setTarget(a(InstructionConstants.ICONST_M1));
- a(InstructionConstants.IRETURN);
+ bh.setTarget(a(InstructionConstants.POP));
+ a(InstructionConstants.ICONST_M1);
+ a(InstructionConstants.IRETURN);
lookupSymbol.setMaxLocals();
lookupSymbol.setMaxStack();
cl.addMethod(lookupSymbol.getMethod());
a(InstructionConstants.ALOAD_1);
a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","pc",Type.INT,GETFIELD));
a(fac.createFieldAccess(fullClassName,"pc",Type.INT, PUTFIELD));
+
a(InstructionConstants.RETURN);
setCPUState.setMaxLocals();
setCPUState.setMaxStack();
cl.addMethod(setCPUState.getMethod());
- MethodGen getCPUState = newMethod(ACC_PROTECTED,Type.getType("Lorg/ibex/nestedvm/Runtime$CPUState;"),Type.NO_ARGS,"getCPUState");
+ MethodGen getCPUState = newMethod(ACC_PROTECTED,Type.VOID,new Type[]{Type.getType("Lorg/ibex/nestedvm/Runtime$CPUState;")},"getCPUState");
selectMethod(getCPUState);
- a(fac.createNew("org.ibex.nestedvm.Runtime$CPUState"));
- a(InstructionConstants.DUP);
- a(fac.createInvoke("org.ibex.nestedvm.Runtime$CPUState","<init>",Type.VOID,Type.NO_ARGS,INVOKESPECIAL));
- a(InstructionConstants.ASTORE_1);
-
a(InstructionConstants.ALOAD_1);
a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","r",new ArrayType(Type.INT,1),GETFIELD));
a(InstructionConstants.ASTORE_2);
a(fac.createFieldAccess(fullClassName,"pc",Type.INT, GETFIELD));
a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","pc",Type.INT,PUTFIELD));
- a(InstructionConstants.ALOAD_1);
- a(InstructionConstants.ARETURN);
+ a(InstructionConstants.RETURN);
getCPUState.setMaxLocals();
getCPUState.setMaxStack();
cl.addMethod(getCPUState.getMethod());
MethodGen execute = newMethod(ACC_PROTECTED,Type.VOID,Type.NO_ARGS,"_execute");
selectMethod(execute);
- a(InstructionConstants.ALOAD_0);
- a(fac.createInvoke(fullClassName,"trampoline",Type.VOID,Type.NO_ARGS,INVOKESPECIAL));
+ InstructionHandle tryStart = a(InstructionConstants.ALOAD_0);
+ InstructionHandle tryEnd = a(fac.createInvoke(fullClassName,"trampoline",Type.VOID,Type.NO_ARGS,INVOKESPECIAL));
a(InstructionConstants.RETURN);
+
+ InstructionHandle catchInsn = a(InstructionConstants.ASTORE_1);
+ a(fac.createNew("org.ibex.nestedvm.Runtime$FaultException"));
+ a(InstructionConstants.DUP);
+ a(InstructionConstants.ALOAD_1);
+ a(fac.createInvoke("org.ibex.nestedvm.Runtime$FaultException","<init>",Type.VOID,new Type[]{new ObjectType("java.lang.RuntimeException")},INVOKESPECIAL));
+ a(InstructionConstants.ATHROW);
+
+ execute.addExceptionHandler(tryStart,tryEnd,catchInsn,new ObjectType("java.lang.RuntimeException"));
execute.setMaxLocals();
execute.setMaxStack();
cl.addMethod(execute.getMethod());
a(fac.createInvoke(fullClassName,"<init>",Type.VOID,Type.NO_ARGS,INVOKESPECIAL));
a(new PUSH(cp,fullClassName));
a(InstructionConstants.ALOAD_0);
- a(fac.createInvoke(fullClassName,"run",Type.INT,new Type[]{Type.STRING,new ArrayType(Type.STRING,1)},INVOKEVIRTUAL));
+ if(unixRuntime)
+ a(fac.createInvoke("org.ibex.nestedvm.UnixRuntime","runAndExec",Type.INT,
+ new Type[]{Type.getType("Lorg/ibex/nestedvm/UnixRuntime;"),Type.STRING,new ArrayType(Type.STRING,1)},
+ INVOKESTATIC));
+ else
+ a(fac.createInvoke(fullClassName,"run",Type.INT,new Type[]{Type.STRING,new ArrayType(Type.STRING,1)},INVOKEVIRTUAL));
a(fac.createInvoke("java.lang.System","exit",Type.VOID,new Type[]{Type.INT},INVOKESTATIC));
a(InstructionConstants.RETURN);
main.setMaxLocals();
main.setMaxStack();
cl.addMethod(main.getMethod());
+ if(printStats)
+ System.out.println("Constant Pool Size: " + cp.getSize());
cl.getJavaClass().dump(os);
}
+
+ private void addConstReturnMethod(String name, int val) {
+ MethodGen method = newMethod(ACC_PROTECTED,Type.INT, Type.NO_ARGS,name);
+ selectMethod(method);
+ pushConst(val);
+ a(InstructionConstants.IRETURN);
+ method.setMaxLocals();
+ method.setMaxStack();
+ cl.addMethod(method.getMethod());
+ }
private static int initDataCount;
private void emitData(int addr, DataInputStream dis, int size, boolean readOnly) throws Exn,IOException {
private InstructionHandle realStart;
private MethodGen curMethod;
- private boolean jumpable(int addr) { return jumpableAddresses.contains(new Integer(addr)); }
+ private boolean jumpable(int addr) { return jumpableAddresses.get(new Integer(addr)) != null; }
private void emitText(int addr, DataInputStream dis, int size) throws Exn,IOException {
if(textDone) throw new Exn("Multiple text segments");
pushConst(firstAddrOfNext);
setPC();
// mark the start of the next method as jumpable
- jumpableAddresses.add(new Integer(firstAddrOfNext));
+ jumpableAddresses.put(new Integer(firstAddrOfNext),Boolean.TRUE);
}
insnList.move(returnHandle,insnList.getEnd());
//System.err.println("Delay slot is jumpable - This code is untested + " + toHex(nextInsn));
if(pc+4==endOfMethod) {
// the delay slot is at the start of the next method
- jumpableAddresses.add(new Integer(pc+8)); // make the 2nd insn of the next method jumpable
+ 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;
pushRegZ(R+A1);
pushRegZ(R+A2);
pushRegZ(R+A3);
- a(fac.createInvoke(fullClassName,"syscall",Type.INT,new Type[]{Type.INT,Type.INT,Type.INT,Type.INT,Type.INT},INVOKEVIRTUAL));
+ pushRegZ(R+T0);
+ pushRegZ(R+T1);
+ a(fac.createInvoke(fullClassName,"syscall",Type.INT,new Type[]{Type.INT,Type.INT,Type.INT,Type.INT,Type.INT,Type.INT,Type.INT},INVOKEVIRTUAL));
setReg();
a(InstructionConstants.ALOAD_0);
case 32: // ADD
throw new Exn("ADD (add with oveflow trap) not suported");
case 33: // ADDU
- preSetReg(R+rd);
+ preSetReg(R+rd);
if(rt != 0 && rs != 0) {
pushReg(R+rs);
pushReg(R+rt);
setReg();
break;
default:
- throw new RuntimeException("Illegal instruction 0/" + subcode);
+ throw new Exn("Illegal instruction 0/" + subcode);
}
break;
}
if(b1 == null) unreachable = true;
break;
default:
- throw new RuntimeException("Illegal Instruction 1/" + rt);
+ throw new Exn("Illegal Instruction 1/" + rt);
}
break;
}
if(pc == -1) throw new Exn("pc modifying insn in delay slot");
int target = (pc&0xf0000000)|(jumpTarget << 2);
emitInstruction(-1,nextInsn,-1);
- if(optimizedMemcpy && (target == memcpy || target == memset)) {
- a(InstructionConstants.ALOAD_0);
- pushRegZ(R+4);
- pushRegZ(R+5);
- pushRegZ(R+6);
- a(fac.createInvoke(fullClassName,target==memcpy ? "memcpy" : "memset", Type.VOID, new Type[]{Type.INT,Type.INT,Type.INT},INVOKEVIRTUAL));
- preSetReg(R+2);
- pushReg(R+4);
- setReg();
- branch(pc,pc+8);
- } else {
- preSetReg(R+RA);
- pushConst(pc+8);
- setReg();
- branch(pc, target);
- }
+ preSetReg(R+RA);
+ pushConst(pc+8);
+ setReg();
+ branch(pc, target);
unreachable = true;
break;
}
a(InstructionConstants.I2L);
pushConst(0xffffffffL);
a(InstructionConstants.LAND);
- pushConst((long)unsignedImmediate);
+ // Yes, this is correct, you have to sign extend the immediate then do an UNSIGNED comparison
+ pushConst(signedImmediate&0xffffffffL);
a(InstructionConstants.LCMP);
b1 = a(InstructionFactory.createBranchInstruction(IFLT,null));
pushDouble(F+fs,d);
pushDouble(F+ft,d);
a(d ? InstructionConstants.DSUB : InstructionConstants.FSUB);
- setDouble(d);
+ setDouble(d);
break;
case 2: // MUL.X
preSetDouble(F+fd,d);
b1 = a(InstructionFactory.createBranchInstruction(IFGT,null));
a(d ? InstructionConstants.DCONST_0 : InstructionConstants.FCONST_0);
- if(d) {
- a(InstructionConstants.DUP2_X2);
- a(InstructionConstants.POP2);
- } else {
- a(InstructionConstants.POP);
- }
- a(InstructionConstants.DSUB);
+ a(d ? InstructionConstants.DSUB : InstructionConstants.FSUB);
b1.setTarget(setDouble(d));
pushReg(F+fs);
setReg();
- preSetReg(F+fd+1);
- pushReg(F+fs+1);
- setReg();
+ if(d) {
+ preSetReg(F+fd+1);
+ pushReg(F+fs+1);
+ setReg();
+ }
break;
case 7: // NEG.X
preSetDouble(F+fd,d);
pushDouble(F+fs,d);
a(d ? InstructionConstants.DNEG : InstructionConstants.FNEG);
- setDouble(d);
+ setDouble(d);
break;
case 32: // CVT.S.X
preSetFloat(F+fd);
- pushDouble(F+fd,d);
+ pushDouble(F+fs,d);
if(d) a(InstructionConstants.D2F);
setFloat();
break;
case 33: // CVT.D.X
preSetDouble(F+fd);
- pushDouble(F+fd,d);
+ pushDouble(F+fs,d);
if(!d) a(InstructionConstants.F2D);
setDouble();
break;
case 62: b1 = a(InstructionFactory.createBranchInstruction(IFLE,null)); break;
default: b1 = null;
}
-
+ // FIXME: We probably don't need to pushConst(0x00000)
pushConst(0x000000);
b2 = a(InstructionFactory.createBranchInstruction(GOTO,null));
b1.setTarget(pushConst(0x800000));
memWrite();
break;
}
- // FEATURE: This need to be atomic if we ever support threads (see SWC0/SC)
+ // This need to be atomic if we ever support threads (see SWC0/SC)
case 48: // LWC0/LL
preSetReg(R+rt);
memRead(R+rs,signedImmediate);
setReg();
break;
- /* FEATURE: This needs to fail (set rt to 0) if the memory location was modified
+ /* This needs to fail (set rt to 0) if the memory location was modified
* between the LL and SC if we every support threads.
*/
case 56: // SWC0/SC
}
}
- private String regField(int reg) {
- String field;
+ 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];
+
+ /*String field;
switch(reg) {
case HI: field = "hi"; break;
case LO: field = "lo"; break;
case FCSR: field = "fcsr"; break;
default:
- if(reg > R && reg < R+32) field="r"+(reg-R);
- else if(reg >= F && reg < F+32) field="f"+(reg-F);
+ if(reg > R && reg < R+32) regFieldR[reg-R];
+ else if(reg >= F && reg < F+32) return regFieldF[
else throw new IllegalArgumentException(""+reg);
}
- return field;
+ return field;*/
}
private boolean doLocal(int reg) {
return h;
}
+ private Hashtable intCache = new Hashtable();
+
private InstructionHandle pushConst(int n) {
- if(n >= 0 && n <= 5) {
+ if(n >= -1 && n <= 5) {
switch(n) {
+ case -1: return a(InstructionConstants.ICONST_M1);
case 0: return a(InstructionConstants.ICONST_0);
case 1: return a(InstructionConstants.ICONST_1);
case 2: return a(InstructionConstants.ICONST_2);
case 5: return a(InstructionConstants.ICONST_5);
default: return null;
}
- } else if(n == -1) {
- return a(InstructionConstants.ICONST_M1);
} else if(n >= -128 && n <= 127) {
return a(new BIPUSH((byte) n));
} else if(n >= -32768 && n <= 32767) {