OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/globals.h" // NOLINT | 5 #include "vm/globals.h" // NOLINT |
6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
7 | 7 |
8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
9 #include "vm/cpu.h" | 9 #include "vm/cpu.h" |
10 #include "vm/heap.h" | 10 #include "vm/heap.h" |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 EmitRegisterREX(TMP, REX_W); | 76 EmitRegisterREX(TMP, REX_W); |
77 EmitUint8(0xB8 | (TMP & 7)); | 77 EmitUint8(0xB8 | (TMP & 7)); |
78 EmitInt64(label->address()); | 78 EmitInt64(label->address()); |
79 } | 79 } |
80 call(TMP); | 80 call(TMP); |
81 } | 81 } |
82 | 82 |
83 | 83 |
84 void Assembler::CallPatchable(const StubEntry& stub_entry) { | 84 void Assembler::CallPatchable(const StubEntry& stub_entry) { |
85 ASSERT(constant_pool_allowed()); | 85 ASSERT(constant_pool_allowed()); |
| 86 const Code& target = Code::Handle(stub_entry.code()); |
86 intptr_t call_start = buffer_.GetPosition(); | 87 intptr_t call_start = buffer_.GetPosition(); |
87 const int32_t offset = ObjectPool::element_offset( | 88 const int32_t offset = ObjectPool::element_offset( |
88 object_pool_wrapper_.FindExternalLabel(&stub_entry.label(), kPatchable)); | 89 object_pool_wrapper_.FindObject(target, kPatchable)); |
89 call(Address::AddressBaseImm32(PP, offset - kHeapObjectTag)); | 90 LoadWordFromPoolOffset(CODE_REG, offset - kHeapObjectTag); |
| 91 movq(TMP, FieldAddress(CODE_REG, Code::entry_point_offset())); |
| 92 call(TMP); |
90 ASSERT((buffer_.GetPosition() - call_start) == kCallExternalLabelSize); | 93 ASSERT((buffer_.GetPosition() - call_start) == kCallExternalLabelSize); |
91 } | 94 } |
92 | 95 |
93 | 96 |
94 void Assembler::Call(const StubEntry& stub_entry) { | 97 void Assembler::Call(const StubEntry& stub_entry) { |
95 ASSERT(constant_pool_allowed()); | 98 ASSERT(constant_pool_allowed()); |
| 99 const Code& target = Code::Handle(stub_entry.code()); |
96 const int32_t offset = ObjectPool::element_offset( | 100 const int32_t offset = ObjectPool::element_offset( |
97 object_pool_wrapper_.FindExternalLabel(&stub_entry.label(), | 101 object_pool_wrapper_.FindObject(target, kNotPatchable)); |
98 kNotPatchable)); | 102 LoadWordFromPoolOffset(CODE_REG, offset - kHeapObjectTag); |
99 call(Address::AddressBaseImm32(PP, offset - kHeapObjectTag)); | 103 movq(TMP, FieldAddress(CODE_REG, Code::entry_point_offset())); |
| 104 call(TMP); |
100 } | 105 } |
101 | 106 |
102 | 107 |
103 void Assembler::pushq(Register reg) { | 108 void Assembler::pushq(Register reg) { |
104 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 109 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
105 EmitRegisterREX(reg, REX_NONE); | 110 EmitRegisterREX(reg, REX_NONE); |
106 EmitUint8(0x50 | (reg & 7)); | 111 EmitUint8(0x50 | (reg & 7)); |
107 } | 112 } |
108 | 113 |
109 | 114 |
(...skipping 2416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2526 EmitUint8(0x70 + condition); | 2531 EmitUint8(0x70 + condition); |
2527 EmitNearLabelLink(label); | 2532 EmitNearLabelLink(label); |
2528 } else { | 2533 } else { |
2529 EmitUint8(0x0F); | 2534 EmitUint8(0x0F); |
2530 EmitUint8(0x80 + condition); | 2535 EmitUint8(0x80 + condition); |
2531 EmitLabelLink(label); | 2536 EmitLabelLink(label); |
2532 } | 2537 } |
2533 } | 2538 } |
2534 | 2539 |
2535 | 2540 |
2536 void Assembler::J(Condition condition, const StubEntry& stub_entry, | 2541 void Assembler::J(Condition condition, |
| 2542 const StubEntry& stub_entry, |
2537 Register pp) { | 2543 Register pp) { |
2538 Label no_jump; | 2544 Label no_jump; |
2539 // Negate condition. | 2545 // Negate condition. |
2540 j(static_cast<Condition>(condition ^ 1), &no_jump, Assembler::kNearJump); | 2546 j(static_cast<Condition>(condition ^ 1), &no_jump, kNearJump); |
2541 Jmp(stub_entry, pp); | 2547 Jmp(stub_entry, pp); |
2542 Bind(&no_jump); | 2548 Bind(&no_jump); |
2543 } | 2549 } |
2544 | 2550 |
2545 | 2551 |
2546 void Assembler::jmp(Register reg) { | 2552 void Assembler::jmp(Register reg) { |
2547 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 2553 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
2548 Operand operand(reg); | 2554 Operand operand(reg); |
2549 EmitOperandREX(4, operand, REX_NONE); | 2555 EmitOperandREX(4, operand, REX_NONE); |
2550 EmitUint8(0xFF); | 2556 EmitUint8(0xFF); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2591 { // Encode movq(TMP, Immediate(label->address())), but always as imm64. | 2597 { // Encode movq(TMP, Immediate(label->address())), but always as imm64. |
2592 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 2598 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
2593 EmitRegisterREX(TMP, REX_W); | 2599 EmitRegisterREX(TMP, REX_W); |
2594 EmitUint8(0xB8 | (TMP & 7)); | 2600 EmitUint8(0xB8 | (TMP & 7)); |
2595 EmitInt64(label->address()); | 2601 EmitInt64(label->address()); |
2596 } | 2602 } |
2597 jmp(TMP); | 2603 jmp(TMP); |
2598 } | 2604 } |
2599 | 2605 |
2600 | 2606 |
2601 void Assembler::jmp(const StubEntry& stub_entry) { | |
2602 jmp(&stub_entry.label()); | |
2603 } | |
2604 | |
2605 | |
2606 void Assembler::JmpPatchable(const StubEntry& stub_entry, Register pp) { | 2607 void Assembler::JmpPatchable(const StubEntry& stub_entry, Register pp) { |
2607 ASSERT((pp != PP) || constant_pool_allowed()); | 2608 ASSERT((pp != PP) || constant_pool_allowed()); |
2608 intptr_t call_start = buffer_.GetPosition(); | 2609 const Code& target = Code::Handle(stub_entry.code()); |
2609 const int32_t offset = ObjectPool::element_offset( | 2610 const int32_t offset = ObjectPool::element_offset( |
2610 object_pool_wrapper_.FindExternalLabel(&stub_entry.label(), kPatchable)); | 2611 object_pool_wrapper_.FindObject(target, kPatchable)); |
2611 // Patchable jumps always use a 32-bit immediate encoding. | 2612 movq(CODE_REG, Address::AddressBaseImm32(pp, offset - kHeapObjectTag)); |
2612 jmp(Address::AddressBaseImm32(pp, offset - kHeapObjectTag)); | 2613 movq(TMP, FieldAddress(CODE_REG, Code::entry_point_offset())); |
2613 ASSERT((buffer_.GetPosition() - call_start) == JumpPattern::kLengthInBytes); | 2614 jmp(TMP); |
2614 } | 2615 } |
2615 | 2616 |
2616 | 2617 |
2617 void Assembler::Jmp(const StubEntry& stub_entry, Register pp) { | 2618 void Assembler::Jmp(const StubEntry& stub_entry, Register pp) { |
2618 ASSERT((pp != PP) || constant_pool_allowed()); | 2619 ASSERT((pp != PP) || constant_pool_allowed()); |
| 2620 const Code& target = Code::Handle(stub_entry.code()); |
2619 const int32_t offset = ObjectPool::element_offset( | 2621 const int32_t offset = ObjectPool::element_offset( |
2620 object_pool_wrapper_.FindExternalLabel(&stub_entry.label(), | 2622 object_pool_wrapper_.FindObject(target, kNotPatchable)); |
2621 kNotPatchable)); | 2623 movq(CODE_REG, FieldAddress(pp, offset)); |
2622 jmp(Address(pp, offset - kHeapObjectTag)); | 2624 movq(TMP, FieldAddress(CODE_REG, Code::entry_point_offset())); |
| 2625 jmp(TMP); |
2623 } | 2626 } |
2624 | 2627 |
2625 | 2628 |
2626 void Assembler::lock() { | 2629 void Assembler::lock() { |
2627 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 2630 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
2628 EmitUint8(0xF0); | 2631 EmitUint8(0xF0); |
2629 } | 2632 } |
2630 | 2633 |
2631 | 2634 |
2632 void Assembler::cmpxchgl(const Address& address, Register reg) { | 2635 void Assembler::cmpxchgl(const Address& address, Register reg) { |
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3055 if (can_value_be_smi) { | 3058 if (can_value_be_smi) { |
3056 StoreIntoObjectFilter(object, value, &done); | 3059 StoreIntoObjectFilter(object, value, &done); |
3057 } else { | 3060 } else { |
3058 StoreIntoObjectFilterNoSmi(object, value, &done); | 3061 StoreIntoObjectFilterNoSmi(object, value, &done); |
3059 } | 3062 } |
3060 // A store buffer update is required. | 3063 // A store buffer update is required. |
3061 if (value != RDX) pushq(RDX); | 3064 if (value != RDX) pushq(RDX); |
3062 if (object != RDX) { | 3065 if (object != RDX) { |
3063 movq(RDX, object); | 3066 movq(RDX, object); |
3064 } | 3067 } |
| 3068 pushq(CODE_REG); |
| 3069 movq(CODE_REG, Address(THR, Thread::update_store_buffer_code_offset())); |
3065 movq(TMP, Address(THR, Thread::update_store_buffer_entry_point_offset())); | 3070 movq(TMP, Address(THR, Thread::update_store_buffer_entry_point_offset())); |
3066 call(TMP); | 3071 call(TMP); |
| 3072 |
| 3073 popq(CODE_REG); |
3067 if (value != RDX) popq(RDX); | 3074 if (value != RDX) popq(RDX); |
3068 Bind(&done); | 3075 Bind(&done); |
3069 } | 3076 } |
3070 | 3077 |
3071 | 3078 |
3072 void Assembler::StoreIntoObjectNoBarrier(Register object, | 3079 void Assembler::StoreIntoObjectNoBarrier(Register object, |
3073 const Address& dest, | 3080 const Address& dest, |
3074 Register value, | 3081 Register value, |
3075 FieldContent old_content) { | 3082 FieldContent old_content) { |
3076 VerifiedWrite(dest, value, old_content); | 3083 VerifiedWrite(dest, value, old_content); |
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3357 call(reg); | 3364 call(reg); |
3358 } | 3365 } |
3359 | 3366 |
3360 | 3367 |
3361 void Assembler::CallRuntime(const RuntimeEntry& entry, | 3368 void Assembler::CallRuntime(const RuntimeEntry& entry, |
3362 intptr_t argument_count) { | 3369 intptr_t argument_count) { |
3363 entry.Call(this, argument_count); | 3370 entry.Call(this, argument_count); |
3364 } | 3371 } |
3365 | 3372 |
3366 | 3373 |
| 3374 void Assembler::RestoreCodePointer() { |
| 3375 movq(CODE_REG, Address(RBP, kPcMarkerSlotFromFp * kWordSize)); |
| 3376 } |
| 3377 |
| 3378 |
3367 void Assembler::LoadPoolPointer(Register pp) { | 3379 void Assembler::LoadPoolPointer(Register pp) { |
3368 // Load new pool pointer. | 3380 // Load new pool pointer. |
3369 const intptr_t kRIPRelativeMovqSize = 7; | 3381 CheckCodePointer(); |
3370 const intptr_t entry_to_rip_offset = CodeSize() + kRIPRelativeMovqSize; | 3382 movq(pp, FieldAddress(CODE_REG, Code::object_pool_offset())); |
3371 const intptr_t object_pool_pc_dist = | |
3372 Instructions::HeaderSize() - Instructions::object_pool_offset(); | |
3373 movq(pp, Address::AddressRIPRelative( | |
3374 -entry_to_rip_offset - object_pool_pc_dist)); | |
3375 ASSERT(CodeSize() == entry_to_rip_offset); | |
3376 set_constant_pool_allowed(pp == PP); | 3383 set_constant_pool_allowed(pp == PP); |
3377 } | 3384 } |
3378 | 3385 |
3379 | 3386 |
3380 void Assembler::EnterDartFrame(intptr_t frame_size, | 3387 void Assembler::EnterDartFrame(intptr_t frame_size, Register new_pp) { |
3381 Register new_pp, | 3388 CheckCodePointer(); |
3382 Register pc_marker_override) { | |
3383 ASSERT(!constant_pool_allowed()); | 3389 ASSERT(!constant_pool_allowed()); |
3384 EnterFrame(0); | 3390 EnterFrame(0); |
3385 pushq(pc_marker_override); | 3391 pushq(CODE_REG); |
3386 pushq(PP); | 3392 pushq(PP); |
3387 movq(PP, new_pp); | 3393 if (new_pp == kNoRegister) { |
| 3394 LoadPoolPointer(PP); |
| 3395 } else { |
| 3396 movq(PP, new_pp); |
| 3397 } |
3388 set_constant_pool_allowed(true); | 3398 set_constant_pool_allowed(true); |
3389 if (frame_size != 0) { | 3399 if (frame_size != 0) { |
3390 subq(RSP, Immediate(frame_size)); | 3400 subq(RSP, Immediate(frame_size)); |
3391 } | 3401 } |
3392 } | 3402 } |
3393 | 3403 |
3394 | 3404 |
3395 void Assembler::LeaveDartFrame() { | 3405 void Assembler::LeaveDartFrame(RestorePP restore_pp) { |
3396 set_constant_pool_allowed(false); | |
3397 // Restore caller's PP register that was pushed in EnterDartFrame. | 3406 // Restore caller's PP register that was pushed in EnterDartFrame. |
3398 movq(PP, Address(RBP, (kSavedCallerPpSlotFromFp * kWordSize))); | 3407 if (restore_pp == kRestoreCallerPP) { |
| 3408 movq(PP, Address(RBP, (kSavedCallerPpSlotFromFp * kWordSize))); |
| 3409 set_constant_pool_allowed(false); |
| 3410 } |
3399 LeaveFrame(); | 3411 LeaveFrame(); |
3400 } | 3412 } |
3401 | 3413 |
3402 | 3414 |
| 3415 void Assembler::CheckCodePointer() { |
| 3416 #ifdef DEBUG |
| 3417 Label cid_ok, instructions_ok; |
| 3418 pushq(RAX); |
| 3419 LoadClassId(RAX, CODE_REG); |
| 3420 cmpq(RAX, Immediate(kCodeCid)); |
| 3421 j(EQUAL, &cid_ok); |
| 3422 int3(); |
| 3423 Bind(&cid_ok); |
| 3424 { |
| 3425 const intptr_t kRIPRelativeLeaqSize = 7; |
| 3426 const intptr_t header_to_entry_offset = |
| 3427 (Instructions::HeaderSize() - kHeapObjectTag); |
| 3428 const intptr_t header_to_rip_offset = |
| 3429 CodeSize() + kRIPRelativeLeaqSize + header_to_entry_offset; |
| 3430 leaq(RAX, Address::AddressRIPRelative(-header_to_rip_offset)); |
| 3431 ASSERT(CodeSize() == (header_to_rip_offset - header_to_entry_offset)); |
| 3432 } |
| 3433 cmpq(RAX, FieldAddress(CODE_REG, Code::instructions_offset())); |
| 3434 j(EQUAL, &instructions_ok); |
| 3435 int3(); |
| 3436 Bind(&instructions_ok); |
| 3437 popq(RAX); |
| 3438 #endif |
| 3439 } |
| 3440 |
| 3441 |
3403 // On entry to a function compiled for OSR, the caller's frame pointer, the | 3442 // On entry to a function compiled for OSR, the caller's frame pointer, the |
3404 // stack locals, and any copied parameters are already in place. The frame | 3443 // stack locals, and any copied parameters are already in place. The frame |
3405 // pointer is already set up. The PC marker is not correct for the | 3444 // pointer is already set up. The PC marker is not correct for the |
3406 // optimized function and there may be extra space for spill slots to | 3445 // optimized function and there may be extra space for spill slots to |
3407 // allocate. | 3446 // allocate. |
3408 void Assembler::EnterOsrFrame(intptr_t extra_size, | 3447 void Assembler::EnterOsrFrame(intptr_t extra_size) { |
3409 Register new_pp, | |
3410 Register pc_marker_override) { | |
3411 ASSERT(!constant_pool_allowed()); | 3448 ASSERT(!constant_pool_allowed()); |
3412 if (prologue_offset_ == -1) { | 3449 if (prologue_offset_ == -1) { |
3413 Comment("PrologueOffset = %" Pd "", CodeSize()); | 3450 Comment("PrologueOffset = %" Pd "", CodeSize()); |
3414 prologue_offset_ = CodeSize(); | 3451 prologue_offset_ = CodeSize(); |
3415 } | 3452 } |
3416 movq(Address(RBP, kPcMarkerSlotFromFp * kWordSize), pc_marker_override); | 3453 RestoreCodePointer(); |
3417 movq(PP, new_pp); | 3454 LoadPoolPointer(); |
3418 set_constant_pool_allowed(true); | 3455 |
3419 if (extra_size != 0) { | 3456 if (extra_size != 0) { |
3420 subq(RSP, Immediate(extra_size)); | 3457 subq(RSP, Immediate(extra_size)); |
3421 } | 3458 } |
3422 } | 3459 } |
3423 | 3460 |
3424 | 3461 |
3425 void Assembler::EnterStubFrame() { | 3462 void Assembler::EnterStubFrame() { |
3426 set_constant_pool_allowed(false); | 3463 EnterDartFrame(0, kNoRegister); |
3427 EnterFrame(0); | |
3428 pushq(Immediate(0)); // Push 0 in the saved PC area for stub frames. | |
3429 pushq(PP); // Save caller's pool pointer | |
3430 LoadPoolPointer(); | |
3431 } | 3464 } |
3432 | 3465 |
3433 | 3466 |
3434 void Assembler::LeaveStubFrame() { | 3467 void Assembler::LeaveStubFrame() { |
3435 LeaveDartFrame(); | 3468 LeaveDartFrame(); |
3436 } | 3469 } |
3437 | 3470 |
3438 | 3471 |
3439 void Assembler::MaybeTraceAllocation(intptr_t cid, | 3472 void Assembler::MaybeTraceAllocation(intptr_t cid, |
3440 Label* trace, | 3473 Label* trace, |
(...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3927 | 3960 |
3928 | 3961 |
3929 const char* Assembler::FpuRegisterName(FpuRegister reg) { | 3962 const char* Assembler::FpuRegisterName(FpuRegister reg) { |
3930 ASSERT((0 <= reg) && (reg < kNumberOfXmmRegisters)); | 3963 ASSERT((0 <= reg) && (reg < kNumberOfXmmRegisters)); |
3931 return xmm_reg_names[reg]; | 3964 return xmm_reg_names[reg]; |
3932 } | 3965 } |
3933 | 3966 |
3934 } // namespace dart | 3967 } // namespace dart |
3935 | 3968 |
3936 #endif // defined TARGET_ARCH_X64 | 3969 #endif // defined TARGET_ARCH_X64 |
OLD | NEW |