Index: src/ia32/builtins-ia32.cc |
diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc |
index bf4ee949ed29be5be0cf4b661922a30873f5ebec..c3490a31251790eaac31861d496179cc00a54c66 100644 |
--- a/src/ia32/builtins-ia32.cc |
+++ b/src/ia32/builtins-ia32.cc |
@@ -1015,427 +1015,6 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { |
} |
-// Allocate an empty JSArray. The allocated array is put into the result |
-// register. If the parameter initial_capacity is larger than zero an elements |
-// backing store is allocated with this size and filled with the hole values. |
-// Otherwise the elements backing store is set to the empty FixedArray. |
-static void AllocateEmptyJSArray(MacroAssembler* masm, |
- Register array_function, |
- Register result, |
- Register scratch1, |
- Register scratch2, |
- Register scratch3, |
- Label* gc_required) { |
- const int initial_capacity = JSArray::kPreallocatedArrayElements; |
- STATIC_ASSERT(initial_capacity >= 0); |
- |
- __ LoadInitialArrayMap(array_function, scratch2, scratch1, false); |
- |
- // Allocate the JSArray object together with space for a fixed array with the |
- // requested elements. |
- int size = JSArray::kSize; |
- if (initial_capacity > 0) { |
- size += FixedArray::SizeFor(initial_capacity); |
- } |
- __ Allocate(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; |
- } |
- |
- // 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); |
- |
- // 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 |
- __ mov(FieldOperand(scratch1, FixedArray::kMapOffset), |
- factory->fixed_array_map()); |
- __ mov(FieldOperand(scratch1, FixedArray::kLengthOffset), |
- Immediate(Smi::FromInt(initial_capacity))); |
- |
- // 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) { |
- // 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++) { |
- __ mov(FieldOperand(scratch1, |
- FixedArray::kHeaderSize + i * kPointerSize), |
- scratch3); |
- } |
- } else { |
- Label loop, entry; |
- __ mov(scratch2, Immediate(initial_capacity)); |
- __ jmp(&entry); |
- __ bind(&loop); |
- __ mov(FieldOperand(scratch1, |
- scratch2, |
- times_pointer_size, |
- FixedArray::kHeaderSize), |
- factory->the_hole_value()); |
- __ bind(&entry); |
- __ dec(scratch2); |
- __ j(not_sign, &loop); |
- } |
-} |
- |
- |
-// Allocate a JSArray with the number of elements stored in a register. The |
-// register array_function holds the built-in Array function and the register |
-// array_size holds the size of the array as a smi. The allocated array is put |
-// into the result register and beginning and end of the FixedArray elements |
-// storage is put into registers elements_array and elements_array_end (see |
-// below for when that is not the case). If the parameter fill_with_holes is |
-// true the allocated elements backing store is filled with the hole values |
-// otherwise it is left uninitialized. When the backing store is filled the |
-// register elements_array is scratched. |
-static void AllocateJSArray(MacroAssembler* masm, |
- Register array_function, // Array function. |
- Register array_size, // As a smi, cannot be 0. |
- Register result, |
- Register elements_array, |
- Register elements_array_end, |
- Register scratch, |
- bool fill_with_hole, |
- Label* gc_required) { |
- ASSERT(scratch.is(edi)); // rep stos destination |
- ASSERT(!fill_with_hole || array_size.is(ecx)); // rep stos count |
- ASSERT(!fill_with_hole || !result.is(eax)); // result is never eax |
- |
- __ LoadInitialArrayMap(array_function, scratch, |
- elements_array, fill_with_hole); |
- |
- // Allocate the JSArray object together with space for a FixedArray with the |
- // requested elements. |
- STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
- __ Allocate(JSArray::kSize + FixedArray::kHeaderSize, |
- times_pointer_size, |
- array_size, |
- REGISTER_VALUE_IS_SMI, |
- result, |
- elements_array_end, |
- scratch, |
- gc_required, |
- TAG_OBJECT); |
- |
- // Allocated the JSArray. Now initialize the fields except for the elements |
- // array. |
- // result: JSObject |
- // elements_array: initial map |
- // elements_array_end: start of next object |
- // array_size: size of array (smi) |
- __ mov(FieldOperand(result, JSObject::kMapOffset), elements_array); |
- Factory* factory = masm->isolate()->factory(); |
- __ mov(elements_array, factory->empty_fixed_array()); |
- __ mov(FieldOperand(result, JSArray::kPropertiesOffset), elements_array); |
- // Field JSArray::kElementsOffset is initialized later. |
- __ mov(FieldOperand(result, JSArray::kLengthOffset), array_size); |
- |
- // Calculate the location of the elements array and set elements array member |
- // of the JSArray. |
- // result: JSObject |
- // elements_array_end: start of next object |
- // array_size: size of array (smi) |
- __ lea(elements_array, Operand(result, JSArray::kSize)); |
- __ mov(FieldOperand(result, JSArray::kElementsOffset), elements_array); |
- |
- // Initialize the fixed array. FixedArray length is stored as a smi. |
- // result: JSObject |
- // elements_array: elements array |
- // elements_array_end: start of next object |
- // array_size: size of array (smi) |
- __ mov(FieldOperand(elements_array, FixedArray::kMapOffset), |
- factory->fixed_array_map()); |
- // For non-empty JSArrays the length of the FixedArray and the JSArray is the |
- // same. |
- __ mov(FieldOperand(elements_array, FixedArray::kLengthOffset), array_size); |
- |
- // Fill the allocated FixedArray with the hole value if requested. |
- // result: JSObject |
- // elements_array: elements array |
- if (fill_with_hole) { |
- __ SmiUntag(array_size); |
- __ lea(edi, Operand(elements_array, |
- FixedArray::kHeaderSize - kHeapObjectTag)); |
- __ mov(eax, factory->the_hole_value()); |
- __ cld(); |
- // Do not use rep stos when filling less than kRepStosThreshold |
- // words. |
- const int kRepStosThreshold = 16; |
- Label loop, entry, done; |
- __ cmp(ecx, kRepStosThreshold); |
- __ j(below, &loop); // Note: ecx > 0. |
- __ rep_stos(); |
- __ jmp(&done); |
- __ bind(&loop); |
- __ stos(); |
- __ bind(&entry); |
- __ cmp(edi, elements_array_end); |
- __ j(below, &loop); |
- __ bind(&done); |
- } |
-} |
- |
- |
-// Create a new array for the built-in Array function. This function allocates |
-// the JSArray object and the FixedArray elements array and initializes these. |
-// If the Array cannot be constructed in native code the runtime is called. This |
-// function assumes the following state: |
-// edi: constructor (built-in Array function) |
-// eax: argc |
-// esp[0]: return address |
-// esp[4]: last argument |
-// This function is used for both construct and normal calls of Array. Whether |
-// it is a construct call or not is indicated by the construct_call parameter. |
-// The only difference between handling a construct call and a normal call is |
-// that for a construct call the constructor function in edi needs to be |
-// preserved for entering the generic code. In both cases argc in eax needs to |
-// be preserved. |
-void ArrayNativeCode(MacroAssembler* masm, |
- bool construct_call, |
- Label* call_generic_code) { |
- Label argc_one_or_more, argc_two_or_more, prepare_generic_code_call, |
- empty_array, not_empty_array, finish, cant_transition_map, not_double; |
- |
- // Push the constructor and argc. No need to tag argc as a smi, as there will |
- // be no garbage collection with this on the stack. |
- int push_count = 0; |
- if (construct_call) { |
- push_count++; |
- __ push(edi); |
- } |
- push_count++; |
- __ push(eax); |
- |
- // Check for array construction with zero arguments. |
- __ test(eax, eax); |
- __ j(not_zero, &argc_one_or_more); |
- |
- __ bind(&empty_array); |
- // Handle construction of an empty array. |
- AllocateEmptyJSArray(masm, |
- edi, |
- eax, |
- ebx, |
- ecx, |
- edi, |
- &prepare_generic_code_call); |
- __ IncrementCounter(masm->isolate()->counters()->array_function_native(), 1); |
- __ pop(ebx); |
- if (construct_call) { |
- __ pop(edi); |
- } |
- __ ret(kPointerSize); |
- |
- // Check for one argument. Bail out if argument is not smi or if it is |
- // negative. |
- __ bind(&argc_one_or_more); |
- __ cmp(eax, 1); |
- __ j(not_equal, &argc_two_or_more); |
- STATIC_ASSERT(kSmiTag == 0); |
- __ mov(ecx, Operand(esp, (push_count + 1) * kPointerSize)); |
- __ test(ecx, ecx); |
- __ j(not_zero, ¬_empty_array); |
- |
- // The single argument passed is zero, so we jump to the code above used to |
- // handle the case of no arguments passed. To adapt the stack for that we move |
- // the return address and the pushed constructor (if pushed) one stack slot up |
- // thereby removing the passed argument. Argc is also on the stack - at the |
- // bottom - and it needs to be changed from 1 to 0 to have the call into the |
- // runtime system work in case a GC is required. |
- for (int i = push_count; i > 0; i--) { |
- __ mov(eax, Operand(esp, i * kPointerSize)); |
- __ mov(Operand(esp, (i + 1) * kPointerSize), eax); |
- } |
- __ Drop(2); // Drop two stack slots. |
- __ push(Immediate(0)); // Treat this as a call with argc of zero. |
- __ jmp(&empty_array); |
- |
- __ bind(¬_empty_array); |
- __ test(ecx, Immediate(kIntptrSignBit | kSmiTagMask)); |
- __ j(not_zero, &prepare_generic_code_call); |
- |
- // Handle construction of an empty array of a certain size. Get the size from |
- // the stack and bail out if size is to large to actually allocate an elements |
- // array. |
- __ cmp(ecx, JSObject::kInitialMaxFastElementArray << kSmiTagSize); |
- __ j(greater_equal, &prepare_generic_code_call); |
- |
- // edx: array_size (smi) |
- // edi: constructor |
- // esp[0]: argc (cannot be 0 here) |
- // esp[4]: constructor (only if construct_call) |
- // esp[8]: return address |
- // esp[C]: argument |
- AllocateJSArray(masm, |
- edi, |
- ecx, |
- ebx, |
- eax, |
- edx, |
- edi, |
- true, |
- &prepare_generic_code_call); |
- Counters* counters = masm->isolate()->counters(); |
- __ IncrementCounter(counters->array_function_native(), 1); |
- __ mov(eax, ebx); |
- __ pop(ebx); |
- if (construct_call) { |
- __ pop(edi); |
- } |
- __ ret(2 * kPointerSize); |
- |
- // Handle construction of an array from a list of arguments. |
- __ bind(&argc_two_or_more); |
- STATIC_ASSERT(kSmiTag == 0); |
- __ SmiTag(eax); // Convet argc to a smi. |
- // eax: array_size (smi) |
- // edi: constructor |
- // esp[0] : argc |
- // esp[4]: constructor (only if construct_call) |
- // esp[8] : return address |
- // esp[C] : last argument |
- AllocateJSArray(masm, |
- edi, |
- eax, |
- ebx, |
- ecx, |
- edx, |
- edi, |
- false, |
- &prepare_generic_code_call); |
- __ IncrementCounter(counters->array_function_native(), 1); |
- __ push(ebx); |
- __ mov(ebx, Operand(esp, kPointerSize)); |
- // ebx: argc |
- // edx: elements_array_end (untagged) |
- // esp[0]: JSArray |
- // esp[4]: argc |
- // esp[8]: constructor (only if construct_call) |
- // esp[12]: return address |
- // esp[16]: last argument |
- |
- // Location of the last argument |
- int last_arg_offset = (construct_call ? 4 : 3) * kPointerSize; |
- __ lea(edi, Operand(esp, last_arg_offset)); |
- |
- // Location of the first array element (Parameter fill_with_holes to |
- // AllocateJSArray is false, so the FixedArray is returned in ecx). |
- __ lea(edx, Operand(ecx, FixedArray::kHeaderSize - kHeapObjectTag)); |
- |
- Label has_non_smi_element; |
- |
- // ebx: argc |
- // edx: location of the first array element |
- // edi: location of the last argument |
- // esp[0]: JSArray |
- // esp[4]: argc |
- // esp[8]: constructor (only if construct_call) |
- // esp[12]: return address |
- // esp[16]: last argument |
- Label loop, entry; |
- __ mov(ecx, ebx); |
- __ jmp(&entry); |
- __ bind(&loop); |
- __ mov(eax, Operand(edi, ecx, times_pointer_size, 0)); |
- if (FLAG_smi_only_arrays) { |
- __ JumpIfNotSmi(eax, &has_non_smi_element); |
- } |
- __ mov(Operand(edx, 0), eax); |
- __ add(edx, Immediate(kPointerSize)); |
- __ bind(&entry); |
- __ dec(ecx); |
- __ j(greater_equal, &loop); |
- |
- // Remove caller arguments from the stack and return. |
- // ebx: argc |
- // esp[0]: JSArray |
- // esp[4]: argc |
- // esp[8]: constructor (only if construct_call) |
- // esp[12]: return address |
- // esp[16]: last argument |
- __ bind(&finish); |
- __ mov(ecx, Operand(esp, last_arg_offset - kPointerSize)); |
- __ pop(eax); |
- __ pop(ebx); |
- __ lea(esp, Operand(esp, ebx, times_pointer_size, |
- last_arg_offset - kPointerSize)); |
- __ jmp(ecx); |
- |
- __ bind(&has_non_smi_element); |
- // Double values are handled by the runtime. |
- __ CheckMap(eax, |
- masm->isolate()->factory()->heap_number_map(), |
- ¬_double, |
- DONT_DO_SMI_CHECK); |
- __ bind(&cant_transition_map); |
- // Throw away the array that's only been partially constructed. |
- __ pop(eax); |
- __ UndoAllocationInNewSpace(eax); |
- __ jmp(&prepare_generic_code_call); |
- |
- __ bind(¬_double); |
- // Transition FAST_SMI_ELEMENTS to FAST_ELEMENTS. |
- __ mov(ebx, Operand(esp, 0)); |
- __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset)); |
- __ LoadTransitionedArrayMapConditional( |
- FAST_SMI_ELEMENTS, |
- FAST_ELEMENTS, |
- edi, |
- eax, |
- &cant_transition_map); |
- __ mov(FieldOperand(ebx, HeapObject::kMapOffset), edi); |
- __ RecordWriteField(ebx, HeapObject::kMapOffset, edi, eax, |
- kDontSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
- |
- // Prepare to re-enter the loop |
- __ lea(edi, Operand(esp, last_arg_offset)); |
- |
- // Finish the array initialization loop. |
- Label loop2; |
- __ bind(&loop2); |
- __ mov(eax, Operand(edi, ecx, times_pointer_size, 0)); |
- __ mov(Operand(edx, 0), eax); |
- __ add(edx, Immediate(kPointerSize)); |
- __ dec(ecx); |
- __ j(greater_equal, &loop2); |
- __ jmp(&finish); |
- |
- // Restore argc and constructor before running the generic code. |
- __ bind(&prepare_generic_code_call); |
- __ pop(eax); |
- if (construct_call) { |
- __ pop(edi); |
- } |
- __ jmp(call_generic_code); |
-} |
- |
- |
void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { |
// ----------- S t a t e ------------- |
// -- eax : argc |
@@ -1459,20 +1038,9 @@ void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { |
// Run the native code for the InternalArray function called as a normal |
// function. |
- if (FLAG_optimize_constructed_arrays) { |
- // tail call a stub |
- InternalArrayConstructorStub stub(masm->isolate()); |
- __ TailCallStub(&stub); |
- } else { |
- ArrayNativeCode(masm, false, &generic_array_code); |
- |
- // Jump to the generic internal array code in case the specialized code |
- // cannot handle the construction. |
- __ bind(&generic_array_code); |
- Handle<Code> array_code = |
- masm->isolate()->builtins()->InternalArrayCodeGeneric(); |
- __ jmp(array_code, RelocInfo::CODE_TARGET); |
- } |
+ // tail call a stub |
+ InternalArrayConstructorStub stub(masm->isolate()); |
+ __ TailCallStub(&stub); |
} |
@@ -1498,58 +1066,13 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) { |
} |
// Run the native code for the Array function called as a normal function. |
- if (FLAG_optimize_constructed_arrays) { |
- // tail call a stub |
- Handle<Object> undefined_sentinel( |
- masm->isolate()->heap()->undefined_value(), |
- masm->isolate()); |
- __ mov(ebx, Immediate(undefined_sentinel)); |
- ArrayConstructorStub stub(masm->isolate()); |
- __ TailCallStub(&stub); |
- } else { |
- ArrayNativeCode(masm, false, &generic_array_code); |
- |
- // Jump to the generic internal array code in case the specialized code |
- // cannot handle the construction. |
- __ bind(&generic_array_code); |
- Handle<Code> array_code = |
- masm->isolate()->builtins()->ArrayCodeGeneric(); |
- __ jmp(array_code, RelocInfo::CODE_TARGET); |
- } |
-} |
- |
- |
-void Builtins::Generate_CommonArrayConstructCode(MacroAssembler* masm) { |
- // ----------- S t a t e ------------- |
- // -- eax : argc |
- // -- ebx : type info cell |
- // -- edi : constructor |
- // -- esp[0] : return address |
- // -- esp[4] : last argument |
- // ----------------------------------- |
- if (FLAG_debug_code) { |
- // The array construct code is only set for the global and natives |
- // builtin Array functions which always have maps. |
- |
- // Initial map for the builtin Array function should be a map. |
- __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); |
- // Will both indicate a NULL and a Smi. |
- __ test(ecx, Immediate(kSmiTagMask)); |
- __ Assert(not_zero, "Unexpected initial map for Array function"); |
- __ CmpObjectType(ecx, MAP_TYPE, ecx); |
- __ Assert(equal, "Unexpected initial map for Array function"); |
- } |
- |
- Label generic_constructor; |
- // Run the native code for the Array function called as constructor. |
- ArrayNativeCode(masm, true, &generic_constructor); |
- |
- // Jump to the generic construct code in case the specialized code cannot |
- // handle the construction. |
- __ bind(&generic_constructor); |
- Handle<Code> generic_construct_stub = |
- masm->isolate()->builtins()->JSConstructStubGeneric(); |
- __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); |
+ // tail call a stub |
+ Handle<Object> undefined_sentinel( |
+ masm->isolate()->heap()->undefined_value(), |
+ masm->isolate()); |
+ __ mov(ebx, Immediate(undefined_sentinel)); |
+ ArrayConstructorStub stub(masm->isolate()); |
+ __ TailCallStub(&stub); |
} |