From 5521e2e825fc20df870ad27d7b6561c8f76b723d Mon Sep 17 00:00:00 2001 From: "mvstanton@chromium.org" Date: Thu, 12 Sep 2013 17:59:41 +0000 Subject: [PATCH] Bugfix: array constructors that expect a type feedback cell that points to an AllocationSite were being passed the undefined object in some cases. Clearly separate the cases where we have an AllocationSite and where we don't in the general ArrayConstructorStub. BUG= R=mstarzinger@chromium.org Review URL: https://codereview.chromium.org/23477071 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16693 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/code-stubs-arm.cc | 212 +++++++++++++++++++++-------------- src/code-stubs.h | 20 ++-- src/ia32/code-stubs-ia32.cc | 218 +++++++++++++++++++++--------------- src/objects.h | 2 + src/x64/code-stubs-x64.cc | 214 ++++++++++++++++++++--------------- 5 files changed, 390 insertions(+), 276 deletions(-) diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index 8ec05910a5..cd1809fb2a 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -6837,90 +6837,128 @@ void ProfileEntryHookStub::Generate(MacroAssembler* masm) { template -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); - __ cmp(r3, Operand(kind)); - __ b(ne, &next); - T stub(kind); +static void CreateArrayDispatch(MacroAssembler* masm, + AllocationSiteOverrideMode mode) { + if (mode == DISABLE_ALLOCATION_SITES) { + T stub(GetInitialFastElementsKind(), + CONTEXT_CHECK_REQUIRED, + mode); __ TailCallStub(&stub); - __ bind(&next); - } + } else if (mode == DONT_OVERRIDE) { + int last_index = GetSequenceIndexFromFastElementsKind( + TERMINAL_FAST_ELEMENTS_KIND); + for (int i = 0; i <= last_index; ++i) { + Label next; + ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); + __ cmp(r3, Operand(kind)); + __ b(ne, &next); + T stub(kind); + __ TailCallStub(&stub); + __ bind(&next); + } - // If we reached this point there is a problem. - __ Abort(kUnexpectedElementsKindInArrayConstructor); + // If we reached this point there is a problem. + __ Abort(kUnexpectedElementsKindInArrayConstructor); + } else { + UNREACHABLE(); + } } -static void CreateArrayDispatchOneArgument(MacroAssembler* masm) { - // r2 - type info cell - // r3 - kind +static void CreateArrayDispatchOneArgument(MacroAssembler* masm, + AllocationSiteOverrideMode mode) { + // r2 - type info cell (if mode != DISABLE_ALLOCATION_SITES) + // r3 - kind (if mode != DISABLE_ALLOCATION_SITES) // r0 - number of arguments // r1 - constructor? // sp[0] - 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); - - // is the low bit set? If so, we are holey and that is good. - __ tst(r3, Operand(1)); Label normal_sequence; - __ b(ne, &normal_sequence); + if (mode == DONT_OVERRIDE) { + 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); + + // is the low bit set? If so, we are holey and that is good. + __ tst(r3, Operand(1)); + __ b(ne, &normal_sequence); + } // look at the first argument __ ldr(r5, MemOperand(sp, 0)); __ cmp(r5, Operand::Zero()); __ b(eq, &normal_sequence); - // We are going to create a holey array, but our kind is non-holey. - // Fix kind and retry (only if we have an allocation site in the cell). - __ add(r3, r3, Operand(1)); - __ CompareRoot(r2, Heap::kUndefinedValueRootIndex); - __ b(eq, &normal_sequence); - __ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset)); - __ ldr(r5, FieldMemOperand(r5, 0)); - __ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex); - __ b(ne, &normal_sequence); + if (mode == DISABLE_ALLOCATION_SITES) { + ElementsKind initial = GetInitialFastElementsKind(); + ElementsKind holey_initial = GetHoleyElementsKind(initial); - // Save the resulting elements kind in type info - __ SmiTag(r3); - __ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset)); - __ str(r3, FieldMemOperand(r5, AllocationSite::kTransitionInfoOffset)); - __ SmiUntag(r3); + ArraySingleArgumentConstructorStub stub_holey(holey_initial, + CONTEXT_CHECK_REQUIRED, + DISABLE_ALLOCATION_SITES); + __ TailCallStub(&stub_holey); - __ 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); - __ cmp(r3, Operand(kind)); - __ b(ne, &next); - ArraySingleArgumentConstructorStub stub(kind); + __ bind(&normal_sequence); + ArraySingleArgumentConstructorStub stub(initial, + CONTEXT_CHECK_REQUIRED, + DISABLE_ALLOCATION_SITES); __ TailCallStub(&stub); - __ bind(&next); - } + } else if (mode == DONT_OVERRIDE) { + // We are going to create a holey array, but our kind is non-holey. + // Fix kind and retry (only if we have an allocation site in the cell). + __ add(r3, r3, Operand(1)); + __ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset)); - // If we reached this point there is a problem. - __ Abort(kUnexpectedElementsKindInArrayConstructor); + if (FLAG_debug_code) { + __ ldr(r5, FieldMemOperand(r5, 0)); + __ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex); + __ Assert(eq, kExpectedAllocationSiteInCell); + __ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset)); + } + + // Save the resulting elements kind in type info + __ SmiTag(r3); + __ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset)); + __ str(r3, FieldMemOperand(r5, AllocationSite::kTransitionInfoOffset)); + __ SmiUntag(r3); + + __ 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); + __ cmp(r3, Operand(kind)); + __ b(ne, &next); + ArraySingleArgumentConstructorStub stub(kind); + __ TailCallStub(&stub); + __ bind(&next); + } + + // If we reached this point there is a problem. + __ Abort(kUnexpectedElementsKindInArrayConstructor); + } else { + UNREACHABLE(); + } } template static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) { + ElementsKind initial_kind = GetInitialFastElementsKind(); + ElementsKind initial_holey_kind = GetHoleyElementsKind(initial_kind); + 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); - if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) { + if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE || + (!FLAG_track_allocation_sites && + (kind == initial_kind || kind == initial_holey_kind))) { T stub1(kind, CONTEXT_CHECK_REQUIRED, DISABLE_ALLOCATION_SITES); stub1.GetCode(isolate)->set_is_pregenerated(true); } @@ -6953,6 +6991,34 @@ void InternalArrayConstructorStubBase::GenerateStubsAheadOfTime( } +void ArrayConstructorStub::GenerateDispatchToArrayStub( + MacroAssembler* masm, + AllocationSiteOverrideMode mode) { + if (argument_count_ == ANY) { + Label not_zero_case, not_one_case; + __ tst(r0, r0); + __ b(ne, ¬_zero_case); + CreateArrayDispatch(masm, mode); + + __ bind(¬_zero_case); + __ cmp(r0, Operand(1)); + __ b(gt, ¬_one_case); + CreateArrayDispatchOneArgument(masm, mode); + + __ bind(¬_one_case); + CreateArrayDispatch(masm, mode); + } else if (argument_count_ == NONE) { + CreateArrayDispatch(masm, mode); + } else if (argument_count_ == ONE) { + CreateArrayDispatchOneArgument(masm, mode); + } else if (argument_count_ == MORE_THAN_ONE) { + CreateArrayDispatch(masm, mode); + } else { + UNREACHABLE(); + } +} + + void ArrayConstructorStub::Generate(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- r0 : argc (only if argument_count_ == ANY) @@ -6984,50 +7050,24 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) { __ bind(&okay_here); } - Label no_info, switch_ready; + Label no_info; // Get the elements kind and case on that. __ CompareRoot(r2, Heap::kUndefinedValueRootIndex); __ b(eq, &no_info); __ ldr(r3, FieldMemOperand(r2, Cell::kValueOffset)); - // The type cell may have undefined in its value. - __ CompareRoot(r3, Heap::kUndefinedValueRootIndex); - __ b(eq, &no_info); - - // The type cell has either an AllocationSite or a JSFunction + // If the type cell is undefined, or contains anything other than an + // AllocationSite, call an array constructor that doesn't use AllocationSites. __ ldr(r4, FieldMemOperand(r3, 0)); __ CompareRoot(r4, Heap::kAllocationSiteMapRootIndex); __ b(ne, &no_info); __ ldr(r3, FieldMemOperand(r3, AllocationSite::kTransitionInfoOffset)); __ SmiUntag(r3); - __ jmp(&switch_ready); + GenerateDispatchToArrayStub(masm, DONT_OVERRIDE); + __ bind(&no_info); - __ mov(r3, Operand(GetInitialFastElementsKind())); - __ bind(&switch_ready); - - if (argument_count_ == ANY) { - Label not_zero_case, not_one_case; - __ tst(r0, r0); - __ b(ne, ¬_zero_case); - CreateArrayDispatch(masm); - - __ bind(¬_zero_case); - __ cmp(r0, Operand(1)); - __ b(gt, ¬_one_case); - CreateArrayDispatchOneArgument(masm); - - __ bind(¬_one_case); - CreateArrayDispatch(masm); - } else if (argument_count_ == NONE) { - CreateArrayDispatch(masm); - } else if (argument_count_ == ONE) { - CreateArrayDispatchOneArgument(masm); - } else if (argument_count_ == MORE_THAN_ONE) { - CreateArrayDispatch(masm); - } else { - UNREACHABLE(); - } + GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES); } diff --git a/src/code-stubs.h b/src/code-stubs.h index 81bbb52a1f..946eb76962 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -736,6 +736,13 @@ class InstanceofStub: public PlatformCodeStub { }; +enum AllocationSiteOverrideMode { + DONT_OVERRIDE, + DISABLE_ALLOCATION_SITES, + LAST_ALLOCATION_SITE_OVERRIDE_MODE = DISABLE_ALLOCATION_SITES +}; + + class ArrayConstructorStub: public PlatformCodeStub { public: enum ArgumentCountKey { ANY, NONE, ONE, MORE_THAN_ONE }; @@ -745,6 +752,9 @@ class ArrayConstructorStub: public PlatformCodeStub { void Generate(MacroAssembler* masm); private: + void GenerateDispatchToArrayStub(MacroAssembler* masm, + AllocationSiteOverrideMode mode); + virtual CodeStub::Major MajorKey() { return ArrayConstructor; } virtual int MinorKey() { return argument_count_; } @@ -1863,13 +1873,6 @@ enum ContextCheckMode { }; -enum AllocationSiteOverrideMode { - DONT_OVERRIDE, - DISABLE_ALLOCATION_SITES, - LAST_ALLOCATION_SITE_OVERRIDE_MODE = DISABLE_ALLOCATION_SITES -}; - - class ArrayConstructorStubBase : public HydrogenCodeStub { public: ArrayConstructorStubBase(ElementsKind kind, ContextCheckMode context_mode, @@ -1877,7 +1880,8 @@ class ArrayConstructorStubBase : public HydrogenCodeStub { // It only makes sense to override local allocation site behavior // if there is a difference between the global allocation site policy // for an ElementsKind and the desired usage of the stub. - ASSERT(override_mode != DISABLE_ALLOCATION_SITES || + ASSERT(!(FLAG_track_allocation_sites && + override_mode == DISABLE_ALLOCATION_SITES) || AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE); bit_field_ = ElementsKindBits::encode(kind) | AllocationSiteOverrideModeBits::encode(override_mode) | diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index fd58f00b1c..a83c1ae91d 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -7225,96 +7225,128 @@ void ProfileEntryHookStub::Generate(MacroAssembler* masm) { template -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); - __ cmp(edx, kind); - __ j(not_equal, &next); - T stub(kind); +static void CreateArrayDispatch(MacroAssembler* masm, + AllocationSiteOverrideMode mode) { + if (mode == DISABLE_ALLOCATION_SITES) { + T stub(GetInitialFastElementsKind(), + CONTEXT_CHECK_REQUIRED, + mode); __ TailCallStub(&stub); - __ bind(&next); - } + } else if (mode == DONT_OVERRIDE) { + int last_index = GetSequenceIndexFromFastElementsKind( + TERMINAL_FAST_ELEMENTS_KIND); + for (int i = 0; i <= last_index; ++i) { + Label next; + ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); + __ cmp(edx, kind); + __ j(not_equal, &next); + T stub(kind); + __ TailCallStub(&stub); + __ bind(&next); + } - // If we reached this point there is a problem. - __ Abort(kUnexpectedElementsKindInArrayConstructor); + // If we reached this point there is a problem. + __ Abort(kUnexpectedElementsKindInArrayConstructor); + } else { + UNREACHABLE(); + } } -static void CreateArrayDispatchOneArgument(MacroAssembler* masm) { - // ebx - type info cell - // edx - kind +static void CreateArrayDispatchOneArgument(MacroAssembler* masm, + AllocationSiteOverrideMode mode) { + // ebx - type info cell (if mode != DISABLE_ALLOCATION_SITES) + // edx - kind (if mode != DISABLE_ALLOCATION_SITES) // eax - number of arguments // edi - 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 undefined_sentinel( - masm->isolate()->heap()->undefined_value(), - masm->isolate()); - - // is the low bit set? If so, we are holey and that is good. - __ test_b(edx, 1); Label normal_sequence; - __ j(not_zero, &normal_sequence); + if (mode == DONT_OVERRIDE) { + 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); + + // is the low bit set? If so, we are holey and that is good. + __ test_b(edx, 1); + __ j(not_zero, &normal_sequence); + } // look at the first argument __ mov(ecx, Operand(esp, kPointerSize)); __ test(ecx, ecx); __ j(zero, &normal_sequence); - // We are going to create a holey array, but our kind is non-holey. - // Fix kind and retry (only if we have an allocation site in the cell). - __ inc(edx); - __ cmp(ebx, Immediate(undefined_sentinel)); - __ j(equal, &normal_sequence); - __ mov(ecx, FieldOperand(ebx, Cell::kValueOffset)); - Handle allocation_site_map( - masm->isolate()->heap()->allocation_site_map(), - masm->isolate()); - __ cmp(FieldOperand(ecx, 0), Immediate(allocation_site_map)); - __ j(not_equal, &normal_sequence); + if (mode == DISABLE_ALLOCATION_SITES) { + ElementsKind initial = GetInitialFastElementsKind(); + ElementsKind holey_initial = GetHoleyElementsKind(initial); - // Save the resulting elements kind in type info - __ SmiTag(edx); - __ mov(FieldOperand(ecx, AllocationSite::kTransitionInfoOffset), edx); - __ SmiUntag(edx); + ArraySingleArgumentConstructorStub stub_holey(holey_initial, + CONTEXT_CHECK_REQUIRED, + DISABLE_ALLOCATION_SITES); + __ TailCallStub(&stub_holey); - __ 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); - __ cmp(edx, kind); - __ j(not_equal, &next); - ArraySingleArgumentConstructorStub stub(kind); + __ bind(&normal_sequence); + ArraySingleArgumentConstructorStub stub(initial, + CONTEXT_CHECK_REQUIRED, + DISABLE_ALLOCATION_SITES); __ TailCallStub(&stub); - __ bind(&next); - } + } else if (mode == DONT_OVERRIDE) { + // We are going to create a holey array, but our kind is non-holey. + // Fix kind and retry. + __ inc(edx); + __ mov(ecx, FieldOperand(ebx, Cell::kValueOffset)); + if (FLAG_debug_code) { + Handle allocation_site_map( + masm->isolate()->heap()->allocation_site_map(), + masm->isolate()); + __ cmp(FieldOperand(ecx, 0), Immediate(allocation_site_map)); + __ Assert(equal, kExpectedAllocationSiteInCell); + } - // If we reached this point there is a problem. - __ Abort(kUnexpectedElementsKindInArrayConstructor); + // Save the resulting elements kind in type info + __ SmiTag(edx); + __ mov(FieldOperand(ecx, AllocationSite::kTransitionInfoOffset), edx); + __ SmiUntag(edx); + + __ 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); + __ cmp(edx, kind); + __ j(not_equal, &next); + ArraySingleArgumentConstructorStub stub(kind); + __ TailCallStub(&stub); + __ bind(&next); + } + + // If we reached this point there is a problem. + __ Abort(kUnexpectedElementsKindInArrayConstructor); + } else { + UNREACHABLE(); + } } template static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) { + ElementsKind initial_kind = GetInitialFastElementsKind(); + ElementsKind initial_holey_kind = GetHoleyElementsKind(initial_kind); + 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); - if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) { + if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE || + (!FLAG_track_allocation_sites && + (kind == initial_kind || kind == initial_holey_kind))) { T stub1(kind, CONTEXT_CHECK_REQUIRED, DISABLE_ALLOCATION_SITES); stub1.GetCode(isolate)->set_is_pregenerated(true); } @@ -7347,6 +7379,34 @@ void InternalArrayConstructorStubBase::GenerateStubsAheadOfTime( } +void ArrayConstructorStub::GenerateDispatchToArrayStub( + MacroAssembler* masm, + AllocationSiteOverrideMode mode) { + if (argument_count_ == ANY) { + Label not_zero_case, not_one_case; + __ test(eax, eax); + __ j(not_zero, ¬_zero_case); + CreateArrayDispatch(masm, mode); + + __ bind(¬_zero_case); + __ cmp(eax, 1); + __ j(greater, ¬_one_case); + CreateArrayDispatchOneArgument(masm, mode); + + __ bind(¬_one_case); + CreateArrayDispatch(masm, mode); + } else if (argument_count_ == NONE) { + CreateArrayDispatch(masm, mode); + } else if (argument_count_ == ONE) { + CreateArrayDispatchOneArgument(masm, mode); + } else if (argument_count_ == MORE_THAN_ONE) { + CreateArrayDispatch(masm, mode); + } else { + UNREACHABLE(); + } +} + + void ArrayConstructorStub::Generate(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- eax : argc (only if argument_count_ == ANY) @@ -7381,50 +7441,22 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) { __ bind(&okay_here); } - Label no_info, switch_ready; - // Get the elements kind and case on that. + Label no_info; + // If the type cell is undefined, or contains anything other than an + // AllocationSite, call an array constructor that doesn't use AllocationSites. __ cmp(ebx, Immediate(undefined_sentinel)); __ j(equal, &no_info); __ mov(edx, FieldOperand(ebx, Cell::kValueOffset)); - - // The type cell may have undefined in its value. - __ cmp(edx, Immediate(undefined_sentinel)); - __ j(equal, &no_info); - - // The type cell has either an AllocationSite or a JSFunction __ cmp(FieldOperand(edx, 0), Immediate(Handle( masm->isolate()->heap()->allocation_site_map()))); __ j(not_equal, &no_info); __ mov(edx, FieldOperand(edx, AllocationSite::kTransitionInfoOffset)); __ SmiUntag(edx); - __ jmp(&switch_ready); + GenerateDispatchToArrayStub(masm, DONT_OVERRIDE); + __ bind(&no_info); - __ mov(edx, Immediate(GetInitialFastElementsKind())); - __ bind(&switch_ready); - - if (argument_count_ == ANY) { - Label not_zero_case, not_one_case; - __ test(eax, eax); - __ j(not_zero, ¬_zero_case); - CreateArrayDispatch(masm); - - __ bind(¬_zero_case); - __ cmp(eax, 1); - __ j(greater, ¬_one_case); - CreateArrayDispatchOneArgument(masm); - - __ bind(¬_one_case); - CreateArrayDispatch(masm); - } else if (argument_count_ == NONE) { - CreateArrayDispatch(masm); - } else if (argument_count_ == ONE) { - CreateArrayDispatchOneArgument(masm); - } else if (argument_count_ == MORE_THAN_ONE) { - CreateArrayDispatch(masm); - } else { - UNREACHABLE(); - } + GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES); } diff --git a/src/objects.h b/src/objects.h index 1e324e6df1..71d395ebbd 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1113,6 +1113,8 @@ class MaybeObject BASE_EMBEDDED { V(kEval, "eval") \ V(kExpected0AsASmiSentinel, "Expected 0 as a Smi sentinel") \ V(kExpectedAlignmentMarker, "expected alignment marker") \ + V(kExpectedAllocationSiteInCell, \ + "Expected AllocationSite in property cell") \ V(kExpectedPropertyCellInRegisterA2, \ "Expected property cell in register a2") \ V(kExpectedPropertyCellInRegisterEbx, \ diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 12f6c171d1..51e1a5395c 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -6312,46 +6312,59 @@ void ProfileEntryHookStub::Generate(MacroAssembler* masm) { template -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); +static void CreateArrayDispatch(MacroAssembler* masm, + AllocationSiteOverrideMode mode) { + if (mode == DISABLE_ALLOCATION_SITES) { + T stub(GetInitialFastElementsKind(), + CONTEXT_CHECK_REQUIRED, + mode); __ TailCallStub(&stub); - __ bind(&next); - } + } else if (mode == DONT_OVERRIDE) { + 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(kUnexpectedElementsKindInArrayConstructor); + // If we reached this point there is a problem. + __ Abort(kUnexpectedElementsKindInArrayConstructor); + } else { + UNREACHABLE(); + } } -static void CreateArrayDispatchOneArgument(MacroAssembler* masm) { - // rbx - type info cell - // rdx - kind +static void CreateArrayDispatchOneArgument(MacroAssembler* masm, + AllocationSiteOverrideMode mode) { + // rbx - type info cell (if mode != DISABLE_ALLOCATION_SITES) + // rdx - kind (if mode != DISABLE_ALLOCATION_SITES) // rax - number of arguments // rdi - constructor? // rsp[0] - return address // rsp[8] - 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 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); + if (mode == DONT_OVERRIDE) { + 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); + + // is the low bit set? If so, we are holey and that is good. + __ testb(rdx, Immediate(1)); + __ j(not_zero, &normal_sequence); + } // look at the first argument StackArgumentsAccessor args(rsp, 1, ARGUMENTS_DONT_CONTAIN_RECEIVER); @@ -6359,50 +6372,73 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm) { __ 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 (only if we have an allocation site in the cell). - __ incl(rdx); - __ Cmp(rbx, undefined_sentinel); - __ j(equal, &normal_sequence); - __ movq(rcx, FieldOperand(rbx, Cell::kValueOffset)); - Handle allocation_site_map( - masm->isolate()->heap()->allocation_site_map(), - masm->isolate()); - __ Cmp(FieldOperand(rcx, 0), allocation_site_map); - __ j(not_equal, &normal_sequence); + if (mode == DISABLE_ALLOCATION_SITES) { + ElementsKind initial = GetInitialFastElementsKind(); + ElementsKind holey_initial = GetHoleyElementsKind(initial); - // Save the resulting elements kind in type info - __ Integer32ToSmi(rdx, rdx); - __ movq(FieldOperand(rcx, AllocationSite::kTransitionInfoOffset), rdx); - __ SmiToInteger32(rdx, rdx); + ArraySingleArgumentConstructorStub stub_holey(holey_initial, + CONTEXT_CHECK_REQUIRED, + DISABLE_ALLOCATION_SITES); + __ TailCallStub(&stub_holey); - __ 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); + __ bind(&normal_sequence); + ArraySingleArgumentConstructorStub stub(initial, + CONTEXT_CHECK_REQUIRED, + DISABLE_ALLOCATION_SITES); __ TailCallStub(&stub); - __ bind(&next); - } + } else if (mode == DONT_OVERRIDE) { + // We are going to create a holey array, but our kind is non-holey. + // Fix kind and retry (only if we have an allocation site in the cell). + __ incl(rdx); + __ movq(rcx, FieldOperand(rbx, Cell::kValueOffset)); + if (FLAG_debug_code) { + Handle allocation_site_map( + masm->isolate()->heap()->allocation_site_map(), + masm->isolate()); + __ Cmp(FieldOperand(rcx, 0), allocation_site_map); + __ Assert(equal, kExpectedAllocationSiteInCell); + } - // If we reached this point there is a problem. - __ Abort(kUnexpectedElementsKindInArrayConstructor); + // Save the resulting elements kind in type info + __ Integer32ToSmi(rdx, rdx); + __ movq(FieldOperand(rcx, AllocationSite::kTransitionInfoOffset), 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(kUnexpectedElementsKindInArrayConstructor); + } else { + UNREACHABLE(); + } } template static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) { + ElementsKind initial_kind = GetInitialFastElementsKind(); + ElementsKind initial_holey_kind = GetHoleyElementsKind(initial_kind); + 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); - if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) { + if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE || + (!FLAG_track_allocation_sites && + (kind == initial_kind || kind == initial_holey_kind))) { T stub1(kind, CONTEXT_CHECK_REQUIRED, DISABLE_ALLOCATION_SITES); stub1.GetCode(isolate)->set_is_pregenerated(true); } @@ -6435,6 +6471,34 @@ void InternalArrayConstructorStubBase::GenerateStubsAheadOfTime( } +void ArrayConstructorStub::GenerateDispatchToArrayStub( + MacroAssembler* masm, + AllocationSiteOverrideMode mode) { + if (argument_count_ == ANY) { + Label not_zero_case, not_one_case; + __ testq(rax, rax); + __ j(not_zero, ¬_zero_case); + CreateArrayDispatch(masm, mode); + + __ bind(¬_zero_case); + __ cmpl(rax, Immediate(1)); + __ j(greater, ¬_one_case); + CreateArrayDispatchOneArgument(masm, mode); + + __ bind(¬_one_case); + CreateArrayDispatch(masm, mode); + } else if (argument_count_ == NONE) { + CreateArrayDispatch(masm, mode); + } else if (argument_count_ == ONE) { + CreateArrayDispatchOneArgument(masm, mode); + } else if (argument_count_ == MORE_THAN_ONE) { + CreateArrayDispatch(masm, mode); + } else { + UNREACHABLE(); + } +} + + void ArrayConstructorStub::Generate(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- rax : argc @@ -6470,50 +6534,22 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) { __ bind(&okay_here); } - Label no_info, switch_ready; - // Get the elements kind and case on that. + Label no_info; + // If the type cell is undefined, or contains anything other than an + // AllocationSite, call an array constructor that doesn't use AllocationSites. __ Cmp(rbx, undefined_sentinel); __ j(equal, &no_info); __ movq(rdx, FieldOperand(rbx, Cell::kValueOffset)); - - // The type cell may have undefined in its value. - __ Cmp(rdx, undefined_sentinel); - __ j(equal, &no_info); - - // The type cell has either an AllocationSite or a JSFunction __ Cmp(FieldOperand(rdx, 0), Handle(masm->isolate()->heap()->allocation_site_map())); __ j(not_equal, &no_info); __ movq(rdx, FieldOperand(rdx, AllocationSite::kTransitionInfoOffset)); __ SmiToInteger32(rdx, rdx); - __ jmp(&switch_ready); + GenerateDispatchToArrayStub(masm, DONT_OVERRIDE); + __ 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(masm); - - __ bind(¬_zero_case); - __ cmpl(rax, Immediate(1)); - __ j(greater, ¬_one_case); - CreateArrayDispatchOneArgument(masm); - - __ bind(¬_one_case); - CreateArrayDispatch(masm); - } else if (argument_count_ == NONE) { - CreateArrayDispatch(masm); - } else if (argument_count_ == ONE) { - CreateArrayDispatchOneArgument(masm); - } else if (argument_count_ == MORE_THAN_ONE) { - CreateArrayDispatch(masm); - } else { - UNREACHABLE(); - } + GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES); }