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
This commit is contained in:
parent
139134acc2
commit
73b679cbee
@ -3268,17 +3268,12 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
|
|||||||
// x1 : the function to call
|
// x1 : the function to call
|
||||||
// x2 : feedback vector
|
// x2 : feedback vector
|
||||||
// x3 : slot in feedback vector (smi)
|
// 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()),
|
ASSERT_EQ(*TypeFeedbackInfo::MegamorphicSentinel(masm->isolate()),
|
||||||
masm->isolate()->heap()->undefined_value());
|
masm->isolate()->heap()->undefined_value());
|
||||||
Heap::RootListIndex kMegamorphicRootIndex = Heap::kUndefinedValueRootIndex;
|
|
||||||
ASSERT_EQ(*TypeFeedbackInfo::UninitializedSentinel(masm->isolate()),
|
ASSERT_EQ(*TypeFeedbackInfo::UninitializedSentinel(masm->isolate()),
|
||||||
masm->isolate()->heap()->the_hole_value());
|
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.
|
// Load the cache state.
|
||||||
__ Add(x4, x2, Operand::UntagSmiAndScale(x3, kPointerSizeLog2));
|
__ Add(x4, x2, Operand::UntagSmiAndScale(x3, kPointerSizeLog2));
|
||||||
@ -3288,44 +3283,43 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
|
|||||||
// function without changing the state.
|
// function without changing the state.
|
||||||
__ Cmp(x4, x1);
|
__ Cmp(x4, x1);
|
||||||
__ B(eq, &done);
|
__ B(eq, &done);
|
||||||
__ JumpIfRoot(x4, kMegamorphicRootIndex, &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.
|
||||||
__ LoadArrayFunction(x5);
|
// If we didn't have a matching function, and we didn't find the megamorph
|
||||||
__ Cmp(x1, x5);
|
// sentinel, then we have in the slot either some other function or an
|
||||||
__ B(eq, &check_array);
|
// AllocationSite. Do a map check on the object in ecx.
|
||||||
|
__ Ldr(x5, FieldMemOperand(x4, AllocationSite::kMapOffset));
|
||||||
|
__ JumpIfNotRoot(x5, Heap::kAllocationSiteMapRootIndex, &miss);
|
||||||
|
|
||||||
// Non-array cache: Check the cache state.
|
// Make sure the function is the Array() function
|
||||||
__ JumpIfRoot(x4, kPremonomorphicRootIndex, &initialize_non_array);
|
__ LoadArrayFunction(x4);
|
||||||
__ JumpIfNotRoot(x4, kUninitializedRootIndex, &megamorphic);
|
__ Cmp(x1, x4);
|
||||||
|
__ B(ne, &megamorphic);
|
||||||
// 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));
|
|
||||||
__ B(&done);
|
__ B(&done);
|
||||||
|
|
||||||
// Array cache: Check the cache state to see if we're in a monomorphic
|
__ Bind(&miss);
|
||||||
// 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.
|
// A monomorphic miss (i.e, here the cache is not uninitialized) goes
|
||||||
__ JumpIfRoot(x4, kUninitializedRootIndex, &initialize_array);
|
// megamorphic.
|
||||||
__ JumpIfRoot(x4, kPremonomorphicRootIndex, &initialize_array);
|
__ JumpIfRoot(x4, Heap::kTheHoleValueRootIndex, &initialize);
|
||||||
|
// MegamorphicSentinel is an immortal immovable object (undefined) so no
|
||||||
// Both caches: Monomorphic -> megamorphic. The sentinel is an
|
// write-barrier is needed.
|
||||||
// immortal immovable object (undefined) so no write-barrier is needed.
|
|
||||||
__ Bind(&megamorphic);
|
__ Bind(&megamorphic);
|
||||||
__ Add(x4, x2, Operand::UntagSmiAndScale(x3, kPointerSizeLog2));
|
__ Add(x4, x2, Operand::UntagSmiAndScale(x3, kPointerSizeLog2));
|
||||||
__ LoadRoot(x10, kMegamorphicRootIndex);
|
__ LoadRoot(x10, Heap::kUndefinedValueRootIndex);
|
||||||
__ Str(x10, FieldMemOperand(x4, FixedArray::kHeaderSize));
|
__ Str(x10, FieldMemOperand(x4, FixedArray::kHeaderSize));
|
||||||
__ B(&done);
|
__ B(&done);
|
||||||
|
|
||||||
// Array cache: Uninitialized or premonomorphic -> monomorphic.
|
// An uninitialized cache is patched with the function or sentinel to
|
||||||
__ Bind(&initialize_array);
|
// 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);
|
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||||
CreateAllocationSiteStub create_stub;
|
CreateAllocationSiteStub create_stub;
|
||||||
@ -3341,8 +3335,9 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
__ B(&done);
|
__ B(&done);
|
||||||
|
|
||||||
// Non-array cache: Premonomorphic -> monomorphic.
|
__ Bind(¬_array_function);
|
||||||
__ Bind(&initialize_non_array);
|
// An uninitialized cache is patched with the function.
|
||||||
|
|
||||||
__ Add(x4, x2, Operand::UntagSmiAndScale(x3, kPointerSizeLog2));
|
__ Add(x4, x2, Operand::UntagSmiAndScale(x3, kPointerSizeLog2));
|
||||||
// TODO(all): Does the value need to be left in x4? If not, FieldMemOperand
|
// TODO(all): Does the value need to be left in x4? If not, FieldMemOperand
|
||||||
// could be used to avoid this add.
|
// could be used to avoid this add.
|
||||||
@ -3355,6 +3350,7 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
|
|||||||
__ Pop(x1, x2, x4);
|
__ Pop(x1, x2, x4);
|
||||||
|
|
||||||
// TODO(all): Are x4, x2 and x1 outputs? This isn't clear.
|
// TODO(all): Are x4, x2 and x1 outputs? This isn't clear.
|
||||||
|
|
||||||
__ Bind(&done);
|
__ Bind(&done);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3012,17 +3012,12 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
|
|||||||
// r1 : the function to call
|
// r1 : the function to call
|
||||||
// r2 : Feedback vector
|
// r2 : Feedback vector
|
||||||
// r3 : slot in feedback vector (Smi)
|
// 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()),
|
ASSERT_EQ(*TypeFeedbackInfo::MegamorphicSentinel(masm->isolate()),
|
||||||
masm->isolate()->heap()->undefined_value());
|
masm->isolate()->heap()->undefined_value());
|
||||||
Heap::RootListIndex kMegamorphicRootIndex = Heap::kUndefinedValueRootIndex;
|
|
||||||
ASSERT_EQ(*TypeFeedbackInfo::UninitializedSentinel(masm->isolate()),
|
ASSERT_EQ(*TypeFeedbackInfo::UninitializedSentinel(masm->isolate()),
|
||||||
masm->isolate()->heap()->the_hole_value());
|
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.
|
// Load the cache state into r4.
|
||||||
__ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
|
__ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
|
||||||
@ -3032,50 +3027,45 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
|
|||||||
// function without changing the state.
|
// function without changing the state.
|
||||||
__ cmp(r4, r1);
|
__ cmp(r4, r1);
|
||||||
__ b(eq, &done);
|
__ b(eq, &done);
|
||||||
__ CompareRoot(r4, kMegamorphicRootIndex);
|
|
||||||
__ b(eq, &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.
|
||||||
__ LoadArrayFunction(r5);
|
// If we didn't have a matching function, and we didn't find the megamorph
|
||||||
__ cmp(r1, r5);
|
// sentinel, then we have in the slot either some other function or an
|
||||||
__ b(eq, &check_array);
|
// AllocationSite. Do a map check on the object in ecx.
|
||||||
|
|
||||||
// Non-array cache: Check the cache state.
|
|
||||||
__ CompareRoot(r4, kPremonomorphicRootIndex);
|
|
||||||
__ b(eq, &initialize_non_array);
|
|
||||||
__ CompareRoot(r4, kUninitializedRootIndex);
|
|
||||||
__ 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));
|
__ ldr(r5, FieldMemOperand(r4, 0));
|
||||||
__ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex);
|
__ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex);
|
||||||
__ b(eq, &done);
|
__ b(ne, &miss);
|
||||||
|
|
||||||
// Array cache: Uninitialized or premonomorphic -> monomorphic.
|
// Make sure the function is the Array() function
|
||||||
__ CompareRoot(r4, kUninitializedRootIndex);
|
__ LoadArrayFunction(r4);
|
||||||
__ b(eq, &initialize_array);
|
__ cmp(r1, r4);
|
||||||
__ CompareRoot(r4, kPremonomorphicRootIndex);
|
__ b(ne, &megamorphic);
|
||||||
__ b(eq, &initialize_array);
|
__ jmp(&done);
|
||||||
|
|
||||||
// Both caches: Monomorphic -> megamorphic. The sentinel is an
|
__ bind(&miss);
|
||||||
// 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);
|
__ bind(&megamorphic);
|
||||||
__ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
|
__ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
|
||||||
__ LoadRoot(ip, kMegamorphicRootIndex);
|
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
|
||||||
__ str(ip, FieldMemOperand(r4, FixedArray::kHeaderSize));
|
__ str(ip, FieldMemOperand(r4, FixedArray::kHeaderSize));
|
||||||
__ jmp(&done);
|
__ jmp(&done);
|
||||||
|
|
||||||
// Array cache: Uninitialized or premonomorphic -> monomorphic.
|
// An uninitialized cache is patched with the function or sentinel to
|
||||||
__ bind(&initialize_array);
|
// 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);
|
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||||
|
|
||||||
@ -3091,8 +3081,8 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
__ b(&done);
|
__ b(&done);
|
||||||
|
|
||||||
// Non-array cache: Premonomorphic -> monomorphic.
|
__ bind(¬_array_function);
|
||||||
__ bind(&initialize_non_array);
|
|
||||||
__ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
|
__ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
|
||||||
__ add(r4, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
|
__ add(r4, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
|
||||||
__ str(r1, MemOperand(r4, 0));
|
__ str(r1, MemOperand(r4, 0));
|
||||||
|
@ -2330,7 +2330,7 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
|
|||||||
// edx : slot in feedback vector (Smi)
|
// edx : slot in feedback vector (Smi)
|
||||||
// edi : the function to call
|
// edi : the function to call
|
||||||
Isolate* isolate = masm->isolate();
|
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.
|
// Load the cache state into ecx.
|
||||||
__ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size,
|
__ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size,
|
||||||
@ -2343,53 +2343,48 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
|
|||||||
__ cmp(ecx, Immediate(TypeFeedbackInfo::MegamorphicSentinel(isolate)));
|
__ cmp(ecx, Immediate(TypeFeedbackInfo::MegamorphicSentinel(isolate)));
|
||||||
__ j(equal, &done, Label::kFar);
|
__ j(equal, &done, Label::kFar);
|
||||||
|
|
||||||
// Load the global or builtins object from the current context and check
|
// If we came here, we need to see if we are the array function.
|
||||||
// if we're dealing with the Array function or not.
|
// 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<Map> 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);
|
__ LoadGlobalContext(ecx);
|
||||||
|
// Make sure the function is the Array() function
|
||||||
__ cmp(edi, Operand(ecx,
|
__ cmp(edi, Operand(ecx,
|
||||||
Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
|
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);
|
__ 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);
|
__ jmp(&done, Label::kFar);
|
||||||
|
|
||||||
// Array cache: Reload the cache state and check to see if we're in a
|
__ bind(&miss);
|
||||||
// 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<Map> allocation_site_map = isolate->factory()->allocation_site_map();
|
|
||||||
__ cmp(FieldOperand(ecx, 0), Immediate(allocation_site_map));
|
|
||||||
__ j(equal, &done, Label::kFar);
|
|
||||||
|
|
||||||
// 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)));
|
__ cmp(ecx, Immediate(TypeFeedbackInfo::UninitializedSentinel(isolate)));
|
||||||
__ j(equal, &initialize_array);
|
__ j(equal, &initialize);
|
||||||
__ cmp(ecx, Immediate(TypeFeedbackInfo::PremonomorphicSentinel(isolate)));
|
// MegamorphicSentinel is an immortal immovable object (undefined) so no
|
||||||
__ j(equal, &initialize_array);
|
// write-barrier is needed.
|
||||||
|
|
||||||
// Both caches: Monomorphic -> megamorphic. The sentinel is an
|
|
||||||
// immortal immovable object (undefined) so no write-barrier is needed.
|
|
||||||
__ bind(&megamorphic);
|
__ bind(&megamorphic);
|
||||||
__ mov(FieldOperand(ebx, edx, times_half_pointer_size,
|
__ mov(FieldOperand(ebx, edx, times_half_pointer_size,
|
||||||
FixedArray::kHeaderSize),
|
FixedArray::kHeaderSize),
|
||||||
Immediate(TypeFeedbackInfo::MegamorphicSentinel(isolate)));
|
Immediate(TypeFeedbackInfo::MegamorphicSentinel(isolate)));
|
||||||
__ jmp(&done, Label::kFar);
|
__ jmp(&done, Label::kFar);
|
||||||
|
|
||||||
// Array cache: Uninitialized or premonomorphic -> monomorphic.
|
// An uninitialized cache is patched with the function or sentinel to
|
||||||
__ bind(&initialize_array);
|
// 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);
|
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||||
|
|
||||||
@ -2411,11 +2406,11 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
__ jmp(&done);
|
__ jmp(&done);
|
||||||
|
|
||||||
// Non-array cache: Premonomorphic -> monomorphic.
|
__ bind(¬_array_function);
|
||||||
__ bind(&initialize_non_array);
|
|
||||||
__ mov(FieldOperand(ebx, edx, times_half_pointer_size,
|
__ mov(FieldOperand(ebx, edx, times_half_pointer_size,
|
||||||
FixedArray::kHeaderSize),
|
FixedArray::kHeaderSize),
|
||||||
edi);
|
edi);
|
||||||
|
// We won't need edx or ebx anymore, just save edi
|
||||||
__ push(edi);
|
__ push(edi);
|
||||||
__ push(ebx);
|
__ push(ebx);
|
||||||
__ push(edx);
|
__ push(edx);
|
||||||
|
@ -3159,17 +3159,12 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
|
|||||||
// a1 : the function to call
|
// a1 : the function to call
|
||||||
// a2 : Feedback vector
|
// a2 : Feedback vector
|
||||||
// a3 : slot in feedback vector (Smi)
|
// 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()),
|
ASSERT_EQ(*TypeFeedbackInfo::MegamorphicSentinel(masm->isolate()),
|
||||||
masm->isolate()->heap()->undefined_value());
|
masm->isolate()->heap()->undefined_value());
|
||||||
Heap::RootListIndex kMegamorphicRootIndex = Heap::kUndefinedValueRootIndex;
|
|
||||||
ASSERT_EQ(*TypeFeedbackInfo::UninitializedSentinel(masm->isolate()),
|
ASSERT_EQ(*TypeFeedbackInfo::UninitializedSentinel(masm->isolate()),
|
||||||
masm->isolate()->heap()->the_hole_value());
|
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.
|
// Load the cache state into t0.
|
||||||
__ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize);
|
__ 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
|
// A monomorphic cache hit or an already megamorphic state: invoke the
|
||||||
// function without changing the state.
|
// function without changing the state.
|
||||||
__ Branch(&done, eq, t0, Operand(a1));
|
__ 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.
|
// If we came here, we need to see if we are the array function.
|
||||||
__ LoadArrayFunction(t1);
|
// If we didn't have a matching function, and we didn't find the megamorph
|
||||||
__ Branch(&check_array, eq, a1, Operand(t1));
|
// sentinel, then we have in the slot either some other function or an
|
||||||
|
// AllocationSite. Do a map check on the object in a3.
|
||||||
// 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);
|
|
||||||
__ lw(t1, FieldMemOperand(t0, 0));
|
__ lw(t1, FieldMemOperand(t0, 0));
|
||||||
__ LoadRoot(at, Heap::kAllocationSiteMapRootIndex);
|
__ LoadRoot(at, Heap::kAllocationSiteMapRootIndex);
|
||||||
__ Branch(&done, eq, t1, Operand(at));
|
__ Branch(&miss, ne, t1, Operand(at));
|
||||||
|
|
||||||
// Array cache: Uninitialized or premonomorphic -> monomorphic.
|
// Make sure the function is the Array() function
|
||||||
__ LoadRoot(at, kUninitializedRootIndex);
|
__ LoadArrayFunction(t0);
|
||||||
__ Branch(&initialize_array, eq, t0, Operand(at));
|
__ Branch(&megamorphic, ne, a1, Operand(t0));
|
||||||
__ LoadRoot(at, kPremonomorphicRootIndex);
|
__ jmp(&done);
|
||||||
__ Branch(&initialize_array, eq, t0, Operand(at));
|
|
||||||
|
|
||||||
// Both caches: Monomorphic -> megamorphic. The sentinel is an
|
__ bind(&miss);
|
||||||
// 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);
|
__ bind(&megamorphic);
|
||||||
__ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize);
|
__ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize);
|
||||||
__ Addu(t0, a2, Operand(t0));
|
__ Addu(t0, a2, Operand(t0));
|
||||||
__ LoadRoot(at, kMegamorphicRootIndex);
|
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
|
||||||
__ Branch(USE_DELAY_SLOT, &done);
|
__ sw(at, FieldMemOperand(t0, FixedArray::kHeaderSize));
|
||||||
__ sw(at, FieldMemOperand(t0, FixedArray::kHeaderSize)); // In delay slot.
|
__ jmp(&done);
|
||||||
|
|
||||||
// Array cache: Uninitialized or premonomorphic -> monomorphic.
|
// An uninitialized cache is patched with the function or sentinel to
|
||||||
__ bind(&initialize_array);
|
// 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);
|
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||||
const RegList kSavedRegs =
|
const RegList kSavedRegs =
|
||||||
@ -3244,8 +3232,8 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
__ Branch(&done);
|
__ Branch(&done);
|
||||||
|
|
||||||
// Non-array cache: Premonomorphic -> monomorphic.
|
__ bind(¬_array_function);
|
||||||
__ bind(&initialize_non_array);
|
|
||||||
__ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize);
|
__ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize);
|
||||||
__ Addu(t0, a2, Operand(t0));
|
__ Addu(t0, a2, Operand(t0));
|
||||||
__ Addu(t0, t0, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
|
__ Addu(t0, t0, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
|
||||||
|
@ -6543,11 +6543,6 @@ Handle<Object> TypeFeedbackInfo::UninitializedSentinel(Isolate* isolate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Handle<Object> TypeFeedbackInfo::PremonomorphicSentinel(Isolate* isolate) {
|
|
||||||
return isolate->factory()->null_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Handle<Object> TypeFeedbackInfo::MegamorphicSentinel(Isolate* isolate) {
|
Handle<Object> TypeFeedbackInfo::MegamorphicSentinel(Isolate* isolate) {
|
||||||
return isolate->factory()->undefined_value();
|
return isolate->factory()->undefined_value();
|
||||||
}
|
}
|
||||||
|
@ -8177,9 +8177,6 @@ class TypeFeedbackInfo: public Struct {
|
|||||||
// The object that indicates an uninitialized cache.
|
// The object that indicates an uninitialized cache.
|
||||||
static inline Handle<Object> UninitializedSentinel(Isolate* isolate);
|
static inline Handle<Object> UninitializedSentinel(Isolate* isolate);
|
||||||
|
|
||||||
// The object that indicates a cache in pre-monomorphic state.
|
|
||||||
static inline Handle<Object> PremonomorphicSentinel(Isolate* isolate);
|
|
||||||
|
|
||||||
// The object that indicates a megamorphic state.
|
// The object that indicates a megamorphic state.
|
||||||
static inline Handle<Object> MegamorphicSentinel(Isolate* isolate);
|
static inline Handle<Object> MegamorphicSentinel(Isolate* isolate);
|
||||||
|
|
||||||
|
@ -14841,7 +14841,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConstructor) {
|
|||||||
|
|
||||||
Handle<AllocationSite> site;
|
Handle<AllocationSite> site;
|
||||||
if (!type_info.is_null() &&
|
if (!type_info.is_null() &&
|
||||||
*type_info != isolate->heap()->null_value() &&
|
|
||||||
*type_info != isolate->heap()->undefined_value()) {
|
*type_info != isolate->heap()->undefined_value()) {
|
||||||
site = Handle<AllocationSite>::cast(type_info);
|
site = Handle<AllocationSite>::cast(type_info);
|
||||||
ASSERT(!site->SitePointsToLiteral());
|
ASSERT(!site->SitePointsToLiteral());
|
||||||
|
@ -2169,7 +2169,8 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
|
|||||||
// rdx : slot in feedback vector (Smi)
|
// rdx : slot in feedback vector (Smi)
|
||||||
// rdi : the function to call
|
// rdi : the function to call
|
||||||
Isolate* isolate = masm->isolate();
|
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.
|
// Load the cache state into rcx.
|
||||||
__ SmiToInteger32(rdx, rdx);
|
__ SmiToInteger32(rdx, rdx);
|
||||||
@ -2183,49 +2184,44 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
|
|||||||
__ Cmp(rcx, TypeFeedbackInfo::MegamorphicSentinel(isolate));
|
__ Cmp(rcx, TypeFeedbackInfo::MegamorphicSentinel(isolate));
|
||||||
__ j(equal, &done);
|
__ 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<Map> 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);
|
__ LoadArrayFunction(rcx);
|
||||||
__ cmpq(rdi, 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);
|
__ j(not_equal, &megamorphic);
|
||||||
|
__ jmp(&done);
|
||||||
|
|
||||||
// Non-array cache: Uninitialized -> premonomorphic. The sentinel is an
|
__ bind(&miss);
|
||||||
// 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
|
// A monomorphic miss (i.e, here the cache is not uninitialized) goes
|
||||||
// monomorphic state where the state object is an AllocationSite object.
|
// megamorphic.
|
||||||
__ bind(&check_array);
|
|
||||||
__ movp(rcx, FieldOperand(rbx, rdx, times_pointer_size,
|
|
||||||
FixedArray::kHeaderSize));
|
|
||||||
Handle<Map> allocation_site_map = isolate->factory()->allocation_site_map();
|
|
||||||
__ Cmp(FieldOperand(rcx, 0), allocation_site_map);
|
|
||||||
__ j(equal, &done);
|
|
||||||
|
|
||||||
// Array cache: Uninitialized or premonomorphic -> monomorphic.
|
|
||||||
__ Cmp(rcx, TypeFeedbackInfo::UninitializedSentinel(isolate));
|
__ Cmp(rcx, TypeFeedbackInfo::UninitializedSentinel(isolate));
|
||||||
__ j(equal, &initialize_array);
|
__ j(equal, &initialize);
|
||||||
__ Cmp(rcx, TypeFeedbackInfo::PremonomorphicSentinel(isolate));
|
// MegamorphicSentinel is an immortal immovable object (undefined) so no
|
||||||
__ j(equal, &initialize_array);
|
// write-barrier is needed.
|
||||||
|
|
||||||
// Both caches: Monomorphic -> megamorphic. The sentinel is an
|
|
||||||
// immortal immovable object (undefined) so no write-barrier is needed.
|
|
||||||
__ bind(&megamorphic);
|
__ bind(&megamorphic);
|
||||||
__ Move(FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize),
|
__ Move(FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize),
|
||||||
TypeFeedbackInfo::MegamorphicSentinel(isolate));
|
TypeFeedbackInfo::MegamorphicSentinel(isolate));
|
||||||
__ jmp(&done);
|
__ jmp(&done);
|
||||||
|
|
||||||
// Array cache: Uninitialized or premonomorphic -> monomorphic.
|
// An uninitialized cache is patched with the function or sentinel to
|
||||||
__ bind(&initialize_array);
|
// 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);
|
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||||
|
|
||||||
@ -2246,13 +2242,13 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
|
|||||||
__ pop(rax);
|
__ pop(rax);
|
||||||
__ SmiToInteger32(rax, rax);
|
__ SmiToInteger32(rax, rax);
|
||||||
}
|
}
|
||||||
Label done_no_smi_convert;
|
|
||||||
__ jmp(&done_no_smi_convert);
|
__ jmp(&done_no_smi_convert);
|
||||||
|
|
||||||
// Non-array cache: Premonomorphic -> monomorphic.
|
__ bind(¬_array_function);
|
||||||
__ bind(&initialize_non_array);
|
|
||||||
__ movp(FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize),
|
__ movp(FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize),
|
||||||
rdi);
|
rdi);
|
||||||
|
|
||||||
|
// We won't need rdx or rbx anymore, just save rdi
|
||||||
__ push(rdi);
|
__ push(rdi);
|
||||||
__ push(rbx);
|
__ push(rbx);
|
||||||
__ push(rdx);
|
__ push(rdx);
|
||||||
|
@ -2848,9 +2848,7 @@ TEST(IncrementalMarkingClearsTypeFeedbackInfo) {
|
|||||||
// originating from two different native contexts.
|
// originating from two different native contexts.
|
||||||
CcTest::global()->Set(v8_str("fun1"), fun1);
|
CcTest::global()->Set(v8_str("fun1"), fun1);
|
||||||
CcTest::global()->Set(v8_str("fun2"), fun2);
|
CcTest::global()->Set(v8_str("fun2"), fun2);
|
||||||
CompileRun("function f(a, b) { a(); b(); }"
|
CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);");
|
||||||
"f(fun1, fun2);" // Run twice to skip premonomorphic state.
|
|
||||||
"f(fun1, fun2)");
|
|
||||||
|
|
||||||
Handle<JSFunction> f =
|
Handle<JSFunction> f =
|
||||||
v8::Utils::OpenHandle(
|
v8::Utils::OpenHandle(
|
||||||
|
Loading…
Reference in New Issue
Block a user