From: mvstanton@chromium.org Date: Wed, 19 Feb 2014 13:55:25 +0000 (+0000) Subject: Revert "Second attempt at introducing a premonomorphic state in the call" X-Git-Tag: upstream/4.7.83~10613 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=73b679cbee7586e17802087d6900e4e977630803;p=platform%2Fupstream%2Fv8.git Revert "Second attempt at introducing a premonomorphic state in the call" This reverts commits r19463 and r19457 (includes MIPS port), there was a Sunspider perf issue and on reflection we can achieve the necessary result in a new way. TBR=verwaest@chromium.org Review URL: https://codereview.chromium.org/172383003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19488 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/a64/code-stubs-a64.cc b/src/a64/code-stubs-a64.cc index 145b37d..da5b4ae 100644 --- a/src/a64/code-stubs-a64.cc +++ b/src/a64/code-stubs-a64.cc @@ -3268,17 +3268,12 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { // x1 : the function to call // x2 : feedback vector // x3 : slot in feedback vector (smi) - Label check_array, initialize_array, initialize_non_array, megamorphic, done; + Label initialize, done, miss, megamorphic, not_array_function; ASSERT_EQ(*TypeFeedbackInfo::MegamorphicSentinel(masm->isolate()), masm->isolate()->heap()->undefined_value()); - Heap::RootListIndex kMegamorphicRootIndex = Heap::kUndefinedValueRootIndex; ASSERT_EQ(*TypeFeedbackInfo::UninitializedSentinel(masm->isolate()), masm->isolate()->heap()->the_hole_value()); - Heap::RootListIndex kUninitializedRootIndex = Heap::kTheHoleValueRootIndex; - ASSERT_EQ(*TypeFeedbackInfo::PremonomorphicSentinel(masm->isolate()), - masm->isolate()->heap()->null_value()); - Heap::RootListIndex kPremonomorphicRootIndex = Heap::kNullValueRootIndex; // Load the cache state. __ Add(x4, x2, Operand::UntagSmiAndScale(x3, kPointerSizeLog2)); @@ -3288,44 +3283,43 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { // function without changing the state. __ Cmp(x4, x1); __ B(eq, &done); - __ JumpIfRoot(x4, kMegamorphicRootIndex, &done); - // Check if we're dealing with the Array function or not. - __ LoadArrayFunction(x5); - __ Cmp(x1, x5); - __ B(eq, &check_array); - - // Non-array cache: Check the cache state. - __ JumpIfRoot(x4, kPremonomorphicRootIndex, &initialize_non_array); - __ JumpIfNotRoot(x4, kUninitializedRootIndex, &megamorphic); + // If we came here, we need to see if we are the array function. + // If we didn't have a matching function, and we didn't find the megamorph + // sentinel, then we have in the slot either some other function or an + // AllocationSite. Do a map check on the object in ecx. + __ Ldr(x5, FieldMemOperand(x4, AllocationSite::kMapOffset)); + __ JumpIfNotRoot(x5, Heap::kAllocationSiteMapRootIndex, &miss); - // Non-array cache: Uninitialized -> premonomorphic. The sentinel is an - // immortal immovable object (null) so no write-barrier is needed. - __ Add(x4, x2, Operand::UntagSmiAndScale(x3, kPointerSizeLog2)); - __ LoadRoot(x10, kPremonomorphicRootIndex); - __ Str(x10, FieldMemOperand(x4, FixedArray::kHeaderSize)); + // Make sure the function is the Array() function + __ LoadArrayFunction(x4); + __ Cmp(x1, x4); + __ B(ne, &megamorphic); __ B(&done); - // Array cache: Check the cache state to see if we're in a monomorphic - // state where the state object is an AllocationSite object. - __ Bind(&check_array); - __ Ldr(x5, FieldMemOperand(x4, AllocationSite::kMapOffset)); - __ JumpIfRoot(x5, Heap::kAllocationSiteMapRootIndex, &done); - - // Array cache: Uninitialized or premonomorphic -> monomorphic. - __ JumpIfRoot(x4, kUninitializedRootIndex, &initialize_array); - __ JumpIfRoot(x4, kPremonomorphicRootIndex, &initialize_array); + __ Bind(&miss); - // Both caches: Monomorphic -> megamorphic. The sentinel is an - // immortal immovable object (undefined) so no write-barrier is needed. + // A monomorphic miss (i.e, here the cache is not uninitialized) goes + // megamorphic. + __ JumpIfRoot(x4, Heap::kTheHoleValueRootIndex, &initialize); + // MegamorphicSentinel is an immortal immovable object (undefined) so no + // write-barrier is needed. __ Bind(&megamorphic); __ Add(x4, x2, Operand::UntagSmiAndScale(x3, kPointerSizeLog2)); - __ LoadRoot(x10, kMegamorphicRootIndex); + __ LoadRoot(x10, Heap::kUndefinedValueRootIndex); __ Str(x10, FieldMemOperand(x4, FixedArray::kHeaderSize)); __ B(&done); - // Array cache: Uninitialized or premonomorphic -> monomorphic. - __ Bind(&initialize_array); + // An uninitialized cache is patched with the function or sentinel to + // indicate the ElementsKind if function is the Array constructor. + __ Bind(&initialize); + // Make sure the function is the Array() function + __ LoadArrayFunction(x4); + __ Cmp(x1, x4); + __ B(ne, ¬_array_function); + + // The target function is the Array constructor, + // Create an AllocationSite if we don't already have it, store it in the slot. { FrameScope scope(masm, StackFrame::INTERNAL); CreateAllocationSiteStub create_stub; @@ -3341,8 +3335,9 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { } __ B(&done); - // Non-array cache: Premonomorphic -> monomorphic. - __ Bind(&initialize_non_array); + __ Bind(¬_array_function); + // An uninitialized cache is patched with the function. + __ Add(x4, x2, Operand::UntagSmiAndScale(x3, kPointerSizeLog2)); // TODO(all): Does the value need to be left in x4? If not, FieldMemOperand // could be used to avoid this add. @@ -3355,6 +3350,7 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { __ Pop(x1, x2, x4); // TODO(all): Are x4, x2 and x1 outputs? This isn't clear. + __ Bind(&done); } diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index 501b5c7..b3a3acf 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -3012,17 +3012,12 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { // r1 : the function to call // r2 : Feedback vector // r3 : slot in feedback vector (Smi) - Label check_array, initialize_array, initialize_non_array, megamorphic, done; + Label initialize, done, miss, megamorphic, not_array_function; ASSERT_EQ(*TypeFeedbackInfo::MegamorphicSentinel(masm->isolate()), masm->isolate()->heap()->undefined_value()); - Heap::RootListIndex kMegamorphicRootIndex = Heap::kUndefinedValueRootIndex; ASSERT_EQ(*TypeFeedbackInfo::UninitializedSentinel(masm->isolate()), masm->isolate()->heap()->the_hole_value()); - Heap::RootListIndex kUninitializedRootIndex = Heap::kTheHoleValueRootIndex; - ASSERT_EQ(*TypeFeedbackInfo::PremonomorphicSentinel(masm->isolate()), - masm->isolate()->heap()->null_value()); - Heap::RootListIndex kPremonomorphicRootIndex = Heap::kNullValueRootIndex; // Load the cache state into r4. __ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3)); @@ -3032,50 +3027,45 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { // function without changing the state. __ cmp(r4, r1); __ b(eq, &done); - __ CompareRoot(r4, kMegamorphicRootIndex); - __ b(eq, &done); - // Check if we're dealing with the Array function or not. - __ LoadArrayFunction(r5); - __ cmp(r1, r5); - __ b(eq, &check_array); + // If we came here, we need to see if we are the array function. + // If we didn't have a matching function, and we didn't find the megamorph + // sentinel, then we have in the slot either some other function or an + // AllocationSite. Do a map check on the object in ecx. + __ ldr(r5, FieldMemOperand(r4, 0)); + __ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex); + __ b(ne, &miss); - // Non-array cache: Check the cache state. - __ CompareRoot(r4, kPremonomorphicRootIndex); - __ b(eq, &initialize_non_array); - __ CompareRoot(r4, kUninitializedRootIndex); + // Make sure the function is the Array() function + __ LoadArrayFunction(r4); + __ cmp(r1, r4); __ b(ne, &megamorphic); - - // Non-array cache: Uninitialized -> premonomorphic. The sentinel is an - // immortal immovable object (null) so no write-barrier is needed. - __ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3)); - __ LoadRoot(ip, kPremonomorphicRootIndex); - __ str(ip, FieldMemOperand(r4, FixedArray::kHeaderSize)); __ jmp(&done); - // Array cache: Check the cache state to see if we're in a monomorphic - // state where the state object is an AllocationSite object. - __ bind(&check_array); - __ ldr(r5, FieldMemOperand(r4, 0)); - __ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex); - __ b(eq, &done); - - // Array cache: Uninitialized or premonomorphic -> monomorphic. - __ CompareRoot(r4, kUninitializedRootIndex); - __ b(eq, &initialize_array); - __ CompareRoot(r4, kPremonomorphicRootIndex); - __ b(eq, &initialize_array); + __ bind(&miss); - // Both caches: Monomorphic -> megamorphic. The sentinel is an - // immortal immovable object (undefined) so no write-barrier is needed. + // A monomorphic miss (i.e, here the cache is not uninitialized) goes + // megamorphic. + __ CompareRoot(r4, Heap::kTheHoleValueRootIndex); + __ b(eq, &initialize); + // MegamorphicSentinel is an immortal immovable object (undefined) so no + // write-barrier is needed. __ bind(&megamorphic); __ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3)); - __ LoadRoot(ip, kMegamorphicRootIndex); + __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); __ str(ip, FieldMemOperand(r4, FixedArray::kHeaderSize)); __ jmp(&done); - // Array cache: Uninitialized or premonomorphic -> monomorphic. - __ bind(&initialize_array); + // An uninitialized cache is patched with the function or sentinel to + // indicate the ElementsKind if function is the Array constructor. + __ bind(&initialize); + // Make sure the function is the Array() function + __ LoadArrayFunction(r4); + __ cmp(r1, r4); + __ b(ne, ¬_array_function); + + // The target function is the Array constructor, + // Create an AllocationSite if we don't already have it, store it in the slot. { FrameScope scope(masm, StackFrame::INTERNAL); @@ -3091,8 +3081,8 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { } __ b(&done); - // Non-array cache: Premonomorphic -> monomorphic. - __ bind(&initialize_non_array); + __ bind(¬_array_function); + __ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3)); __ add(r4, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); __ str(r1, MemOperand(r4, 0)); diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index 22709e4..7882419 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -2330,7 +2330,7 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { // edx : slot in feedback vector (Smi) // edi : the function to call Isolate* isolate = masm->isolate(); - Label check_array, initialize_array, initialize_non_array, megamorphic, done; + Label initialize, done, miss, megamorphic, not_array_function; // Load the cache state into ecx. __ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size, @@ -2343,53 +2343,48 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { __ cmp(ecx, Immediate(TypeFeedbackInfo::MegamorphicSentinel(isolate))); __ j(equal, &done, Label::kFar); - // Load the global or builtins object from the current context and check - // if we're dealing with the Array function or not. + // If we came here, we need to see if we are the array function. + // If we didn't have a matching function, and we didn't find the megamorph + // sentinel, then we have in the slot either some other function or an + // AllocationSite. Do a map check on the object in ecx. + Handle allocation_site_map = + masm->isolate()->factory()->allocation_site_map(); + __ cmp(FieldOperand(ecx, 0), Immediate(allocation_site_map)); + __ j(not_equal, &miss); + + // Load the global or builtins object from the current context __ LoadGlobalContext(ecx); + // Make sure the function is the Array() function __ cmp(edi, Operand(ecx, Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX))); - __ j(equal, &check_array); - - // Non-array cache: Reload the cache state and check it. - __ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size, - FixedArray::kHeaderSize)); - __ cmp(ecx, Immediate(TypeFeedbackInfo::PremonomorphicSentinel(isolate))); - __ j(equal, &initialize_non_array); - __ cmp(ecx, Immediate(TypeFeedbackInfo::UninitializedSentinel(isolate))); __ j(not_equal, &megamorphic); - - // Non-array cache: Uninitialized -> premonomorphic. The sentinel is an - // immortal immovable object (null) so no write-barrier is needed. - __ mov(FieldOperand(ebx, edx, times_half_pointer_size, - FixedArray::kHeaderSize), - Immediate(TypeFeedbackInfo::PremonomorphicSentinel(isolate))); __ jmp(&done, Label::kFar); - // Array cache: Reload the cache state and check to see if we're in a - // monomorphic state where the state object is an AllocationSite object. - __ bind(&check_array); - __ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size, - FixedArray::kHeaderSize)); - Handle allocation_site_map = isolate->factory()->allocation_site_map(); - __ cmp(FieldOperand(ecx, 0), Immediate(allocation_site_map)); - __ j(equal, &done, Label::kFar); + __ bind(&miss); - // Array cache: Uninitialized or premonomorphic -> monomorphic. + // A monomorphic miss (i.e, here the cache is not uninitialized) goes + // megamorphic. __ cmp(ecx, Immediate(TypeFeedbackInfo::UninitializedSentinel(isolate))); - __ j(equal, &initialize_array); - __ cmp(ecx, Immediate(TypeFeedbackInfo::PremonomorphicSentinel(isolate))); - __ j(equal, &initialize_array); - - // Both caches: Monomorphic -> megamorphic. The sentinel is an - // immortal immovable object (undefined) so no write-barrier is needed. + __ j(equal, &initialize); + // MegamorphicSentinel is an immortal immovable object (undefined) so no + // write-barrier is needed. __ bind(&megamorphic); __ mov(FieldOperand(ebx, edx, times_half_pointer_size, FixedArray::kHeaderSize), Immediate(TypeFeedbackInfo::MegamorphicSentinel(isolate))); __ jmp(&done, Label::kFar); - // Array cache: Uninitialized or premonomorphic -> monomorphic. - __ bind(&initialize_array); + // An uninitialized cache is patched with the function or sentinel to + // indicate the ElementsKind if function is the Array constructor. + __ bind(&initialize); + __ LoadGlobalContext(ecx); + // Make sure the function is the Array() function + __ cmp(edi, Operand(ecx, + Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX))); + __ j(not_equal, ¬_array_function); + + // The target function is the Array constructor, + // Create an AllocationSite if we don't already have it, store it in the slot. { FrameScope scope(masm, StackFrame::INTERNAL); @@ -2411,11 +2406,11 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { } __ jmp(&done); - // Non-array cache: Premonomorphic -> monomorphic. - __ bind(&initialize_non_array); + __ bind(¬_array_function); __ mov(FieldOperand(ebx, edx, times_half_pointer_size, FixedArray::kHeaderSize), edi); + // We won't need edx or ebx anymore, just save edi __ push(edi); __ push(ebx); __ push(edx); diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc index e83447a..4b3107f 100644 --- a/src/mips/code-stubs-mips.cc +++ b/src/mips/code-stubs-mips.cc @@ -3159,17 +3159,12 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { // a1 : the function to call // a2 : Feedback vector // a3 : slot in feedback vector (Smi) - Label check_array, initialize_array, initialize_non_array, megamorphic, done; + Label initialize, done, miss, megamorphic, not_array_function; ASSERT_EQ(*TypeFeedbackInfo::MegamorphicSentinel(masm->isolate()), masm->isolate()->heap()->undefined_value()); - Heap::RootListIndex kMegamorphicRootIndex = Heap::kUndefinedValueRootIndex; ASSERT_EQ(*TypeFeedbackInfo::UninitializedSentinel(masm->isolate()), masm->isolate()->heap()->the_hole_value()); - Heap::RootListIndex kUninitializedRootIndex = Heap::kTheHoleValueRootIndex; - ASSERT_EQ(*TypeFeedbackInfo::PremonomorphicSentinel(masm->isolate()), - masm->isolate()->heap()->null_value()); - Heap::RootListIndex kPremonomorphicRootIndex = Heap::kNullValueRootIndex; // Load the cache state into t0. __ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize); @@ -3179,51 +3174,44 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { // A monomorphic cache hit or an already megamorphic state: invoke the // function without changing the state. __ Branch(&done, eq, t0, Operand(a1)); - __ LoadRoot(at, kMegamorphicRootIndex); - __ Branch(&done, eq, t0, Operand(at)); - - // Check if we're dealing with the Array function or not. - __ LoadArrayFunction(t1); - __ Branch(&check_array, eq, a1, Operand(t1)); - - // Non-array cache: Check the cache state. - __ LoadRoot(at, kPremonomorphicRootIndex); - __ Branch(&initialize_non_array, eq, t0, Operand(at)); - __ LoadRoot(at, kUninitializedRootIndex); - __ Branch(&megamorphic, ne, t0, Operand(at)); - - // Non-array cache: Uninitialized -> premonomorphic. The sentinel is an - // immortal immovable object (null) so no write-barrier is needed. - __ sll(at, a3, kPointerSizeLog2 - kSmiTagSize); - __ Addu(t0, a2, at); - __ LoadRoot(at, kPremonomorphicRootIndex); - __ Branch(USE_DELAY_SLOT, &done); - __ sw(at, FieldMemOperand(t0, FixedArray::kHeaderSize)); // In delay slot. - - // Array cache: Check the cache state to see if we're in a monomorphic - // state where the state object is an AllocationSite object. - __ bind(&check_array); + + // If we came here, we need to see if we are the array function. + // If we didn't have a matching function, and we didn't find the megamorph + // sentinel, then we have in the slot either some other function or an + // AllocationSite. Do a map check on the object in a3. __ lw(t1, FieldMemOperand(t0, 0)); __ LoadRoot(at, Heap::kAllocationSiteMapRootIndex); - __ Branch(&done, eq, t1, Operand(at)); + __ Branch(&miss, ne, t1, Operand(at)); + + // Make sure the function is the Array() function + __ LoadArrayFunction(t0); + __ Branch(&megamorphic, ne, a1, Operand(t0)); + __ jmp(&done); - // Array cache: Uninitialized or premonomorphic -> monomorphic. - __ LoadRoot(at, kUninitializedRootIndex); - __ Branch(&initialize_array, eq, t0, Operand(at)); - __ LoadRoot(at, kPremonomorphicRootIndex); - __ Branch(&initialize_array, eq, t0, Operand(at)); + __ bind(&miss); - // Both caches: Monomorphic -> megamorphic. The sentinel is an - // immortal immovable object (undefined) so no write-barrier is needed. + // A monomorphic miss (i.e, here the cache is not uninitialized) goes + // megamorphic. + __ LoadRoot(at, Heap::kTheHoleValueRootIndex); + __ Branch(&initialize, eq, t0, Operand(at)); + // MegamorphicSentinel is an immortal immovable object (undefined) so no + // write-barrier is needed. __ bind(&megamorphic); __ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize); __ Addu(t0, a2, Operand(t0)); - __ LoadRoot(at, kMegamorphicRootIndex); - __ Branch(USE_DELAY_SLOT, &done); - __ sw(at, FieldMemOperand(t0, FixedArray::kHeaderSize)); // In delay slot. - - // Array cache: Uninitialized or premonomorphic -> monomorphic. - __ bind(&initialize_array); + __ LoadRoot(at, Heap::kUndefinedValueRootIndex); + __ sw(at, FieldMemOperand(t0, FixedArray::kHeaderSize)); + __ jmp(&done); + + // An uninitialized cache is patched with the function or sentinel to + // indicate the ElementsKind if function is the Array constructor. + __ bind(&initialize); + // Make sure the function is the Array() function + __ LoadArrayFunction(t0); + __ Branch(¬_array_function, ne, a1, Operand(t0)); + + // The target function is the Array constructor. + // Create an AllocationSite if we don't already have it, store it in the slot. { FrameScope scope(masm, StackFrame::INTERNAL); const RegList kSavedRegs = @@ -3244,8 +3232,8 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { } __ Branch(&done); - // Non-array cache: Premonomorphic -> monomorphic. - __ bind(&initialize_non_array); + __ bind(¬_array_function); + __ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize); __ Addu(t0, a2, Operand(t0)); __ Addu(t0, t0, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); diff --git a/src/objects-inl.h b/src/objects-inl.h index ffec178..4f16806 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -6543,11 +6543,6 @@ Handle TypeFeedbackInfo::UninitializedSentinel(Isolate* isolate) { } -Handle TypeFeedbackInfo::PremonomorphicSentinel(Isolate* isolate) { - return isolate->factory()->null_value(); -} - - Handle TypeFeedbackInfo::MegamorphicSentinel(Isolate* isolate) { return isolate->factory()->undefined_value(); } diff --git a/src/objects.h b/src/objects.h index 88a6077..4a1b328 100644 --- a/src/objects.h +++ b/src/objects.h @@ -8177,9 +8177,6 @@ class TypeFeedbackInfo: public Struct { // The object that indicates an uninitialized cache. static inline Handle UninitializedSentinel(Isolate* isolate); - // The object that indicates a cache in pre-monomorphic state. - static inline Handle PremonomorphicSentinel(Isolate* isolate); - // The object that indicates a megamorphic state. static inline Handle MegamorphicSentinel(Isolate* isolate); diff --git a/src/runtime.cc b/src/runtime.cc index 3b56d32..7eaf5a7 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -14841,7 +14841,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConstructor) { Handle site; if (!type_info.is_null() && - *type_info != isolate->heap()->null_value() && *type_info != isolate->heap()->undefined_value()) { site = Handle::cast(type_info); ASSERT(!site->SitePointsToLiteral()); diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 92af1f0..8c5a430 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -2169,7 +2169,8 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { // rdx : slot in feedback vector (Smi) // rdi : the function to call Isolate* isolate = masm->isolate(); - Label check_array, initialize_array, initialize_non_array, megamorphic, done; + Label initialize, done, miss, megamorphic, not_array_function, + done_no_smi_convert; // Load the cache state into rcx. __ SmiToInteger32(rdx, rdx); @@ -2183,49 +2184,44 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { __ Cmp(rcx, TypeFeedbackInfo::MegamorphicSentinel(isolate)); __ j(equal, &done); - // Check if we're dealing with the Array function or not. + // If we came here, we need to see if we are the array function. + // If we didn't have a matching function, and we didn't find the megamorph + // sentinel, then we have in the slot either some other function or an + // AllocationSite. Do a map check on the object in rcx. + Handle allocation_site_map = + masm->isolate()->factory()->allocation_site_map(); + __ Cmp(FieldOperand(rcx, 0), allocation_site_map); + __ j(not_equal, &miss); + + // Make sure the function is the Array() function __ LoadArrayFunction(rcx); __ cmpq(rdi, rcx); - __ j(equal, &check_array); - - // Non-array cache: Reload the cache state and check it. - __ movp(rcx, FieldOperand(rbx, rdx, times_pointer_size, - FixedArray::kHeaderSize)); - __ Cmp(rcx, TypeFeedbackInfo::PremonomorphicSentinel(isolate)); - __ j(equal, &initialize_non_array); - __ Cmp(rcx, TypeFeedbackInfo::UninitializedSentinel(isolate)); __ j(not_equal, &megamorphic); + __ jmp(&done); - // Non-array cache: Uninitialized -> premonomorphic. The sentinel is an - // immortal immovable object (null) so no write-barrier is needed. - __ Move(FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize), - TypeFeedbackInfo::PremonomorphicSentinel(isolate)); - __ jmp(&done, Label::kFar); - - // Array cache: Reload the cache state and check to see if we're in a - // monomorphic state where the state object is an AllocationSite object. - __ bind(&check_array); - __ movp(rcx, FieldOperand(rbx, rdx, times_pointer_size, - FixedArray::kHeaderSize)); - Handle allocation_site_map = isolate->factory()->allocation_site_map(); - __ Cmp(FieldOperand(rcx, 0), allocation_site_map); - __ j(equal, &done); + __ bind(&miss); - // Array cache: Uninitialized or premonomorphic -> monomorphic. + // A monomorphic miss (i.e, here the cache is not uninitialized) goes + // megamorphic. __ Cmp(rcx, TypeFeedbackInfo::UninitializedSentinel(isolate)); - __ j(equal, &initialize_array); - __ Cmp(rcx, TypeFeedbackInfo::PremonomorphicSentinel(isolate)); - __ j(equal, &initialize_array); - - // Both caches: Monomorphic -> megamorphic. The sentinel is an - // immortal immovable object (undefined) so no write-barrier is needed. + __ j(equal, &initialize); + // MegamorphicSentinel is an immortal immovable object (undefined) so no + // write-barrier is needed. __ bind(&megamorphic); __ Move(FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize), TypeFeedbackInfo::MegamorphicSentinel(isolate)); __ jmp(&done); - // Array cache: Uninitialized or premonomorphic -> monomorphic. - __ bind(&initialize_array); + // An uninitialized cache is patched with the function or sentinel to + // indicate the ElementsKind if function is the Array constructor. + __ bind(&initialize); + // Make sure the function is the Array() function + __ LoadArrayFunction(rcx); + __ cmpq(rdi, rcx); + __ j(not_equal, ¬_array_function); + + // The target function is the Array constructor, + // Create an AllocationSite if we don't already have it, store it in the slot. { FrameScope scope(masm, StackFrame::INTERNAL); @@ -2246,13 +2242,13 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { __ pop(rax); __ SmiToInteger32(rax, rax); } - Label done_no_smi_convert; __ jmp(&done_no_smi_convert); - // Non-array cache: Premonomorphic -> monomorphic. - __ bind(&initialize_non_array); + __ bind(¬_array_function); __ movp(FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize), rdi); + + // We won't need rdx or rbx anymore, just save rdi __ push(rdi); __ push(rbx); __ push(rdx); diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc index 0efbbfd..f8757e1 100644 --- a/test/cctest/test-heap.cc +++ b/test/cctest/test-heap.cc @@ -2848,9 +2848,7 @@ TEST(IncrementalMarkingClearsTypeFeedbackInfo) { // originating from two different native contexts. CcTest::global()->Set(v8_str("fun1"), fun1); CcTest::global()->Set(v8_str("fun2"), fun2); - CompileRun("function f(a, b) { a(); b(); }" - "f(fun1, fun2);" // Run twice to skip premonomorphic state. - "f(fun1, fun2)"); + CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);"); Handle f = v8::Utils::OpenHandle(