Chromium Code Reviews| Index: runtime/vm/assembler_mips.cc |
| =================================================================== |
| --- runtime/vm/assembler_mips.cc (revision 20565) |
| +++ runtime/vm/assembler_mips.cc (working copy) |
| @@ -76,6 +76,27 @@ |
| } |
| +void Assembler::LoadObject(Register rd, const Object& object) { |
| + // Smi's and VM heap objects are never relocated; do not use object pool. |
| + if (object.IsSmi()) { |
| + LoadImmediate(rd, reinterpret_cast<int32_t>(object.raw())); |
| + } else if (object.InVMHeap()) { |
| + // Make sure that class CallPattern is able to decode this load immediate. |
| + int32_t object_raw = reinterpret_cast<int32_t>(object.raw()); |
| + const uint16_t object_low = Utils::Low16Bits(object_raw); |
| + const uint16_t object_high = Utils::High16Bits(object_raw); |
| + lui(rd, Immediate(object_high)); |
| + ori(rd, rd, Immediate(object_low)); |
| + } else { |
| + // Make sure that class CallPattern is able to decode this load from the |
| + // object pool. |
| + const int32_t offset = |
| + Array::data_offset() + 4*AddObject(object) - kHeapObjectTag; |
| + LoadWordFromPoolOffset(rd, offset); |
| + } |
| +} |
| + |
| + |
| int32_t Assembler::AddObject(const Object& obj) { |
| ASSERT(obj.IsNotTemporaryScopedHandle()); |
| ASSERT(obj.IsOld()); |
| @@ -94,6 +115,152 @@ |
| } |
| +void Assembler::PushObject(const Object& object) { |
| + LoadObject(TMP, object); |
| + Push(TMP); |
| +} |
| + |
| + |
| +void Assembler::CompareObject(Register rd, Register rn, const Object& object) { |
| + ASSERT(rn != TMP); |
| + LoadObject(TMP, object); |
| + subu(rd, rn, TMP); |
| +} |
| + |
| + |
| +void Assembler::GetPC(Register rd) { |
| + Label next; |
| + |
| + mov(TMP, RA); // Save the return address. |
| + bal(&next); // Branch and link to the next instruction. |
| + |
| + // This instruction is the return address for the bal, so rd will |
| + // have the PC of this mov instruction. |
| + Bind(&next); |
| + mov(rd, RA); |
| + |
| + mov(RA, TMP); // Restore the return address. |
| + return; |
| +} |
| + |
| + |
| +// Pushes registers onto the stack starting with R31. |
| +void Assembler::PushList(RegList regs) { |
|
regis
2013/03/28 21:43:25
I am not sure why you need this, since it is reall
|
| + for (int i = kNumberOfCpuRegisters - 1; i >= 0; i--) { |
| + if ((regs & (1 << i)) != 0) { |
| + Push(static_cast<Register>(i)); |
| + } |
| + } |
| +} |
| + |
| + |
| +// Pops from stack into registers starting with R30. |
| +void Assembler::PopList(RegList regs) { |
|
regis
2013/03/28 21:43:25
ditto
|
| + for (int i = 0; i < kNumberOfCpuRegisters; i++) { |
| + if ((regs & (1 << i)) != 0) { |
| + Pop(static_cast<Register>(i)); |
| + } |
| + } |
| +} |
| + |
| + |
| +static int NumRegsBelowFP(RegList regs) { |
|
regis
2013/03/28 21:43:25
I do not think you will need this either if you do
|
| + int count = 0; |
| + for (int i = 0; i < FP; i++) { |
| + if ((regs & (1 << i)) != 0) { |
| + count++; |
| + } |
| + } |
| + return count; |
| +} |
| + |
| + |
| +void Assembler::EnterStubFrame() { |
| + // Push 0 as saved PC for stub frames. |
| + mov(TMP, RA); |
| + mov(RA, ZR); |
| + |
| + // We don't use EnterFrame here because TMP is the RA we want to restore. |
| + // If we used EnterFrame, it would call PushList, and not push in the right |
| + // order. |
| + Push(RA); |
| + Push(FP); |
| + Push(TMP); |
| + addiu(FP, SP, Immediate(1 * kWordSize)); |
|
regis
2013/03/28 21:43:25
The sequence above is not optimal. Do not use Push
|
| +} |
| + |
| + |
| +void Assembler::LeaveStubFrame() { |
| + addiu(SP, FP, Immediate(-1 * kWordSize)); |
| + Pop(RA); |
| + Pop(FP); |
|
regis
2013/03/28 21:43:25
Do not use Pop. Emit loads and only then adjust th
|
| + |
| + // Adjust SP for null PC pushed in EnterStubFrame. |
| + addiu(SP, SP, Immediate(kWordSize)); |
| +} |
| + |
| + |
| +void Assembler::EnterFrame(RegList regs, intptr_t frame_space) { |
| + if (prologue_offset_ == -1) { |
| + prologue_offset_ = CodeSize(); |
| + } |
| + PushList(regs); |
| + if ((regs & (1 << FP)) != 0) { |
| + // Set FP to the saved previous FP. |
| + addiu(FP, SP, Immediate(kWordSize * NumRegsBelowFP(regs))); |
| + } |
| + addiu(SP, SP, Immediate(-frame_space)); |
| +} |
| + |
| + |
| +void Assembler::LeaveFrame(RegList regs) { |
| + if ((regs & (1 << FP)) != 0) { |
| + // Use FP to set SP. |
| + addiu(SP, FP, Immediate(-kWordSize * NumRegsBelowFP(regs))); |
| + } |
| + PopList(regs); |
| +} |
| + |
| + |
| +void Assembler::EnterDartFrame(intptr_t frame_size) { |
| + const intptr_t offset = CodeSize(); |
| + |
| + // Save PC in frame for fast identification of corresponding code. |
| + GetPC(T0); |
| + Push(T0); |
| + |
| + // Note that callee-saved registers can be added to the register list. |
| + EnterFrame((1 << PP) | (1 << FP) | (1 << RA), 0); |
| + |
| + if (offset != 0) { |
| + // Adjust saved PC for any intrinsic code that could have been generated |
| + // before a frame is created. Use PP as temp register. |
| + lw(PP, Address(FP, 2 * kWordSize)); |
| + addiu(PP, PP, Immediate(-offset)); |
| + sw(PP, Address(FP, 2 * kWordSize)); |
| + } |
| + |
| + // Grab the PC again for looking up the pool pointer. |
| + GetPC(T0); |
| + |
| + // Setup pool pointer for this dart function. |
| + const intptr_t object_pool_pc_dist = |
| + Instructions::HeaderSize() - Instructions::object_pool_offset() + |
| + CodeSize() - (2 * Instr::kInstrSize); |
| + lw(PP, Address(T0 /* PC - 8 */, -object_pool_pc_dist)); |
| + |
| + // Reserve space for locals. |
| + addiu(SP, SP, Immediate(-frame_size)); |
| +} |
| + |
| + |
| +void Assembler::LeaveDartFrame() { |
| + LeaveFrame((1 << PP) | (1 << FP) | (1 << RA)); |
| + // Adjust SP for PC pushed in EnterDartFrame. |
| + addiu(SP, SP, Immediate(kWordSize)); |
| +} |
| + |
| + |
| int32_t Assembler::AddExternalLabel(const ExternalLabel* label) { |
| if (object_pool_.IsNull()) { |
| // The object pool cannot be used in the vm isolate. |