| 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 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 EmitRegisterREX(TMP, REX_W); | 86 EmitRegisterREX(TMP, REX_W); |
| 87 EmitUint8(0xB8 | (TMP & 7)); | 87 EmitUint8(0xB8 | (TMP & 7)); |
| 88 EmitInt64(label->address()); | 88 EmitInt64(label->address()); |
| 89 } | 89 } |
| 90 call(TMP); | 90 call(TMP); |
| 91 } | 91 } |
| 92 | 92 |
| 93 | 93 |
| 94 void Assembler::CallPatchable(const StubEntry& stub_entry) { | 94 void Assembler::CallPatchable(const StubEntry& stub_entry) { |
| 95 ASSERT(constant_pool_allowed()); | 95 ASSERT(constant_pool_allowed()); |
| 96 const Code& target = Code::Handle(stub_entry.code()); |
| 96 intptr_t call_start = buffer_.GetPosition(); | 97 intptr_t call_start = buffer_.GetPosition(); |
| 97 const int32_t offset = ObjectPool::element_offset( | 98 const int32_t offset = ObjectPool::element_offset( |
| 98 object_pool_wrapper_.FindExternalLabel(&stub_entry.label(), kPatchable)); | 99 object_pool_wrapper_.FindObject(target, kPatchable)); |
| 99 call(Address::AddressBaseImm32(PP, offset - kHeapObjectTag)); | 100 LoadWordFromPoolOffset(CODE_REG, offset - kHeapObjectTag); |
| 101 movq(TMP, FieldAddress(CODE_REG, Code::entry_point_offset())); |
| 102 call(TMP); |
| 100 ASSERT((buffer_.GetPosition() - call_start) == kCallExternalLabelSize); | 103 ASSERT((buffer_.GetPosition() - call_start) == kCallExternalLabelSize); |
| 101 } | 104 } |
| 102 | 105 |
| 103 | 106 |
| 104 void Assembler::Call(const StubEntry& stub_entry) { | 107 void Assembler::Call(const StubEntry& stub_entry) { |
| 105 ASSERT(constant_pool_allowed()); | 108 ASSERT(constant_pool_allowed()); |
| 109 const Code& target = Code::Handle(stub_entry.code()); |
| 106 const int32_t offset = ObjectPool::element_offset( | 110 const int32_t offset = ObjectPool::element_offset( |
| 107 object_pool_wrapper_.FindExternalLabel(&stub_entry.label(), | 111 object_pool_wrapper_.FindObject(target, kNotPatchable)); |
| 108 kNotPatchable)); | 112 LoadWordFromPoolOffset(CODE_REG, offset - kHeapObjectTag); |
| 109 call(Address::AddressBaseImm32(PP, offset - kHeapObjectTag)); | 113 movq(TMP, FieldAddress(CODE_REG, Code::entry_point_offset())); |
| 114 call(TMP); |
| 110 } | 115 } |
| 111 | 116 |
| 112 | 117 |
| 113 void Assembler::pushq(Register reg) { | 118 void Assembler::pushq(Register reg) { |
| 114 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 119 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 115 EmitRegisterREX(reg, REX_NONE); | 120 EmitRegisterREX(reg, REX_NONE); |
| 116 EmitUint8(0x50 | (reg & 7)); | 121 EmitUint8(0x50 | (reg & 7)); |
| 117 } | 122 } |
| 118 | 123 |
| 119 | 124 |
| (...skipping 2416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2536 EmitUint8(0x70 + condition); | 2541 EmitUint8(0x70 + condition); |
| 2537 EmitNearLabelLink(label); | 2542 EmitNearLabelLink(label); |
| 2538 } else { | 2543 } else { |
| 2539 EmitUint8(0x0F); | 2544 EmitUint8(0x0F); |
| 2540 EmitUint8(0x80 + condition); | 2545 EmitUint8(0x80 + condition); |
| 2541 EmitLabelLink(label); | 2546 EmitLabelLink(label); |
| 2542 } | 2547 } |
| 2543 } | 2548 } |
| 2544 | 2549 |
| 2545 | 2550 |
| 2546 void Assembler::J(Condition condition, const StubEntry& stub_entry, | 2551 void Assembler::J(Condition condition, |
| 2552 const StubEntry& stub_entry, |
| 2547 Register pp) { | 2553 Register pp) { |
| 2548 Label no_jump; | 2554 Label no_jump; |
| 2549 // Negate condition. | 2555 // Negate condition. |
| 2550 j(static_cast<Condition>(condition ^ 1), &no_jump, Assembler::kNearJump); | 2556 j(static_cast<Condition>(condition ^ 1), &no_jump, kNearJump); |
| 2551 Jmp(stub_entry, pp); | 2557 Jmp(stub_entry, pp); |
| 2552 Bind(&no_jump); | 2558 Bind(&no_jump); |
| 2553 } | 2559 } |
| 2554 | 2560 |
| 2555 | 2561 |
| 2556 void Assembler::jmp(Register reg) { | 2562 void Assembler::jmp(Register reg) { |
| 2557 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 2563 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 2558 Operand operand(reg); | 2564 Operand operand(reg); |
| 2559 EmitOperandREX(4, operand, REX_NONE); | 2565 EmitOperandREX(4, operand, REX_NONE); |
| 2560 EmitUint8(0xFF); | 2566 EmitUint8(0xFF); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2601 { // Encode movq(TMP, Immediate(label->address())), but always as imm64. | 2607 { // Encode movq(TMP, Immediate(label->address())), but always as imm64. |
| 2602 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 2608 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 2603 EmitRegisterREX(TMP, REX_W); | 2609 EmitRegisterREX(TMP, REX_W); |
| 2604 EmitUint8(0xB8 | (TMP & 7)); | 2610 EmitUint8(0xB8 | (TMP & 7)); |
| 2605 EmitInt64(label->address()); | 2611 EmitInt64(label->address()); |
| 2606 } | 2612 } |
| 2607 jmp(TMP); | 2613 jmp(TMP); |
| 2608 } | 2614 } |
| 2609 | 2615 |
| 2610 | 2616 |
| 2611 void Assembler::jmp(const StubEntry& stub_entry) { | |
| 2612 jmp(&stub_entry.label()); | |
| 2613 } | |
| 2614 | |
| 2615 | |
| 2616 void Assembler::JmpPatchable(const StubEntry& stub_entry, Register pp) { | 2617 void Assembler::JmpPatchable(const StubEntry& stub_entry, Register pp) { |
| 2617 ASSERT((pp != PP) || constant_pool_allowed()); | 2618 ASSERT((pp != PP) || constant_pool_allowed()); |
| 2618 intptr_t call_start = buffer_.GetPosition(); | 2619 const Code& target = Code::Handle(stub_entry.code()); |
| 2619 const int32_t offset = ObjectPool::element_offset( | 2620 const int32_t offset = ObjectPool::element_offset( |
| 2620 object_pool_wrapper_.FindExternalLabel(&stub_entry.label(), kPatchable)); | 2621 object_pool_wrapper_.FindObject(target, kPatchable)); |
| 2621 // Patchable jumps always use a 32-bit immediate encoding. | 2622 movq(CODE_REG, Address::AddressBaseImm32(pp, offset - kHeapObjectTag)); |
| 2622 jmp(Address::AddressBaseImm32(pp, offset - kHeapObjectTag)); | 2623 movq(TMP, FieldAddress(CODE_REG, Code::entry_point_offset())); |
| 2623 ASSERT((buffer_.GetPosition() - call_start) == JumpPattern::kLengthInBytes); | 2624 jmp(TMP); |
| 2624 } | 2625 } |
| 2625 | 2626 |
| 2626 | 2627 |
| 2627 void Assembler::Jmp(const StubEntry& stub_entry, Register pp) { | 2628 void Assembler::Jmp(const StubEntry& stub_entry, Register pp) { |
| 2628 ASSERT((pp != PP) || constant_pool_allowed()); | 2629 ASSERT((pp != PP) || constant_pool_allowed()); |
| 2630 const Code& target = Code::Handle(stub_entry.code()); |
| 2629 const int32_t offset = ObjectPool::element_offset( | 2631 const int32_t offset = ObjectPool::element_offset( |
| 2630 object_pool_wrapper_.FindExternalLabel(&stub_entry.label(), | 2632 object_pool_wrapper_.FindObject(target, kNotPatchable)); |
| 2631 kNotPatchable)); | 2633 movq(CODE_REG, FieldAddress(pp, offset)); |
| 2632 jmp(Address(pp, offset - kHeapObjectTag)); | 2634 movq(TMP, FieldAddress(CODE_REG, Code::entry_point_offset())); |
| 2635 jmp(TMP); |
| 2633 } | 2636 } |
| 2634 | 2637 |
| 2635 | 2638 |
| 2636 void Assembler::lock() { | 2639 void Assembler::lock() { |
| 2637 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 2640 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 2638 EmitUint8(0xF0); | 2641 EmitUint8(0xF0); |
| 2639 } | 2642 } |
| 2640 | 2643 |
| 2641 | 2644 |
| 2642 void Assembler::cmpxchgl(const Address& address, Register reg) { | 2645 void Assembler::cmpxchgl(const Address& address, Register reg) { |
| (...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3070 if (can_value_be_smi) { | 3073 if (can_value_be_smi) { |
| 3071 StoreIntoObjectFilter(object, value, &done); | 3074 StoreIntoObjectFilter(object, value, &done); |
| 3072 } else { | 3075 } else { |
| 3073 StoreIntoObjectFilterNoSmi(object, value, &done); | 3076 StoreIntoObjectFilterNoSmi(object, value, &done); |
| 3074 } | 3077 } |
| 3075 // A store buffer update is required. | 3078 // A store buffer update is required. |
| 3076 if (value != RDX) pushq(RDX); | 3079 if (value != RDX) pushq(RDX); |
| 3077 if (object != RDX) { | 3080 if (object != RDX) { |
| 3078 movq(RDX, object); | 3081 movq(RDX, object); |
| 3079 } | 3082 } |
| 3083 pushq(CODE_REG); |
| 3084 movq(CODE_REG, Address(THR, Thread::update_store_buffer_code_offset())); |
| 3080 movq(TMP, Address(THR, Thread::update_store_buffer_entry_point_offset())); | 3085 movq(TMP, Address(THR, Thread::update_store_buffer_entry_point_offset())); |
| 3081 call(TMP); | 3086 call(TMP); |
| 3087 |
| 3088 popq(CODE_REG); |
| 3082 if (value != RDX) popq(RDX); | 3089 if (value != RDX) popq(RDX); |
| 3083 Bind(&done); | 3090 Bind(&done); |
| 3084 } | 3091 } |
| 3085 | 3092 |
| 3086 | 3093 |
| 3087 void Assembler::StoreIntoObjectNoBarrier(Register object, | 3094 void Assembler::StoreIntoObjectNoBarrier(Register object, |
| 3088 const Address& dest, | 3095 const Address& dest, |
| 3089 Register value, | 3096 Register value, |
| 3090 FieldContent old_content) { | 3097 FieldContent old_content) { |
| 3091 VerifiedWrite(dest, value, old_content); | 3098 VerifiedWrite(dest, value, old_content); |
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3372 call(reg); | 3379 call(reg); |
| 3373 } | 3380 } |
| 3374 | 3381 |
| 3375 | 3382 |
| 3376 void Assembler::CallRuntime(const RuntimeEntry& entry, | 3383 void Assembler::CallRuntime(const RuntimeEntry& entry, |
| 3377 intptr_t argument_count) { | 3384 intptr_t argument_count) { |
| 3378 entry.Call(this, argument_count); | 3385 entry.Call(this, argument_count); |
| 3379 } | 3386 } |
| 3380 | 3387 |
| 3381 | 3388 |
| 3389 void Assembler::RestoreCodePointer() { |
| 3390 movq(CODE_REG, Address(RBP, kPcMarkerSlotFromFp * kWordSize)); |
| 3391 } |
| 3392 |
| 3393 |
| 3382 void Assembler::LoadPoolPointer(Register pp) { | 3394 void Assembler::LoadPoolPointer(Register pp) { |
| 3383 // Load new pool pointer. | 3395 // Load new pool pointer. |
| 3384 const intptr_t kRIPRelativeMovqSize = 7; | 3396 CheckCodePointer(); |
| 3385 const intptr_t entry_to_rip_offset = CodeSize() + kRIPRelativeMovqSize; | 3397 movq(pp, FieldAddress(CODE_REG, Code::object_pool_offset())); |
| 3386 const intptr_t object_pool_pc_dist = | |
| 3387 Instructions::HeaderSize() - Instructions::object_pool_offset(); | |
| 3388 movq(pp, Address::AddressRIPRelative( | |
| 3389 -entry_to_rip_offset - object_pool_pc_dist)); | |
| 3390 ASSERT(CodeSize() == entry_to_rip_offset); | |
| 3391 set_constant_pool_allowed(pp == PP); | 3398 set_constant_pool_allowed(pp == PP); |
| 3392 } | 3399 } |
| 3393 | 3400 |
| 3394 | 3401 |
| 3395 void Assembler::EnterDartFrame(intptr_t frame_size, | 3402 void Assembler::EnterDartFrame(intptr_t frame_size, Register new_pp) { |
| 3396 Register new_pp, | |
| 3397 Register pc_marker_override) { | |
| 3398 ASSERT(!constant_pool_allowed()); | 3403 ASSERT(!constant_pool_allowed()); |
| 3399 EnterFrame(0); | 3404 EnterFrame(0); |
| 3400 pushq(pc_marker_override); | 3405 pushq(CODE_REG); |
| 3401 pushq(PP); | 3406 pushq(PP); |
| 3402 movq(PP, new_pp); | 3407 if (new_pp == kNoRegister) { |
| 3408 LoadPoolPointer(PP); |
| 3409 } else { |
| 3410 movq(PP, new_pp); |
| 3411 } |
| 3403 set_constant_pool_allowed(true); | 3412 set_constant_pool_allowed(true); |
| 3404 if (frame_size != 0) { | 3413 if (frame_size != 0) { |
| 3405 subq(RSP, Immediate(frame_size)); | 3414 subq(RSP, Immediate(frame_size)); |
| 3406 } | 3415 } |
| 3407 } | 3416 } |
| 3408 | 3417 |
| 3409 | 3418 |
| 3410 void Assembler::LeaveDartFrame() { | 3419 void Assembler::LeaveDartFrame(RestorePP restore_pp) { |
| 3411 set_constant_pool_allowed(false); | |
| 3412 // Restore caller's PP register that was pushed in EnterDartFrame. | 3420 // Restore caller's PP register that was pushed in EnterDartFrame. |
| 3413 movq(PP, Address(RBP, (kSavedCallerPpSlotFromFp * kWordSize))); | 3421 if (restore_pp == kRestoreCallerPP) { |
| 3422 movq(PP, Address(RBP, (kSavedCallerPpSlotFromFp * kWordSize))); |
| 3423 set_constant_pool_allowed(false); |
| 3424 } |
| 3414 LeaveFrame(); | 3425 LeaveFrame(); |
| 3415 } | 3426 } |
| 3416 | 3427 |
| 3417 | 3428 |
| 3429 void Assembler::CheckCodePointer() { |
| 3430 #ifdef DEBUG |
| 3431 Label cid_ok, instructions_ok; |
| 3432 pushq(RAX); |
| 3433 LoadClassId(RAX, CODE_REG); |
| 3434 cmpq(RAX, Immediate(kCodeCid)); |
| 3435 j(EQUAL, &cid_ok); |
| 3436 int3(); |
| 3437 Bind(&cid_ok); |
| 3438 { |
| 3439 const intptr_t kRIPRelativeLeaqSize = 7; |
| 3440 const intptr_t header_to_entry_offset = |
| 3441 (Instructions::HeaderSize() - kHeapObjectTag); |
| 3442 const intptr_t header_to_rip_offset = |
| 3443 CodeSize() + kRIPRelativeLeaqSize + header_to_entry_offset; |
| 3444 leaq(RAX, Address::AddressRIPRelative(-header_to_rip_offset)); |
| 3445 ASSERT(CodeSize() == (header_to_rip_offset - header_to_entry_offset)); |
| 3446 } |
| 3447 cmpq(RAX, FieldAddress(CODE_REG, Code::saved_instructions_offset())); |
| 3448 j(EQUAL, &instructions_ok); |
| 3449 int3(); |
| 3450 Bind(&instructions_ok); |
| 3451 popq(RAX); |
| 3452 #endif |
| 3453 } |
| 3454 |
| 3455 |
| 3418 // On entry to a function compiled for OSR, the caller's frame pointer, the | 3456 // On entry to a function compiled for OSR, the caller's frame pointer, the |
| 3419 // stack locals, and any copied parameters are already in place. The frame | 3457 // stack locals, and any copied parameters are already in place. The frame |
| 3420 // pointer is already set up. The PC marker is not correct for the | 3458 // pointer is already set up. The PC marker is not correct for the |
| 3421 // optimized function and there may be extra space for spill slots to | 3459 // optimized function and there may be extra space for spill slots to |
| 3422 // allocate. | 3460 // allocate. |
| 3423 void Assembler::EnterOsrFrame(intptr_t extra_size, | 3461 void Assembler::EnterOsrFrame(intptr_t extra_size) { |
| 3424 Register new_pp, | |
| 3425 Register pc_marker_override) { | |
| 3426 ASSERT(!constant_pool_allowed()); | 3462 ASSERT(!constant_pool_allowed()); |
| 3427 if (prologue_offset_ == -1) { | 3463 if (prologue_offset_ == -1) { |
| 3428 Comment("PrologueOffset = %" Pd "", CodeSize()); | 3464 Comment("PrologueOffset = %" Pd "", CodeSize()); |
| 3429 prologue_offset_ = CodeSize(); | 3465 prologue_offset_ = CodeSize(); |
| 3430 } | 3466 } |
| 3431 movq(Address(RBP, kPcMarkerSlotFromFp * kWordSize), pc_marker_override); | 3467 RestoreCodePointer(); |
| 3432 movq(PP, new_pp); | 3468 LoadPoolPointer(); |
| 3433 set_constant_pool_allowed(true); | 3469 |
| 3434 if (extra_size != 0) { | 3470 if (extra_size != 0) { |
| 3435 subq(RSP, Immediate(extra_size)); | 3471 subq(RSP, Immediate(extra_size)); |
| 3436 } | 3472 } |
| 3437 } | 3473 } |
| 3438 | 3474 |
| 3439 | 3475 |
| 3440 void Assembler::EnterStubFrame() { | 3476 void Assembler::EnterStubFrame() { |
| 3441 set_constant_pool_allowed(false); | 3477 EnterDartFrame(0, kNoRegister); |
| 3442 EnterFrame(0); | |
| 3443 pushq(Immediate(0)); // Push 0 in the saved PC area for stub frames. | |
| 3444 pushq(PP); // Save caller's pool pointer | |
| 3445 LoadPoolPointer(); | |
| 3446 } | 3478 } |
| 3447 | 3479 |
| 3448 | 3480 |
| 3449 void Assembler::LeaveStubFrame() { | 3481 void Assembler::LeaveStubFrame() { |
| 3450 LeaveDartFrame(); | 3482 LeaveDartFrame(); |
| 3451 } | 3483 } |
| 3452 | 3484 |
| 3453 | 3485 |
| 3454 void Assembler::MaybeTraceAllocation(intptr_t cid, | 3486 void Assembler::MaybeTraceAllocation(intptr_t cid, |
| 3455 Label* trace, | 3487 Label* trace, |
| (...skipping 488 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3944 | 3976 |
| 3945 | 3977 |
| 3946 const char* Assembler::FpuRegisterName(FpuRegister reg) { | 3978 const char* Assembler::FpuRegisterName(FpuRegister reg) { |
| 3947 ASSERT((0 <= reg) && (reg < kNumberOfXmmRegisters)); | 3979 ASSERT((0 <= reg) && (reg < kNumberOfXmmRegisters)); |
| 3948 return xmm_reg_names[reg]; | 3980 return xmm_reg_names[reg]; |
| 3949 } | 3981 } |
| 3950 | 3982 |
| 3951 } // namespace dart | 3983 } // namespace dart |
| 3952 | 3984 |
| 3953 #endif // defined TARGET_ARCH_X64 | 3985 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |