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