Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(348)

Side by Side Diff: runtime/vm/assembler_x64.cc

Issue 1192103004: VM: New calling convention for generated code. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: ARM working, x64 cleanup Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698