Index: src/ia32/builtins-ia32.cc |
diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc |
index 9bc15e90986c54048aa950b7bac9b3391ba0c0be..81824397121e3db005656830b836a035989aece4 100644 |
--- a/src/ia32/builtins-ia32.cc |
+++ b/src/ia32/builtins-ia32.cc |
@@ -930,91 +930,137 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { |
static void AllocateEmptyJSArray(MacroAssembler* masm, |
Register array_function, |
Register result, |
- Register scratch1, |
+ Register type_info_cell, |
Register scratch2, |
Register scratch3, |
Label* gc_required) { |
- const int initial_capacity = JSArray::kPreallocatedArrayElements; |
- STATIC_ASSERT(initial_capacity >= 0); |
- |
- __ LoadInitialArrayMap(array_function, scratch2, scratch1, false); |
- |
+ Label with_alloc_info, no_alloc_info, common_init, empty_double; |
+ Label no_known_elements_kind, init_js_array; |
+ Register scratch1 = type_info_cell; |
+ |
+ // If no type info cell is provided, then there's no point in tracking |
+ // site allocation info. |
+ Handle<Object> undefined_value(masm->isolate()->heap()->undefined_value()); |
+ __ cmp(type_info_cell, Immediate(undefined_value)); |
+ __ j(equal, &no_known_elements_kind); |
+ |
+ // If there is a type info cell provided, only track information about the |
+ // allocation site if the no ElementsKind transition has been detected. |
+ __ mov(scratch3, FieldOperand(type_info_cell, |
+ JSGlobalPropertyCell::kValueOffset)); |
+ __ JumpIfNotSmi(scratch3, &no_known_elements_kind); |
+ __ cmp(scratch3, Immediate(Smi::FromInt(GetInitialFastElementsKind()))); |
+ __ j(equal, &with_alloc_info); |
+ |
+ STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); |
+ STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); |
+ STATIC_ASSERT(FAST_ELEMENTS == 2); |
+ STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3); |
+ __ cmp(scratch3, Immediate(Smi::FromInt(FAST_HOLEY_ELEMENTS))); |
+ __ j(above, gc_required); |
+ |
+ __ LoadInitialArrayMap(array_function, scratch3, scratch2); |
+ __ jmp(&no_alloc_info); |
+ |
// Allocate the JSArray object together with space for a fixed array with the |
- // requested elements. |
+ // requested elements and an AllocationSiteInfo object to later be able to |
+ // feed back array transition information to the allocation site. |
+ __ bind(&with_alloc_info); |
int size = JSArray::kSize; |
- if (initial_capacity > 0) { |
- size += FixedArray::SizeFor(initial_capacity); |
- } |
+ int allocation_info_start = size; |
+ int elements_offset = size; |
+ size += AllocationSiteInfo::kSize; |
+ elements_offset = size; |
+ size += FixedArray::SizeFor(JSArray::kPreallocatedArrayElements); |
__ AllocateInNewSpace(size, |
result, |
scratch2, |
scratch3, |
gc_required, |
- TAG_OBJECT); |
- |
- // Allocated the JSArray. Now initialize the fields except for the elements |
- // array. |
- // result: JSObject |
- // scratch1: initial map |
- // scratch2: start of next object |
- __ mov(FieldOperand(result, JSObject::kMapOffset), scratch1); |
- Factory* factory = masm->isolate()->factory(); |
- __ mov(FieldOperand(result, JSArray::kPropertiesOffset), |
- factory->empty_fixed_array()); |
- // Field JSArray::kElementsOffset is initialized later. |
- __ mov(FieldOperand(result, JSArray::kLengthOffset), Immediate(0)); |
- |
- // If no storage is requested for the elements array just set the empty |
- // fixed array. |
- if (initial_capacity == 0) { |
- __ mov(FieldOperand(result, JSArray::kElementsOffset), |
- factory->empty_fixed_array()); |
- return; |
- } |
+ TAG_OBJECT); |
+ |
+ // Track information about the allocation site |
+ __ mov(FieldOperand(result, allocation_info_start), |
+ Immediate(Handle<Map>(masm->isolate()->heap()-> |
+ allocation_site_info_map()))); |
+ __ mov(FieldOperand(result, allocation_info_start + kPointerSize), |
+ type_info_cell); // No write barrier because it's a cell. |
// Calculate the location of the elements array and set elements array member |
// of the JSArray. |
- // result: JSObject |
- // scratch2: start of next object |
- __ lea(scratch1, Operand(result, JSArray::kSize)); |
- __ mov(FieldOperand(result, JSArray::kElementsOffset), scratch1); |
- |
+ // result: JSArray |
+ __ LoadInitialArrayMap(array_function, GetInitialFastElementsKind(), scratch2); |
+ __ lea(scratch1, Operand(result, elements_offset)); |
+ __ jmp(&common_init); |
+ |
+ __ bind(&no_known_elements_kind); |
+ __ LoadInitialArrayMap(array_function, GetInitialFastElementsKind(), scratch2); |
+ |
+ // Allocate the JSArray object together with space for a fixed array with the |
+ // requested elements. |
+ __ bind(&no_alloc_info); |
+ size = JSArray::kSize; |
+ elements_offset = size; |
+ size += FixedArray::SizeFor(JSArray::kPreallocatedArrayElements); |
+ __ AllocateInNewSpace(size, |
+ result, |
+ scratch1, |
+ scratch3, |
+ gc_required, |
+ TAG_OBJECT); |
+ // Calculate the location of the elements array and set elements array member |
+ // of the JSArray. |
+ // result: JSArray |
+ __ lea(scratch1, Operand(result, elements_offset)); |
+ |
+ __ bind(&common_init); |
// Initialize the FixedArray and fill it with holes. FixedArray length is |
// stored as a smi. |
// result: JSObject |
// scratch1: elements array |
- // scratch2: start of next object |
+ Factory* factory = masm->isolate()->factory(); |
__ mov(FieldOperand(scratch1, FixedArray::kMapOffset), |
factory->fixed_array_map()); |
__ mov(FieldOperand(scratch1, FixedArray::kLengthOffset), |
- Immediate(Smi::FromInt(initial_capacity))); |
+ Immediate(Smi::FromInt(JSArray::kPreallocatedArrayElements))); |
// Fill the FixedArray with the hole value. Inline the code if short. |
// Reconsider loop unfolding if kPreallocatedArrayElements gets changed. |
static const int kLoopUnfoldLimit = 4; |
- if (initial_capacity <= kLoopUnfoldLimit) { |
+ if (JSArray::kPreallocatedArrayElements <= kLoopUnfoldLimit) { |
// Use a scratch register here to have only one reloc info when unfolding |
// the loop. |
__ mov(scratch3, factory->the_hole_value()); |
- for (int i = 0; i < initial_capacity; i++) { |
+ for (int i = 0; i < JSArray::kPreallocatedArrayElements; i++) { |
__ mov(FieldOperand(scratch1, |
FixedArray::kHeaderSize + i * kPointerSize), |
scratch3); |
} |
} else { |
Label loop, entry; |
- __ mov(scratch2, Immediate(initial_capacity)); |
+ __ mov(scratch3, Immediate(JSArray::kPreallocatedArrayElements)); |
__ jmp(&entry); |
__ bind(&loop); |
__ mov(FieldOperand(scratch1, |
- scratch2, |
+ scratch3, |
times_pointer_size, |
FixedArray::kHeaderSize), |
factory->the_hole_value()); |
__ bind(&entry); |
- __ dec(scratch2); |
+ __ dec(scratch3); |
__ j(not_sign, &loop); |
} |
+ |
+ __ bind(&init_js_array); |
+ // Initialize the fields of the JSArray |
+ // result: JSArray |
+ // scratch1: elements array |
+ // scratch2: map for Array |
+ __ mov(FieldOperand(result, JSArray::kElementsOffset), scratch1); |
+ __ mov(FieldOperand(result, JSObject::kMapOffset), scratch2); |
+ __ mov(FieldOperand(result, JSArray::kPropertiesOffset), |
+ factory->empty_fixed_array()); |
+ __ mov(FieldOperand(result, JSArray::kLengthOffset), Immediate(0)); |
} |
@@ -1046,7 +1092,10 @@ static void AllocateJSArray(MacroAssembler* masm, |
// Allocate the JSArray object together with space for a FixedArray with the |
// requested elements. |
STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
- __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize, |
+ |
+ int fixed_size = JSArray::kSize + FixedArray::kHeaderSize + |
+ AllocationSiteInfo::kSize; |
+ __ AllocateInNewSpace(fixed_size, |
times_half_pointer_size, // array_size is a smi. |
array_size, |
result, |
@@ -1054,6 +1103,7 @@ static void AllocateJSArray(MacroAssembler* masm, |
scratch, |
gc_required, |
TAG_OBJECT); |
+ __ sub(elements_array_end, Immediate(AllocationSiteInfo::kSize)); |
// Allocated the JSArray. Now initialize the fields except for the elements |
// array. |
@@ -1111,6 +1161,13 @@ static void AllocateJSArray(MacroAssembler* masm, |
__ j(below, &loop); |
__ bind(&done); |
} |
+ |
+ // Track information about the allocation site |
+ __ mov(Operand(elements_array_end, 0), |
+ Immediate(Handle<Map>(masm->isolate()->heap()-> |
+ allocation_site_info_map()))); |
+ __ mov(Operand(elements_array_end, kPointerSize), |
+ Immediate(Handle<HeapObject>(masm->isolate()->heap()->null_value()))); |
} |
@@ -1120,6 +1177,7 @@ static void AllocateJSArray(MacroAssembler* masm, |
// function assumes the following state: |
// edi: constructor (built-in Array function) |
// eax: argc |
+// ebx: cell containing type feedback cell for Array's ElementsKind |
// esp[0]: return address |
// esp[4]: last argument |
// This function is used for both construct and normal calls of Array. Whether |
@@ -1155,7 +1213,7 @@ static void ArrayNativeCode(MacroAssembler* masm, |
eax, |
ebx, |
ecx, |
- edi, |
+ edx, |
&prepare_generic_code_call); |
__ IncrementCounter(masm->isolate()->counters()->array_function_native(), 1); |
__ pop(ebx); |
@@ -1361,14 +1419,18 @@ void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { |
if (FLAG_debug_code) { |
// Initial map for the builtin InternalArray function should be a map. |
- __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); |
+ __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); |
// Will both indicate a NULL and a Smi. |
- __ test(ebx, Immediate(kSmiTagMask)); |
+ __ test(ecx, Immediate(kSmiTagMask)); |
__ Assert(not_zero, "Unexpected initial map for InternalArray function"); |
- __ CmpObjectType(ebx, MAP_TYPE, ecx); |
+ __ CmpObjectType(ecx, MAP_TYPE, ecx); |
__ Assert(equal, "Unexpected initial map for InternalArray function"); |
} |
+ // No type feedback cell is available |
+ Handle<Object> undefined_sentinel(masm->isolate()->heap()->undefined_value()); |
+ __ mov(ebx, Immediate(undefined_sentinel)); |
+ |
// Run the native code for the InternalArray function called as a normal |
// function. |
ArrayNativeCode(masm, false, &generic_array_code); |
@@ -1395,14 +1457,18 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { |
if (FLAG_debug_code) { |
// Initial map for the builtin Array function should be a map. |
- __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); |
+ __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); |
// Will both indicate a NULL and a Smi. |
- __ test(ebx, Immediate(kSmiTagMask)); |
+ __ test(ecx, Immediate(kSmiTagMask)); |
__ Assert(not_zero, "Unexpected initial map for Array function"); |
- __ CmpObjectType(ebx, MAP_TYPE, ecx); |
+ __ CmpObjectType(ecx, MAP_TYPE, ecx); |
__ Assert(equal, "Unexpected initial map for Array function"); |
} |
+ // No type feedback cell is available |
+ Handle<Object> undefined_sentinel(masm->isolate()->heap()->undefined_value()); |
+ __ mov(ebx, Immediate(undefined_sentinel)); |
+ |
// Run the native code for the Array function called as a normal function. |
ArrayNativeCode(masm, false, &generic_array_code); |
@@ -1429,11 +1495,11 @@ void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) { |
// builtin Array functions which always have maps. |
// Initial map for the builtin Array function should be a map. |
- __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); |
+ __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); |
// Will both indicate a NULL and a Smi. |
- __ test(ebx, Immediate(kSmiTagMask)); |
+ __ test(ecx, Immediate(kSmiTagMask)); |
__ Assert(not_zero, "Unexpected initial map for Array function"); |
- __ CmpObjectType(ebx, MAP_TYPE, ecx); |
+ __ CmpObjectType(ecx, MAP_TYPE, ecx); |
__ Assert(equal, "Unexpected initial map for Array function"); |
} |