| 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
|
|
|