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:
danno@chromium.org 2011-10-19 11:36:55 +00:00
parent e27d8fcbdc
commit e5f23399b4
23 changed files with 581 additions and 177 deletions

View File

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

View File

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

View File

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

View File

@ -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_;
}
};

View File

@ -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,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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;

View File

@ -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;

View File

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

View File

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

View File

@ -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) \

View File

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

View File

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

View File

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

View File

@ -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(&not_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);
}

View File

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

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

View File

@ -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.