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
This commit is contained in:
parent
c6464d500b
commit
5f7f79b012
@ -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
|
||||
// register. An elements backing store is allocated with size initial_capacity
|
||||
// and filled with the hole values.
|
||||
@ -101,9 +95,9 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
Register scratch3,
|
||||
int initial_capacity,
|
||||
Label* gc_required) {
|
||||
ASSERT(initial_capacity > 0);
|
||||
int initial_capacity = JSArray::kPreallocatedArrayElements;
|
||||
ASSERT(initial_capacity >= 0);
|
||||
// Load the initial map from the array function.
|
||||
__ ldr(scratch1, FieldMemOperand(array_function,
|
||||
JSFunction::kPrototypeOrInitialMapOffset));
|
||||
@ -155,7 +149,6 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
|
||||
|
||||
// Fill the FixedArray with the hole value.
|
||||
ASSERT_EQ(2 * kPointerSize, FixedArray::kHeaderSize);
|
||||
ASSERT(initial_capacity <= kLoopUnfoldLimit);
|
||||
__ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex);
|
||||
for (int i = 0; i < initial_capacity; i++) {
|
||||
__ str(scratch3, MemOperand(scratch1, kPointerSize, PostIndex));
|
||||
@ -173,7 +166,7 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
|
||||
// register elements_array_storage is scratched.
|
||||
static void AllocateJSArray(MacroAssembler* masm,
|
||||
Register array_function, // Array function.
|
||||
Register array_size, // As a smi.
|
||||
Register array_size, // As a smi, cannot be 0.
|
||||
Register result,
|
||||
Register elements_array_storage,
|
||||
Register elements_array_end,
|
||||
@ -181,32 +174,21 @@ static void AllocateJSArray(MacroAssembler* masm,
|
||||
Register scratch2,
|
||||
bool fill_with_hole,
|
||||
Label* gc_required) {
|
||||
Label not_empty, allocated;
|
||||
|
||||
// Load the initial map from the array function.
|
||||
__ ldr(elements_array_storage,
|
||||
FieldMemOperand(array_function,
|
||||
JSFunction::kPrototypeOrInitialMapOffset));
|
||||
|
||||
// Check whether an empty sized array is requested.
|
||||
__ tst(array_size, array_size);
|
||||
__ b(ne, ¬_empty);
|
||||
|
||||
// If an empty array is requested allocate a small elements array anyway. This
|
||||
// keeps the code below free of special casing for the empty array.
|
||||
int size = JSArray::kSize +
|
||||
FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
|
||||
__ AllocateInNewSpace(size,
|
||||
result,
|
||||
elements_array_end,
|
||||
scratch1,
|
||||
gc_required,
|
||||
TAG_OBJECT);
|
||||
__ jmp(&allocated);
|
||||
if (FLAG_debug_code) { // Assert that array size is not zero.
|
||||
Label not_empty;
|
||||
__ tst(array_size, array_size);
|
||||
__ b(ne, ¬_empty);
|
||||
__ Abort("array size is unexpectedly 0");
|
||||
__ bind(¬_empty);
|
||||
}
|
||||
|
||||
// Allocate the JSArray object together with space for a FixedArray with the
|
||||
// requested number of elements.
|
||||
__ bind(¬_empty);
|
||||
STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
|
||||
__ mov(elements_array_end,
|
||||
Operand((JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize));
|
||||
@ -226,7 +208,6 @@ static void AllocateJSArray(MacroAssembler* masm,
|
||||
// result: JSObject
|
||||
// elements_array_storage: initial map
|
||||
// array_size: size of array (smi)
|
||||
__ bind(&allocated);
|
||||
__ str(elements_array_storage, FieldMemOperand(result, JSObject::kMapOffset));
|
||||
__ LoadRoot(elements_array_storage, Heap::kEmptyFixedArrayRootIndex);
|
||||
__ str(elements_array_storage,
|
||||
@ -256,14 +237,6 @@ static void AllocateJSArray(MacroAssembler* masm,
|
||||
ASSERT_EQ(0 * kPointerSize, FixedArray::kMapOffset);
|
||||
__ str(scratch1, MemOperand(elements_array_storage, kPointerSize, PostIndex));
|
||||
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);
|
||||
__ str(array_size,
|
||||
MemOperand(elements_array_storage, kPointerSize, PostIndex));
|
||||
@ -311,20 +284,20 @@ static void AllocateJSArray(MacroAssembler* masm,
|
||||
static void ArrayNativeCode(MacroAssembler* masm,
|
||||
Label* call_generic_code) {
|
||||
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.
|
||||
__ cmp(r0, Operand(0, RelocInfo::NONE));
|
||||
__ b(ne, &argc_one_or_more);
|
||||
|
||||
// Handle construction of an empty array.
|
||||
__ bind(&empty_array);
|
||||
AllocateEmptyJSArray(masm,
|
||||
r1,
|
||||
r2,
|
||||
r3,
|
||||
r4,
|
||||
r5,
|
||||
JSArray::kPreallocatedArrayElements,
|
||||
call_generic_code);
|
||||
__ IncrementCounter(counters->array_function_native(), 1, r3, r4);
|
||||
// Setup return value, remove receiver from stack and return.
|
||||
@ -339,6 +312,13 @@ static void ArrayNativeCode(MacroAssembler* masm,
|
||||
__ b(ne, &argc_two_or_more);
|
||||
STATIC_ASSERT(kSmiTag == 0);
|
||||
__ ldr(r2, MemOperand(sp)); // Get the argument from the stack.
|
||||
__ tst(r2, r2);
|
||||
__ b(ne, ¬_empty_array);
|
||||
__ Drop(1); // Adjust stack.
|
||||
__ mov(r0, Operand(0)); // Treat this as a call with argc of zero.
|
||||
__ b(&empty_array);
|
||||
|
||||
__ bind(¬_empty_array);
|
||||
__ and_(r3, r2, Operand(kIntptrSignBit | kSmiTagMask), SetCC);
|
||||
__ b(ne, call_generic_code);
|
||||
|
||||
|
@ -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
|
||||
// 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.
|
||||
@ -929,10 +925,9 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
Register scratch3,
|
||||
int initial_capacity,
|
||||
Label* gc_required) {
|
||||
int initial_capacity = JSArray::kPreallocatedArrayElements;
|
||||
ASSERT(initial_capacity >= 0);
|
||||
|
||||
// Load the initial map from the array function.
|
||||
__ mov(scratch1, FieldOperand(array_function,
|
||||
JSFunction::kPrototypeOrInitialMapOffset));
|
||||
@ -990,7 +985,6 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
|
||||
// Fill the FixedArray with the hole value. Inline the code if short.
|
||||
// Reconsider loop unfolding if kPreallocatedArrayElements gets changed.
|
||||
static const int kLoopUnfoldLimit = 4;
|
||||
STATIC_ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit);
|
||||
if (initial_capacity <= kLoopUnfoldLimit) {
|
||||
// Use a scratch register here to have only one reloc info when unfolding
|
||||
// the loop.
|
||||
@ -1153,7 +1147,6 @@ static void ArrayNativeCode(MacroAssembler* masm,
|
||||
ebx,
|
||||
ecx,
|
||||
edi,
|
||||
kPreallocatedArrayElements,
|
||||
&prepare_generic_code_call);
|
||||
__ IncrementCounter(masm->isolate()->counters()->array_function_native(), 1);
|
||||
__ pop(ebx);
|
||||
@ -1182,7 +1175,7 @@ static void ArrayNativeCode(MacroAssembler* masm,
|
||||
__ mov(eax, Operand(esp, i * kPointerSize));
|
||||
__ 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.
|
||||
__ jmp(&empty_array);
|
||||
|
||||
|
@ -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
|
||||
// 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.
|
||||
@ -1007,8 +1003,8 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
Register scratch3,
|
||||
int initial_capacity,
|
||||
Label* gc_required) {
|
||||
int initial_capacity = JSArray::kPreallocatedArrayElements;
|
||||
ASSERT(initial_capacity >= 0);
|
||||
|
||||
// Load the initial map from the array function.
|
||||
@ -1067,7 +1063,6 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
|
||||
// Fill the FixedArray with the hole value. Inline the code if short.
|
||||
// Reconsider loop unfolding if kPreallocatedArrayElements gets changed.
|
||||
static const int kLoopUnfoldLimit = 4;
|
||||
ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit);
|
||||
__ Move(scratch3, FACTORY->the_hole_value());
|
||||
if (initial_capacity <= kLoopUnfoldLimit) {
|
||||
// Use a scratch register here to have only one reloc info when unfolding
|
||||
@ -1101,38 +1096,28 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
|
||||
// register elements_array is scratched.
|
||||
static void AllocateJSArray(MacroAssembler* masm,
|
||||
Register array_function, // Array function.
|
||||
Register array_size, // As a smi.
|
||||
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) {
|
||||
Label not_empty, allocated;
|
||||
|
||||
// Load the initial map from the array function.
|
||||
__ movq(elements_array,
|
||||
FieldOperand(array_function,
|
||||
JSFunction::kPrototypeOrInitialMapOffset));
|
||||
|
||||
// Check whether an empty sized array is requested.
|
||||
__ testq(array_size, array_size);
|
||||
__ j(not_zero, ¬_empty);
|
||||
|
||||
// If an empty array is requested allocate a small elements array anyway. This
|
||||
// keeps the code below free of special casing for the empty array.
|
||||
int size = JSArray::kSize + FixedArray::SizeFor(kPreallocatedArrayElements);
|
||||
__ AllocateInNewSpace(size,
|
||||
result,
|
||||
elements_array_end,
|
||||
scratch,
|
||||
gc_required,
|
||||
TAG_OBJECT);
|
||||
__ jmp(&allocated);
|
||||
if (FLAG_debug_code) { // Assert that array size is not zero.
|
||||
Label not_empty;
|
||||
__ testq(array_size, array_size);
|
||||
__ j(not_zero, ¬_empty);
|
||||
__ int3();
|
||||
__ bind(¬_empty);
|
||||
}
|
||||
|
||||
// Allocate the JSArray object together with space for a FixedArray with the
|
||||
// requested elements.
|
||||
__ bind(¬_empty);
|
||||
SmiIndex index =
|
||||
masm->SmiToIndex(kScratchRegister, array_size, kPointerSizeLog2);
|
||||
__ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize,
|
||||
@ -1150,7 +1135,6 @@ static void AllocateJSArray(MacroAssembler* masm,
|
||||
// elements_array: initial map
|
||||
// elements_array_end: start of next object
|
||||
// array_size: size of array (smi)
|
||||
__ bind(&allocated);
|
||||
__ movq(FieldOperand(result, JSObject::kMapOffset), elements_array);
|
||||
__ Move(elements_array, FACTORY->empty_fixed_array());
|
||||
__ movq(FieldOperand(result, JSArray::kPropertiesOffset), elements_array);
|
||||
@ -1172,15 +1156,6 @@ static void AllocateJSArray(MacroAssembler* masm,
|
||||
// array_size: size of array (smi)
|
||||
__ Move(FieldOperand(elements_array, JSObject::kMapOffset),
|
||||
FACTORY->fixed_array_map());
|
||||
Label not_empty_2, fill_array;
|
||||
__ SmiTest(array_size);
|
||||
__ j(not_zero, ¬_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(¬_empty_2);
|
||||
// For non-empty JSArrays the length of the FixedArray and the JSArray is the
|
||||
// same.
|
||||
__ movq(FieldOperand(elements_array, FixedArray::kLengthOffset), array_size);
|
||||
@ -1189,7 +1164,6 @@ static void AllocateJSArray(MacroAssembler* masm,
|
||||
// result: JSObject
|
||||
// elements_array: elements array
|
||||
// elements_array_end: start of next object
|
||||
__ bind(&fill_array);
|
||||
if (fill_with_hole) {
|
||||
Label loop, entry;
|
||||
__ Move(scratch, FACTORY->the_hole_value());
|
||||
@ -1222,12 +1196,13 @@ static void AllocateJSArray(MacroAssembler* masm,
|
||||
// a construct call and a normal call.
|
||||
static void ArrayNativeCode(MacroAssembler* masm,
|
||||
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.
|
||||
__ testq(rax, rax);
|
||||
__ j(not_zero, &argc_one_or_more);
|
||||
|
||||
__ bind(&empty_array);
|
||||
// Handle construction of an empty array.
|
||||
AllocateEmptyJSArray(masm,
|
||||
rdi,
|
||||
@ -1235,7 +1210,6 @@ static void ArrayNativeCode(MacroAssembler* masm,
|
||||
rcx,
|
||||
rdx,
|
||||
r8,
|
||||
kPreallocatedArrayElements,
|
||||
call_generic_code);
|
||||
Counters* counters = masm->isolate()->counters();
|
||||
__ IncrementCounter(counters->array_function_native(), 1);
|
||||
@ -1248,6 +1222,16 @@ static void ArrayNativeCode(MacroAssembler* masm,
|
||||
__ cmpq(rax, Immediate(1));
|
||||
__ j(not_equal, &argc_two_or_more);
|
||||
__ movq(rdx, Operand(rsp, kPointerSize)); // Get the argument from the stack.
|
||||
|
||||
__ SmiTest(rdx);
|
||||
__ j(not_zero, ¬_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(¬_empty_array);
|
||||
__ JumpUnlessNonNegativeSmi(rdx, call_generic_code);
|
||||
|
||||
// Handle construction of an empty array of a certain size. Bail out if size
|
||||
|
Loading…
Reference in New Issue
Block a user