Commit 5f7f79b0 authored by yangguo@chromium.org's avatar yangguo@chromium.org

Refactor and clean up array allocation across platforms.

Review URL: http://codereview.chromium.org/8359034

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9747 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent c6464d50
...@@ -86,12 +86,6 @@ static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) { ...@@ -86,12 +86,6 @@ static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) {
} }
// This constant has the same value as JSArray::kPreallocatedArrayElements and
// if JSArray::kPreallocatedArrayElements is changed handling of loop unfolding
// below should be reconsidered.
static const int kLoopUnfoldLimit = 4;
// Allocate an empty JSArray. The allocated array is put into the result // Allocate an empty JSArray. The allocated array is put into the result
// register. An elements backing store is allocated with size initial_capacity // register. An elements backing store is allocated with size initial_capacity
// and filled with the hole values. // and filled with the hole values.
...@@ -101,9 +95,9 @@ static void AllocateEmptyJSArray(MacroAssembler* masm, ...@@ -101,9 +95,9 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
Register scratch1, Register scratch1,
Register scratch2, Register scratch2,
Register scratch3, Register scratch3,
int initial_capacity,
Label* gc_required) { Label* gc_required) {
ASSERT(initial_capacity > 0); int initial_capacity = JSArray::kPreallocatedArrayElements;
ASSERT(initial_capacity >= 0);
// Load the initial map from the array function. // Load the initial map from the array function.
__ ldr(scratch1, FieldMemOperand(array_function, __ ldr(scratch1, FieldMemOperand(array_function,
JSFunction::kPrototypeOrInitialMapOffset)); JSFunction::kPrototypeOrInitialMapOffset));
...@@ -155,7 +149,6 @@ static void AllocateEmptyJSArray(MacroAssembler* masm, ...@@ -155,7 +149,6 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
// Fill the FixedArray with the hole value. // Fill the FixedArray with the hole value.
ASSERT_EQ(2 * kPointerSize, FixedArray::kHeaderSize); ASSERT_EQ(2 * kPointerSize, FixedArray::kHeaderSize);
ASSERT(initial_capacity <= kLoopUnfoldLimit);
__ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex); __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex);
for (int i = 0; i < initial_capacity; i++) { for (int i = 0; i < initial_capacity; i++) {
__ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex)); __ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex));
...@@ -173,7 +166,7 @@ static void AllocateEmptyJSArray(MacroAssembler* masm, ...@@ -173,7 +166,7 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
// register elements_array_storage is scratched. // register elements_array_storage is scratched.
static void AllocateJSArray(MacroAssembler* masm, static void AllocateJSArray(MacroAssembler* masm,
Register array_function, // Array function. Register array_function, // Array function.
Register array_size, // As a smi. Register array_size, // As a smi, cannot be 0.
Register result, Register result,
Register elements_array_storage, Register elements_array_storage,
Register elements_array_end, Register elements_array_end,
...@@ -181,32 +174,21 @@ static void AllocateJSArray(MacroAssembler* masm, ...@@ -181,32 +174,21 @@ static void AllocateJSArray(MacroAssembler* masm,
Register scratch2, Register scratch2,
bool fill_with_hole, bool fill_with_hole,
Label* gc_required) { Label* gc_required) {
Label not_empty, allocated;
// Load the initial map from the array function. // Load the initial map from the array function.
__ ldr(elements_array_storage, __ ldr(elements_array_storage,
FieldMemOperand(array_function, FieldMemOperand(array_function,
JSFunction::kPrototypeOrInitialMapOffset)); JSFunction::kPrototypeOrInitialMapOffset));
// Check whether an empty sized array is requested. if (FLAG_debug_code) { // Assert that array size is not zero.
__ tst(array_size, array_size); Label not_empty;
__ b(ne, &not_empty); __ tst(array_size, array_size);
__ b(ne, &not_empty);
// If an empty array is requested allocate a small elements array anyway. This __ Abort("array size is unexpectedly 0");
// keeps the code below free of special casing for the empty array. __ bind(&not_empty);
int size = JSArray::kSize + }
FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
__ AllocateInNewSpace(size,
result,
elements_array_end,
scratch1,
gc_required,
TAG_OBJECT);
__ jmp(&allocated);
// Allocate the JSArray object together with space for a FixedArray with the // Allocate the JSArray object together with space for a FixedArray with the
// requested number of elements. // requested number of elements.
__ bind(&not_empty);
STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
__ mov(elements_array_end, __ mov(elements_array_end,
Operand((JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize)); Operand((JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize));
...@@ -226,7 +208,6 @@ static void AllocateJSArray(MacroAssembler* masm, ...@@ -226,7 +208,6 @@ static void AllocateJSArray(MacroAssembler* masm,
// result: JSObject // result: JSObject
// elements_array_storage: initial map // elements_array_storage: initial map
// array_size: size of array (smi) // array_size: size of array (smi)
__ bind(&allocated);
__ str(elements_array_storage, FieldMemOperand(result, JSObject::kMapOffset)); __ str(elements_array_storage, FieldMemOperand(result, JSObject::kMapOffset));
__ LoadRoot(elements_array_storage, Heap::kEmptyFixedArrayRootIndex); __ LoadRoot(elements_array_storage, Heap::kEmptyFixedArrayRootIndex);
__ str(elements_array_storage, __ str(elements_array_storage,
...@@ -256,14 +237,6 @@ static void AllocateJSArray(MacroAssembler* masm, ...@@ -256,14 +237,6 @@ static void AllocateJSArray(MacroAssembler* masm,
ASSERT_EQ(0 * kPointerSize, FixedArray::kMapOffset); ASSERT_EQ(0 * kPointerSize, FixedArray::kMapOffset);
__ str(scratch1, MemOperand(elements_array_storage, kPointerSize, PostIndex)); __ str(scratch1, MemOperand(elements_array_storage, kPointerSize, PostIndex));
STATIC_ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTag == 0);
__ tst(array_size, array_size);
// Length of the FixedArray is the number of pre-allocated elements if
// the actual JSArray has length 0 and the size of the JSArray for non-empty
// JSArrays. The length of a FixedArray is stored as a smi.
__ mov(array_size,
Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)),
LeaveCC,
eq);
ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset); ASSERT_EQ(1 * kPointerSize, FixedArray::kLengthOffset);
__ str(array_size, __ str(array_size,
MemOperand(elements_array_storage, kPointerSize, PostIndex)); MemOperand(elements_array_storage, kPointerSize, PostIndex));
...@@ -311,20 +284,20 @@ static void AllocateJSArray(MacroAssembler* masm, ...@@ -311,20 +284,20 @@ static void AllocateJSArray(MacroAssembler* masm,
static void ArrayNativeCode(MacroAssembler* masm, static void ArrayNativeCode(MacroAssembler* masm,
Label* call_generic_code) { Label* call_generic_code) {
Counters* counters = masm->isolate()->counters(); Counters* counters = masm->isolate()->counters();
Label argc_one_or_more, argc_two_or_more; Label argc_one_or_more, argc_two_or_more, not_empty_array, empty_array;
// Check for array construction with zero arguments or one. // Check for array construction with zero arguments or one.
__ cmp(r0, Operand(0, RelocInfo::NONE)); __ cmp(r0, Operand(0, RelocInfo::NONE));
__ b(ne, &argc_one_or_more); __ b(ne, &argc_one_or_more);
// Handle construction of an empty array. // Handle construction of an empty array.
__ bind(&empty_array);
AllocateEmptyJSArray(masm, AllocateEmptyJSArray(masm,
r1, r1,
r2, r2,
r3, r3,
r4, r4,
r5, r5,
JSArray::kPreallocatedArrayElements,
call_generic_code); call_generic_code);
__ IncrementCounter(counters->array_function_native(), 1, r3, r4); __ IncrementCounter(counters->array_function_native(), 1, r3, r4);
// Setup return value, remove receiver from stack and return. // Setup return value, remove receiver from stack and return.
...@@ -339,6 +312,13 @@ static void ArrayNativeCode(MacroAssembler* masm, ...@@ -339,6 +312,13 @@ static void ArrayNativeCode(MacroAssembler* masm,
__ b(ne, &argc_two_or_more); __ b(ne, &argc_two_or_more);
STATIC_ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTag == 0);
__ ldr(r2, MemOperand(sp)); // Get the argument from the stack. __ ldr(r2, MemOperand(sp)); // Get the argument from the stack.
__ tst(r2, r2);
__ b(ne, &not_empty_array);
__ Drop(1); // Adjust stack.
__ mov(r0, Operand(0)); // Treat this as a call with argc of zero.
__ b(&empty_array);
__ bind(&not_empty_array);
__ and_(r3, r2, Operand(kIntptrSignBit | kSmiTagMask), SetCC); __ and_(r3, r2, Operand(kIntptrSignBit | kSmiTagMask), SetCC);
__ b(ne, call_generic_code); __ b(ne, call_generic_code);
......
...@@ -915,10 +915,6 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { ...@@ -915,10 +915,6 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
} }
// Number of empty elements to allocate for an empty array.
static const int kPreallocatedArrayElements = 4;
// Allocate an empty JSArray. The allocated array is put into the result // Allocate an empty JSArray. The allocated array is put into the result
// register. If the parameter initial_capacity is larger than zero an elements // 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. // backing store is allocated with this size and filled with the hole values.
...@@ -929,10 +925,9 @@ static void AllocateEmptyJSArray(MacroAssembler* masm, ...@@ -929,10 +925,9 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
Register scratch1, Register scratch1,
Register scratch2, Register scratch2,
Register scratch3, Register scratch3,
int initial_capacity,
Label* gc_required) { Label* gc_required) {
int initial_capacity = JSArray::kPreallocatedArrayElements;
ASSERT(initial_capacity >= 0); ASSERT(initial_capacity >= 0);
// Load the initial map from the array function. // Load the initial map from the array function.
__ mov(scratch1, FieldOperand(array_function, __ mov(scratch1, FieldOperand(array_function,
JSFunction::kPrototypeOrInitialMapOffset)); JSFunction::kPrototypeOrInitialMapOffset));
...@@ -990,7 +985,6 @@ static void AllocateEmptyJSArray(MacroAssembler* masm, ...@@ -990,7 +985,6 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
// Fill the FixedArray with the hole value. Inline the code if short. // Fill the FixedArray with the hole value. Inline the code if short.
// Reconsider loop unfolding if kPreallocatedArrayElements gets changed. // Reconsider loop unfolding if kPreallocatedArrayElements gets changed.
static const int kLoopUnfoldLimit = 4; static const int kLoopUnfoldLimit = 4;
STATIC_ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit);
if (initial_capacity <= kLoopUnfoldLimit) { if (initial_capacity <= kLoopUnfoldLimit) {
// Use a scratch register here to have only one reloc info when unfolding // Use a scratch register here to have only one reloc info when unfolding
// the loop. // the loop.
...@@ -1153,7 +1147,6 @@ static void ArrayNativeCode(MacroAssembler* masm, ...@@ -1153,7 +1147,6 @@ static void ArrayNativeCode(MacroAssembler* masm,
ebx, ebx,
ecx, ecx,
edi, edi,
kPreallocatedArrayElements,
&prepare_generic_code_call); &prepare_generic_code_call);
__ IncrementCounter(masm->isolate()->counters()->array_function_native(), 1); __ IncrementCounter(masm->isolate()->counters()->array_function_native(), 1);
__ pop(ebx); __ pop(ebx);
...@@ -1182,7 +1175,7 @@ static void ArrayNativeCode(MacroAssembler* masm, ...@@ -1182,7 +1175,7 @@ static void ArrayNativeCode(MacroAssembler* masm,
__ mov(eax, Operand(esp, i * kPointerSize)); __ mov(eax, Operand(esp, i * kPointerSize));
__ mov(Operand(esp, (i + 1) * kPointerSize), eax); __ mov(Operand(esp, (i + 1) * kPointerSize), eax);
} }
__ add(esp, Immediate(2 * kPointerSize)); // Drop two stack slots. __ Drop(2); // Drop two stack slots.
__ push(Immediate(0)); // Treat this as a call with argc of zero. __ push(Immediate(0)); // Treat this as a call with argc of zero.
__ jmp(&empty_array); __ jmp(&empty_array);
......
...@@ -993,10 +993,6 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { ...@@ -993,10 +993,6 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
} }
// Number of empty elements to allocate for an empty array.
static const int kPreallocatedArrayElements = 4;
// Allocate an empty JSArray. The allocated array is put into the result // Allocate an empty JSArray. The allocated array is put into the result
// register. If the parameter initial_capacity is larger than zero an elements // 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. // backing store is allocated with this size and filled with the hole values.
...@@ -1007,8 +1003,8 @@ static void AllocateEmptyJSArray(MacroAssembler* masm, ...@@ -1007,8 +1003,8 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
Register scratch1, Register scratch1,
Register scratch2, Register scratch2,
Register scratch3, Register scratch3,
int initial_capacity,
Label* gc_required) { Label* gc_required) {
int initial_capacity = JSArray::kPreallocatedArrayElements;
ASSERT(initial_capacity >= 0); ASSERT(initial_capacity >= 0);
// Load the initial map from the array function. // Load the initial map from the array function.
...@@ -1067,7 +1063,6 @@ static void AllocateEmptyJSArray(MacroAssembler* masm, ...@@ -1067,7 +1063,6 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
// Fill the FixedArray with the hole value. Inline the code if short. // Fill the FixedArray with the hole value. Inline the code if short.
// Reconsider loop unfolding if kPreallocatedArrayElements gets changed. // Reconsider loop unfolding if kPreallocatedArrayElements gets changed.
static const int kLoopUnfoldLimit = 4; static const int kLoopUnfoldLimit = 4;
ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit);
__ Move(scratch3, FACTORY->the_hole_value()); __ Move(scratch3, FACTORY->the_hole_value());
if (initial_capacity <= kLoopUnfoldLimit) { if (initial_capacity <= kLoopUnfoldLimit) {
// Use a scratch register here to have only one reloc info when unfolding // Use a scratch register here to have only one reloc info when unfolding
...@@ -1101,38 +1096,28 @@ static void AllocateEmptyJSArray(MacroAssembler* masm, ...@@ -1101,38 +1096,28 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
// register elements_array is scratched. // register elements_array is scratched.
static void AllocateJSArray(MacroAssembler* masm, static void AllocateJSArray(MacroAssembler* masm,
Register array_function, // Array function. Register array_function, // Array function.
Register array_size, // As a smi. Register array_size, // As a smi, cannot be 0.
Register result, Register result,
Register elements_array, Register elements_array,
Register elements_array_end, Register elements_array_end,
Register scratch, Register scratch,
bool fill_with_hole, bool fill_with_hole,
Label* gc_required) { Label* gc_required) {
Label not_empty, allocated;
// Load the initial map from the array function. // Load the initial map from the array function.
__ movq(elements_array, __ movq(elements_array,
FieldOperand(array_function, FieldOperand(array_function,
JSFunction::kPrototypeOrInitialMapOffset)); JSFunction::kPrototypeOrInitialMapOffset));
// Check whether an empty sized array is requested. if (FLAG_debug_code) { // Assert that array size is not zero.
__ testq(array_size, array_size); Label not_empty;
__ j(not_zero, &not_empty); __ testq(array_size, array_size);
__ j(not_zero, &not_empty);
// If an empty array is requested allocate a small elements array anyway. This __ int3();
// keeps the code below free of special casing for the empty array. __ bind(&not_empty);
int size = JSArray::kSize + FixedArray::SizeFor(kPreallocatedArrayElements); }
__ AllocateInNewSpace(size,
result,
elements_array_end,
scratch,
gc_required,
TAG_OBJECT);
__ jmp(&allocated);
// Allocate the JSArray object together with space for a FixedArray with the // Allocate the JSArray object together with space for a FixedArray with the
// requested elements. // requested elements.
__ bind(&not_empty);
SmiIndex index = SmiIndex index =
masm->SmiToIndex(kScratchRegister, array_size, kPointerSizeLog2); masm->SmiToIndex(kScratchRegister, array_size, kPointerSizeLog2);
__ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize, __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize,
...@@ -1150,7 +1135,6 @@ static void AllocateJSArray(MacroAssembler* masm, ...@@ -1150,7 +1135,6 @@ static void AllocateJSArray(MacroAssembler* masm,
// elements_array: initial map // elements_array: initial map
// elements_array_end: start of next object // elements_array_end: start of next object
// array_size: size of array (smi) // array_size: size of array (smi)
__ bind(&allocated);
__ movq(FieldOperand(result, JSObject::kMapOffset), elements_array); __ movq(FieldOperand(result, JSObject::kMapOffset), elements_array);
__ Move(elements_array, FACTORY->empty_fixed_array()); __ Move(elements_array, FACTORY->empty_fixed_array());
__ movq(FieldOperand(result, JSArray::kPropertiesOffset), elements_array); __ movq(FieldOperand(result, JSArray::kPropertiesOffset), elements_array);
...@@ -1172,15 +1156,6 @@ static void AllocateJSArray(MacroAssembler* masm, ...@@ -1172,15 +1156,6 @@ static void AllocateJSArray(MacroAssembler* masm,
// array_size: size of array (smi) // array_size: size of array (smi)
__ Move(FieldOperand(elements_array, JSObject::kMapOffset), __ Move(FieldOperand(elements_array, JSObject::kMapOffset),
FACTORY->fixed_array_map()); FACTORY->fixed_array_map());
Label not_empty_2, fill_array;
__ SmiTest(array_size);
__ j(not_zero, &not_empty_2);
// Length of the FixedArray is the number of pre-allocated elements even
// though the actual JSArray has length 0.
__ Move(FieldOperand(elements_array, FixedArray::kLengthOffset),
Smi::FromInt(kPreallocatedArrayElements));
__ jmp(&fill_array);
__ bind(&not_empty_2);
// For non-empty JSArrays the length of the FixedArray and the JSArray is the // For non-empty JSArrays the length of the FixedArray and the JSArray is the
// same. // same.
__ movq(FieldOperand(elements_array, FixedArray::kLengthOffset), array_size); __ movq(FieldOperand(elements_array, FixedArray::kLengthOffset), array_size);
...@@ -1189,7 +1164,6 @@ static void AllocateJSArray(MacroAssembler* masm, ...@@ -1189,7 +1164,6 @@ static void AllocateJSArray(MacroAssembler* masm,
// result: JSObject // result: JSObject
// elements_array: elements array // elements_array: elements array
// elements_array_end: start of next object // elements_array_end: start of next object
__ bind(&fill_array);
if (fill_with_hole) { if (fill_with_hole) {
Label loop, entry; Label loop, entry;
__ Move(scratch, FACTORY->the_hole_value()); __ Move(scratch, FACTORY->the_hole_value());
...@@ -1222,12 +1196,13 @@ static void AllocateJSArray(MacroAssembler* masm, ...@@ -1222,12 +1196,13 @@ static void AllocateJSArray(MacroAssembler* masm,
// a construct call and a normal call. // a construct call and a normal call.
static void ArrayNativeCode(MacroAssembler* masm, static void ArrayNativeCode(MacroAssembler* masm,
Label *call_generic_code) { Label *call_generic_code) {
Label argc_one_or_more, argc_two_or_more; Label argc_one_or_more, argc_two_or_more, empty_array, not_empty_array;
// Check for array construction with zero arguments. // Check for array construction with zero arguments.
__ testq(rax, rax); __ testq(rax, rax);
__ j(not_zero, &argc_one_or_more); __ j(not_zero, &argc_one_or_more);
__ bind(&empty_array);
// Handle construction of an empty array. // Handle construction of an empty array.
AllocateEmptyJSArray(masm, AllocateEmptyJSArray(masm,
rdi, rdi,
...@@ -1235,7 +1210,6 @@ static void ArrayNativeCode(MacroAssembler* masm, ...@@ -1235,7 +1210,6 @@ static void ArrayNativeCode(MacroAssembler* masm,
rcx, rcx,
rdx, rdx,
r8, r8,
kPreallocatedArrayElements,
call_generic_code); call_generic_code);
Counters* counters = masm->isolate()->counters(); Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->array_function_native(), 1); __ IncrementCounter(counters->array_function_native(), 1);
...@@ -1248,6 +1222,16 @@ static void ArrayNativeCode(MacroAssembler* masm, ...@@ -1248,6 +1222,16 @@ static void ArrayNativeCode(MacroAssembler* masm,
__ cmpq(rax, Immediate(1)); __ cmpq(rax, Immediate(1));
__ j(not_equal, &argc_two_or_more); __ j(not_equal, &argc_two_or_more);
__ movq(rdx, Operand(rsp, kPointerSize)); // Get the argument from the stack. __ movq(rdx, Operand(rsp, kPointerSize)); // Get the argument from the stack.
__ SmiTest(rdx);
__ j(not_zero, &not_empty_array);
__ pop(r8); // Adjust stack.
__ Drop(1);
__ push(r8);
__ movq(rax, Immediate(0)); // Treat this as a call with argc of zero.
__ jmp(&empty_array);
__ bind(&not_empty_array);
__ JumpUnlessNonNegativeSmi(rdx, call_generic_code); __ JumpUnlessNonNegativeSmi(rdx, call_generic_code);
// Handle construction of an empty array of a certain size. Bail out if size // Handle construction of an empty array of a certain size. Bail out if size
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment