Commit 38acad67 authored by antonm@chromium.org's avatar antonm@chromium.org

Faster filling newly allocated arrays with the holes from the Array construction stub.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3995 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 6bee49dd
...@@ -753,6 +753,13 @@ void Assembler::cmov(Condition cc, Register dst, const Operand& src) { ...@@ -753,6 +753,13 @@ void Assembler::cmov(Condition cc, Register dst, const Operand& src) {
} }
void Assembler::cld() {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xFC);
}
void Assembler::rep_movs() { void Assembler::rep_movs() {
EnsureSpace ensure_space(this); EnsureSpace ensure_space(this);
last_pc_ = pc_; last_pc_ = pc_;
...@@ -761,6 +768,14 @@ void Assembler::rep_movs() { ...@@ -761,6 +768,14 @@ void Assembler::rep_movs() {
} }
void Assembler::rep_stos() {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xF3);
EMIT(0xAB);
}
void Assembler::xchg(Register dst, Register src) { void Assembler::xchg(Register dst, Register src) {
EnsureSpace ensure_space(this); EnsureSpace ensure_space(this);
last_pc_ = pc_; last_pc_ = pc_;
......
...@@ -542,8 +542,12 @@ class Assembler : public Malloced { ...@@ -542,8 +542,12 @@ class Assembler : public Malloced {
void cmov(Condition cc, Register dst, Handle<Object> handle); void cmov(Condition cc, Register dst, Handle<Object> handle);
void cmov(Condition cc, Register dst, const Operand& src); void cmov(Condition cc, Register dst, const Operand& src);
// Flag management.
void cld();
// Repetitive string instructions. // Repetitive string instructions.
void rep_movs(); void rep_movs();
void rep_stos();
// Exchange two registers // Exchange two registers
void xchg(Register dst, Register src); void xchg(Register dst, Register src);
......
...@@ -797,38 +797,23 @@ static void AllocateEmptyJSArray(MacroAssembler* masm, ...@@ -797,38 +797,23 @@ 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; ASSERT(scratch.is(edi)); // rep stos destination
ASSERT(!fill_with_hole || array_size.is(ecx)); // rep stos count
// Load the initial map from the array function. // Load the initial map from the array function.
__ mov(elements_array, __ mov(elements_array,
FieldOperand(array_function, FieldOperand(array_function,
JSFunction::kPrototypeOrInitialMapOffset)); JSFunction::kPrototypeOrInitialMapOffset));
// Check whether an empty sized array is requested.
__ test(array_size, Operand(array_size));
__ j(not_zero, &not_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);
// 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);
ASSERT(kSmiTagSize == 1 && kSmiTag == 0); ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
__ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize, __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize,
times_half_pointer_size, // array_size is a smi. times_half_pointer_size, // array_size is a smi.
...@@ -845,7 +830,6 @@ static void AllocateJSArray(MacroAssembler* masm, ...@@ -845,7 +830,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);
__ mov(FieldOperand(result, JSObject::kMapOffset), elements_array); __ mov(FieldOperand(result, JSObject::kMapOffset), elements_array);
__ mov(elements_array, Factory::empty_fixed_array()); __ mov(elements_array, Factory::empty_fixed_array());
__ mov(FieldOperand(result, JSArray::kPropertiesOffset), elements_array); __ mov(FieldOperand(result, JSArray::kPropertiesOffset), elements_array);
...@@ -869,15 +853,6 @@ static void AllocateJSArray(MacroAssembler* masm, ...@@ -869,15 +853,6 @@ static void AllocateJSArray(MacroAssembler* masm,
__ SmiUntag(array_size); // Convert from smi to value. __ SmiUntag(array_size); // Convert from smi to value.
__ mov(FieldOperand(elements_array, JSObject::kMapOffset), __ mov(FieldOperand(elements_array, JSObject::kMapOffset),
Factory::fixed_array_map()); Factory::fixed_array_map());
Label not_empty_2, fill_array;
__ test(array_size, Operand(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.
__ mov(FieldOperand(elements_array, Array::kLengthOffset),
Immediate(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.
__ mov(FieldOperand(elements_array, Array::kLengthOffset), array_size); __ mov(FieldOperand(elements_array, Array::kLengthOffset), array_size);
...@@ -885,20 +860,18 @@ static void AllocateJSArray(MacroAssembler* masm, ...@@ -885,20 +860,18 @@ static void AllocateJSArray(MacroAssembler* masm,
// Fill the allocated FixedArray with the hole value if requested. // Fill the allocated FixedArray with the hole value if requested.
// result: JSObject // result: JSObject
// elements_array: elements array // elements_array: elements array
// elements_array_end: start of next object
__ bind(&fill_array);
if (fill_with_hole) { if (fill_with_hole) {
Label loop, entry; __ lea(edi, Operand(elements_array,
__ mov(scratch, Factory::the_hole_value()); FixedArray::kHeaderSize - kHeapObjectTag));
__ lea(elements_array, Operand(elements_array,
FixedArray::kHeaderSize - kHeapObjectTag)); __ push(eax);
__ jmp(&entry); __ mov(eax, Factory::the_hole_value());
__ bind(&loop);
__ mov(Operand(elements_array, 0), scratch); __ cld();
__ add(Operand(elements_array), Immediate(kPointerSize)); __ rep_stos();
__ bind(&entry);
__ cmp(elements_array, Operand(elements_array_end)); // Restore saved registers.
__ j(below, &loop); __ pop(eax);
} }
} }
...@@ -920,7 +893,8 @@ static void AllocateJSArray(MacroAssembler* masm, ...@@ -920,7 +893,8 @@ static void AllocateJSArray(MacroAssembler* masm,
static void ArrayNativeCode(MacroAssembler* masm, static void ArrayNativeCode(MacroAssembler* masm,
bool construct_call, bool construct_call,
Label* call_generic_code) { Label* call_generic_code) {
Label argc_one_or_more, argc_two_or_more, prepare_generic_code_call; Label argc_one_or_more, argc_two_or_more, prepare_generic_code_call,
empty_array, not_empty_array;
// Push the constructor and argc. No need to tag argc as a smi, as there will // 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. // be no garbage collection with this on the stack.
...@@ -936,6 +910,7 @@ static void ArrayNativeCode(MacroAssembler* masm, ...@@ -936,6 +910,7 @@ static void ArrayNativeCode(MacroAssembler* masm,
__ test(eax, Operand(eax)); __ test(eax, Operand(eax));
__ 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,
edi, edi,
...@@ -958,30 +933,41 @@ static void ArrayNativeCode(MacroAssembler* masm, ...@@ -958,30 +933,41 @@ static void ArrayNativeCode(MacroAssembler* masm,
__ cmp(eax, 1); __ cmp(eax, 1);
__ j(not_equal, &argc_two_or_more); __ j(not_equal, &argc_two_or_more);
ASSERT(kSmiTag == 0); ASSERT(kSmiTag == 0);
__ test(Operand(esp, (push_count + 1) * kPointerSize), __ mov(ecx, Operand(esp, (push_count + 1) * kPointerSize));
Immediate(kIntptrSignBit | kSmiTagMask)); __ test(ecx, Operand(ecx));
__ j(not_zero, &not_empty_array);
// Case above assumes there is only a single slot to drop in
// ret, but we have two.
for (int i = push_count; i >= 0; i--) {
__ mov(eax, Operand(esp, i * kPointerSize));
__ mov(Operand(esp, (i + 1) * kPointerSize), eax);
}
__ add(Operand(esp), Immediate(kPointerSize));
__ jmp(&empty_array);
__ bind(&not_empty_array);
__ test(ecx, Immediate(kIntptrSignBit | kSmiTagMask));
__ j(not_zero, &prepare_generic_code_call); __ j(not_zero, &prepare_generic_code_call);
// Handle construction of an empty array of a certain size. Get the size from // 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 // the stack and bail out if size is to large to actually allocate an elements
// array. // array.
__ mov(edx, Operand(esp, (push_count + 1) * kPointerSize)); __ cmp(ecx, JSObject::kInitialMaxFastElementArray << kSmiTagSize);
ASSERT(kSmiTag == 0);
__ cmp(edx, JSObject::kInitialMaxFastElementArray << kSmiTagSize);
__ j(greater_equal, &prepare_generic_code_call); __ j(greater_equal, &prepare_generic_code_call);
// edx: array_size (smi) // edx: array_size (smi)
// edi: constructor // edi: constructor
// esp[0]: argc // esp[0]: argc (cannot be 0 here)
// esp[4]: constructor (only if construct_call) // esp[4]: constructor (only if construct_call)
// esp[8]: return address // esp[8]: return address
// esp[C]: argument // esp[C]: argument
AllocateJSArray(masm, AllocateJSArray(masm,
edi, edi,
edx, ecx,
eax, eax,
ebx, ebx,
ecx, edx,
edi, edi,
true, true,
&prepare_generic_code_call); &prepare_generic_code_call);
......
...@@ -89,6 +89,7 @@ static ByteMnemonic zero_operands_instr[] = { ...@@ -89,6 +89,7 @@ static ByteMnemonic zero_operands_instr[] = {
{0x9E, "sahf", UNSET_OP_ORDER}, {0x9E, "sahf", UNSET_OP_ORDER},
{0x99, "cdq", UNSET_OP_ORDER}, {0x99, "cdq", UNSET_OP_ORDER},
{0x9B, "fwait", UNSET_OP_ORDER}, {0x9B, "fwait", UNSET_OP_ORDER},
{0xFC, "cld", UNSET_OP_ORDER},
{-1, "", UNSET_OP_ORDER} {-1, "", UNSET_OP_ORDER}
}; };
...@@ -1218,6 +1219,9 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer, ...@@ -1218,6 +1219,9 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
} else if (*(data+1) == 0xA5) { } else if (*(data+1) == 0xA5) {
data += 2; data += 2;
AppendToBuffer("rep_movs"); AppendToBuffer("rep_movs");
} else if (*(data+1) == 0xAB) {
data += 2;
AppendToBuffer("rep_stos");
} else { } else {
UnimplementedInstruction(); UnimplementedInstruction();
} }
......
...@@ -234,7 +234,9 @@ TEST(DisasmIa320) { ...@@ -234,7 +234,9 @@ TEST(DisasmIa320) {
__ imul(edx, ecx, 12); __ imul(edx, ecx, 12);
__ imul(edx, ecx, 1000); __ imul(edx, ecx, 1000);
__ cld();
__ rep_movs(); __ rep_movs();
__ rep_stos();
__ sub(edx, Operand(ebx, ecx, times_4, 10000)); __ sub(edx, Operand(ebx, ecx, times_4, 10000));
__ sub(edx, Operand(ebx)); __ sub(edx, Operand(ebx));
......
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