Chromium Code Reviews| Index: runtime/vm/assembler_x64.cc |
| =================================================================== |
| --- runtime/vm/assembler_x64.cc (revision 26436) |
| +++ runtime/vm/assembler_x64.cc (working copy) |
| @@ -95,9 +95,14 @@ |
| } |
| +void Assembler::LoadExternalLabel(const ExternalLabel* label) { |
| + const int32_t offset = Array::element_offset(AddExternalLabel(label)); |
| + LoadWordFromPoolOffset(TMP, offset - kHeapObjectTag); |
| +} |
| + |
| + |
| void Assembler::call(const ExternalLabel* label) { |
| AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| - intptr_t call_start = buffer_.GetPosition(); |
| // Encode movq(TMP, Immediate(label->address())), but always as imm64. |
| EmitRegisterREX(TMP, REX_W); |
| @@ -109,11 +114,21 @@ |
| EmitOperandREX(2, operand, REX_NONE); |
| EmitUint8(0xFF); |
| EmitOperand(2, operand); |
| +} |
| - ASSERT((buffer_.GetPosition() - call_start) == kCallExternalLabelSize); |
| + |
| +void Assembler::CallPatchable(const ExternalLabel* label) { |
| + LoadExternalLabel(label); |
| + { |
| + AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| + // Encode call(TMP). |
| + Operand operand(TMP); |
| + EmitOperandREX(2, operand, REX_NONE); |
| + EmitUint8(0xFF); |
| + EmitOperand(2, operand); |
| + } |
| } |
| - |
| void Assembler::pushq(Register reg) { |
| AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| EmitRegisterREX(reg, REX_NONE); |
| @@ -1995,7 +2010,6 @@ |
| void Assembler::jmp(const ExternalLabel* label) { |
| AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| - intptr_t call_start = buffer_.GetPosition(); |
| // Encode movq(TMP, Immediate(label->address())), but always as imm64. |
| EmitRegisterREX(TMP, REX_W); |
| @@ -2007,8 +2021,6 @@ |
| EmitOperandREX(4, operand, REX_NONE); |
| EmitUint8(0xFF); |
| EmitOperand(4, operand); |
| - |
| - ASSERT((buffer_.GetPosition() - call_start) == kCallExternalLabelSize); |
| } |
| @@ -2091,16 +2103,59 @@ |
| } |
| +int32_t Assembler::AddObject(const Object& obj) { |
| + ASSERT(obj.IsNotTemporaryScopedHandle()); |
| + ASSERT(obj.IsOld()); |
| + if (object_pool_.IsNull()) { |
| + // The object pool cannot be used in the vm isolate. |
| + ASSERT(Isolate::Current() != Dart::vm_isolate()); |
| + object_pool_ = GrowableObjectArray::New(Heap::kOld); |
| + } |
| + for (int i = 0; i < object_pool_.Length(); i++) { |
| + if (object_pool_.At(i) == obj.raw()) { |
| + return i; |
| + } |
| + } |
| + object_pool_.Add(obj, Heap::kOld); |
| + return object_pool_.Length() - 1; |
| +} |
| + |
| + |
| +int32_t Assembler::AddExternalLabel(const ExternalLabel* label) { |
| + if (object_pool_.IsNull()) { |
| + // The object pool cannot be used in the vm isolate. |
| + ASSERT(Isolate::Current() != Dart::vm_isolate()); |
| + object_pool_ = GrowableObjectArray::New(Heap::kOld); |
| + } |
| + const word address = label->address(); |
| + ASSERT(Utils::IsAligned(address, 4)); |
| + // The address is stored in the object array as a RawSmi. |
| + const Smi& smi = Smi::Handle(Smi::New(address >> kSmiTagShift)); |
| + // Do not reuse an existing entry, since each reference may be patched |
| + // independently. |
| + object_pool_.Add(smi, Heap::kOld); |
| + return object_pool_.Length() - 1; |
| +} |
| + |
| + |
| +void Assembler::LoadWordFromPoolOffset(Register dst, int32_t offset) { |
| + movq(dst, Address(PP, offset)); |
| + // This sequence must be of fixed size. If offset fits in a signed byte we |
| + // have to pad with nops. |
| + if (Utils::IsInt(8, offset)) { |
| + nop(3); |
| + } |
| +} |
| + |
| + |
| void Assembler::LoadObject(Register dst, const Object& object) { |
| if (object.IsSmi() || object.InVMHeap()) { |
| movq(dst, Immediate(reinterpret_cast<int64_t>(object.raw()))); |
| } else { |
| ASSERT(object.IsNotTemporaryScopedHandle()); |
| ASSERT(object.IsOld()); |
| - AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| - EmitRegisterREX(dst, REX_W); |
| - EmitUint8(0xB8 | (dst & 7)); |
| - buffer_.EmitObject(object); |
| + const int32_t offset = Array::element_offset(AddObject(object)); |
| + LoadWordFromPoolOffset(dst, offset - kHeapObjectTag); |
| } |
| } |
| @@ -2292,9 +2347,15 @@ |
| } |
| -void Assembler::LeaveFrame() { |
| - movq(RSP, RBP); |
| - popq(RBP); |
| +void Assembler::LeaveFrame(bool restore_pp) { |
| + if (restore_pp) { |
| + leaq(RSP, Address(RBP, -2 * kWordSize)); // Restore stack pointer. |
|
Ivan Posva
2013/08/22 05:26:25
Wouldn't this be shorter?
if (restore_pp) {
mov
|
| + popq(PP); // Restore PP. |
| + popq(RBP); // Ignore PC marker. |
| + } else { |
| + movq(RSP, RBP); // Restore stack pointer. |
| + } |
| + popq(RBP); // Restore frame pointer. |
| } |
| @@ -2377,6 +2438,21 @@ |
| } |
| +void Assembler::LoadPoolPointer() { |
| + Label next; |
| + call(&next); |
| + Bind(&next); |
| + |
| + // Load new pool pointer. |
| + const intptr_t object_pool_pc_dist = |
| + Instructions::HeaderSize() - Instructions::object_pool_offset() + |
| + CodeSize(); |
| + addq(Address(RSP, 0), Immediate(-object_pool_pc_dist)); |
| + popq(PP); |
| + movq(PP, Address(PP, 0)); |
|
Ivan Posva
2013/08/22 05:26:25
popq(PP);
movq(PP, Address(PP, -object_pool_pc_dis
|
| +} |
| + |
| + |
| void Assembler::EnterDartFrame(intptr_t frame_size) { |
| EnterFrame(0); |
| Label dart_entry; |
| @@ -2385,10 +2461,21 @@ |
| // The runtime system assumes that the code marker address is |
| // kEntryPointToPcMarkerOffset bytes from the entry. If there is any code |
| // generated before entering the frame, the address needs to be adjusted. |
| + const intptr_t object_pool_pc_dist = |
| + Instructions::HeaderSize() - Instructions::object_pool_offset() + |
| + CodeSize(); |
| const intptr_t offset = kEntryPointToPcMarkerOffset - CodeSize(); |
| if (offset != 0) { |
| addq(Address(RSP, 0), Immediate(offset)); |
| } |
| + // Save caller's pool pointer |
| + pushq(PP); |
| + |
| + // Load callee's pool pointer. |
| + movq(PP, Address(RSP, 1 * kWordSize)); |
| + addq(PP, Immediate(-object_pool_pc_dist - offset)); |
| + movq(PP, Address(PP, 0)); |
|
Ivan Posva
2013/08/22 05:26:25
Wouldn't this be shorter?
movq(PP, Address(RSP, 1*
|
| + |
| if (frame_size != 0) { |
| subq(RSP, Immediate(frame_size)); |
| } |
| @@ -2407,20 +2494,37 @@ |
| // The runtime system assumes that the code marker address is |
| // kEntryPointToPcMarkerOffset bytes from the entry. Since there is no |
| // code to set up the frame pointer, the address needs to be adjusted. |
| + const intptr_t object_pool_pc_dist = |
| + Instructions::HeaderSize() - Instructions::object_pool_offset() + |
| + CodeSize(); |
| const intptr_t offset = kEntryPointToPcMarkerOffset - CodeSize(); |
| if (offset != 0) { |
| addq(Address(RSP, 0), Immediate(offset)); |
| } |
| + |
| + // Load callee's pool pointer. |
| + movq(PP, Address(RSP, 0)); |
| + addq(PP, Immediate(-object_pool_pc_dist - offset)); |
| + movq(PP, Address(PP, 0)); |
| + |
| popq(Address(RBP, kPcMarkerSlotFromFp * kWordSize)); |
| + |
| if (extra_size != 0) { |
| subq(RSP, Immediate(extra_size)); |
| } |
| } |
| -void Assembler::EnterStubFrame() { |
| - EnterFrame(0); |
| - pushq(Immediate(0)); // Push 0 in the saved PC area for stub frames. |
| +void Assembler::EnterStubFrame(bool save_pp) { |
| + if (save_pp) { |
| + EnterFrame(0); |
| + pushq(Immediate(0)); // Push 0 in the saved PC area for stub frames. |
| + pushq(PP); // Save caller's pool pointer |
| + LoadPoolPointer(); |
| + } else { |
| + EnterFrame(0); |
| + pushq(Immediate(0)); // Push 0 in the saved PC area for stub frames. |
| + } |
| } |