// [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
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";
__ str(r2, FieldMemOperand(r0, JSArray::kElementsOffset));
// Copy the elements array.
+ ASSERT((elements_size % kPointerSize) == 0);
__ CopyFields(r2, r3, r1.bit(), elements_size / kPointerSize);
}
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);
} 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);
}
}
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);
}
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.
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);
}
enum Mode {
CLONE_ELEMENTS,
+ CLONE_DOUBLE_ELEMENTS,
COPY_ON_WRITE_ELEMENTS
};
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_;
}
};
}
-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);
}
}
+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,
PretenureFlag pretenure = NOT_TENURED);
// Allocate a new uninitialized fixed double array.
- Handle<FixedArray> NewFixedDoubleArray(
+ Handle<FixedDoubleArray> NewFixedDoubleArray(
int size,
PretenureFlag pretenure = NOT_TENURED);
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);
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();
}
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)),
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));
// [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
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";
__ 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);
}
}
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(
} 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);
}
// 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);
}
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();
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);
}
}
+MaybeObject* FixedDoubleArray::Copy() {
+ if (length() == 0) return this;
+ return GetHeap()->CopyFixedDoubleArray(this);
+}
+
+
Relocatable::Relocatable(Isolate* isolate) {
ASSERT(isolate == Isolate::Current());
isolate_ = isolate;
// 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;
// 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;
}
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);
}
// Create the JSArray.
Handle<JSFunction> constructor(
JSFunction::GlobalContextFromLiterals(*literals)->array_function());
- Handle<Object> object = 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);
- }
-
- const bool is_cow =
- (elements->map() == isolate->heap()->fixed_cow_array_map());
- Handle<FixedArray> copied_elements =
- is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
-
- 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;
- }
- }
+ Handle<JSArray> object =
+ Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
+
+ 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;
+ }
+
+ // 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<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 {
+ 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
- for (int i = 0; i < content->length(); i++) {
- ASSERT(!content->get(i)->IsFixedArray());
- }
+ 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 {
- 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;
+ } 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;
}
}
-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);
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();
}
\
/* 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) \
F(InitializeConstContextSlot, 3, 1) \
F(OptimizeObjectForAddingMultipleProperties, 2, 1) \
\
- /* Arrays */ \
- F(NonSmiElementStored, 1, 1) \
/* Debugging */ \
F(DebugPrint, 1, 1) \
F(DebugTrace, 0, 1) \
// [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
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";
__ 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);
}
}
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);
} 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);
}
// 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);
}
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));
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);
}
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;
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);
// 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);
}
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);
--- /dev/null
+// 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();
+}
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.