Index: src/ia32/code-stubs-ia32.cc |
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc |
index 3b6987e6f4f0b195a44439e4a92c136e1ee49432..3db541aeee12c2524435dbc04ca135f139828017 100644 |
--- a/src/ia32/code-stubs-ia32.cc |
+++ b/src/ia32/code-stubs-ia32.cc |
@@ -319,12 +319,18 @@ static void GenerateFastCloneShallowArrayCommon( |
// All sizes here are multiples of kPointerSize. |
int elements_size = 0; |
+ int allocation_site_info_size = 0; |
if (length > 0) { |
elements_size = mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS |
? FixedDoubleArray::SizeFor(length) |
: FixedArray::SizeFor(length); |
+ } else { |
+ // Empty or COW arrays need to track type information to adjust the |
+ // boilerplate ElementsKind on subsequent stores. |
+ allocation_site_info_size = AllocationSiteInfo::kSize; |
} |
- int size = JSArray::kSize + elements_size; |
+ int allocation_offset = JSArray::kSize + elements_size; |
+ int size = allocation_offset + allocation_site_info_size; |
// Allocate both the JS array and the elements array in one big |
// allocation. This avoids multiple limit checks. |
@@ -365,6 +371,12 @@ static void GenerateFastCloneShallowArrayCommon( |
} |
ASSERT(i == elements_size); |
} |
+ } else { |
+ // Track information about the allocation site |
+ __ mov(FieldOperand(eax, allocation_offset), |
+ Immediate(Handle<Map>(masm->isolate()->heap()-> |
+ allocation_site_info_map()))); |
+ __ mov(FieldOperand(eax, allocation_offset + kPointerSize), ecx); |
} |
} |
@@ -4683,7 +4695,7 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { |
// ebx : cache cell for call target |
// edi : the function to call |
Isolate* isolate = masm->isolate(); |
- Label initialize, done; |
+ Label initialize, done, miss, megamorphic, not_array_function; |
// Load the cache state into ecx. |
__ mov(ecx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset)); |
@@ -4691,22 +4703,86 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { |
// A monomorphic cache hit or an already megamorphic state: invoke the |
// function without changing the state. |
__ cmp(ecx, edi); |
- __ j(equal, &done, Label::kNear); |
+ __ j(equal, &done, Label::kFar); |
__ cmp(ecx, Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate))); |
- __ j(equal, &done, Label::kNear); |
+ __ j(equal, &done, Label::kFar); |
+ |
+ // Special handling of the Array() function, which caches not only the |
+ // monomorphic Array function but the initial ElementsKind with special |
+ // sentinels. |
+ Handle<Object> terminal_kind_sentinel = |
+ TypeFeedbackCells::MonomorphicArraySentinel( |
+ LAST_FAST_ELEMENTS_KIND); |
+ __ cmp(ecx, Immediate(terminal_kind_sentinel)); |
+ __ j(above, &miss, Label::kFar); |
+ // Load the global or builtins object from the current context. |
+ __ mov(ecx, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); |
+ __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalContextOffset)); |
+ // Make sure the function is the Array() function. |
+ __ cmp(edi, Operand(ecx, |
+ Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX))); |
+ Label megamorphic_pre; |
+ __ j(not_equal, &megamorphic_pre, Label::kFar); |
+ __ jmp(&done); |
+ |
+ __ bind(&megamorphic_pre); |
+ __ jmp(&megamorphic, Label::kFar); |
+ __ bind(&miss); |
// A monomorphic miss (i.e, here the cache is not uninitialized) goes |
// megamorphic. |
__ cmp(ecx, Immediate(TypeFeedbackCells::UninitializedSentinel(isolate))); |
- __ j(equal, &initialize, Label::kNear); |
+ __ j(equal, &initialize, Label::kFar); |
// MegamorphicSentinel is an immortal immovable object (undefined) so no |
// write-barrier is needed. |
+ __ bind(&megamorphic); |
+ |
+ __ push(eax); |
+ __ push(ebx); |
+ __ push(ecx); |
+ __ push(edx); |
+ __ push(edi); |
+ __ push(esi); |
+ |
+ __ mov(ecx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset)); |
+ Label aligned, done_aligned; |
+ __ mov(esi, esp); |
+ __ test(esi, Immediate(kPointerSize)); |
+ __ j(not_equal, &aligned, Label::kFar); |
+ __ push(Immediate(0)); |
+ __ push(Immediate(4)); |
+ __ mov(esi, Operand(esp, 8)); |
+ __ jmp(&done_aligned, Label::kFar); |
+ __ bind(&aligned); |
+ __ push(Immediate(0)); |
+ __ mov(esi, Operand(esp, 4)); |
+ __ bind(&done_aligned); |
+ |
__ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), |
Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate))); |
__ jmp(&done, Label::kNear); |
- // An uninitialized cache is patched with the function. |
+ // An uninitialized cache is patched with the function or sentinel to |
+ // indicate the ElementsKind if function is the Array constructor. |
__ bind(&initialize); |
+ __ mov(ecx, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); |
+ __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalContextOffset)); |
+ // 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, install a sentinel value in |
+ // the constructor's type info cell that will track the initial ElementsKind |
+ // that should be used for the array when its constructed. |
+ Handle<Object> initial_kind_sentinel = |
+ TypeFeedbackCells::MonomorphicArraySentinel( |
+ GetInitialFastElementsKind()); |
+ __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), |
+ Immediate(initial_kind_sentinel)); |
+ __ jmp(&done); |
+ |
+ __ bind(¬_array_function); |
__ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), edi); |
// No need for a write barrier here - cells are rescanned. |
@@ -4822,10 +4898,10 @@ void CallConstructStub::Generate(MacroAssembler* masm) { |
} |
// Jump to the function-specific construct stub. |
- __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
- __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kConstructStubOffset)); |
- __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize)); |
- __ jmp(ebx); |
+ __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
+ __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset)); |
+ __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); |
+ __ jmp(ecx); |
// edi: called object |
// eax: number of arguments |