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