diff options
Diffstat (limited to 'deps/v8/src/x64/code-stubs-x64.cc')
-rw-r--r-- | deps/v8/src/x64/code-stubs-x64.cc | 354 |
1 files changed, 280 insertions, 74 deletions
diff --git a/deps/v8/src/x64/code-stubs-x64.cc b/deps/v8/src/x64/code-stubs-x64.cc index 3958cf0324..3a9a0234e2 100644 --- a/deps/v8/src/x64/code-stubs-x64.cc +++ b/deps/v8/src/x64/code-stubs-x64.cc @@ -96,16 +96,20 @@ void TransitionElementsKindStub::InitializeInterfaceDescriptor( } -static void InitializeArrayConstructorDescriptor(Isolate* isolate, - CodeStubInterfaceDescriptor* descriptor) { +static void InitializeArrayConstructorDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor, + int constant_stack_parameter_count) { // register state - // rdi -- constructor function + // rax -- number of arguments // rbx -- type info cell with elements kind - // rax -- number of arguments to the constructor function - static Register registers[] = { rdi, rbx }; - descriptor->register_param_count_ = 2; - // stack param count needs (constructor pointer, and single argument) - descriptor->stack_parameter_count_ = &rax; + static Register registers[] = { rbx }; + descriptor->register_param_count_ = 1; + if (constant_stack_parameter_count != 0) { + // stack param count needs (constructor pointer, and single argument) + descriptor->stack_parameter_count_ = &rax; + } + descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count; descriptor->register_params_ = registers; descriptor->function_mode_ = JS_FUNCTION_STUB_MODE; descriptor->deoptimization_handler_ = @@ -116,26 +120,64 @@ static void InitializeArrayConstructorDescriptor(Isolate* isolate, void ArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { - InitializeArrayConstructorDescriptor(isolate, descriptor); + InitializeArrayConstructorDescriptor(isolate, descriptor, 0); } void ArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { - InitializeArrayConstructorDescriptor(isolate, descriptor); + InitializeArrayConstructorDescriptor(isolate, descriptor, 1); } void ArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { - InitializeArrayConstructorDescriptor(isolate, descriptor); + InitializeArrayConstructorDescriptor(isolate, descriptor, -1); +} + + +void CompareNilICStub::InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor) { + static Register registers[] = { rax }; + descriptor->register_param_count_ = 1; + descriptor->register_params_ = registers; + descriptor->deoptimization_handler_ = + FUNCTION_ADDR(CompareNilIC_Miss); + descriptor->miss_handler_ = + ExternalReference(IC_Utility(IC::kCompareNilIC_Miss), isolate); } #define __ ACCESS_MASM(masm) + +void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) { + // Update the static counter each time a new code stub is generated. + Isolate* isolate = masm->isolate(); + isolate->counters()->code_stubs()->Increment(); + + CodeStubInterfaceDescriptor* descriptor = GetInterfaceDescriptor(isolate); + int param_count = descriptor->register_param_count_; + { + // Call the runtime system in a fresh internal frame. + FrameScope scope(masm, StackFrame::INTERNAL); + ASSERT(descriptor->register_param_count_ == 0 || + rax.is(descriptor->register_params_[param_count - 1])); + // Push arguments + for (int i = 0; i < param_count; ++i) { + __ push(descriptor->register_params_[i]); + } + ExternalReference miss = descriptor->miss_handler_; + __ CallExternalReference(miss, descriptor->register_param_count_); + } + + __ Ret(); +} + + void ToNumberStub::Generate(MacroAssembler* masm) { // The ToNumber stub takes one argument in eax. Label check_heap_number, call_builtin; @@ -500,11 +542,8 @@ void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { __ PushCallerSaved(save_doubles_); const int argument_count = 1; __ PrepareCallCFunction(argument_count); -#ifdef _WIN64 - __ LoadAddress(rcx, ExternalReference::isolate_address()); -#else - __ LoadAddress(rdi, ExternalReference::isolate_address()); -#endif + __ LoadAddress(arg_reg_1, + ExternalReference::isolate_address(masm->isolate())); AllowExternalCallThatCantCauseGC scope(masm); __ CallCFunction( @@ -1974,12 +2013,7 @@ void FloatingPointHelper::NumbersToSmis(MacroAssembler* masm, void MathPowStub::Generate(MacroAssembler* masm) { - // Choose register conforming to calling convention (when bailing out). -#ifdef _WIN64 const Register exponent = rdx; -#else - const Register exponent = rdi; -#endif const Register base = rax; const Register scratch = rcx; const XMMRegister double_result = xmm3; @@ -2954,9 +2988,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ EnterApiExitFrame(argument_slots_on_stack); // Argument 9: Pass current isolate address. - // __ movq(Operand(rsp, (argument_slots_on_stack - 1) * kPointerSize), - // Immediate(ExternalReference::isolate_address())); - __ LoadAddress(kScratchRegister, ExternalReference::isolate_address()); + __ LoadAddress(kScratchRegister, + ExternalReference::isolate_address(masm->isolate())); __ movq(Operand(rsp, (argument_slots_on_stack - 1) * kPointerSize), kScratchRegister); @@ -2989,20 +3022,6 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ movq(Operand(rsp, (argument_slots_on_stack - 5) * kPointerSize), r8); #endif - // First four arguments are passed in registers on both Linux and Windows. -#ifdef _WIN64 - Register arg4 = r9; - Register arg3 = r8; - Register arg2 = rdx; - Register arg1 = rcx; -#else - Register arg4 = rcx; - Register arg3 = rdx; - Register arg2 = rsi; - Register arg1 = rdi; -#endif - - // Keep track on aliasing between argX defined above and the registers used. // rdi: subject string // rbx: previous index // rcx: encoding of subject string (1 if ASCII 0 if two_byte); @@ -3011,7 +3030,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // r15: original subject string // Argument 2: Previous index. - __ movq(arg2, rbx); + __ movq(arg_reg_2, rbx); // Argument 4: End of string data // Argument 3: Start of string data @@ -3019,20 +3038,24 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // Prepare start and end index of the input. // Load the length from the original sliced string if that is the case. __ addq(rbx, r14); - __ SmiToInteger32(arg3, FieldOperand(r15, String::kLengthOffset)); - __ addq(r14, arg3); // Using arg3 as scratch. + __ SmiToInteger32(arg_reg_3, FieldOperand(r15, String::kLengthOffset)); + __ addq(r14, arg_reg_3); // Using arg3 as scratch. // rbx: start index of the input // r14: end index of the input // r15: original subject string __ testb(rcx, rcx); // Last use of rcx as encoding of subject string. __ j(zero, &setup_two_byte, Label::kNear); - __ lea(arg4, FieldOperand(rdi, r14, times_1, SeqOneByteString::kHeaderSize)); - __ lea(arg3, FieldOperand(rdi, rbx, times_1, SeqOneByteString::kHeaderSize)); + __ lea(arg_reg_4, + FieldOperand(rdi, r14, times_1, SeqOneByteString::kHeaderSize)); + __ lea(arg_reg_3, + FieldOperand(rdi, rbx, times_1, SeqOneByteString::kHeaderSize)); __ jmp(&setup_rest, Label::kNear); __ bind(&setup_two_byte); - __ lea(arg4, FieldOperand(rdi, r14, times_2, SeqTwoByteString::kHeaderSize)); - __ lea(arg3, FieldOperand(rdi, rbx, times_2, SeqTwoByteString::kHeaderSize)); + __ lea(arg_reg_4, + FieldOperand(rdi, r14, times_2, SeqTwoByteString::kHeaderSize)); + __ lea(arg_reg_3, + FieldOperand(rdi, rbx, times_2, SeqTwoByteString::kHeaderSize)); __ bind(&setup_rest); // Argument 1: Original subject string. @@ -3040,7 +3063,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // use rbp, which points exactly to one pointer size below the previous rsp. // (Because creating a new stack frame pushes the previous rbp onto the stack // and thereby moves up rsp by one kPointerSize.) - __ movq(arg1, r15); + __ movq(arg_reg_1, r15); // Locate the code entry and call it. __ addq(r11, Immediate(Code::kHeaderSize - kHeapObjectTag)); @@ -3796,7 +3819,7 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { TypeFeedbackCells::MonomorphicArraySentinel(isolate, LAST_FAST_ELEMENTS_KIND); __ Cmp(rcx, terminal_kind_sentinel); - __ j(not_equal, &miss); + __ j(above, &miss); // Make sure the function is the Array() function __ LoadArrayFunction(rcx); __ cmpq(rdi, rcx); @@ -4008,6 +4031,9 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { StubFailureTrampolineStub::GenerateAheadOfTime(isolate); // It is important that the store buffer overflow stubs are generated first. RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate); + if (FLAG_optimize_constructed_arrays) { + ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); + } } @@ -4065,11 +4091,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, // PerformGC. No need to use PrepareCallCFunction/CallCFunction here as the // stack is known to be aligned. This function takes one argument which is // passed in register. -#ifdef _WIN64 - __ movq(rcx, rax); -#else // _WIN64 - __ movq(rdi, rax); -#endif + __ movq(arg_reg_1, rax); __ movq(kScratchRegister, ExternalReference::perform_gc_function(masm->isolate())); __ call(kScratchRegister); @@ -4092,21 +4114,21 @@ 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)); - __ LoadAddress(rdx, ExternalReference::isolate_address()); + __ LoadAddress(rdx, ExternalReference::isolate_address(masm->isolate())); } 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)); - __ LoadAddress(r8, ExternalReference::isolate_address()); + __ LoadAddress(r8, ExternalReference::isolate_address(masm->isolate())); } #else // _WIN64 // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9. __ movq(rdi, r14); // argc. __ movq(rsi, r15); // argv. - __ movq(rdx, ExternalReference::isolate_address()); + __ movq(rdx, ExternalReference::isolate_address(masm->isolate())); #endif __ call(rbx); // Result is in rax - do not destroy this register! @@ -4891,16 +4913,16 @@ void StringAddStub::Generate(MacroAssembler* masm) { __ ret(2 * kPointerSize); __ bind(&non_ascii); // At least one of the strings is two-byte. Check whether it happens - // to contain only ASCII characters. + // to contain only one byte characters. // rcx: first instance type AND second instance type. // r8: first instance type. // r9: second instance type. - __ testb(rcx, Immediate(kAsciiDataHintMask)); + __ testb(rcx, Immediate(kOneByteDataHintMask)); __ j(not_zero, &ascii_data); __ xor_(r8, r9); - STATIC_ASSERT(kOneByteStringTag != 0 && kAsciiDataHintTag != 0); - __ andb(r8, Immediate(kOneByteStringTag | kAsciiDataHintTag)); - __ cmpb(r8, Immediate(kOneByteStringTag | kAsciiDataHintTag)); + STATIC_ASSERT(kOneByteStringTag != 0 && kOneByteDataHintTag != 0); + __ andb(r8, Immediate(kOneByteStringTag | kOneByteDataHintTag)); + __ cmpb(r8, Immediate(kOneByteStringTag | kOneByteDataHintTag)); __ j(equal, &ascii_data); // Allocate a two byte cons string. __ AllocateTwoByteConsString(rcx, rdi, no_reg, &call_runtime); @@ -6457,24 +6479,16 @@ void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) { void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm, Mode mode) { regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode_); -#ifdef _WIN64 - Register arg3 = r8; - Register arg2 = rdx; - Register arg1 = rcx; -#else - Register arg3 = rdx; - Register arg2 = rsi; - Register arg1 = rdi; -#endif Register address = - arg1.is(regs_.address()) ? kScratchRegister : regs_.address(); + arg_reg_1.is(regs_.address()) ? kScratchRegister : regs_.address(); ASSERT(!address.is(regs_.object())); - ASSERT(!address.is(arg1)); + ASSERT(!address.is(arg_reg_1)); __ Move(address, regs_.address()); - __ Move(arg1, regs_.object()); + __ Move(arg_reg_1, regs_.object()); // TODO(gc) Can we just set address arg2 in the beginning? - __ Move(arg2, address); - __ LoadAddress(arg3, ExternalReference::isolate_address()); + __ Move(arg_reg_2, address); + __ LoadAddress(arg_reg_3, + ExternalReference::isolate_address(masm->isolate())); int argument_count = 3; AllowExternalCallThatCantCauseGC scope(masm); @@ -6745,6 +6759,198 @@ void ProfileEntryHookStub::Generate(MacroAssembler* masm) { __ Ret(); } + +template<class T> +static void CreateArrayDispatch(MacroAssembler* masm) { + int last_index = GetSequenceIndexFromFastElementsKind( + TERMINAL_FAST_ELEMENTS_KIND); + for (int i = 0; i <= last_index; ++i) { + Label next; + ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); + __ cmpl(rdx, Immediate(kind)); + __ j(not_equal, &next); + T stub(kind); + __ TailCallStub(&stub); + __ bind(&next); + } + + // If we reached this point there is a problem. + __ Abort("Unexpected ElementsKind in array constructor"); +} + + +static void CreateArrayDispatchOneArgument(MacroAssembler* masm) { + // rbx - type info cell + // rdx - kind + // rax - number of arguments + // rdi - constructor? + // esp[0] - return address + // esp[4] - last argument + ASSERT(FAST_SMI_ELEMENTS == 0); + ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); + ASSERT(FAST_ELEMENTS == 2); + ASSERT(FAST_HOLEY_ELEMENTS == 3); + ASSERT(FAST_DOUBLE_ELEMENTS == 4); + ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5); + + Handle<Object> undefined_sentinel( + masm->isolate()->heap()->undefined_value(), + masm->isolate()); + + // is the low bit set? If so, we are holey and that is good. + __ testb(rdx, Immediate(1)); + Label normal_sequence; + __ j(not_zero, &normal_sequence); + + // look at the first argument + __ movq(rcx, Operand(rsp, kPointerSize)); + __ testq(rcx, rcx); + __ j(zero, &normal_sequence); + + // We are going to create a holey array, but our kind is non-holey. + // Fix kind and retry + __ incl(rdx); + __ Cmp(rbx, undefined_sentinel); + __ j(equal, &normal_sequence); + + // Save the resulting elements kind in type info + __ Integer32ToSmi(rdx, rdx); + __ movq(FieldOperand(rbx, kPointerSize), rdx); + __ SmiToInteger32(rdx, rdx); + + __ bind(&normal_sequence); + int last_index = GetSequenceIndexFromFastElementsKind( + TERMINAL_FAST_ELEMENTS_KIND); + for (int i = 0; i <= last_index; ++i) { + Label next; + ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); + __ cmpl(rdx, Immediate(kind)); + __ j(not_equal, &next); + ArraySingleArgumentConstructorStub stub(kind); + __ TailCallStub(&stub); + __ bind(&next); + } + + // If we reached this point there is a problem. + __ Abort("Unexpected ElementsKind in array constructor"); +} + + +template<class T> +static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) { + int to_index = GetSequenceIndexFromFastElementsKind( + TERMINAL_FAST_ELEMENTS_KIND); + for (int i = 0; i <= to_index; ++i) { + ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); + T stub(kind); + stub.GetCode(isolate)->set_is_pregenerated(true); + } +} + + +void ArrayConstructorStubBase::GenerateStubsAheadOfTime(Isolate* isolate) { + ArrayConstructorStubAheadOfTimeHelper<ArrayNoArgumentConstructorStub>( + isolate); + ArrayConstructorStubAheadOfTimeHelper<ArraySingleArgumentConstructorStub>( + isolate); + ArrayConstructorStubAheadOfTimeHelper<ArrayNArgumentsConstructorStub>( + isolate); +} + + + +void ArrayConstructorStub::Generate(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- rax : argc + // -- rbx : type info cell + // -- rdi : constructor + // -- rsp[0] : return address + // -- rsp[4] : last argument + // ----------------------------------- + Handle<Object> undefined_sentinel( + masm->isolate()->heap()->undefined_value(), + masm->isolate()); + + if (FLAG_debug_code) { + // The array construct code is only set for the global and natives + // builtin Array functions which always have maps. + + // Initial map for the builtin Array function should be a map. + __ movq(rcx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); + // Will both indicate a NULL and a Smi. + STATIC_ASSERT(kSmiTag == 0); + Condition not_smi = NegateCondition(masm->CheckSmi(rcx)); + __ Check(not_smi, "Unexpected initial map for Array function"); + __ CmpObjectType(rcx, MAP_TYPE, rcx); + __ Check(equal, "Unexpected initial map for Array function"); + + // We should either have undefined in ebx or a valid jsglobalpropertycell + Label okay_here; + Handle<Map> global_property_cell_map( + masm->isolate()->heap()->global_property_cell_map()); + __ Cmp(rbx, undefined_sentinel); + __ j(equal, &okay_here); + __ Cmp(FieldOperand(rbx, 0), global_property_cell_map); + __ Assert(equal, "Expected property cell in register rbx"); + __ bind(&okay_here); + } + + if (FLAG_optimize_constructed_arrays) { + Label no_info, switch_ready; + // Get the elements kind and case on that. + __ Cmp(rbx, undefined_sentinel); + __ j(equal, &no_info); + __ movq(rdx, FieldOperand(rbx, kPointerSize)); + + // There is no info if the call site went megamorphic either + + // TODO(mvstanton): Really? I thought if it was the array function that + // the cell wouldn't get stamped as megamorphic. + __ Cmp(rdx, TypeFeedbackCells::MegamorphicSentinel(masm->isolate())); + __ j(equal, &no_info); + __ SmiToInteger32(rdx, rdx); + __ jmp(&switch_ready); + __ bind(&no_info); + __ movq(rdx, Immediate(GetInitialFastElementsKind())); + __ bind(&switch_ready); + + if (argument_count_ == ANY) { + Label not_zero_case, not_one_case; + __ testq(rax, rax); + __ j(not_zero, ¬_zero_case); + CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm); + + __ bind(¬_zero_case); + __ cmpl(rax, Immediate(1)); + __ j(greater, ¬_one_case); + CreateArrayDispatchOneArgument(masm); + + __ bind(¬_one_case); + CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm); + } else if (argument_count_ == NONE) { + CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm); + } else if (argument_count_ == ONE) { + CreateArrayDispatchOneArgument(masm); + } else if (argument_count_ == MORE_THAN_ONE) { + CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm); + } else { + UNREACHABLE(); + } + } else { + Label generic_constructor; + // Run the native code for the Array function called as constructor. + ArrayNativeCode(masm, &generic_constructor); + + // Jump to the generic construct code in case the specialized code cannot + // handle the construction. + __ bind(&generic_constructor); + Handle<Code> generic_construct_stub = + masm->isolate()->builtins()->JSConstructStubGeneric(); + __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); + } +} + + #undef __ } } // namespace v8::internal |