From a224db3a50f094ba90b0e94d5df7e345fb032929 Mon Sep 17 00:00:00 2001 From: "lrn@chromium.org" Date: Wed, 23 Mar 2011 09:05:13 +0000 Subject: [PATCH] X64: Optimize access to external references. Access to an ExternalReference in non-serializable code will try to use an offset relative to the root-array register. Since the root-array is in the Heap object, and the Heap object is in the Isolate object, there's a good chance that any external data field is within a 32-bit offset of the root array register. It falls back on the original behavior if the serializer is enabled, if the root register isn't initialized or if the offset is not representable as a 32-bit value. Review URL: http://codereview.chromium.org/6716018 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7315 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/x64/code-stubs-x64.cc | 138 ++++++++-------- src/x64/deoptimizer-x64.cc | 1 - src/x64/ic-x64.cc | 6 +- src/x64/lithium-codegen-x64.cc | 3 +- src/x64/macro-assembler-x64.cc | 275 +++++++++++++++++++++----------- src/x64/macro-assembler-x64.h | 48 +++++- src/x64/regexp-macro-assembler-x64.cc | 5 + src/x64/regexp-macro-assembler-x64.h | 1 + src/x64/stub-cache-x64.cc | 15 +- test/cctest/test-macro-assembler-x64.cc | 1 + 10 files changed, 319 insertions(+), 174 deletions(-) diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 5e53360..9196e3a 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -2449,8 +2449,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { ExternalReference::address_of_regexp_stack_memory_address(isolate); ExternalReference address_of_regexp_stack_memory_size = ExternalReference::address_of_regexp_stack_memory_size(isolate); - __ movq(kScratchRegister, address_of_regexp_stack_memory_size); - __ movq(kScratchRegister, Operand(kScratchRegister, 0)); + __ Load(kScratchRegister, address_of_regexp_stack_memory_size); __ testq(kScratchRegister, kScratchRegister); __ j(zero, &runtime); @@ -2611,7 +2610,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // Argument 8: Pass current isolate address. // __ movq(Operand(rsp, (argument_slots_on_stack - 1) * kPointerSize), // Immediate(ExternalReference::isolate_address())); - __ movq(kScratchRegister, ExternalReference::isolate_address()); + __ LoadAddress(kScratchRegister, ExternalReference::isolate_address()); __ movq(Operand(rsp, (argument_slots_on_stack - 1) * kPointerSize), kScratchRegister); @@ -2630,7 +2629,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { #endif // Argument 5: static offsets vector buffer. - __ movq(r8, ExternalReference::address_of_static_offsets_vector(isolate)); + __ LoadAddress(r8, + ExternalReference::address_of_static_offsets_vector(isolate)); // Argument 5 passed in r8 on Linux and on the stack on Windows. #ifdef _WIN64 __ movq(Operand(rsp, (argument_slots_on_stack - 4) * kPointerSize), r8); @@ -2734,7 +2734,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ RecordWrite(rcx, RegExpImpl::kLastInputOffset, rax, rdi); // Get the static offsets vector filled by the native regexp code. - __ movq(rcx, ExternalReference::address_of_static_offsets_vector(isolate)); + __ LoadAddress(rcx, + ExternalReference::address_of_static_offsets_vector(isolate)); // rbx: last_match_info backing store (FixedArray) // rcx: offsets vector @@ -2768,12 +2769,13 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // TODO(592): Rerunning the RegExp to get the stack overflow exception. ExternalReference pending_exception_address( Isolate::k_pending_exception_address, isolate); - __ movq(rbx, pending_exception_address); - __ movq(rax, Operand(rbx, 0)); + Operand pending_exception_operand = + masm->ExternalOperand(pending_exception_address, rbx); + __ movq(rax, pending_exception_operand); __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); __ cmpq(rax, rdx); __ j(equal, &runtime); - __ movq(Operand(rbx, 0), rdx); + __ movq(pending_exception_operand, rdx); __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex); NearLabel termination_exception; @@ -3385,8 +3387,8 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, ExternalReference scope_depth = ExternalReference::heap_always_allocate_scope_depth(masm->isolate()); if (always_allocate_scope) { - __ movq(kScratchRegister, scope_depth); - __ incl(Operand(kScratchRegister, 0)); + Operand scope_depth_operand = masm->ExternalOperand(scope_depth); + __ incl(scope_depth_operand); } // Call C function. @@ -3399,14 +3401,14 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, // Pass a pointer to the Arguments object as the first argument. // Return result in single register (rax). __ lea(rcx, StackSpaceOperand(0)); - __ movq(rdx, ExternalReference::isolate_address()); + __ LoadAddress(rdx, ExternalReference::isolate_address()); } else { ASSERT_EQ(2, result_size_); // Pass a pointer to the result location as the first argument. __ lea(rcx, StackSpaceOperand(2)); // Pass a pointer to the Arguments object as the second argument. __ lea(rdx, StackSpaceOperand(0)); - __ movq(r8, ExternalReference::isolate_address()); + __ LoadAddress(r8, ExternalReference::isolate_address()); } #else // _WIN64 @@ -3419,8 +3421,8 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, // Result is in rax - do not destroy this register! if (always_allocate_scope) { - __ movq(kScratchRegister, scope_depth); - __ decl(Operand(kScratchRegister, 0)); + Operand scope_depth_operand = masm->ExternalOperand(scope_depth); + __ decl(scope_depth_operand); } // Check for failure result. @@ -3463,11 +3465,11 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, // Retrieve the pending exception and clear the variable. ExternalReference pending_exception_address( Isolate::k_pending_exception_address, masm->isolate()); - __ movq(kScratchRegister, pending_exception_address); - __ movq(rax, Operand(kScratchRegister, 0)); - __ movq(rdx, ExternalReference::the_hole_value_location(masm->isolate())); - __ movq(rdx, Operand(rdx, 0)); - __ movq(Operand(kScratchRegister, 0), rdx); + Operand pending_exception_operand = + masm->ExternalOperand(pending_exception_address); + __ movq(rax, pending_exception_operand); + __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); + __ movq(pending_exception_operand, rdx); // Special handling of termination exceptions which are uncatchable // by javascript code. @@ -3566,54 +3568,58 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { #ifdef ENABLE_LOGGING_AND_PROFILING Label not_outermost_js, not_outermost_js_2; #endif - - // Setup frame. - __ push(rbp); - __ movq(rbp, rsp); - - // Push the stack frame type marker twice. - int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; - // Scratch register is neither callee-save, nor an argument register on any - // platform. It's free to use at this point. - // Cannot use smi-register for loading yet. - __ movq(kScratchRegister, - reinterpret_cast(Smi::FromInt(marker)), - RelocInfo::NONE); - __ push(kScratchRegister); // context slot - __ push(kScratchRegister); // function slot - // Save callee-saved registers (X64/Win64 calling conventions). - __ push(r12); - __ push(r13); - __ push(r14); - __ push(r15); + { // NOLINT. Scope block confuses linter. + MacroAssembler::NoRootArrayScope uninitialized_root_register(masm); + // Setup frame. + __ push(rbp); + __ movq(rbp, rsp); + + // Push the stack frame type marker twice. + int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; + // Scratch register is neither callee-save, nor an argument register on any + // platform. It's free to use at this point. + // Cannot use smi-register for loading yet. + __ movq(kScratchRegister, + reinterpret_cast(Smi::FromInt(marker)), + RelocInfo::NONE); + __ push(kScratchRegister); // context slot + __ push(kScratchRegister); // function slot + // Save callee-saved registers (X64/Win64 calling conventions). + __ push(r12); + __ push(r13); + __ push(r14); + __ push(r15); #ifdef _WIN64 - __ push(rdi); // Only callee save in Win64 ABI, argument in AMD64 ABI. - __ push(rsi); // Only callee save in Win64 ABI, argument in AMD64 ABI. + __ push(rdi); // Only callee save in Win64 ABI, argument in AMD64 ABI. + __ push(rsi); // Only callee save in Win64 ABI, argument in AMD64 ABI. #endif - __ push(rbx); - // TODO(X64): On Win64, if we ever use XMM6-XMM15, the low low 64 bits are - // callee save as well. + __ push(rbx); + // TODO(X64): On Win64, if we ever use XMM6-XMM15, the low low 64 bits are + // callee save as well. + + // Set up the roots and smi constant registers. + // Needs to be done before any further smi loads. + __ InitializeSmiConstantRegister(); + __ InitializeRootRegister(); + } Isolate* isolate = masm->isolate(); // Save copies of the top frame descriptor on the stack. ExternalReference c_entry_fp(Isolate::k_c_entry_fp_address, isolate); - __ load_rax(c_entry_fp); - __ push(rax); - - // Set up the roots and smi constant registers. - // Needs to be done before any further smi loads. - __ InitializeRootRegister(); - __ InitializeSmiConstantRegister(); + { + Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp); + __ push(c_entry_fp_operand); + } #ifdef ENABLE_LOGGING_AND_PROFILING // If this is the outermost JS call, set js_entry_sp value. ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address, isolate); - __ load_rax(js_entry_sp); + __ Load(rax, js_entry_sp); __ testq(rax, rax); __ j(not_zero, ¬_outermost_js); __ movq(rax, rbp); - __ store_rax(js_entry_sp); + __ Store(js_entry_sp, rax); __ bind(¬_outermost_js); #endif @@ -3624,7 +3630,7 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { // exception field in the JSEnv and return a failure sentinel. ExternalReference pending_exception(Isolate::k_pending_exception_address, isolate); - __ store_rax(pending_exception); + __ Store(pending_exception, rax); __ movq(rax, Failure::Exception(), RelocInfo::NONE); __ jmp(&exit); @@ -3633,8 +3639,8 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER); // Clear any pending exceptions. - __ load_rax(ExternalReference::the_hole_value_location(isolate)); - __ store_rax(pending_exception); + __ LoadRoot(rax, Heap::kTheHoleValueRootIndex); + __ Store(pending_exception, rax); // Fake a receiver (NULL). __ push(Immediate(0)); // receiver @@ -3647,18 +3653,19 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { if (is_construct) { ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline, isolate); - __ load_rax(construct_entry); + __ Load(rax, construct_entry); } else { ExternalReference entry(Builtins::JSEntryTrampoline, isolate); - __ load_rax(entry); + __ Load(rax, entry); } __ lea(kScratchRegister, FieldOperand(rax, Code::kHeaderSize)); __ call(kScratchRegister); // Unlink this frame from the handler chain. - __ movq(kScratchRegister, - ExternalReference(Isolate::k_handler_address, isolate)); - __ pop(Operand(kScratchRegister, 0)); + Operand handler_operand = + masm->ExternalOperand(ExternalReference(Isolate::k_handler_address, + isolate)); + __ pop(handler_operand); // Pop next_sp. __ addq(rsp, Immediate(StackHandlerConstants::kSize - kPointerSize)); @@ -3674,9 +3681,10 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { // Restore the top frame descriptor from the stack. __ bind(&exit); - __ movq(kScratchRegister, - ExternalReference(Isolate::k_c_entry_fp_address, isolate)); - __ pop(Operand(kScratchRegister, 0)); + { + Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp); + __ pop(c_entry_fp_operand); + } // Restore callee-saved registers (X64 conventions). __ pop(rbx); @@ -3716,7 +3724,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) { static const int kOffsetToResultValue = 21; // The last 4 bytes of the instruction sequence // movq(rax, FieldOperand(rdi, HeapObject::kMapOffset) - // Move(kScratchRegister, Factory::the_hole_value) + // Move(kScratchRegister, FACTORY->the_hole_value()) // in front of the hole value address. static const unsigned int kWordBeforeMapCheckValue = 0xBA49FF78; // The last 4 bytes of the instruction sequence diff --git a/src/x64/deoptimizer-x64.cc b/src/x64/deoptimizer-x64.cc index b1c4274..63067bd 100644 --- a/src/x64/deoptimizer-x64.cc +++ b/src/x64/deoptimizer-x64.cc @@ -760,7 +760,6 @@ void Deoptimizer::EntryGenerator::Generate() { } // Set up the roots register. - ExternalReference roots_address = ExternalReference::roots_address(isolate); __ InitializeRootRegister(); __ InitializeSmiConstantRegister(); diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc index 64b1f06..7755493 100644 --- a/src/x64/ic-x64.cc +++ b/src/x64/ic-x64.cc @@ -633,7 +633,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { = ExternalReference::keyed_lookup_cache_keys(masm->isolate()); __ movq(rdi, rcx); __ shl(rdi, Immediate(kPointerSizeLog2 + 1)); - __ movq(kScratchRegister, cache_keys); + __ LoadAddress(kScratchRegister, cache_keys); __ cmpq(rbx, Operand(kScratchRegister, rdi, times_1, 0)); __ j(not_equal, &slow); __ cmpq(rax, Operand(kScratchRegister, rdi, times_1, kPointerSize)); @@ -642,7 +642,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { // Get field offset, which is a 32-bit integer. ExternalReference cache_field_offsets = ExternalReference::keyed_lookup_cache_field_offsets(masm->isolate()); - __ movq(kScratchRegister, cache_field_offsets); + __ LoadAddress(kScratchRegister, cache_field_offsets); __ movl(rdi, Operand(kScratchRegister, rcx, times_4, 0)); __ movzxbq(rcx, FieldOperand(rbx, Map::kInObjectPropertiesOffset)); __ subq(rdi, rcx); @@ -1009,7 +1009,7 @@ static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) { // Call the entry. CEntryStub stub(1); __ movq(rax, Immediate(2)); - __ movq(rbx, ExternalReference(IC_Utility(id), masm->isolate())); + __ LoadAddress(rbx, ExternalReference(IC_Utility(id), masm->isolate())); __ CallStub(&stub); // Move result to rdi and exit the internal frame. diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 6385416..5af2795 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -1911,7 +1911,8 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { Register map = ToRegister(instr->TempAt(0)); __ movq(map, FieldOperand(object, HeapObject::kMapOffset)); __ bind(deferred->map_check()); // Label for calculating code patching. - __ Move(kScratchRegister, factory()->the_hole_value()); + __ movq(kScratchRegister, factory()->the_hole_value(), + RelocInfo::EMBEDDED_OBJECT); __ cmpq(map, kScratchRegister); // Patched to cached map. __ j(not_equal, &cache_miss); // Patched to load either true or false. diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc index 75a0d9a..b73f5d1 100644 --- a/src/x64/macro-assembler-x64.cc +++ b/src/x64/macro-assembler-x64.cc @@ -44,11 +44,110 @@ MacroAssembler::MacroAssembler(void* buffer, int size) : Assembler(buffer, size), generating_stub_(false), allow_stub_calls_(true), + root_array_available_(true), code_object_(HEAP->undefined_value()) { } +static intptr_t RootRegisterDelta(ExternalReference other) { + Address roots_register_value = kRootRegisterBias + + reinterpret_cast
(Isolate::Current()->heap()->roots_address()); + intptr_t delta = other.address() - roots_register_value; + return delta; +} + + +Operand MacroAssembler::ExternalOperand(ExternalReference target, + Register scratch) { + if (root_array_available_ && !Serializer::enabled()) { + intptr_t delta = RootRegisterDelta(target); + if (is_int32(delta)) { + Serializer::TooLateToEnableNow(); + return Operand(kRootRegister, delta); + } + } + movq(scratch, target); + return Operand(scratch, 0); +} + + +void MacroAssembler::Load(Register destination, ExternalReference source) { + if (root_array_available_ && !Serializer::enabled()) { + intptr_t delta = RootRegisterDelta(source); + if (is_int32(delta)) { + Serializer::TooLateToEnableNow(); + movq(destination, Operand(kRootRegister, static_cast(delta))); + return; + } + } + // Safe code. + if (destination.is(rax)) { + load_rax(source); + } else { + movq(kScratchRegister, source); + movq(destination, Operand(kScratchRegister, 0)); + } +} + + +void MacroAssembler::Store(ExternalReference destination, Register source) { + if (root_array_available_ && !Serializer::enabled()) { + intptr_t delta = RootRegisterDelta(destination); + if (is_int32(delta)) { + Serializer::TooLateToEnableNow(); + movq(Operand(kRootRegister, static_cast(delta)), source); + return; + } + } + // Safe code. + if (source.is(rax)) { + store_rax(destination); + } else { + movq(kScratchRegister, destination); + movq(Operand(kScratchRegister, 0), source); + } +} + + +void MacroAssembler::LoadAddress(Register destination, + ExternalReference source) { + if (root_array_available_ && !Serializer::enabled()) { + intptr_t delta = RootRegisterDelta(source); + if (is_int32(delta)) { + Serializer::TooLateToEnableNow(); + lea(destination, Operand(kRootRegister, static_cast(delta))); + return; + } + } + // Safe code. + movq(destination, source); +} + + +int MacroAssembler::LoadAddressSize(ExternalReference source) { + if (root_array_available_ && !Serializer::enabled()) { + // This calculation depends on the internals of LoadAddress. + // It's correctness is ensured by the asserts in the Call + // instruction below. + intptr_t delta = RootRegisterDelta(source); + if (is_int32(delta)) { + Serializer::TooLateToEnableNow(); + // Operand is lea(scratch, Operand(kRootRegister, delta)); + // Opcodes : REX.W 8D ModRM Disp8/Disp32 - 4 or 7. + int size = 4; + if (!is_int8(static_cast(delta))) { + size += 3; // Need full four-byte displacement in lea. + } + return size; + } + } + // Size of movq(destination, src); + return 10; +} + + void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index) { + ASSERT(root_array_available_); movq(destination, Operand(kRootRegister, (index << kPointerSizeLog2) - kRootRegisterBias)); } @@ -57,6 +156,7 @@ void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index) { void MacroAssembler::LoadRootIndexed(Register destination, Register variable_offset, int fixed_offset) { + ASSERT(root_array_available_); movq(destination, Operand(kRootRegister, variable_offset, times_pointer_size, @@ -65,17 +165,20 @@ void MacroAssembler::LoadRootIndexed(Register destination, void MacroAssembler::StoreRoot(Register source, Heap::RootListIndex index) { + ASSERT(root_array_available_); movq(Operand(kRootRegister, (index << kPointerSizeLog2) - kRootRegisterBias), source); } void MacroAssembler::PushRoot(Heap::RootListIndex index) { + ASSERT(root_array_available_); push(Operand(kRootRegister, (index << kPointerSizeLog2) - kRootRegisterBias)); } void MacroAssembler::CompareRoot(Register with, Heap::RootListIndex index) { + ASSERT(root_array_available_); cmpq(with, Operand(kRootRegister, (index << kPointerSizeLog2) - kRootRegisterBias)); } @@ -83,6 +186,7 @@ void MacroAssembler::CompareRoot(Register with, Heap::RootListIndex index) { void MacroAssembler::CompareRoot(const Operand& with, Heap::RootListIndex index) { + ASSERT(root_array_available_); ASSERT(!with.AddressUsesRegister(kScratchRegister)); LoadRoot(kScratchRegister, index); cmpq(with, kScratchRegister); @@ -393,7 +497,7 @@ void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) { void MacroAssembler::CallRuntimeSaveDoubles(Runtime::FunctionId id) { const Runtime::Function* function = Runtime::FunctionForId(id); Set(rax, function->nargs); - movq(rbx, ExternalReference(function, isolate())); + LoadAddress(rbx, ExternalReference(function, isolate())); CEntryStub ces(1); ces.SaveDoubles(); CallStub(&ces); @@ -421,7 +525,7 @@ void MacroAssembler::CallRuntime(const Runtime::Function* f, // should remove this need and make the runtime routine entry code // smarter. Set(rax, num_arguments); - movq(rbx, ExternalReference(f, isolate())); + LoadAddress(rbx, ExternalReference(f, isolate())); CEntryStub ces(f->result_size); CallStub(&ces); } @@ -441,7 +545,7 @@ MaybeObject* MacroAssembler::TryCallRuntime(const Runtime::Function* f, // should remove this need and make the runtime routine entry code // smarter. Set(rax, num_arguments); - movq(rbx, ExternalReference(f, isolate())); + LoadAddress(rbx, ExternalReference(f, isolate())); CEntryStub ces(f->result_size); return TryCallStub(&ces); } @@ -450,7 +554,7 @@ MaybeObject* MacroAssembler::TryCallRuntime(const Runtime::Function* f, void MacroAssembler::CallExternalReference(const ExternalReference& ext, int num_arguments) { Set(rax, num_arguments); - movq(rbx, ext); + LoadAddress(rbx, ext); CEntryStub stub(1); CallStub(&stub); @@ -613,11 +717,12 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn( movq(Operand(base_reg, kLimitOffset), prev_limit_reg); movq(prev_limit_reg, rax); #ifdef _WIN64 - movq(rcx, ExternalReference::isolate_address()); + LoadAddress(rcx, ExternalReference::isolate_address()); #else - movq(rdi, ExternalReference::isolate_address()); + LoadAddress(rdi, ExternalReference::isolate_address()); #endif - movq(rax, ExternalReference::delete_handle_scope_extensions(isolate())); + LoadAddress(rax, + ExternalReference::delete_handle_scope_extensions(isolate())); call(rax); movq(rax, prev_limit_reg); jmp(&leave_exit_frame); @@ -629,7 +734,7 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn( void MacroAssembler::JumpToExternalReference(const ExternalReference& ext, int result_size) { // Set the entry point and jump to the C entry runtime stub. - movq(rbx, ext); + LoadAddress(rbx, ext); CEntryStub ces(result_size); jmp(ces.GetCode(), RelocInfo::CODE_TARGET); } @@ -638,7 +743,7 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& ext, MaybeObject* MacroAssembler::TryJumpToExternalReference( const ExternalReference& ext, int result_size) { // Set the entry point and jump to the C entry runtime stub. - movq(rbx, ext); + LoadAddress(rbx, ext); CEntryStub ces(result_size); return TryTailCallStub(&ces); } @@ -1445,7 +1550,7 @@ void MacroAssembler::Test(const Operand& src, Smi* source) { void MacroAssembler::Jump(ExternalReference ext) { - movq(kScratchRegister, ext); + LoadAddress(kScratchRegister, ext); jmp(kScratchRegister); } @@ -1462,41 +1567,45 @@ void MacroAssembler::Jump(Handle code_object, RelocInfo::Mode rmode) { } +int MacroAssembler::CallSize(ExternalReference ext) { + // Opcode for call kScratchRegister is: Rex.B FF D4 (three bytes). + const int kCallInstructionSize = 3; + return LoadAddressSize(ext) + kCallInstructionSize; +} + + void MacroAssembler::Call(ExternalReference ext) { #ifdef DEBUG - int pre_position = pc_offset(); + int end_position = pc_offset() + CallSize(ext); #endif - movq(kScratchRegister, ext); + LoadAddress(kScratchRegister, ext); call(kScratchRegister); #ifdef DEBUG - int post_position = pc_offset(); - CHECK_EQ(pre_position + CallSize(ext), post_position); + CHECK_EQ(end_position, pc_offset()); #endif } void MacroAssembler::Call(Address destination, RelocInfo::Mode rmode) { #ifdef DEBUG - int pre_position = pc_offset(); + int end_position = pc_offset() + CallSize(destination, rmode); #endif movq(kScratchRegister, destination, rmode); call(kScratchRegister); #ifdef DEBUG - int post_position = pc_offset(); - CHECK_EQ(pre_position + CallSize(destination, rmode), post_position); + CHECK_EQ(pc_offset(), end_position); #endif } void MacroAssembler::Call(Handle code_object, RelocInfo::Mode rmode) { #ifdef DEBUG - int pre_position = pc_offset(); + int end_position = pc_offset() + CallSize(code_object); #endif ASSERT(RelocInfo::IsCodeTarget(rmode)); call(code_object, rmode); #ifdef DEBUG - int post_position = pc_offset(); - CHECK_EQ(pre_position + CallSize(code_object), post_position); + CHECK_EQ(end_position, pc_offset()); #endif } @@ -1617,20 +1726,20 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location, push(Immediate(0)); // NULL frame pointer. } // Save the current handler. - movq(kScratchRegister, - ExternalReference(Isolate::k_handler_address, isolate())); - push(Operand(kScratchRegister, 0)); + Operand handler_operand = + ExternalOperand(ExternalReference(Isolate::k_handler_address, isolate())); + push(handler_operand); // Link this handler. - movq(Operand(kScratchRegister, 0), rsp); + movq(handler_operand, rsp); } void MacroAssembler::PopTryHandler() { ASSERT_EQ(0, StackHandlerConstants::kNextOffset); // Unlink this handler. - movq(kScratchRegister, - ExternalReference(Isolate::k_handler_address, isolate())); - pop(Operand(kScratchRegister, 0)); + Operand handler_operand = + ExternalOperand(ExternalReference(Isolate::k_handler_address, isolate())); + pop(handler_operand); // Remove the remaining fields. addq(rsp, Immediate(StackHandlerConstants::kSize - kPointerSize)); } @@ -1649,11 +1758,10 @@ void MacroAssembler::Throw(Register value) { } ExternalReference handler_address(Isolate::k_handler_address, isolate()); - movq(kScratchRegister, handler_address); - movq(rsp, Operand(kScratchRegister, 0)); + Operand handler_operand = ExternalOperand(handler_address); + movq(rsp, handler_operand); // get next in chain - pop(rcx); - movq(Operand(kScratchRegister, 0), rcx); + pop(handler_operand); pop(rbp); // pop frame pointer pop(rdx); // remove state @@ -1677,8 +1785,7 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, } // Fetch top stack handler. ExternalReference handler_address(Isolate::k_handler_address, isolate()); - movq(kScratchRegister, handler_address); - movq(rsp, Operand(kScratchRegister, 0)); + Load(rsp, handler_address); // Unwind the handlers until the ENTRY handler is found. NearLabel loop, done; @@ -1694,21 +1801,21 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, bind(&done); // Set the top handler address to next handler past the current ENTRY handler. - movq(kScratchRegister, handler_address); - pop(Operand(kScratchRegister, 0)); + Operand handler_operand = ExternalOperand(handler_address); + pop(handler_operand); if (type == OUT_OF_MEMORY) { // Set external caught exception to false. ExternalReference external_caught( Isolate::k_external_caught_exception_address, isolate()); movq(rax, Immediate(false)); - store_rax(external_caught); + Store(external_caught, rax); // Set pending exception and rax to out of memory exception. ExternalReference pending_exception(Isolate::k_pending_exception_address, isolate()); movq(rax, Failure::OutOfMemoryException(), RelocInfo::NONE); - store_rax(pending_exception); + Store(pending_exception, rax); } // Clear the context pointer. @@ -1716,14 +1823,14 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, // Restore registers from handler. STATIC_ASSERT(StackHandlerConstants::kNextOffset + kPointerSize == - StackHandlerConstants::kFPOffset); + StackHandlerConstants::kFPOffset); pop(rbp); // FP STATIC_ASSERT(StackHandlerConstants::kFPOffset + kPointerSize == - StackHandlerConstants::kStateOffset); + StackHandlerConstants::kStateOffset); pop(rdx); // State STATIC_ASSERT(StackHandlerConstants::kStateOffset + kPointerSize == - StackHandlerConstants::kPCOffset); + StackHandlerConstants::kPCOffset); ret(0); } @@ -1888,8 +1995,8 @@ void MacroAssembler::TryGetFunctionPrototype(Register function, void MacroAssembler::SetCounter(StatsCounter* counter, int value) { if (FLAG_native_code_counters && counter->Enabled()) { - movq(kScratchRegister, ExternalReference(counter)); - movl(Operand(kScratchRegister, 0), Immediate(value)); + Operand counter_operand = ExternalOperand(ExternalReference(counter)); + movq(counter_operand, Immediate(value)); } } @@ -1897,12 +2004,11 @@ void MacroAssembler::SetCounter(StatsCounter* counter, int value) { void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) { ASSERT(value > 0); if (FLAG_native_code_counters && counter->Enabled()) { - movq(kScratchRegister, ExternalReference(counter)); - Operand operand(kScratchRegister, 0); + Operand counter_operand = ExternalOperand(ExternalReference(counter)); if (value == 1) { - incl(operand); + incl(counter_operand); } else { - addl(operand, Immediate(value)); + addl(counter_operand, Immediate(value)); } } } @@ -1911,12 +2017,11 @@ void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) { void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) { ASSERT(value > 0); if (FLAG_native_code_counters && counter->Enabled()) { - movq(kScratchRegister, ExternalReference(counter)); - Operand operand(kScratchRegister, 0); + Operand counter_operand = ExternalOperand(ExternalReference(counter)); if (value == 1) { - decl(operand); + decl(counter_operand); } else { - subl(operand, Immediate(value)); + subl(counter_operand, Immediate(value)); } } } @@ -1926,7 +2031,7 @@ void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) { void MacroAssembler::DebugBreak() { ASSERT(allow_stub_calls()); Set(rax, 0); // No arguments. - movq(rbx, ExternalReference(Runtime::kDebugBreak, isolate())); + LoadAddress(rbx, ExternalReference(Runtime::kDebugBreak, isolate())); CEntryStub ces(1); Call(ces.GetCode(), RelocInfo::DEBUG_BREAK); } @@ -2080,13 +2185,8 @@ void MacroAssembler::EnterExitFramePrologue(bool save_rax) { movq(r14, rax); // Backup rax in callee-save register. } - movq(kScratchRegister, - ExternalReference(Isolate::k_c_entry_fp_address, isolate())); - movq(Operand(kScratchRegister, 0), rbp); - - movq(kScratchRegister, - ExternalReference(Isolate::k_context_address, isolate())); - movq(Operand(kScratchRegister, 0), rsi); + Store(ExternalReference(Isolate::k_c_entry_fp_address, isolate()), rbp); + Store(ExternalReference(Isolate::k_context_address, isolate()), rsi); } @@ -2178,17 +2278,17 @@ void MacroAssembler::LeaveApiExitFrame() { void MacroAssembler::LeaveExitFrameEpilogue() { // Restore current context from top and clear it in debug mode. ExternalReference context_address(Isolate::k_context_address, isolate()); - movq(kScratchRegister, context_address); - movq(rsi, Operand(kScratchRegister, 0)); + Operand context_operand = ExternalOperand(context_address); + movq(rsi, context_operand); #ifdef DEBUG - movq(Operand(kScratchRegister, 0), Immediate(0)); + movq(context_operand, Immediate(0)); #endif // Clear the top frame. ExternalReference c_entry_fp_address(Isolate::k_c_entry_fp_address, isolate()); - movq(kScratchRegister, c_entry_fp_address); - movq(Operand(kScratchRegister, 0), Immediate(0)); + Operand c_entry_fp_operand = ExternalOperand(c_entry_fp_address); + movq(c_entry_fp_operand, Immediate(0)); } @@ -2267,8 +2367,8 @@ void MacroAssembler::LoadAllocationTopHelper(Register result, ASSERT(!scratch.is_valid()); #ifdef DEBUG // Assert that result actually contains top on entry. - movq(kScratchRegister, new_space_allocation_top); - cmpq(result, Operand(kScratchRegister, 0)); + Operand top_operand = ExternalOperand(new_space_allocation_top); + cmpq(result, top_operand); Check(equal, "Unexpected allocation top"); #endif return; @@ -2277,13 +2377,10 @@ void MacroAssembler::LoadAllocationTopHelper(Register result, // Move address of new object to result. Use scratch register if available, // and keep address in scratch until call to UpdateAllocationTopHelper. if (scratch.is_valid()) { - movq(scratch, new_space_allocation_top); + LoadAddress(scratch, new_space_allocation_top); movq(result, Operand(scratch, 0)); - } else if (result.is(rax)) { - load_rax(new_space_allocation_top); } else { - movq(kScratchRegister, new_space_allocation_top); - movq(result, Operand(kScratchRegister, 0)); + Load(result, new_space_allocation_top); } } @@ -2299,17 +2396,11 @@ void MacroAssembler::UpdateAllocationTopHelper(Register result_end, ExternalReference::new_space_allocation_top_address(isolate()); // Update new top. - if (result_end.is(rax)) { - // rax can be stored directly to a memory location. - store_rax(new_space_allocation_top); + if (scratch.is_valid()) { + // Scratch already contains address of allocation top. + movq(Operand(scratch, 0), result_end); } else { - // Register required - use scratch provided if available. - if (scratch.is_valid()) { - movq(Operand(scratch, 0), result_end); - } else { - movq(kScratchRegister, new_space_allocation_top); - movq(Operand(kScratchRegister, 0), result_end); - } + Store(new_space_allocation_top, result_end); } } @@ -2350,8 +2441,8 @@ void MacroAssembler::AllocateInNewSpace(int object_size, } addq(top_reg, Immediate(object_size)); j(carry, gc_required); - movq(kScratchRegister, new_space_allocation_limit); - cmpq(top_reg, Operand(kScratchRegister, 0)); + Operand limit_operand = ExternalOperand(new_space_allocation_limit); + cmpq(top_reg, limit_operand); j(above, gc_required); // Update allocation top. @@ -2405,8 +2496,8 @@ void MacroAssembler::AllocateInNewSpace(int header_size, lea(result_end, Operand(element_count, element_size, header_size)); addq(result_end, result); j(carry, gc_required); - movq(kScratchRegister, new_space_allocation_limit); - cmpq(result_end, Operand(kScratchRegister, 0)); + Operand limit_operand = ExternalOperand(new_space_allocation_limit); + cmpq(result_end, limit_operand); j(above, gc_required); // Update allocation top. @@ -2451,8 +2542,8 @@ void MacroAssembler::AllocateInNewSpace(Register object_size, } addq(result_end, result); j(carry, gc_required); - movq(kScratchRegister, new_space_allocation_limit); - cmpq(result_end, Operand(kScratchRegister, 0)); + Operand limit_operand = ExternalOperand(new_space_allocation_limit); + cmpq(result_end, limit_operand); j(above, gc_required); // Update allocation top. @@ -2471,12 +2562,12 @@ void MacroAssembler::UndoAllocationInNewSpace(Register object) { // Make sure the object has no tag before resetting top. and_(object, Immediate(~kHeapObjectTagMask)); - movq(kScratchRegister, new_space_allocation_top); + Operand top_operand = ExternalOperand(new_space_allocation_top); #ifdef DEBUG - cmpq(object, Operand(kScratchRegister, 0)); + cmpq(object, top_operand); Check(below, "Undo allocation of non allocated memory"); #endif - movq(Operand(kScratchRegister, 0), object); + movq(top_operand, object); } @@ -2711,7 +2802,7 @@ void MacroAssembler::PrepareCallCFunction(int num_arguments) { void MacroAssembler::CallCFunction(ExternalReference function, int num_arguments) { - movq(rax, function); + LoadAddress(rax, function); CallCFunction(rax, num_arguments); } @@ -2727,12 +2818,12 @@ void MacroAssembler::CallCFunction(Register function, int num_arguments) { Register arg_to_reg[] = {rdi, rsi, rdx, rcx, r8, r9}; #endif Register reg = arg_to_reg[num_arguments]; - movq(reg, ExternalReference::isolate_address()); + LoadAddress(reg, ExternalReference::isolate_address()); } else { // Push Isolate pointer after all parameters. int argument_slots_on_stack = ArgumentStackSlotsForCFunctionCall(num_arguments); - movq(kScratchRegister, ExternalReference::isolate_address()); + LoadAddress(kScratchRegister, ExternalReference::isolate_address()); movq(Operand(rsp, argument_slots_on_stack * kPointerSize), kScratchRegister); } diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h index 9653e1c..eb1f42d 100644 --- a/src/x64/macro-assembler-x64.h +++ b/src/x64/macro-assembler-x64.h @@ -76,7 +76,49 @@ class MacroAssembler: public Assembler { public: MacroAssembler(void* buffer, int size); + // Prevent the use of the RootArray during the lifetime of this + // scope object. + class NoRootArrayScope BASE_EMBEDDED { + public: + explicit NoRootArrayScope(MacroAssembler* assembler) + : variable_(&assembler->root_array_available_), + old_value_(assembler->root_array_available_) { + assembler->root_array_available_ = false; + } + ~NoRootArrayScope() { + *variable_ = old_value_; + } + private: + bool* variable_; + bool old_value_; + }; + + // Operand pointing to an external reference. + // May emit code to set up the scratch register. The operand is + // only guaranteed to be correct as long as the scratch register + // isn't changed. + // If the operand is used more than once, use a scratch register + // that is guaranteed not to be clobbered. + Operand ExternalOperand(ExternalReference reference, + Register scratch = kScratchRegister); + // Loads and stores the value of an external reference. + // Special case code for load and store to take advantage of + // load_rax/store_rax if possible/necessary. + // For other operations, just use: + // Operand operand = ExternalOperand(extref); + // operation(operand, ..); + void Load(Register destination, ExternalReference source); + void Store(ExternalReference destination, Register source); + // Loads the address of the external reference into the destination + // register. + void LoadAddress(Register destination, ExternalReference source); + // Returns the size of the code generated by LoadAddress. + // Used by CallSize(ExternalReference) to find the size of a call. + int LoadAddressSize(ExternalReference source); + + // Operations on roots in the root-array. void LoadRoot(Register destination, Heap::RootListIndex index); + void StoreRoot(Register source, Heap::RootListIndex index); // Load a root value where the index (or part of it) is variable. // The variable_offset register is added to the fixed_offset value // to get the index into the root-array. @@ -86,7 +128,6 @@ class MacroAssembler: public Assembler { void CompareRoot(Register with, Heap::RootListIndex index); void CompareRoot(const Operand& with, Heap::RootListIndex index); void PushRoot(Heap::RootListIndex index); - void StoreRoot(Register source, Heap::RootListIndex index); // --------------------------------------------------------------------------- // GC Support @@ -634,9 +675,7 @@ class MacroAssembler: public Assembler { int CallSize(Address destination, RelocInfo::Mode rmode) { return kCallInstructionLength; } - int CallSize(ExternalReference ext) { - return kCallInstructionLength; - } + int CallSize(ExternalReference ext); int CallSize(Handle code_object) { // Code calls use 32-bit relative addressing. return kShortCallInstructionLength; @@ -1024,6 +1063,7 @@ class MacroAssembler: public Assembler { bool generating_stub_; bool allow_stub_calls_; + bool root_array_available_; // Returns a register holding the smi value. The register MUST NOT be // modified. It may be the "smi 1 constant" register. diff --git a/src/x64/regexp-macro-assembler-x64.cc b/src/x64/regexp-macro-assembler-x64.cc index 49c1377..99e1627 100644 --- a/src/x64/regexp-macro-assembler-x64.cc +++ b/src/x64/regexp-macro-assembler-x64.cc @@ -63,6 +63,10 @@ namespace internal { * * The registers rax, rbx, r9 and r11 are free to use for computations. * If changed to use r12+, they should be saved as callee-save registers. + * The macro assembler special registers r12 and r13 (kSmiConstantRegister, + * kRootRegister) aren't special during execution of RegExp code (they don't + * hold the values assumed when creating JS code), so no Smi or Root related + * macro operations can be used. * * Each call to a C++ method should retain these registers. * @@ -111,6 +115,7 @@ RegExpMacroAssemblerX64::RegExpMacroAssemblerX64( Mode mode, int registers_to_save) : masm_(new MacroAssembler(NULL, kRegExpCodeSize)), + no_root_array_scope_(masm_), code_relative_fixup_positions_(4), mode_(mode), num_registers_(registers_to_save), diff --git a/src/x64/regexp-macro-assembler-x64.h b/src/x64/regexp-macro-assembler-x64.h index 864441a..564669e 100644 --- a/src/x64/regexp-macro-assembler-x64.h +++ b/src/x64/regexp-macro-assembler-x64.h @@ -251,6 +251,7 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler { inline void Drop(); MacroAssembler* masm_; + MacroAssembler::NoRootArrayScope no_root_array_scope_; ZoneList code_relative_fixup_positions_; diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc index 9090516..ac2a305 100644 --- a/src/x64/stub-cache-x64.cc +++ b/src/x64/stub-cache-x64.cc @@ -52,7 +52,7 @@ static void ProbeTable(Isolate* isolate, ExternalReference key_offset(isolate->stub_cache()->key_reference(table)); Label miss; - __ movq(kScratchRegister, key_offset); + __ LoadAddress(kScratchRegister, key_offset); // Check that the key in the entry matches the name. // Multiply entry offset by 16 to get the entry address. Since the // offset register already holds the entry offset times four, multiply @@ -398,7 +398,7 @@ static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm, ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly), masm->isolate()); __ movq(rax, Immediate(5)); - __ movq(rbx, ref); + __ LoadAddress(rbx, ref); CEntryStub stub(1); __ CallStub(&stub); @@ -1491,8 +1491,7 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object, const int kAllocationDelta = 4; // Load top. - __ movq(rcx, new_space_allocation_top); - __ movq(rcx, Operand(rcx, 0)); + __ Load(rcx, new_space_allocation_top); // Check if it's the end of elements. __ lea(rdx, FieldOperand(rbx, @@ -1501,13 +1500,13 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object, __ cmpq(rdx, rcx); __ j(not_equal, &call_builtin); __ addq(rcx, Immediate(kAllocationDelta * kPointerSize)); - __ movq(kScratchRegister, new_space_allocation_limit); - __ cmpq(rcx, Operand(kScratchRegister, 0)); + Operand limit_operand = + masm()->ExternalOperand(new_space_allocation_limit); + __ cmpq(rcx, limit_operand); __ j(above, &call_builtin); // We fit and could grow elements. - __ movq(kScratchRegister, new_space_allocation_top); - __ movq(Operand(kScratchRegister, 0), rcx); + __ Store(new_space_allocation_top, rcx); __ movq(rcx, Operand(rsp, argc * kPointerSize)); // Push the argument... diff --git a/test/cctest/test-macro-assembler-x64.cc b/test/cctest/test-macro-assembler-x64.cc index 6e059df..15dc6db 100755 --- a/test/cctest/test-macro-assembler-x64.cc +++ b/test/cctest/test-macro-assembler-x64.cc @@ -96,6 +96,7 @@ static void EntryCode(MacroAssembler* masm) { // Smi constant register is callee save. __ push(v8::internal::kSmiConstantRegister); __ InitializeSmiConstantRegister(); + __ InitializeRootRegister(); } -- 2.7.4