/** * Rewrites a move instruction if it has 2 memory operands. One of the 2 memory operands must be a * stack location operand. Move the SP to the appropriate location and use a push or pop * instruction. * * @param s the instruction to rewrite */ private void rewriteMoveInstruction(Instruction s) { // first attempt to mutate the move into a noop if (mutateMoveToNop(s)) return; Operand result = MIR_Move.getResult(s); Operand val = MIR_Move.getValue(s); if (result instanceof StackLocationOperand) { if (val instanceof MemoryOperand || val instanceof StackLocationOperand) { int offset = ((StackLocationOperand) result).getOffset(); byte size = ((StackLocationOperand) result).getSize(); offset = FPOffset2SPOffset(offset) + size; moveESPBefore(s, offset); MIR_UnaryNoRes.mutate(s, IA32_PUSH, val); } } else { if (result instanceof MemoryOperand) { if (val instanceof StackLocationOperand) { int offset = ((StackLocationOperand) val).getOffset(); offset = FPOffset2SPOffset(offset); moveESPBefore(s, offset); MIR_Nullary.mutate(s, IA32_POP, result); } } } }
/** * expand an FCLEAR pseudo-insruction using FFREEs. * * @param s the instruction to expand * @param ir the containing IR */ private static void expandFClear(Instruction s, IR ir) { int nSave = MIR_UnaryNoRes.getVal(s).asIntConstant().value; int fpStackHeight = ir.MIRInfo.fpStackHeight; PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet().asIA32(); for (int i = nSave; i < fpStackHeight; i++) { Register f = phys.getFPR(i); s.insertBefore(MIR_Nullary.create(IA32_FFREE, D(f))); } // Remove the FCLEAR. s.remove(); }
/** * Insert the epilogue before a particular return instruction. * * @param ret the return instruction. */ private void insertEpilogue(Instruction ret) { // 1. Restore any saved registers if (ir.compiledMethod.isSaveVolatile()) { restoreVolatileRegisters(ret); restoreFloatingPointState(ret); } restoreNonVolatiles(ret); // 2. Restore caller's stackpointer and framepointer int frameSize = getFrameFixedSize(); ret.insertBefore(MIR_UnaryNoRes.create(REQUIRE_ESP, IC(frameSize))); MemoryOperand fpHome = MemoryOperand.BD( ir.regpool.makeTROp(), ArchEntrypoints.framePointerField.getOffset(), (byte) WORDSIZE, null, null); ret.insertBefore(MIR_Nullary.create(IA32_POP, fpHome)); }
/** * Walks through the IR. For each StackLocationOperand, replace the operand with the appropriate * MemoryOperand. */ private void rewriteStackLocations() { // ESP is initially WORDSIZE above where the framepointer is going to be. ESPOffset = getFrameFixedSize() + WORDSIZE; Register ESP = ((PhysicalRegisterSet) ir.regpool.getPhysicalRegisterSet()).getESP(); boolean seenReturn = false; for (Enumeration<Instruction> e = ir.forwardInstrEnumerator(); e.hasMoreElements(); ) { Instruction s = e.nextElement(); if (s.isReturn()) { seenReturn = true; continue; } if (s.isBranch()) { // restore ESP to home location at end of basic block. moveESPBefore(s, 0); continue; } if (s.operator() == BBEND) { if (seenReturn) { // at a return ESP will be at FrameFixedSize, seenReturn = false; ESPOffset = 0; } else { moveESPBefore(s, 0); } continue; } if (s.operator() == ADVISE_ESP) { ESPOffset = MIR_UnaryNoRes.getVal(s).asIntConstant().value; continue; } if (s.operator() == REQUIRE_ESP) { // ESP is required to be at the given offset from the bottom of the frame moveESPBefore(s, MIR_UnaryNoRes.getVal(s).asIntConstant().value); continue; } if (s.operator() == YIELDPOINT_PROLOGUE || s.operator() == YIELDPOINT_BACKEDGE || s.operator() == YIELDPOINT_EPILOGUE) { moveESPBefore(s, 0); continue; } if (s.operator() == IA32_MOV) { rewriteMoveInstruction(s); } // pop computes the effective address of its operand after ESP // is incremented. Therefore update ESPOffset before rewriting // stacklocation and memory operands. if (s.operator() == IA32_POP) { ESPOffset += WORDSIZE; } for (Enumeration<Operand> ops = s.getOperands(); ops.hasMoreElements(); ) { Operand op = ops.nextElement(); if (op instanceof StackLocationOperand) { StackLocationOperand sop = (StackLocationOperand) op; int offset = sop.getOffset(); if (sop.isFromTop()) { offset = FPOffset2SPOffset(offset); } offset -= ESPOffset; byte size = sop.getSize(); MemoryOperand M = MemoryOperand.BD( new RegisterOperand(ESP, PRIMITIVE_TYPE_FOR_WORD), Offset.fromIntSignExtend(offset), size, null, null); s.replaceOperand(op, M); } else if (op instanceof MemoryOperand) { MemoryOperand M = op.asMemory(); if ((M.base != null && M.base.getRegister() == ESP) || (M.index != null && M.index.getRegister() == ESP)) { M.disp = M.disp.minus(ESPOffset); } } } // push computes the effective address of its operand after ESP // is decremented. Therefore update ESPOffset after rewriting // stacklocation and memory operands. if (s.operator() == IA32_PUSH) { ESPOffset -= WORDSIZE; } } }
/** * Insert the prologue for a normal method. * * <p>Assume we are inserting the prologue for method B called from method A. * * <ul> * <li>Perform a stack overflow check. * <li>Store a back pointer to A's frame * <li>Store B's compiled method id * <li>Adjust frame pointer to point to B's frame * <li>Save any used non-volatile registers * </ul> */ @Override public void insertNormalPrologue() { PhysicalRegisterSet phys = (PhysicalRegisterSet) ir.regpool.getPhysicalRegisterSet(); Register ESP = phys.getESP(); MemoryOperand fpHome = MemoryOperand.BD( ir.regpool.makeTROp(), ArchEntrypoints.framePointerField.getOffset(), (byte) WORDSIZE, null, null); // the prologue instruction Instruction plg = ir.firstInstructionInCodeOrder().nextInstructionInCodeOrder(); // inst is the instruction immediately after the IR_PROLOGUE // instruction Instruction inst = plg.nextInstructionInCodeOrder(); int frameFixedSize = getFrameFixedSize(); ir.compiledMethod.setFrameFixedSize(frameFixedSize); // I. Buy a stackframe (including overflow check) // NOTE: We play a little game here. If the frame we are buying is // very small (less than 256) then we can be sloppy with the // stackoverflow check and actually allocate the frame in the guard // region. We'll notice when this frame calls someone and take the // stackoverflow in the callee. We can't do this if the frame is too big, // because growing the stack in the callee and/or handling a hardware trap // in this frame will require most of the guard region to complete. // See libvm.C. if (frameFixedSize >= 256) { // 1. Insert Stack overflow check. insertBigFrameStackOverflowCheck(plg); // 2. Save caller's frame pointer inst.insertBefore(MIR_UnaryNoRes.create(IA32_PUSH, fpHome)); // 3. Set my frame pointer to current value of stackpointer inst.insertBefore( MIR_Move.create( IA32_MOV, fpHome.copy(), new RegisterOperand(ESP, PRIMITIVE_TYPE_FOR_WORD))); // 4. Store my compiled method id int cmid = ir.compiledMethod.getId(); inst.insertBefore(MIR_UnaryNoRes.create(IA32_PUSH, VM.BuildFor32Addr ? IC(cmid) : LC(cmid))); } else { // 1. Save caller's frame pointer inst.insertBefore(MIR_UnaryNoRes.create(IA32_PUSH, fpHome)); // 2. Set my frame pointer to current value of stackpointer inst.insertBefore( MIR_Move.create( IA32_MOV, fpHome.copy(), new RegisterOperand(ESP, PRIMITIVE_TYPE_FOR_WORD))); // 3. Store my compiled method id int cmid = ir.compiledMethod.getId(); inst.insertBefore(MIR_UnaryNoRes.create(IA32_PUSH, VM.BuildFor32Addr ? IC(cmid) : LC(cmid))); // 4. Insert Stack overflow check. insertNormalStackOverflowCheck(plg); } // II. Save any used volatile and non-volatile registers if (ir.compiledMethod.isSaveVolatile()) { saveVolatiles(inst); saveFloatingPointState(inst); } saveNonVolatiles(inst); }