private LInstruction readInstruction(SPOpcode op) throws Exception { switch (op) { case load_pri: case load_alt: { Register reg = (op == SPOpcode.load_pri) ? Register.Pri : Register.Alt; return new LLoadGlobal(trackGlobal(readInt32()), reg); } case load_s_pri: case load_s_alt: { Register reg = (op == SPOpcode.load_s_pri) ? Register.Pri : Register.Alt; return new LLoadLocal(trackStack(readInt32()), reg); } case lref_s_pri: case lref_s_alt: { Register reg = (op == SPOpcode.lref_s_pri) ? Register.Pri : Register.Alt; return new LLoadLocalRef(trackStack(readInt32()), reg); } case stor_s_pri: case stor_s_alt: { Register reg = (op == SPOpcode.stor_s_pri) ? Register.Pri : Register.Alt; return new LStoreLocal(reg, trackStack(readInt32())); } case sref_s_pri: case sref_s_alt: { Register reg = (op == SPOpcode.sref_s_pri) ? Register.Pri : Register.Alt; return new LStoreLocalRef(reg, trackStack(readInt32())); } case load_i: return new LLoad(4); case lodb_i: return new LLoad(readInt32()); case const_pri: case const_alt: { Register reg = (op == SPOpcode.const_pri) ? Register.Pri : Register.Alt; return new LConstant(readInt32(), reg); } case addr_pri: case addr_alt: { Register reg = (op == SPOpcode.addr_pri) ? Register.Pri : Register.Alt; return new LStackAddress(trackStack(readInt32()), reg); } case stor_pri: case stor_alt: { Register reg = (op == SPOpcode.stor_pri) ? Register.Pri : Register.Alt; return new LStoreGlobal(trackGlobal(readInt32()), reg); } case stor_i: return new LStore(4); case strb_i: return new LStore(readInt32()); case lidx: return new LLoadIndex(4); case lidx_b: return new LLoadIndex(readInt32()); case idxaddr: return new LIndexAddress(2); case idxaddr_b: return new LIndexAddress(readInt32()); case move_pri: case move_alt: { Register reg = (op == SPOpcode.move_pri) ? Register.Pri : Register.Alt; return new LMove(reg); } case xchg: return new LExchange(); case push_pri: case push_alt: { Register reg = (op == SPOpcode.push_pri) ? Register.Pri : Register.Alt; return new LPushReg(reg); } case push_c: return new LPushConstant(readInt32()); case push: return new LPushGlobal(trackGlobal(readInt32())); case push_s: return new LPushLocal(trackStack(readInt32())); case pop_pri: case pop_alt: { Register reg = (op == SPOpcode.pop_pri) ? Register.Pri : Register.Alt; return new LPop(reg); } case stack: return new LStack(readInt32()); case retn: return new LReturn(); case call: { long addr = readInt32(); file_.addFunction(addr); return new LCall(addr); } case jump: { long offset = readUInt32(); return new LJump(prepareJumpTarget(offset), offset); } case jeq: case jneq: case jnz: case jzer: case jsgeq: case jsless: case jsgrtr: case jsleq: { long offset = readUInt32(); if (offset == pc_) return new LJump(prepareJumpTarget(offset), offset); return new LJumpCondition(op, prepareJumpTarget(offset), prepareJumpTarget(pc_), offset); } case sdiv_alt: case sub_alt: return new LBinary(op, Register.Alt, Register.Pri); case add: case and: case or: case smul: case shr: case shl: case sub: case sshr: case xor: return new LBinary(op, Register.Pri, Register.Alt); case not: case neg: case invert: return new LUnary(op, Register.Pri); case add_c: return new LAddConstant(readInt32()); case smul_c: return new LMulConstant(readInt32()); case zero_pri: case zero_alt: { Register reg = (op == SPOpcode.zero_pri) ? Register.Pri : Register.Alt; return new LConstant(0, reg); } case zero_s: return new LZeroLocal(trackStack(readInt32())); case zero: return new LZeroGlobal(trackGlobal(readInt32())); case eq: case neq: case sleq: case sgeq: case sgrtr: case sless: return new LBinary(op, Register.Pri, Register.Alt); case eq_c_pri: case eq_c_alt: { Register reg = (op == SPOpcode.eq_c_pri) ? Register.Pri : Register.Alt; return new LEqualConstant(reg, readInt32()); } case inc: return new LIncGlobal(trackGlobal(readInt32())); case dec: return new LDecGlobal(trackGlobal(readInt32())); case inc_s: return new LIncLocal(trackStack(readInt32())); case dec_s: return new LDecLocal(trackStack(readInt32())); case inc_i: return new LIncI(); case inc_pri: case inc_alt: { Register reg = (op == SPOpcode.inc_pri) ? Register.Pri : Register.Alt; return new LIncReg(reg); } case dec_pri: case dec_alt: { Register reg = (op == SPOpcode.dec_pri) ? Register.Pri : Register.Alt; return new LDecReg(reg); } case dec_i: return new LDecI(); case fill: return new LFill(readInt32()); case bounds: return new LBounds(readInt32()); case swap_pri: case swap_alt: { Register reg = (op == SPOpcode.swap_pri) ? Register.Pri : Register.Alt; return new LSwap(reg); } case push_adr: return new LPushStackAddress(trackStack(readInt32())); case sysreq_c: { long index = readUInt32(); long prePeep = pc_; SPOpcode nextOp = readOp(); int nextValue = readInt32(); // Assert, that we really clear the stack from the arguments after this. assert (nextOp == SPOpcode.stack && nextValue == ((LPushConstant) lir_.instructions.get(lir_.instructions.size() - 1)).val() * 4 + 4); // Skip the stack op, if it's popping the arguments again. if (nextOp != SPOpcode.stack || nextValue != ((LPushConstant) lir_.instructions.get(lir_.instructions.size() - 1)).val() * 4 + 4) pc_ = prePeep; return new LSysReq(file_.natives()[(int) index]); } case sysreq_n: { long index = readUInt32(); add(new LPushConstant((int) readUInt32())); return new LSysReq(file_.natives()[(int) index]); } case dbreak: return new LDebugBreak(); case endproc: return null; case push2_s: { add(new LPushLocal(trackStack(readInt32()))); return new LPushLocal(trackStack(readInt32())); } case push2_adr: { add(new LPushStackAddress(trackStack(readInt32()))); return new LPushStackAddress(trackStack(readInt32())); } case push2_c: { add(new LPushConstant(readInt32())); return new LPushConstant(readInt32()); } case push2: { add(new LPushGlobal(trackGlobal(readInt32()))); return new LPushGlobal(trackGlobal(readInt32())); } case push3_s: { add(new LPushLocal(trackStack(readInt32()))); add(new LPushLocal(trackStack(readInt32()))); return new LPushLocal(trackStack(readInt32())); } case push3_adr: { add(new LPushStackAddress(trackStack(readInt32()))); add(new LPushStackAddress(trackStack(readInt32()))); return new LPushStackAddress(trackStack(readInt32())); } case push3_c: { add(new LPushConstant(readInt32())); add(new LPushConstant(readInt32())); return new LPushConstant(readInt32()); } case push3: { add(new LPushGlobal(trackGlobal(readInt32()))); add(new LPushGlobal(trackGlobal(readInt32()))); return new LPushGlobal(trackGlobal(readInt32())); } case push4_s: { add(new LPushLocal(trackStack(readInt32()))); add(new LPushLocal(trackStack(readInt32()))); add(new LPushLocal(trackStack(readInt32()))); return new LPushLocal(trackStack(readInt32())); } case push4_adr: { add(new LPushStackAddress(trackStack(readInt32()))); add(new LPushStackAddress(trackStack(readInt32()))); add(new LPushStackAddress(trackStack(readInt32()))); return new LPushStackAddress(trackStack(readInt32())); } case push4_c: { add(new LPushConstant(readInt32())); add(new LPushConstant(readInt32())); add(new LPushConstant(readInt32())); return new LPushConstant(readInt32()); } case push4: { add(new LPushGlobal(trackGlobal(readInt32()))); add(new LPushGlobal(trackGlobal(readInt32()))); add(new LPushGlobal(trackGlobal(readInt32()))); return new LPushGlobal(trackGlobal(readInt32())); } case push5_s: { add(new LPushLocal(trackStack(readInt32()))); add(new LPushLocal(trackStack(readInt32()))); add(new LPushLocal(trackStack(readInt32()))); add(new LPushLocal(trackStack(readInt32()))); return new LPushLocal(trackStack(readInt32())); } case push5_c: { add(new LPushConstant(readInt32())); add(new LPushConstant(readInt32())); add(new LPushConstant(readInt32())); add(new LPushConstant(readInt32())); return new LPushConstant(readInt32()); } case push5_adr: { add(new LPushStackAddress(trackStack(readInt32()))); add(new LPushStackAddress(trackStack(readInt32()))); add(new LPushStackAddress(trackStack(readInt32()))); add(new LPushStackAddress(trackStack(readInt32()))); return new LPushStackAddress(trackStack(readInt32())); } case push5: { add(new LPushGlobal(trackGlobal(readInt32()))); add(new LPushGlobal(trackGlobal(readInt32()))); add(new LPushGlobal(trackGlobal(readInt32()))); add(new LPushGlobal(trackGlobal(readInt32()))); return new LPushGlobal(trackGlobal(readInt32())); } case load_both: { add(new LLoadGlobal(trackGlobal(readInt32()), Register.Pri)); return new LLoadGlobal(trackGlobal(readInt32()), Register.Alt); } case load_s_both: { add(new LLoadLocal(trackStack(readInt32()), Register.Pri)); return new LLoadLocal(trackStack(readInt32()), Register.Alt); } case const_: { return new LStoreGlobalConstant(trackGlobal(readInt32()), readInt32()); } case const_s: { return new LStoreLocalConstant(trackStack(readInt32()), readInt32()); } case heap: { return new LHeap(readInt32()); } case movs: { return new LMemCopy(readInt32()); } case switch_: { long table = readUInt32(); long savePc = pc_; pc_ = table; SPOpcode casetbl = SPOpcode.values()[(int) readUInt32()]; assert (casetbl == SPOpcode.casetbl); int ncases = readInt32(); long defaultCase = readUInt32(); LinkedList<SwitchCase> cases = new LinkedList<SwitchCase>(); boolean bMultipleValues; for (int i = 0; i < ncases; i++) { int value = readInt32(); long pc = readUInt32(); LBlock target = prepareJumpTarget(pc); // Check if there are multiple values for the same case // case 1, 2, 3: bMultipleValues = false; for (int j = 0; j < cases.size(); j++) { if (cases.get(j).target.equals(target)) { cases.get(j).addValue(value); bMultipleValues = true; break; } } if (!bMultipleValues) cases.add(new SwitchCase(value, target)); } pc_ = savePc; return new LSwitch(prepareJumpTarget(defaultCase), cases); } case casetbl: { int ncases = readInt32(); pc_ += (long) ncases * 8 + 4; return new LDebugBreak(); } case genarray: { int dims = readInt32(); return new LGenArray(dims, false); } case genarray_z: { int dims = readInt32(); return new LGenArray(dims, true); } case tracker_pop_setheap: { return new LTrackerPopSetHeap(); } case tracker_push_c: { int value = readInt32(); return new LTrackerPushC(value); } case stradjust_pri: { return new LStradjustPri(); } case stackadjust: { int value = readInt32(); return new LStackAdjust(value); } case nop: { return new LDebugBreak(); } case halt: { readInt32(); return new LDebugBreak(); } default: throw new Exception("Unrecognized opcode: " + op); } }
private SPOpcode readOp() { return SPOpcode.values()[(int) readUInt32()]; }