Support array literals with FAST_DOUBLE_ELEMENTS ElementsKind.
BUG=none TEST=test/mjsunit/array-literal.js Review URL: http://codereview.chromium.org/8258015 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9698 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
e27d8fcbdc
commit
e5f23399b4
@ -263,7 +263,12 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
|
||||
// [sp + (2 * kPointerSize)]: literals array.
|
||||
|
||||
// All sizes here are multiples of kPointerSize.
|
||||
int elements_size = (length_ > 0) ? FixedArray::SizeFor(length_) : 0;
|
||||
int elements_size = 0;
|
||||
if (length_ > 0) {
|
||||
elements_size = mode_ == CLONE_DOUBLE_ELEMENTS
|
||||
? FixedDoubleArray::SizeFor(length_)
|
||||
: FixedArray::SizeFor(length_);
|
||||
}
|
||||
int size = JSArray::kSize + elements_size;
|
||||
|
||||
// Load boilerplate object into r3 and check if we need to create a
|
||||
@ -283,6 +288,9 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
|
||||
if (mode_ == CLONE_ELEMENTS) {
|
||||
message = "Expected (writable) fixed array";
|
||||
expected_map_index = Heap::kFixedArrayMapRootIndex;
|
||||
} else if (mode_ == CLONE_DOUBLE_ELEMENTS) {
|
||||
message = "Expected (writable) fixed double array";
|
||||
expected_map_index = Heap::kFixedDoubleArrayMapRootIndex;
|
||||
} else {
|
||||
ASSERT(mode_ == COPY_ON_WRITE_ELEMENTS);
|
||||
message = "Expected copy-on-write fixed array";
|
||||
@ -322,6 +330,7 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
|
||||
__ str(r2, FieldMemOperand(r0, JSArray::kElementsOffset));
|
||||
|
||||
// Copy the elements array.
|
||||
ASSERT((elements_size % kPointerSize) == 0);
|
||||
__ CopyFields(r2, r3, r1.bit(), elements_size / kPointerSize);
|
||||
}
|
||||
|
||||
|
@ -1467,13 +1467,19 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
|
||||
ZoneList<Expression*>* subexprs = expr->values();
|
||||
int length = subexprs->length();
|
||||
Handle<FixedArray> constant_elements = expr->constant_elements();
|
||||
ASSERT_EQ(2, constant_elements->length());
|
||||
ElementsKind constant_elements_kind =
|
||||
static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
|
||||
Handle<FixedArrayBase> constant_elements_values(
|
||||
FixedArrayBase::cast(constant_elements->get(1)));
|
||||
|
||||
__ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
__ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
|
||||
__ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
|
||||
__ mov(r1, Operand(expr->constant_elements()));
|
||||
__ mov(r1, Operand(constant_elements));
|
||||
__ Push(r3, r2, r1);
|
||||
if (expr->constant_elements()->map() ==
|
||||
if (constant_elements_values->map() ==
|
||||
isolate()->heap()->fixed_cow_array_map()) {
|
||||
FastCloneShallowArrayStub stub(
|
||||
FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
|
||||
@ -1485,8 +1491,14 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
} else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
|
||||
__ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
|
||||
} else {
|
||||
FastCloneShallowArrayStub stub(
|
||||
FastCloneShallowArrayStub::CLONE_ELEMENTS, length);
|
||||
ASSERT(constant_elements_kind == FAST_ELEMENTS ||
|
||||
constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
|
||||
FLAG_smi_only_arrays);
|
||||
FastCloneShallowArrayStub::Mode mode =
|
||||
constant_elements_kind == FAST_DOUBLE_ELEMENTS
|
||||
? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
|
||||
: FastCloneShallowArrayStub::CLONE_ELEMENTS;
|
||||
FastCloneShallowArrayStub stub(mode, length);
|
||||
__ CallStub(&stub);
|
||||
}
|
||||
|
||||
@ -1509,24 +1521,56 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
}
|
||||
VisitForAccumulatorValue(subexpr);
|
||||
|
||||
// Store the subexpression value in the array's elements.
|
||||
__ ldr(r6, MemOperand(sp)); // Copy of array literal.
|
||||
__ ldr(r1, FieldMemOperand(r6, JSObject::kElementsOffset));
|
||||
__ ldr(r2, FieldMemOperand(r6, JSObject::kMapOffset));
|
||||
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
|
||||
__ str(result_register(), FieldMemOperand(r1, offset));
|
||||
|
||||
Label no_map_change;
|
||||
__ JumpIfSmi(result_register(), &no_map_change);
|
||||
// Update the write barrier for the array store with r0 as the scratch
|
||||
// register.
|
||||
Label element_done;
|
||||
Label double_elements;
|
||||
Label smi_element;
|
||||
Label slow_elements;
|
||||
Label fast_elements;
|
||||
__ CheckFastElements(r2, r3, &double_elements);
|
||||
|
||||
// FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS
|
||||
__ JumpIfSmi(result_register(), &smi_element);
|
||||
__ CheckFastSmiOnlyElements(r2, r3, &fast_elements);
|
||||
|
||||
// Store into the array literal requires a elements transition. Call into
|
||||
// the runtime.
|
||||
__ bind(&slow_elements);
|
||||
__ push(r6); // Copy of array literal.
|
||||
__ mov(r1, Operand(Smi::FromInt(i)));
|
||||
__ mov(r2, Operand(Smi::FromInt(NONE))); // PropertyAttributes
|
||||
__ mov(r3, Operand(Smi::FromInt(strict_mode_flag()))); // Strict mode.
|
||||
__ Push(r1, result_register(), r2, r3);
|
||||
__ CallRuntime(Runtime::kSetProperty, 5);
|
||||
__ b(&element_done);
|
||||
|
||||
// Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS.
|
||||
__ bind(&double_elements);
|
||||
__ mov(r3, Operand(Smi::FromInt(i)));
|
||||
__ StoreNumberToDoubleElements(result_register(), r3, r6, r1, r4, r5, r9,
|
||||
r7, &slow_elements);
|
||||
__ b(&element_done);
|
||||
|
||||
// Array literal has ElementsKind of FAST_ELEMENTS and value is an object.
|
||||
__ bind(&fast_elements);
|
||||
__ str(result_register(), FieldMemOperand(r1, offset));
|
||||
// Update the write barrier for the array store.
|
||||
__ RecordWriteField(
|
||||
r1, offset, result_register(), r2, kLRHasBeenSaved, kDontSaveFPRegs,
|
||||
EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
|
||||
__ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
|
||||
__ CheckFastSmiOnlyElements(r3, r2, &no_map_change);
|
||||
__ push(r6); // Copy of array literal.
|
||||
__ CallRuntime(Runtime::kNonSmiElementStored, 1);
|
||||
__ bind(&no_map_change);
|
||||
__ b(&element_done);
|
||||
|
||||
// Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or
|
||||
// FAST_ELEMENTS, and value is Smi.
|
||||
__ bind(&smi_element);
|
||||
__ str(result_register(), FieldMemOperand(r1, offset));
|
||||
// Fall through
|
||||
|
||||
__ bind(&element_done);
|
||||
|
||||
PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
|
||||
}
|
||||
|
@ -4235,10 +4235,15 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
|
||||
Handle<FixedArray> constant_elements = instr->hydrogen()->constant_elements();
|
||||
ASSERT_EQ(2, constant_elements->length());
|
||||
ElementsKind constant_elements_kind =
|
||||
static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
|
||||
|
||||
__ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
__ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
|
||||
__ mov(r2, Operand(Smi::FromInt(instr->hydrogen()->literal_index())));
|
||||
__ mov(r1, Operand(instr->hydrogen()->constant_elements()));
|
||||
__ mov(r1, Operand(constant_elements));
|
||||
__ Push(r3, r2, r1);
|
||||
|
||||
// Pick the right runtime function or stub to call.
|
||||
@ -4255,7 +4260,9 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
|
||||
CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
|
||||
} else {
|
||||
FastCloneShallowArrayStub::Mode mode =
|
||||
FastCloneShallowArrayStub::CLONE_ELEMENTS;
|
||||
constant_elements_kind == FAST_DOUBLE_ELEMENTS
|
||||
? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
|
||||
: FastCloneShallowArrayStub::CLONE_ELEMENTS;
|
||||
FastCloneShallowArrayStub stub(mode, length);
|
||||
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
||||
}
|
||||
|
@ -363,6 +363,7 @@ class FastCloneShallowArrayStub : public CodeStub {
|
||||
|
||||
enum Mode {
|
||||
CLONE_ELEMENTS,
|
||||
CLONE_DOUBLE_ELEMENTS,
|
||||
COPY_ON_WRITE_ELEMENTS
|
||||
};
|
||||
|
||||
@ -381,8 +382,8 @@ class FastCloneShallowArrayStub : public CodeStub {
|
||||
|
||||
Major MajorKey() { return FastCloneShallowArray; }
|
||||
int MinorKey() {
|
||||
ASSERT(mode_ == 0 || mode_ == 1);
|
||||
return (length_ << 1) | mode_;
|
||||
ASSERT(mode_ == 0 || mode_ == 1 || mode_ == 2);
|
||||
return length_ * 3 + mode_;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -59,13 +59,13 @@ Handle<FixedArray> Factory::NewFixedArrayWithHoles(int size,
|
||||
}
|
||||
|
||||
|
||||
Handle<FixedArray> Factory::NewFixedDoubleArray(int size,
|
||||
PretenureFlag pretenure) {
|
||||
Handle<FixedDoubleArray> Factory::NewFixedDoubleArray(int size,
|
||||
PretenureFlag pretenure) {
|
||||
ASSERT(0 <= size);
|
||||
CALL_HEAP_FUNCTION(
|
||||
isolate(),
|
||||
isolate()->heap()->AllocateUninitializedFixedDoubleArray(size, pretenure),
|
||||
FixedArray);
|
||||
FixedDoubleArray);
|
||||
}
|
||||
|
||||
|
||||
@ -471,6 +471,12 @@ Handle<FixedArray> Factory::CopyFixedArray(Handle<FixedArray> array) {
|
||||
}
|
||||
|
||||
|
||||
Handle<FixedDoubleArray> Factory::CopyFixedDoubleArray(
|
||||
Handle<FixedDoubleArray> array) {
|
||||
CALL_HEAP_FUNCTION(isolate(), array->Copy(), FixedDoubleArray);
|
||||
}
|
||||
|
||||
|
||||
Handle<JSFunction> Factory::BaseNewFunctionFromSharedFunctionInfo(
|
||||
Handle<SharedFunctionInfo> function_info,
|
||||
Handle<Map> function_map,
|
||||
|
@ -50,7 +50,7 @@ class Factory {
|
||||
PretenureFlag pretenure = NOT_TENURED);
|
||||
|
||||
// Allocate a new uninitialized fixed double array.
|
||||
Handle<FixedArray> NewFixedDoubleArray(
|
||||
Handle<FixedDoubleArray> NewFixedDoubleArray(
|
||||
int size,
|
||||
PretenureFlag pretenure = NOT_TENURED);
|
||||
|
||||
@ -222,6 +222,9 @@ class Factory {
|
||||
|
||||
Handle<FixedArray> CopyFixedArray(Handle<FixedArray> array);
|
||||
|
||||
Handle<FixedDoubleArray> CopyFixedDoubleArray(
|
||||
Handle<FixedDoubleArray> array);
|
||||
|
||||
// Numbers (eg, literals) are pretenured by the parser.
|
||||
Handle<Object> NewNumber(double value,
|
||||
PretenureFlag pretenure = NOT_TENURED);
|
||||
|
@ -1235,7 +1235,10 @@ void HConstant::PrintDataTo(StringStream* stream) {
|
||||
|
||||
|
||||
bool HArrayLiteral::IsCopyOnWrite() const {
|
||||
return constant_elements()->map() == HEAP->fixed_cow_array_map();
|
||||
Handle<FixedArray> constant_elements = this->constant_elements();
|
||||
FixedArrayBase* constant_elements_values =
|
||||
FixedArrayBase::cast(constant_elements->get(1));
|
||||
return constant_elements_values->map() == HEAP->fixed_cow_array_map();
|
||||
}
|
||||
|
||||
|
||||
|
@ -3337,11 +3337,8 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
HValue* value = Pop();
|
||||
if (!Smi::IsValid(i)) return Bailout("Non-smi key in array literal");
|
||||
|
||||
// Load the elements array before the first store.
|
||||
if (elements == NULL) {
|
||||
elements = new(zone()) HLoadElements(literal);
|
||||
AddInstruction(elements);
|
||||
}
|
||||
elements = new(zone()) HLoadElements(literal);
|
||||
AddInstruction(elements);
|
||||
|
||||
HValue* key = AddInstruction(
|
||||
new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)),
|
||||
@ -3365,10 +3362,10 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
set_current_block(check_smi_only_elements);
|
||||
HCompareConstantEqAndBranch* smi_elements_check =
|
||||
new(zone()) HCompareConstantEqAndBranch(elements_kind,
|
||||
FAST_SMI_ONLY_ELEMENTS,
|
||||
FAST_ELEMENTS,
|
||||
Token::EQ_STRICT);
|
||||
smi_elements_check->SetSuccessorAt(0, store_generic);
|
||||
smi_elements_check->SetSuccessorAt(1, store_fast_edgesplit2);
|
||||
smi_elements_check->SetSuccessorAt(0, store_fast_edgesplit2);
|
||||
smi_elements_check->SetSuccessorAt(1, store_generic);
|
||||
current_block()->Finish(smi_elements_check);
|
||||
store_fast_edgesplit2->Finish(new(zone()) HGoto(store_fast));
|
||||
|
||||
|
@ -239,7 +239,12 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
|
||||
// [esp + (3 * kPointerSize)]: literals array.
|
||||
|
||||
// All sizes here are multiples of kPointerSize.
|
||||
int elements_size = (length_ > 0) ? FixedArray::SizeFor(length_) : 0;
|
||||
int elements_size = 0;
|
||||
if (length_ > 0) {
|
||||
elements_size = mode_ == CLONE_DOUBLE_ELEMENTS
|
||||
? FixedDoubleArray::SizeFor(length_)
|
||||
: FixedArray::SizeFor(length_);
|
||||
}
|
||||
int size = JSArray::kSize + elements_size;
|
||||
|
||||
// Load boilerplate object into ecx and check if we need to create a
|
||||
@ -262,6 +267,9 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
|
||||
if (mode_ == CLONE_ELEMENTS) {
|
||||
message = "Expected (writable) fixed array";
|
||||
expected_map = factory->fixed_array_map();
|
||||
} else if (mode_ == CLONE_DOUBLE_ELEMENTS) {
|
||||
message = "Expected (writable) fixed double array";
|
||||
expected_map = factory->fixed_double_array_map();
|
||||
} else {
|
||||
ASSERT(mode_ == COPY_ON_WRITE_ELEMENTS);
|
||||
message = "Expected copy-on-write fixed array";
|
||||
@ -294,9 +302,24 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
|
||||
__ mov(FieldOperand(eax, JSArray::kElementsOffset), edx);
|
||||
|
||||
// Copy the elements array.
|
||||
for (int i = 0; i < elements_size; i += kPointerSize) {
|
||||
__ mov(ebx, FieldOperand(ecx, i));
|
||||
__ mov(FieldOperand(edx, i), ebx);
|
||||
if (mode_ == CLONE_ELEMENTS) {
|
||||
for (int i = 0; i < elements_size; i += kPointerSize) {
|
||||
__ mov(ebx, FieldOperand(ecx, i));
|
||||
__ mov(FieldOperand(edx, i), ebx);
|
||||
}
|
||||
} else {
|
||||
ASSERT(mode_ == CLONE_DOUBLE_ELEMENTS);
|
||||
int i;
|
||||
for (i = 0; i < FixedDoubleArray::kHeaderSize; i += kPointerSize) {
|
||||
__ mov(ebx, FieldOperand(ecx, i));
|
||||
__ mov(FieldOperand(edx, i), ebx);
|
||||
}
|
||||
while (i < elements_size) {
|
||||
__ fld_d(FieldOperand(ecx, i));
|
||||
__ fstp_d(FieldOperand(edx, i));
|
||||
i += kDoubleSize;
|
||||
}
|
||||
ASSERT(i == elements_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1448,12 +1448,18 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
|
||||
ZoneList<Expression*>* subexprs = expr->values();
|
||||
int length = subexprs->length();
|
||||
Handle<FixedArray> constant_elements = expr->constant_elements();
|
||||
ASSERT_EQ(2, constant_elements->length());
|
||||
ElementsKind constant_elements_kind =
|
||||
static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
|
||||
Handle<FixedArrayBase> constant_elements_values(
|
||||
FixedArrayBase::cast(constant_elements->get(1)));
|
||||
|
||||
__ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
__ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
|
||||
__ push(Immediate(Smi::FromInt(expr->literal_index())));
|
||||
__ push(Immediate(expr->constant_elements()));
|
||||
if (expr->constant_elements()->map() ==
|
||||
__ push(Immediate(constant_elements));
|
||||
if (constant_elements_values->map() ==
|
||||
isolate()->heap()->fixed_cow_array_map()) {
|
||||
ASSERT(expr->depth() == 1);
|
||||
FastCloneShallowArrayStub stub(
|
||||
@ -1465,8 +1471,14 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
} else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
|
||||
__ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
|
||||
} else {
|
||||
FastCloneShallowArrayStub stub(
|
||||
FastCloneShallowArrayStub::CLONE_ELEMENTS, length);
|
||||
ASSERT(constant_elements_kind == FAST_ELEMENTS ||
|
||||
constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
|
||||
FLAG_smi_only_arrays);
|
||||
FastCloneShallowArrayStub::Mode mode =
|
||||
constant_elements_kind == FAST_DOUBLE_ELEMENTS
|
||||
? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
|
||||
: FastCloneShallowArrayStub::CLONE_ELEMENTS;
|
||||
FastCloneShallowArrayStub stub(mode, length);
|
||||
__ CallStub(&stub);
|
||||
}
|
||||
|
||||
@ -1492,22 +1504,61 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
|
||||
// Store the subexpression value in the array's elements.
|
||||
__ mov(ebx, Operand(esp, 0)); // Copy of array literal.
|
||||
__ mov(edi, FieldOperand(ebx, JSObject::kMapOffset));
|
||||
__ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
|
||||
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
|
||||
__ mov(FieldOperand(ebx, offset), result_register());
|
||||
|
||||
Label no_map_change;
|
||||
__ JumpIfSmi(result_register(), &no_map_change);
|
||||
Label element_done;
|
||||
Label double_elements;
|
||||
Label smi_element;
|
||||
Label slow_elements;
|
||||
Label fast_elements;
|
||||
__ CheckFastElements(edi, &double_elements);
|
||||
|
||||
// FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS
|
||||
__ JumpIfSmi(result_register(), &smi_element);
|
||||
__ CheckFastSmiOnlyElements(edi, &fast_elements, Label::kNear);
|
||||
|
||||
// Store into the array literal requires a elements transition. Call into
|
||||
// the runtime.
|
||||
__ bind(&slow_elements);
|
||||
__ push(Operand(esp, 0)); // Copy of array literal.
|
||||
__ push(Immediate(Smi::FromInt(i)));
|
||||
__ push(result_register());
|
||||
__ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
|
||||
__ push(Immediate(Smi::FromInt(strict_mode_flag()))); // Strict mode.
|
||||
__ CallRuntime(Runtime::kSetProperty, 5);
|
||||
__ jmp(&element_done);
|
||||
|
||||
// Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS.
|
||||
__ bind(&double_elements);
|
||||
__ mov(ecx, Immediate(Smi::FromInt(i)));
|
||||
__ StoreNumberToDoubleElements(result_register(),
|
||||
ebx,
|
||||
ecx,
|
||||
edx,
|
||||
xmm0,
|
||||
&slow_elements,
|
||||
false);
|
||||
__ jmp(&element_done);
|
||||
|
||||
// Array literal has ElementsKind of FAST_ELEMENTS and value is an object.
|
||||
__ bind(&fast_elements);
|
||||
__ mov(FieldOperand(ebx, offset), result_register());
|
||||
// Update the write barrier for the array store.
|
||||
__ RecordWriteField(ebx, offset, result_register(), ecx,
|
||||
kDontSaveFPRegs,
|
||||
EMIT_REMEMBERED_SET,
|
||||
OMIT_SMI_CHECK);
|
||||
__ mov(edi, FieldOperand(ebx, JSObject::kMapOffset));
|
||||
__ CheckFastSmiOnlyElements(edi, &no_map_change, Label::kNear);
|
||||
__ push(Operand(esp, 0));
|
||||
__ CallRuntime(Runtime::kNonSmiElementStored, 1);
|
||||
__ bind(&no_map_change);
|
||||
__ jmp(&element_done);
|
||||
|
||||
// Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or
|
||||
// FAST_ELEMENTS, and value is Smi.
|
||||
__ bind(&smi_element);
|
||||
__ mov(FieldOperand(ebx, offset), result_register());
|
||||
// Fall through
|
||||
|
||||
__ bind(&element_done);
|
||||
|
||||
PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
|
||||
}
|
||||
|
@ -4130,11 +4130,17 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
|
||||
|
||||
void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
|
||||
ASSERT(ToRegister(instr->context()).is(esi));
|
||||
|
||||
Handle<FixedArray> constant_elements = instr->hydrogen()->constant_elements();
|
||||
ASSERT_EQ(2, constant_elements->length());
|
||||
ElementsKind constant_elements_kind =
|
||||
static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
|
||||
|
||||
// Setup the parameters to the stub/runtime call.
|
||||
__ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
__ push(FieldOperand(eax, JSFunction::kLiteralsOffset));
|
||||
__ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
|
||||
__ push(Immediate(instr->hydrogen()->constant_elements()));
|
||||
__ push(Immediate(constant_elements));
|
||||
|
||||
// Pick the right runtime function or stub to call.
|
||||
int length = instr->hydrogen()->length();
|
||||
@ -4150,7 +4156,9 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
|
||||
CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
|
||||
} else {
|
||||
FastCloneShallowArrayStub::Mode mode =
|
||||
FastCloneShallowArrayStub::CLONE_ELEMENTS;
|
||||
constant_elements_kind == FAST_DOUBLE_ELEMENTS
|
||||
? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
|
||||
: FastCloneShallowArrayStub::CLONE_ELEMENTS;
|
||||
FastCloneShallowArrayStub stub(mode, length);
|
||||
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
||||
}
|
||||
|
@ -4583,6 +4583,12 @@ MaybeObject* FixedArray::Copy() {
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* FixedDoubleArray::Copy() {
|
||||
if (length() == 0) return this;
|
||||
return GetHeap()->CopyFixedDoubleArray(this);
|
||||
}
|
||||
|
||||
|
||||
Relocatable::Relocatable(Isolate* isolate) {
|
||||
ASSERT(isolate == Isolate::Current());
|
||||
isolate_ = isolate;
|
||||
|
@ -2199,6 +2199,9 @@ class FixedDoubleArray: public FixedArrayBase {
|
||||
// Checking for the hole.
|
||||
inline bool is_the_hole(int index);
|
||||
|
||||
// Copy operations
|
||||
MUST_USE_RESULT inline MaybeObject* Copy();
|
||||
|
||||
// Garbage collection support.
|
||||
inline static int SizeFor(int length) {
|
||||
return kHeaderSize + length * kDoubleSize;
|
||||
|
@ -3288,9 +3288,11 @@ Expression* Parser::ParseArrayLiteral(bool* ok) {
|
||||
// Update the scope information before the pre-parsing bailout.
|
||||
int literal_index = lexical_scope_->NextMaterializedLiteralIndex();
|
||||
|
||||
// Allocate a fixed array with all the literals.
|
||||
Handle<FixedArray> literals =
|
||||
// Allocate a fixed array to hold all the object literals.
|
||||
Handle<FixedArray> object_literals =
|
||||
isolate()->factory()->NewFixedArray(values->length(), TENURED);
|
||||
Handle<FixedDoubleArray> double_literals;
|
||||
ElementsKind elements_kind = FAST_SMI_ONLY_ELEMENTS;
|
||||
|
||||
// Fill in the literals.
|
||||
bool is_simple = true;
|
||||
@ -3302,19 +3304,75 @@ Expression* Parser::ParseArrayLiteral(bool* ok) {
|
||||
}
|
||||
Handle<Object> boilerplate_value = GetBoilerplateValue(values->at(i));
|
||||
if (boilerplate_value->IsUndefined()) {
|
||||
literals->set_the_hole(i);
|
||||
object_literals->set_the_hole(i);
|
||||
if (elements_kind == FAST_DOUBLE_ELEMENTS) {
|
||||
double_literals->set_the_hole(i);
|
||||
}
|
||||
is_simple = false;
|
||||
} else {
|
||||
literals->set(i, *boilerplate_value);
|
||||
// Examine each literal element, and adjust the ElementsKind if the
|
||||
// literal element is not of a type that can be stored in the current
|
||||
// ElementsKind. Start with FAST_SMI_ONLY_ELEMENTS, and transition to
|
||||
// FAST_DOUBLE_ELEMENTS and FAST_ELEMENTS as necessary. Always remember
|
||||
// the tagged value, no matter what the ElementsKind is in case we
|
||||
// ultimately end up in FAST_ELEMENTS.
|
||||
object_literals->set(i, *boilerplate_value);
|
||||
if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
|
||||
// Smi only elements. Notice if a transition to FAST_DOUBLE_ELEMENTS or
|
||||
// FAST_ELEMENTS is required.
|
||||
if (!boilerplate_value->IsSmi()) {
|
||||
if (boilerplate_value->IsNumber() && FLAG_smi_only_arrays) {
|
||||
// Allocate a double array on the FAST_DOUBLE_ELEMENTS transition to
|
||||
// avoid over-allocating in TENURED space.
|
||||
double_literals = isolate()->factory()->NewFixedDoubleArray(
|
||||
values->length(), TENURED);
|
||||
// Copy the contents of the FAST_SMI_ONLY_ELEMENT array to the
|
||||
// FAST_DOUBLE_ELEMENTS array so that they are in sync.
|
||||
for (int j = 0; j < i; ++j) {
|
||||
Object* smi_value = object_literals->get(j);
|
||||
if (smi_value->IsTheHole()) {
|
||||
double_literals->set_the_hole(j);
|
||||
} else {
|
||||
double_literals->set(j, Smi::cast(smi_value)->value());
|
||||
}
|
||||
}
|
||||
double_literals->set(i, boilerplate_value->Number());
|
||||
elements_kind = FAST_DOUBLE_ELEMENTS;
|
||||
} else {
|
||||
elements_kind = FAST_ELEMENTS;
|
||||
}
|
||||
}
|
||||
} else if (elements_kind == FAST_DOUBLE_ELEMENTS) {
|
||||
// Continue to store double values in to FAST_DOUBLE_ELEMENTS arrays
|
||||
// until the first value is seen that can't be stored as a double.
|
||||
if (boilerplate_value->IsNumber()) {
|
||||
double_literals->set(i, boilerplate_value->Number());
|
||||
} else {
|
||||
elements_kind = FAST_ELEMENTS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Simple and shallow arrays can be lazily copied, we transform the
|
||||
// elements array to a copy-on-write array.
|
||||
if (is_simple && depth == 1 && values->length() > 0) {
|
||||
literals->set_map(isolate()->heap()->fixed_cow_array_map());
|
||||
if (is_simple && depth == 1 && values->length() > 0 &&
|
||||
elements_kind != FAST_DOUBLE_ELEMENTS) {
|
||||
object_literals->set_map(isolate()->heap()->fixed_cow_array_map());
|
||||
}
|
||||
|
||||
Handle<FixedArrayBase> element_values = elements_kind == FAST_DOUBLE_ELEMENTS
|
||||
? Handle<FixedArrayBase>(double_literals)
|
||||
: Handle<FixedArrayBase>(object_literals);
|
||||
|
||||
// Remember both the literal's constant values as well as the ElementsKind
|
||||
// in a 2-element FixedArray.
|
||||
Handle<FixedArray> literals =
|
||||
isolate()->factory()->NewFixedArray(2, TENURED);
|
||||
|
||||
literals->set(0, Smi::FromInt(elements_kind));
|
||||
literals->set(1, *element_values);
|
||||
|
||||
return new(zone()) ArrayLiteral(
|
||||
isolate(), literals, values, literal_index, is_simple, depth);
|
||||
}
|
||||
|
145
src/runtime.cc
145
src/runtime.cc
@ -432,64 +432,77 @@ static Handle<Object> CreateArrayLiteralBoilerplate(
|
||||
// Create the JSArray.
|
||||
Handle<JSFunction> constructor(
|
||||
JSFunction::GlobalContextFromLiterals(*literals)->array_function());
|
||||
Handle<Object> object = isolate->factory()->NewJSObject(constructor);
|
||||
Handle<JSArray> object =
|
||||
Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
|
||||
|
||||
if (elements->length() > kSmiOnlyLiteralMinimumLength) {
|
||||
Handle<Map> smi_array_map = isolate->factory()->GetElementsTransitionMap(
|
||||
Handle<JSObject>::cast(object),
|
||||
FAST_SMI_ONLY_ELEMENTS);
|
||||
HeapObject::cast(*object)->set_map(*smi_array_map);
|
||||
ElementsKind constant_elements_kind =
|
||||
static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
|
||||
Handle<FixedArrayBase> constant_elements_values(
|
||||
FixedArrayBase::cast(elements->get(1)));
|
||||
|
||||
ASSERT(FLAG_smi_only_arrays || constant_elements_kind == FAST_ELEMENTS ||
|
||||
constant_elements_kind == FAST_SMI_ONLY_ELEMENTS);
|
||||
bool allow_literal_kind_transition = FLAG_smi_only_arrays &&
|
||||
constant_elements_kind > object->GetElementsKind();
|
||||
|
||||
if (!FLAG_smi_only_arrays &&
|
||||
constant_elements_values->length() > kSmiOnlyLiteralMinimumLength &&
|
||||
constant_elements_kind != object->GetElementsKind()) {
|
||||
allow_literal_kind_transition = true;
|
||||
}
|
||||
|
||||
const bool is_cow =
|
||||
(elements->map() == isolate->heap()->fixed_cow_array_map());
|
||||
Handle<FixedArray> copied_elements =
|
||||
is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
|
||||
// If the ElementsKind of the constant values of the array literal are less
|
||||
// specific than the ElementsKind of the boilerplate array object, change the
|
||||
// boilerplate array object's map to reflect that kind.
|
||||
if (allow_literal_kind_transition) {
|
||||
Handle<Map> transitioned_array_map =
|
||||
isolate->factory()->GetElementsTransitionMap(object,
|
||||
constant_elements_kind);
|
||||
object->set_map(*transitioned_array_map);
|
||||
}
|
||||
|
||||
Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
|
||||
bool has_non_smi = false;
|
||||
if (is_cow) {
|
||||
// Copy-on-write arrays must be shallow (and simple).
|
||||
for (int i = 0; i < content->length(); i++) {
|
||||
Object* current = content->get(i);
|
||||
ASSERT(!current->IsFixedArray());
|
||||
if (!current->IsSmi() && !current->IsTheHole()) {
|
||||
has_non_smi = true;
|
||||
}
|
||||
}
|
||||
#if DEBUG
|
||||
for (int i = 0; i < content->length(); i++) {
|
||||
ASSERT(!content->get(i)->IsFixedArray());
|
||||
}
|
||||
#endif
|
||||
Handle<FixedArrayBase> copied_elements_values;
|
||||
if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
|
||||
ASSERT(FLAG_smi_only_arrays);
|
||||
copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
|
||||
Handle<FixedDoubleArray>::cast(constant_elements_values));
|
||||
} else {
|
||||
for (int i = 0; i < content->length(); i++) {
|
||||
Object* current = content->get(i);
|
||||
if (current->IsFixedArray()) {
|
||||
// The value contains the constant_properties of a
|
||||
// simple object or array literal.
|
||||
Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
|
||||
Handle<Object> result =
|
||||
CreateLiteralBoilerplate(isolate, literals, fa);
|
||||
if (result.is_null()) return result;
|
||||
content->set(i, *result);
|
||||
has_non_smi = true;
|
||||
} else {
|
||||
if (!current->IsSmi() && !current->IsTheHole()) {
|
||||
has_non_smi = true;
|
||||
ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
|
||||
constant_elements_kind == FAST_ELEMENTS);
|
||||
const bool is_cow =
|
||||
(constant_elements_values->map() ==
|
||||
isolate->heap()->fixed_cow_array_map());
|
||||
if (is_cow) {
|
||||
copied_elements_values = constant_elements_values;
|
||||
#if DEBUG
|
||||
Handle<FixedArray> fixed_array_values =
|
||||
Handle<FixedArray>::cast(copied_elements_values);
|
||||
for (int i = 0; i < fixed_array_values->length(); i++) {
|
||||
ASSERT(!fixed_array_values->get(i)->IsFixedArray());
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
Handle<FixedArray> fixed_array_values =
|
||||
Handle<FixedArray>::cast(constant_elements_values);
|
||||
Handle<FixedArray> fixed_array_values_copy =
|
||||
isolate->factory()->CopyFixedArray(fixed_array_values);
|
||||
copied_elements_values = fixed_array_values_copy;
|
||||
for (int i = 0; i < fixed_array_values->length(); i++) {
|
||||
Object* current = fixed_array_values->get(i);
|
||||
if (current->IsFixedArray()) {
|
||||
// The value contains the constant_properties of a
|
||||
// simple object or array literal.
|
||||
Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
|
||||
Handle<Object> result =
|
||||
CreateLiteralBoilerplate(isolate, literals, fa);
|
||||
if (result.is_null()) return result;
|
||||
fixed_array_values_copy->set(i, *result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the elements.
|
||||
Handle<JSArray> js_object(Handle<JSArray>::cast(object));
|
||||
isolate->factory()->SetContent(js_object, content);
|
||||
|
||||
if (has_non_smi && js_object->HasFastSmiOnlyElements()) {
|
||||
isolate->factory()->EnsureCanContainNonSmiElements(js_object);
|
||||
}
|
||||
|
||||
object->set_elements(*copied_elements_values);
|
||||
object->set_length(Smi::FromInt(copied_elements_values->length()));
|
||||
return object;
|
||||
}
|
||||
|
||||
@ -1663,19 +1676,6 @@ RUNTIME_FUNCTION(MaybeObject*,
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_NonSmiElementStored) {
|
||||
ASSERT(args.length() == 1);
|
||||
CONVERT_ARG_CHECKED(JSObject, object, 0);
|
||||
if (object->HasFastSmiOnlyElements()) {
|
||||
MaybeObject* maybe_map = object->GetElementsTransitionMap(FAST_ELEMENTS);
|
||||
Map* map;
|
||||
if (!maybe_map->To<Map>(&map)) return maybe_map;
|
||||
object->set_map(Map::cast(map));
|
||||
}
|
||||
return *object;
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
|
||||
HandleScope scope(isolate);
|
||||
ASSERT(args.length() == 4);
|
||||
@ -7735,14 +7735,21 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
|
||||
int year, month, day;
|
||||
DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
|
||||
|
||||
RUNTIME_ASSERT(res_array->elements()->map() ==
|
||||
isolate->heap()->fixed_array_map());
|
||||
FixedArray* elms = FixedArray::cast(res_array->elements());
|
||||
RUNTIME_ASSERT(elms->length() == 3);
|
||||
FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
|
||||
RUNTIME_ASSERT(elms_base->length() == 3);
|
||||
RUNTIME_ASSERT(res_array->GetElementsKind() <= FAST_DOUBLE_ELEMENTS);
|
||||
|
||||
elms->set(0, Smi::FromInt(year));
|
||||
elms->set(1, Smi::FromInt(month));
|
||||
elms->set(2, Smi::FromInt(day));
|
||||
if (res_array->HasFastDoubleElements()) {
|
||||
FixedDoubleArray* elms = FixedDoubleArray::cast(res_array->elements());
|
||||
elms->set(0, year);
|
||||
elms->set(1, month);
|
||||
elms->set(2, day);
|
||||
} else {
|
||||
FixedArray* elms = FixedArray::cast(res_array->elements());
|
||||
elms->set(0, Smi::FromInt(year));
|
||||
elms->set(1, Smi::FromInt(month));
|
||||
elms->set(2, Smi::FromInt(day));
|
||||
}
|
||||
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
@ -278,7 +278,7 @@ namespace internal {
|
||||
\
|
||||
/* Literals */ \
|
||||
F(MaterializeRegExpLiteral, 4, 1)\
|
||||
F(CreateArrayLiteralBoilerplate, 3, 1) \
|
||||
F(CreateArrayLiteralBoilerplate, 4, 1) \
|
||||
F(CloneLiteralBoilerplate, 1, 1) \
|
||||
F(CloneShallowLiteralBoilerplate, 1, 1) \
|
||||
F(CreateObjectLiteral, 4, 1) \
|
||||
@ -330,8 +330,6 @@ namespace internal {
|
||||
F(InitializeConstContextSlot, 3, 1) \
|
||||
F(OptimizeObjectForAddingMultipleProperties, 2, 1) \
|
||||
\
|
||||
/* Arrays */ \
|
||||
F(NonSmiElementStored, 1, 1) \
|
||||
/* Debugging */ \
|
||||
F(DebugPrint, 1, 1) \
|
||||
F(DebugTrace, 0, 1) \
|
||||
|
@ -227,7 +227,12 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
|
||||
// [rsp + (3 * kPointerSize)]: literals array.
|
||||
|
||||
// All sizes here are multiples of kPointerSize.
|
||||
int elements_size = (length_ > 0) ? FixedArray::SizeFor(length_) : 0;
|
||||
int elements_size = 0;
|
||||
if (length_ > 0) {
|
||||
elements_size = mode_ == CLONE_DOUBLE_ELEMENTS
|
||||
? FixedDoubleArray::SizeFor(length_)
|
||||
: FixedArray::SizeFor(length_);
|
||||
}
|
||||
int size = JSArray::kSize + elements_size;
|
||||
|
||||
// Load boilerplate object into rcx and check if we need to create a
|
||||
@ -247,6 +252,9 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
|
||||
if (mode_ == CLONE_ELEMENTS) {
|
||||
message = "Expected (writable) fixed array";
|
||||
expected_map_index = Heap::kFixedArrayMapRootIndex;
|
||||
} else if (mode_ == CLONE_DOUBLE_ELEMENTS) {
|
||||
message = "Expected (writable) fixed double array";
|
||||
expected_map_index = Heap::kFixedDoubleArrayMapRootIndex;
|
||||
} else {
|
||||
ASSERT(mode_ == COPY_ON_WRITE_ELEMENTS);
|
||||
message = "Expected copy-on-write fixed array";
|
||||
@ -280,9 +288,24 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
|
||||
__ movq(FieldOperand(rax, JSArray::kElementsOffset), rdx);
|
||||
|
||||
// Copy the elements array.
|
||||
for (int i = 0; i < elements_size; i += kPointerSize) {
|
||||
__ movq(rbx, FieldOperand(rcx, i));
|
||||
__ movq(FieldOperand(rdx, i), rbx);
|
||||
if (mode_ == CLONE_ELEMENTS) {
|
||||
for (int i = 0; i < elements_size; i += kPointerSize) {
|
||||
__ movq(rbx, FieldOperand(rcx, i));
|
||||
__ movq(FieldOperand(rdx, i), rbx);
|
||||
}
|
||||
} else {
|
||||
ASSERT(mode_ == CLONE_DOUBLE_ELEMENTS);
|
||||
int i;
|
||||
for (i = 0; i < FixedDoubleArray::kHeaderSize; i += kPointerSize) {
|
||||
__ movq(rbx, FieldOperand(rcx, i));
|
||||
__ movq(FieldOperand(rdx, i), rbx);
|
||||
}
|
||||
while (i < elements_size) {
|
||||
__ movsd(xmm0, FieldOperand(rcx, i));
|
||||
__ movsd(FieldOperand(rdx, i), xmm0);
|
||||
i += kDoubleSize;
|
||||
}
|
||||
ASSERT(i == elements_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1417,12 +1417,18 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
|
||||
ZoneList<Expression*>* subexprs = expr->values();
|
||||
int length = subexprs->length();
|
||||
Handle<FixedArray> constant_elements = expr->constant_elements();
|
||||
ASSERT_EQ(2, constant_elements->length());
|
||||
ElementsKind constant_elements_kind =
|
||||
static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
|
||||
Handle<FixedArrayBase> constant_elements_values(
|
||||
FixedArrayBase::cast(constant_elements->get(1)));
|
||||
|
||||
__ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
__ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
|
||||
__ Push(Smi::FromInt(expr->literal_index()));
|
||||
__ Push(expr->constant_elements());
|
||||
if (expr->constant_elements()->map() ==
|
||||
__ Push(constant_elements);
|
||||
if (constant_elements_values->map() ==
|
||||
isolate()->heap()->fixed_cow_array_map()) {
|
||||
FastCloneShallowArrayStub stub(
|
||||
FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
|
||||
@ -1433,8 +1439,14 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
} else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
|
||||
__ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
|
||||
} else {
|
||||
FastCloneShallowArrayStub stub(
|
||||
FastCloneShallowArrayStub::CLONE_ELEMENTS, length);
|
||||
ASSERT(constant_elements_kind == FAST_ELEMENTS ||
|
||||
constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
|
||||
FLAG_smi_only_arrays);
|
||||
FastCloneShallowArrayStub::Mode mode =
|
||||
constant_elements_kind == FAST_DOUBLE_ELEMENTS
|
||||
? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
|
||||
: FastCloneShallowArrayStub::CLONE_ELEMENTS;
|
||||
FastCloneShallowArrayStub stub(mode, length);
|
||||
__ CallStub(&stub);
|
||||
}
|
||||
|
||||
@ -1459,22 +1471,59 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
|
||||
// Store the subexpression value in the array's elements.
|
||||
__ movq(r8, Operand(rsp, 0)); // Copy of array literal.
|
||||
__ movq(rdi, FieldOperand(r8, JSObject::kMapOffset));
|
||||
__ movq(rbx, FieldOperand(r8, JSObject::kElementsOffset));
|
||||
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
|
||||
__ movq(FieldOperand(rbx, offset), result_register());
|
||||
|
||||
Label no_map_change;
|
||||
__ JumpIfSmi(result_register(), &no_map_change);
|
||||
Label element_done;
|
||||
Label double_elements;
|
||||
Label smi_element;
|
||||
Label slow_elements;
|
||||
Label fast_elements;
|
||||
__ CheckFastElements(rdi, &double_elements);
|
||||
|
||||
// FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS
|
||||
__ JumpIfSmi(result_register(), &smi_element);
|
||||
__ CheckFastSmiOnlyElements(rdi, &fast_elements);
|
||||
|
||||
// Store into the array literal requires a elements transition. Call into
|
||||
// the runtime.
|
||||
__ bind(&slow_elements);
|
||||
__ push(r8); // Copy of array literal.
|
||||
__ Push(Smi::FromInt(i));
|
||||
__ push(result_register());
|
||||
__ Push(Smi::FromInt(NONE)); // PropertyAttributes
|
||||
__ Push(Smi::FromInt(strict_mode_flag())); // Strict mode.
|
||||
__ CallRuntime(Runtime::kSetProperty, 5);
|
||||
__ jmp(&element_done);
|
||||
|
||||
// Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS.
|
||||
__ bind(&double_elements);
|
||||
__ movq(rcx, Immediate(i));
|
||||
__ StoreNumberToDoubleElements(result_register(),
|
||||
rbx,
|
||||
rcx,
|
||||
xmm0,
|
||||
&slow_elements);
|
||||
__ jmp(&element_done);
|
||||
|
||||
// Array literal has ElementsKind of FAST_ELEMENTS and value is an object.
|
||||
__ bind(&fast_elements);
|
||||
__ movq(FieldOperand(rbx, offset), result_register());
|
||||
// Update the write barrier for the array store.
|
||||
__ RecordWriteField(rbx, offset, result_register(), rcx,
|
||||
kDontSaveFPRegs,
|
||||
EMIT_REMEMBERED_SET,
|
||||
OMIT_SMI_CHECK);
|
||||
__ movq(rdi, FieldOperand(rbx, JSObject::kMapOffset));
|
||||
__ CheckFastSmiOnlyElements(rdi, &no_map_change, Label::kNear);
|
||||
__ push(r8);
|
||||
__ CallRuntime(Runtime::kNonSmiElementStored, 1);
|
||||
__ bind(&no_map_change);
|
||||
__ jmp(&element_done);
|
||||
|
||||
// Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or
|
||||
// FAST_ELEMENTS, and value is Smi.
|
||||
__ bind(&smi_element);
|
||||
__ movq(FieldOperand(rbx, offset), result_register());
|
||||
// Fall through
|
||||
|
||||
__ bind(&element_done);
|
||||
|
||||
PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
|
||||
}
|
||||
|
@ -3859,6 +3859,11 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
|
||||
Handle<FixedArray> constant_elements = instr->hydrogen()->constant_elements();
|
||||
ASSERT_EQ(2, constant_elements->length());
|
||||
ElementsKind constant_elements_kind =
|
||||
static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
|
||||
|
||||
// Setup the parameters to the stub/runtime call.
|
||||
__ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
|
||||
__ push(FieldOperand(rax, JSFunction::kLiteralsOffset));
|
||||
@ -3879,7 +3884,9 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
|
||||
CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
|
||||
} else {
|
||||
FastCloneShallowArrayStub::Mode mode =
|
||||
FastCloneShallowArrayStub::CLONE_ELEMENTS;
|
||||
constant_elements_kind == FAST_DOUBLE_ELEMENTS
|
||||
? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
|
||||
: FastCloneShallowArrayStub::CLONE_ELEMENTS;
|
||||
FastCloneShallowArrayStub stub(mode, length);
|
||||
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
||||
}
|
||||
|
@ -2724,7 +2724,7 @@ void MacroAssembler::CheckFastSmiOnlyElements(Register map,
|
||||
void MacroAssembler::StoreNumberToDoubleElements(
|
||||
Register maybe_number,
|
||||
Register elements,
|
||||
Register key,
|
||||
Register index,
|
||||
XMMRegister xmm_scratch,
|
||||
Label* fail) {
|
||||
Label smi_value, is_nan, maybe_nan, not_nan, have_double_value, done;
|
||||
@ -2745,7 +2745,7 @@ void MacroAssembler::StoreNumberToDoubleElements(
|
||||
bind(¬_nan);
|
||||
movsd(xmm_scratch, FieldOperand(maybe_number, HeapNumber::kValueOffset));
|
||||
bind(&have_double_value);
|
||||
movsd(FieldOperand(elements, key, times_8, FixedDoubleArray::kHeaderSize),
|
||||
movsd(FieldOperand(elements, index, times_8, FixedDoubleArray::kHeaderSize),
|
||||
xmm_scratch);
|
||||
jmp(&done);
|
||||
|
||||
@ -2768,7 +2768,7 @@ void MacroAssembler::StoreNumberToDoubleElements(
|
||||
// Preserve original value.
|
||||
SmiToInteger32(kScratchRegister, maybe_number);
|
||||
cvtlsi2sd(xmm_scratch, kScratchRegister);
|
||||
movsd(FieldOperand(elements, key, times_8, FixedDoubleArray::kHeaderSize),
|
||||
movsd(FieldOperand(elements, index, times_8, FixedDoubleArray::kHeaderSize),
|
||||
xmm_scratch);
|
||||
bind(&done);
|
||||
}
|
||||
|
@ -864,12 +864,12 @@ class MacroAssembler: public Assembler {
|
||||
Label::Distance distance = Label::kFar);
|
||||
|
||||
// Check to see if maybe_number can be stored as a double in
|
||||
// FastDoubleElements. If it can, store it at the index specified by key in
|
||||
// the FastDoubleElements array elements, otherwise jump to fail.
|
||||
// Note that key must not be smi-tagged.
|
||||
// FastDoubleElements. If it can, store it at the index specified by index in
|
||||
// the FastDoubleElements array elements, otherwise jump to fail. Note that
|
||||
// index must not be smi-tagged.
|
||||
void StoreNumberToDoubleElements(Register maybe_number,
|
||||
Register elements,
|
||||
Register key,
|
||||
Register index,
|
||||
XMMRegister xmm_scratch,
|
||||
Label* fail);
|
||||
|
||||
|
125
test/mjsunit/array-literal-transitions.js
Normal file
125
test/mjsunit/array-literal-transitions.js
Normal file
@ -0,0 +1,125 @@
|
||||
// Copyright 2011 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Flags: --allow-natives-syntax --smi-only-arrays --expose-gc
|
||||
// Test element kind of objects.
|
||||
// Since --smi-only-arrays affects builtins, its default setting at compile
|
||||
// time sticks if built with snapshot. If --smi-only-arrays is deactivated
|
||||
// by default, only a no-snapshot build actually has smi-only arrays enabled
|
||||
// in this test case. Depending on whether smi-only arrays are actually
|
||||
// enabled, this test takes the appropriate code path to check smi-only arrays.
|
||||
|
||||
support_smi_only_arrays = %HasFastSmiOnlyElements(new Array());
|
||||
|
||||
// IC and Crankshaft support for smi-only elements in dynamic array literals.
|
||||
function get(foo) { return foo; } // Used to generate dynamic values.
|
||||
|
||||
function array_literal_test() {
|
||||
var a0 = [1, 2, 3];
|
||||
assertTrue(%HasFastSmiOnlyElements(a0));
|
||||
var a1 = [get(1), get(2), get(3)];
|
||||
assertTrue(%HasFastSmiOnlyElements(a1));
|
||||
|
||||
var b0 = [1, 2, get("three")];
|
||||
assertTrue(%HasFastElements(b0));
|
||||
var b1 = [get(1), get(2), get("three")];
|
||||
assertTrue(%HasFastElements(b1));
|
||||
|
||||
var c0 = [1, 2, get(3.5)];
|
||||
assertTrue(%HasFastDoubleElements(c0));
|
||||
assertEquals(3.5, c0[2]);
|
||||
assertEquals(2, c0[1]);
|
||||
assertEquals(1, c0[0]);
|
||||
|
||||
var c1 = [1, 2, 3.5];
|
||||
assertTrue(%HasFastDoubleElements(c1));
|
||||
assertEquals(3.5, c1[2]);
|
||||
assertEquals(2, c1[1]);
|
||||
assertEquals(1, c1[0]);
|
||||
|
||||
var c2 = [get(1), get(2), get(3.5)];
|
||||
assertTrue(%HasFastDoubleElements(c2));
|
||||
assertEquals(3.5, c2[2]);
|
||||
assertEquals(2, c2[1]);
|
||||
assertEquals(1, c2[0]);
|
||||
|
||||
var object = new Object();
|
||||
var d0 = [1, 2, object];
|
||||
assertTrue(%HasFastElements(d0));
|
||||
assertEquals(object, d0[2]);
|
||||
assertEquals(2, d0[1]);
|
||||
assertEquals(1, d0[0]);
|
||||
|
||||
var e0 = [1, 2, 3.5];
|
||||
assertTrue(%HasFastDoubleElements(e0));
|
||||
assertEquals(3.5, e0[2]);
|
||||
assertEquals(2, e0[1]);
|
||||
assertEquals(1, e0[0]);
|
||||
|
||||
var f0 = [1, 2, [1, 2]];
|
||||
assertTrue(%HasFastElements(f0));
|
||||
assertEquals([1,2], f0[2]);
|
||||
assertEquals(2, f0[1]);
|
||||
assertEquals(1, f0[0]);
|
||||
}
|
||||
|
||||
if (support_smi_only_arrays) {
|
||||
for (var i = 0; i < 3; i++) {
|
||||
array_literal_test();
|
||||
}
|
||||
%OptimizeFunctionOnNextCall(array_literal_test);
|
||||
array_literal_test();
|
||||
|
||||
function test_large_literal() {
|
||||
|
||||
function d() {
|
||||
gc();
|
||||
return 2.5;
|
||||
}
|
||||
|
||||
function o() {
|
||||
gc();
|
||||
return new Object();
|
||||
}
|
||||
|
||||
large =
|
||||
[ 0, 1, 2, 3, 4, 5, d(), d(), d(), d(), d(), d(), o(), o(), o(), o() ];
|
||||
assertFalse(%HasDictionaryElements(large));
|
||||
assertFalse(%HasFastSmiOnlyElements(large));
|
||||
assertFalse(%HasFastDoubleElements(large));
|
||||
assertTrue(%HasFastElements(large));
|
||||
assertEquals(large,
|
||||
[0, 1, 2, 3, 4, 5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5,
|
||||
new Object(), new Object(), new Object(), new Object()]);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 3; i++) {
|
||||
test_large_literal();
|
||||
}
|
||||
%OptimizeFunctionOnNextCall(test_large_literal);
|
||||
test_large_literal();
|
||||
}
|
@ -196,30 +196,6 @@ for (var i = 0; i < 3; i++) {
|
||||
polymorphic(smis, elements_kind.fast_smi_only);
|
||||
polymorphic(strings, elements_kind.fast);
|
||||
polymorphic(doubles, elements_kind.fast);
|
||||
|
||||
// Crankshaft support for smi-only elements in dynamic array literals.
|
||||
function get(foo) { return foo; } // Used to generate dynamic values.
|
||||
|
||||
function crankshaft_test() {
|
||||
var a = [get(1), get(2), get(3)];
|
||||
assertKind(elements_kind.fast_smi_only, a);
|
||||
var b = [get(1), get(2), get("three")];
|
||||
assertKind(elements_kind.fast, b);
|
||||
var c = [get(1), get(2), get(3.5)];
|
||||
// The full code generator doesn't support conversion to fast_double
|
||||
// yet. Crankshaft does, but only with --smi-only-arrays support.
|
||||
if ((%GetOptimizationStatus(crankshaft_test) & 1) &&
|
||||
support_smi_only_arrays) {
|
||||
assertKind(elements_kind.fast_double, c);
|
||||
} else {
|
||||
assertKind(elements_kind.fast, c);
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < 3; i++) {
|
||||
crankshaft_test();
|
||||
}
|
||||
%OptimizeFunctionOnNextCall(crankshaft_test);
|
||||
crankshaft_test();
|
||||
*/
|
||||
|
||||
// Elements_kind transitions for arrays.
|
||||
|
Loading…
Reference in New Issue
Block a user