diff options
Diffstat (limited to 'src/x64/macro-assembler-x64.cc')
-rw-r--r-- | src/x64/macro-assembler-x64.cc | 376 |
1 files changed, 56 insertions, 320 deletions
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc index 8d70f540..b75b38eb 100644 --- a/src/x64/macro-assembler-x64.cc +++ b/src/x64/macro-assembler-x64.cc @@ -8,11 +8,14 @@ #include "src/base/division-by-constant.h" #include "src/bootstrapper.h" #include "src/codegen.h" +#include "src/counters.h" #include "src/debug/debug.h" -#include "src/heap/heap.h" +#include "src/heap/heap-inl.h" +#include "src/objects-inl.h" #include "src/register-configuration.h" #include "src/x64/assembler-x64.h" -#include "src/x64/macro-assembler-x64.h" + +#include "src/x64/macro-assembler-x64.h" // Cannot be the first include. namespace v8 { namespace internal { @@ -1570,6 +1573,11 @@ void MacroAssembler::JumpIfNotSmi(Register src, j(NegateCondition(smi), on_not_smi, near_jump); } +void MacroAssembler::JumpIfNotSmi(Operand src, Label* on_not_smi, + Label::Distance near_jump) { + Condition smi = CheckSmi(src); + j(NegateCondition(smi), on_not_smi, near_jump); +} void MacroAssembler::JumpUnlessNonNegativeSmi( Register src, Label* on_not_smi_or_negative, @@ -2460,10 +2468,19 @@ void MacroAssembler::Push(Smi* source) { intptr_t smi = reinterpret_cast<intptr_t>(source); if (is_int32(smi)) { Push(Immediate(static_cast<int32_t>(smi))); - } else { - Register constant = GetSmiConstant(source); - Push(constant); + return; } + int first_byte_set = base::bits::CountTrailingZeros64(smi) / 8; + int last_byte_set = (63 - base::bits::CountLeadingZeros64(smi)) / 8; + if (first_byte_set == last_byte_set && kPointerSize == kInt64Size) { + // This sequence has only 7 bytes, compared to the 12 bytes below. + Push(Immediate(0)); + movb(Operand(rsp, first_byte_set), + Immediate(static_cast<int8_t>(smi >> (8 * first_byte_set)))); + return; + } + Register constant = GetSmiConstant(source); + Push(constant); } @@ -2540,30 +2557,15 @@ void MacroAssembler::JumpIfNotBothSequentialOneByteStrings( andl(scratch1, Immediate(kFlatOneByteStringMask)); andl(scratch2, Immediate(kFlatOneByteStringMask)); // Interleave the bits to check both scratch1 and scratch2 in one test. - DCHECK_EQ(0, kFlatOneByteStringMask & (kFlatOneByteStringMask << 3)); - leap(scratch1, Operand(scratch1, scratch2, times_8, 0)); + const int kShift = 8; + DCHECK_EQ(0, kFlatOneByteStringMask & (kFlatOneByteStringMask << kShift)); + shlp(scratch2, Immediate(kShift)); + orp(scratch1, scratch2); cmpl(scratch1, - Immediate(kFlatOneByteStringTag + (kFlatOneByteStringTag << 3))); + Immediate(kFlatOneByteStringTag + (kFlatOneByteStringTag << kShift))); j(not_equal, on_fail, near_jump); } - -void MacroAssembler::JumpIfInstanceTypeIsNotSequentialOneByte( - Register instance_type, Register scratch, Label* failure, - Label::Distance near_jump) { - if (!scratch.is(instance_type)) { - movl(scratch, instance_type); - } - - const int kFlatOneByteStringMask = - kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; - - andl(scratch, Immediate(kFlatOneByteStringMask)); - cmpl(scratch, Immediate(kStringTag | kSeqStringTag | kOneByteStringTag)); - j(not_equal, failure, near_jump); -} - - void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialOneByte( Register first_object_instance_type, Register second_object_instance_type, Register scratch1, Register scratch2, Label* on_fail, @@ -3663,66 +3665,6 @@ void MacroAssembler::CmpInstanceType(Register map, InstanceType type) { Immediate(static_cast<int8_t>(type))); } -void MacroAssembler::CheckFastObjectElements(Register map, - Label* fail, - Label::Distance distance) { - STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); - STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); - STATIC_ASSERT(FAST_ELEMENTS == 2); - STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3); - cmpb(FieldOperand(map, Map::kBitField2Offset), - Immediate(Map::kMaximumBitField2FastHoleySmiElementValue)); - j(below_equal, fail, distance); - cmpb(FieldOperand(map, Map::kBitField2Offset), - Immediate(Map::kMaximumBitField2FastHoleyElementValue)); - j(above, fail, distance); -} - - -void MacroAssembler::CheckFastSmiElements(Register map, - Label* fail, - Label::Distance distance) { - STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); - STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); - cmpb(FieldOperand(map, Map::kBitField2Offset), - Immediate(Map::kMaximumBitField2FastHoleySmiElementValue)); - j(above, fail, distance); -} - - -void MacroAssembler::StoreNumberToDoubleElements( - Register maybe_number, - Register elements, - Register index, - XMMRegister xmm_scratch, - Label* fail, - int elements_offset) { - Label smi_value, done; - - JumpIfSmi(maybe_number, &smi_value, Label::kNear); - - CheckMap(maybe_number, - isolate()->factory()->heap_number_map(), - fail, - DONT_DO_SMI_CHECK); - - // Double value, turn potential sNaN into qNaN. - Move(xmm_scratch, 1.0); - mulsd(xmm_scratch, FieldOperand(maybe_number, HeapNumber::kValueOffset)); - jmp(&done, Label::kNear); - - bind(&smi_value); - // Value is a smi. convert to a double and store. - // Preserve original value. - SmiToInteger32(kScratchRegister, maybe_number); - Cvtlsi2sd(xmm_scratch, kScratchRegister); - bind(&done); - Movsd(FieldOperand(elements, index, times_8, - FixedDoubleArray::kHeaderSize - elements_offset), - xmm_scratch); -} - - void MacroAssembler::CompareMap(Register obj, Handle<Map> map) { Cmp(FieldOperand(obj, HeapObject::kMapOffset), map); } @@ -4099,32 +4041,6 @@ void MacroAssembler::GetMapConstructor(Register result, Register map, bind(&done); } - -void MacroAssembler::TryGetFunctionPrototype(Register function, Register result, - Label* miss) { - // Get the prototype or initial map from the function. - movp(result, - FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); - - // If the prototype or initial map is the hole, don't return it and - // simply miss the cache instead. This will allow us to allocate a - // prototype object on-demand in the runtime system. - CompareRoot(result, Heap::kTheHoleValueRootIndex); - j(equal, miss); - - // If the function does not have an initial map, we're done. - Label done; - CmpObjectType(result, MAP_TYPE, kScratchRegister); - j(not_equal, &done, Label::kNear); - - // Get the prototype from the initial map. - movp(result, FieldOperand(result, Map::kPrototypeOffset)); - - // All done. - bind(&done); -} - - void MacroAssembler::SetCounter(StatsCounter* counter, int value) { if (FLAG_native_code_counters && counter->Enabled()) { Operand counter_operand = ExternalOperand(ExternalReference(counter)); @@ -4158,14 +4074,14 @@ void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) { } } - -void MacroAssembler::DebugBreak() { - Set(rax, 0); // No arguments. - LoadAddress(rbx, - ExternalReference(Runtime::kHandleDebuggerStatement, isolate())); - CEntryStub ces(isolate(), 1); - DCHECK(AllowThisStubCall(&ces)); - Call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT); +void MacroAssembler::MaybeDropFrames() { + // Check whether we need to drop frames to restart a function on the stack. + ExternalReference restart_fp = + ExternalReference::debug_restart_fp_address(isolate()); + Load(rbx, restart_fp); + testp(rbx, rbx); + j(not_zero, isolate()->builtins()->FrameDropperTrampoline(), + RelocInfo::CODE_TARGET); } void MacroAssembler::PrepareForTailCall(const ParameterCount& callee_args_count, @@ -4286,8 +4202,8 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, DCHECK(function.is(rdi)); DCHECK_IMPLIES(new_target.is_valid(), new_target.is(rdx)); - if (call_wrapper.NeedsDebugStepCheck()) { - FloodFunctionIfStepping(function, new_target, expected, actual); + if (call_wrapper.NeedsDebugHookCheck()) { + CheckDebugHook(function, new_target, expected, actual); } // Clear the new.target register if not given. @@ -4367,6 +4283,7 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, DCHECK(actual.reg().is(rax)); DCHECK(expected.reg().is(rbx)); } else { + definitely_matches = true; Move(rax, actual.reg()); } } @@ -4387,17 +4304,15 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, } } - -void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target, - const ParameterCount& expected, - const ParameterCount& actual) { - Label skip_flooding; - ExternalReference last_step_action = - ExternalReference::debug_last_step_action_address(isolate()); - Operand last_step_action_operand = ExternalOperand(last_step_action); - STATIC_ASSERT(StepFrame > StepIn); - cmpb(last_step_action_operand, Immediate(StepIn)); - j(less, &skip_flooding); +void MacroAssembler::CheckDebugHook(Register fun, Register new_target, + const ParameterCount& expected, + const ParameterCount& actual) { + Label skip_hook; + ExternalReference debug_hook_active = + ExternalReference::debug_hook_on_function_call_address(isolate()); + Operand debug_hook_active_operand = ExternalOperand(debug_hook_active); + cmpb(debug_hook_active_operand, Immediate(0)); + j(equal, &skip_hook); { FrameScope frame(this, has_frame() ? StackFrame::NONE : StackFrame::INTERNAL); @@ -4414,7 +4329,7 @@ void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target, } Push(fun); Push(fun); - CallRuntime(Runtime::kDebugPrepareStepInIfStepping); + CallRuntime(Runtime::kDebugOnFunctionCall); Pop(fun); if (new_target.is_valid()) { Pop(new_target); @@ -4428,13 +4343,13 @@ void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target, SmiToInteger64(expected.reg(), expected.reg()); } } - bind(&skip_flooding); + bind(&skip_hook); } void MacroAssembler::StubPrologue(StackFrame::Type type) { pushq(rbp); // Caller's frame pointer. movp(rbp, rsp); - Push(Smi::FromInt(type)); + Push(Immediate(StackFrame::TypeToMarker(type))); } void MacroAssembler::Prologue(bool code_pre_aging) { @@ -4453,11 +4368,10 @@ void MacroAssembler::Prologue(bool code_pre_aging) { } } - -void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) { +void MacroAssembler::EmitLoadFeedbackVector(Register vector) { movp(vector, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); - movp(vector, FieldOperand(vector, JSFunction::kLiteralsOffset)); - movp(vector, FieldOperand(vector, LiteralsArray::kFeedbackVectorOffset)); + movp(vector, FieldOperand(vector, JSFunction::kFeedbackVectorOffset)); + movp(vector, FieldOperand(vector, Cell::kValueOffset)); } @@ -4471,7 +4385,7 @@ void MacroAssembler::EnterFrame(StackFrame::Type type, void MacroAssembler::EnterFrame(StackFrame::Type type) { pushq(rbp); movp(rbp, rsp); - Push(Smi::FromInt(type)); + Push(Immediate(StackFrame::TypeToMarker(type))); if (type == StackFrame::INTERNAL) { Move(kScratchRegister, CodeObject(), RelocInfo::EMBEDDED_OBJECT); Push(kScratchRegister); @@ -4488,9 +4402,8 @@ void MacroAssembler::EnterFrame(StackFrame::Type type) { void MacroAssembler::LeaveFrame(StackFrame::Type type) { if (emit_debug_code()) { - Move(kScratchRegister, Smi::FromInt(type)); cmpp(Operand(rbp, CommonFrameConstants::kContextOrFrameTypeOffset), - kScratchRegister); + Immediate(StackFrame::TypeToMarker(type))); Check(equal, kStackFrameTypesMustMatch); } movp(rsp, rbp); @@ -4529,7 +4442,7 @@ void MacroAssembler::EnterExitFramePrologue(bool save_rax, movp(rbp, rsp); // Reserve room for entry stack pointer and push the code object. - Push(Smi::FromInt(frame_type)); + Push(Immediate(StackFrame::TypeToMarker(frame_type))); DCHECK_EQ(-2 * kPointerSize, ExitFrameConstants::kSPOffset); Push(Immediate(0)); // Saved entry sp, patched before call. Move(kScratchRegister, CodeObject(), RelocInfo::EMBEDDED_OBJECT); @@ -4958,125 +4871,6 @@ void MacroAssembler::AllocateHeapNumber(Register result, movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister); } - -void MacroAssembler::AllocateTwoByteString(Register result, - Register length, - Register scratch1, - Register scratch2, - Register scratch3, - Label* gc_required) { - // Calculate the number of bytes needed for the characters in the string while - // observing object alignment. - const int kHeaderAlignment = SeqTwoByteString::kHeaderSize & - kObjectAlignmentMask; - DCHECK(kShortSize == 2); - // scratch1 = length * 2 + kObjectAlignmentMask. - leap(scratch1, Operand(length, length, times_1, kObjectAlignmentMask + - kHeaderAlignment)); - andp(scratch1, Immediate(~kObjectAlignmentMask)); - if (kHeaderAlignment > 0) { - subp(scratch1, Immediate(kHeaderAlignment)); - } - - // Allocate two byte string in new space. - Allocate(SeqTwoByteString::kHeaderSize, times_1, scratch1, result, scratch2, - scratch3, gc_required, NO_ALLOCATION_FLAGS); - - // Set the map, length and hash field. - LoadRoot(kScratchRegister, Heap::kStringMapRootIndex); - movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister); - Integer32ToSmi(scratch1, length); - movp(FieldOperand(result, String::kLengthOffset), scratch1); - movp(FieldOperand(result, String::kHashFieldOffset), - Immediate(String::kEmptyHashField)); -} - - -void MacroAssembler::AllocateOneByteString(Register result, Register length, - Register scratch1, Register scratch2, - Register scratch3, - Label* gc_required) { - // Calculate the number of bytes needed for the characters in the string while - // observing object alignment. - const int kHeaderAlignment = SeqOneByteString::kHeaderSize & - kObjectAlignmentMask; - movl(scratch1, length); - DCHECK(kCharSize == 1); - addp(scratch1, Immediate(kObjectAlignmentMask + kHeaderAlignment)); - andp(scratch1, Immediate(~kObjectAlignmentMask)); - if (kHeaderAlignment > 0) { - subp(scratch1, Immediate(kHeaderAlignment)); - } - - // Allocate one-byte string in new space. - Allocate(SeqOneByteString::kHeaderSize, times_1, scratch1, result, scratch2, - scratch3, gc_required, NO_ALLOCATION_FLAGS); - - // Set the map, length and hash field. - LoadRoot(kScratchRegister, Heap::kOneByteStringMapRootIndex); - movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister); - Integer32ToSmi(scratch1, length); - movp(FieldOperand(result, String::kLengthOffset), scratch1); - movp(FieldOperand(result, String::kHashFieldOffset), - Immediate(String::kEmptyHashField)); -} - - -void MacroAssembler::AllocateTwoByteConsString(Register result, - Register scratch1, - Register scratch2, - Label* gc_required) { - // Allocate heap number in new space. - Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required, - NO_ALLOCATION_FLAGS); - - // Set the map. The other fields are left uninitialized. - LoadRoot(kScratchRegister, Heap::kConsStringMapRootIndex); - movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister); -} - - -void MacroAssembler::AllocateOneByteConsString(Register result, - Register scratch1, - Register scratch2, - Label* gc_required) { - Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required, - NO_ALLOCATION_FLAGS); - - // Set the map. The other fields are left uninitialized. - LoadRoot(kScratchRegister, Heap::kConsOneByteStringMapRootIndex); - movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister); -} - - -void MacroAssembler::AllocateTwoByteSlicedString(Register result, - Register scratch1, - Register scratch2, - Label* gc_required) { - // Allocate heap number in new space. - Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required, - NO_ALLOCATION_FLAGS); - - // Set the map. The other fields are left uninitialized. - LoadRoot(kScratchRegister, Heap::kSlicedStringMapRootIndex); - movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister); -} - - -void MacroAssembler::AllocateOneByteSlicedString(Register result, - Register scratch1, - Register scratch2, - Label* gc_required) { - // Allocate heap number in new space. - Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required, - NO_ALLOCATION_FLAGS); - - // Set the map. The other fields are left uninitialized. - LoadRoot(kScratchRegister, Heap::kSlicedOneByteStringMapRootIndex); - movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister); -} - - void MacroAssembler::AllocateJSValue(Register result, Register constructor, Register value, Register scratch, Label* gc_required) { @@ -5137,28 +4931,6 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) { } } - -void MacroAssembler::LoadTransitionedArrayMapConditional( - ElementsKind expected_kind, - ElementsKind transitioned_kind, - Register map_in_out, - Register scratch, - Label* no_map_match) { - DCHECK(IsFastElementsKind(expected_kind)); - DCHECK(IsFastElementsKind(transitioned_kind)); - - // Check that the function's map is the same as the expected cached map. - movp(scratch, NativeContextOperand()); - cmpp(map_in_out, - ContextOperand(scratch, Context::ArrayMapIndex(expected_kind))); - j(not_equal, no_map_match); - - // Use the transitioned cached map. - movp(map_in_out, - ContextOperand(scratch, Context::ArrayMapIndex(transitioned_kind))); -} - - #ifdef _WIN64 static const int kRegisterPassedArguments = 4; #else @@ -5501,42 +5273,6 @@ void MacroAssembler::TestJSArrayForAllocationMemento( Heap::kAllocationMementoMapRootIndex); } - -void MacroAssembler::JumpIfDictionaryInPrototypeChain( - Register object, - Register scratch0, - Register scratch1, - Label* found) { - DCHECK(!(scratch0.is(kScratchRegister) && scratch1.is(kScratchRegister))); - DCHECK(!scratch1.is(scratch0)); - Register current = scratch0; - Label loop_again, end; - - movp(current, object); - movp(current, FieldOperand(current, HeapObject::kMapOffset)); - movp(current, FieldOperand(current, Map::kPrototypeOffset)); - CompareRoot(current, Heap::kNullValueRootIndex); - j(equal, &end); - - // Loop based on the map going up the prototype chain. - bind(&loop_again); - movp(current, FieldOperand(current, HeapObject::kMapOffset)); - STATIC_ASSERT(JS_PROXY_TYPE < JS_OBJECT_TYPE); - STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE); - CmpInstanceType(current, JS_OBJECT_TYPE); - j(below, found); - movp(scratch1, FieldOperand(current, Map::kBitField2Offset)); - DecodeField<Map::ElementsKindBits>(scratch1); - cmpp(scratch1, Immediate(DICTIONARY_ELEMENTS)); - j(equal, found); - movp(current, FieldOperand(current, Map::kPrototypeOffset)); - CompareRoot(current, Heap::kNullValueRootIndex); - j(not_equal, &loop_again); - - bind(&end); -} - - void MacroAssembler::TruncatingDiv(Register dividend, int32_t divisor) { DCHECK(!dividend.is(rax)); DCHECK(!dividend.is(rdx)); |