| 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");
|
| }
|
|
|
|
|