From acac89008d09dfee32a0916822d9b1b927dec734 Mon Sep 17 00:00:00 2001 From: "mstarzinger@chromium.org" Date: Thu, 7 Nov 2013 12:08:37 +0000 Subject: [PATCH] Defer allocation of constant literal properties. This moves building of constant properties and elements arrays for all materialized literals into the compiler. The parser no longer allocates while parsing ObjectLiteral and ArrayLiteral expressions. R=ulan@chromium.org Review URL: https://codereview.chromium.org/61873003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17557 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/full-codegen-arm.cc | 10 +- src/ast.cc | 163 +++++++++++++++++++++++++++++++++ src/ast.h | 80 ++++++++-------- src/hydrogen.cc | 2 + src/ia32/full-codegen-ia32.cc | 10 +- src/mips/full-codegen-mips.cc | 10 +- src/parser.cc | 166 ++-------------------------------- src/parser.h | 19 ---- src/x64/full-codegen-x64.cc | 10 +- 9 files changed, 241 insertions(+), 229 deletions(-) diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index a773893452..8fb1e15585 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -1634,6 +1634,9 @@ void FullCodeGenerator::EmitAccessor(Expression* expression) { void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { Comment cmnt(masm_, "[ ObjectLiteral"); + + int depth = 1; + expr->BuildConstantProperties(isolate(), &depth); Handle constant_properties = expr->constant_properties(); __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); @@ -1648,7 +1651,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ mov(r0, Operand(Smi::FromInt(flags))); int properties_count = constant_properties->length() / 2; if ((FLAG_track_double_fields && expr->may_store_doubles()) || - expr->depth() > 1 || Serializer::enabled() || + depth > 1 || Serializer::enabled() || flags != ObjectLiteral::kFastElements || properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) { __ Push(r3, r2, r1, r0); @@ -1767,6 +1770,8 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { Comment cmnt(masm_, "[ ArrayLiteral"); + int depth = 1; + expr->BuildConstantElements(isolate(), &depth); ZoneList* subexprs = expr->values(); int length = subexprs->length(); Handle constant_elements = expr->constant_elements(); @@ -1790,8 +1795,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { __ CallStub(&stub); __ IncrementCounter( isolate()->counters()->cow_arrays_created_stub(), 1, r1, r2); - } else if (expr->depth() > 1 || - Serializer::enabled() || + } else if (depth > 1 || Serializer::enabled() || length > FastCloneShallowArrayStub::kMaximumClonedLength) { __ Push(r3, r2, r1); __ CallRuntime(Runtime::kCreateArrayLiteral, 3); diff --git a/src/ast.cc b/src/ast.cc index 843f8c8960..9deb71d0af 100644 --- a/src/ast.cc +++ b/src/ast.cc @@ -256,6 +256,169 @@ void ObjectLiteral::CalculateEmitStore(Zone* zone) { } +bool ObjectLiteral::IsBoilerplateProperty(ObjectLiteral::Property* property) { + return property != NULL && + property->kind() != ObjectLiteral::Property::PROTOTYPE; +} + + +void ObjectLiteral::BuildConstantProperties(Isolate* isolate, int* depth) { + if (!constant_properties_.is_null()) return; + + // Allocate a fixed array to hold all the constant properties. + Handle constant_properties = isolate->factory()->NewFixedArray( + boilerplate_properties_ * 2, TENURED); + + int position = 0; + // Accumulate the value in local variables and store it at the end. + bool is_simple = true; + int depth_acc = 1; + uint32_t max_element_index = 0; + uint32_t elements = 0; + for (int i = 0; i < properties()->length(); i++) { + ObjectLiteral::Property* property = properties()->at(i); + if (!IsBoilerplateProperty(property)) { + is_simple = false; + continue; + } + MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral(); + if (m_literal != NULL) { + int inner_depth = 1; + m_literal->BuildConstants(isolate, &inner_depth); + if (inner_depth >= depth_acc) depth_acc = inner_depth + 1; + } + + // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined + // value for COMPUTED properties, the real value is filled in at + // runtime. The enumeration order is maintained. + Handle key = property->key()->value(); + Handle value = GetBoilerplateValue(property->value(), isolate); + + // Ensure objects that may, at any point in time, contain fields with double + // representation are always treated as nested objects. This is true for + // computed fields (value is undefined), and smi and double literals + // (value->IsNumber()). + // TODO(verwaest): Remove once we can store them inline. + if (FLAG_track_double_fields && + (value->IsNumber() || value->IsUninitialized())) { + may_store_doubles_ = true; + } + + is_simple = is_simple && !value->IsUninitialized(); + + // Keep track of the number of elements in the object literal and + // the largest element index. If the largest element index is + // much larger than the number of elements, creating an object + // literal with fast elements will be a waste of space. + uint32_t element_index = 0; + if (key->IsString() + && Handle::cast(key)->AsArrayIndex(&element_index) + && element_index > max_element_index) { + max_element_index = element_index; + elements++; + } else if (key->IsSmi()) { + int key_value = Smi::cast(*key)->value(); + if (key_value > 0 + && static_cast(key_value) > max_element_index) { + max_element_index = key_value; + } + elements++; + } + + // Add name, value pair to the fixed array. + constant_properties->set(position++, *key); + constant_properties->set(position++, *value); + } + + constant_properties_ = constant_properties; + fast_elements_ = + (max_element_index <= 32) || ((2 * elements) >= max_element_index); + set_is_simple(is_simple); + if (depth != NULL) *depth = depth_acc; +} + + +void ArrayLiteral::BuildConstantElements(Isolate* isolate, int* depth) { + if (!constant_elements_.is_null()) return; + + // Allocate a fixed array to hold all the object literals. + Handle array = + isolate->factory()->NewJSArray(0, FAST_HOLEY_SMI_ELEMENTS); + isolate->factory()->SetElementsCapacityAndLength( + array, values()->length(), values()->length()); + + // Fill in the literals. + bool is_simple = true; + int depth_acc = 1; + bool is_holey = false; + for (int i = 0, n = values()->length(); i < n; i++) { + Expression* element = values()->at(i); + MaterializedLiteral* m_literal = element->AsMaterializedLiteral(); + if (m_literal != NULL) { + int inner_depth = 1; + m_literal->BuildConstants(isolate, &inner_depth); + if (inner_depth + 1 > depth_acc) depth_acc = inner_depth + 1; + } + Handle boilerplate_value = GetBoilerplateValue(element, isolate); + if (boilerplate_value->IsTheHole()) { + is_holey = true; + } else if (boilerplate_value->IsUninitialized()) { + is_simple = false; + JSObject::SetOwnElement( + array, i, handle(Smi::FromInt(0), isolate), kNonStrictMode); + } else { + JSObject::SetOwnElement(array, i, boilerplate_value, kNonStrictMode); + } + } + + Handle element_values(array->elements()); + + // Simple and shallow arrays can be lazily copied, we transform the + // elements array to a copy-on-write array. + if (is_simple && depth_acc == 1 && values()->length() > 0 && + array->HasFastSmiOrObjectElements()) { + element_values->set_map(isolate->heap()->fixed_cow_array_map()); + } + + // Remember both the literal's constant values as well as the ElementsKind + // in a 2-element FixedArray. + Handle literals = isolate->factory()->NewFixedArray(2, TENURED); + + ElementsKind kind = array->GetElementsKind(); + kind = is_holey ? GetHoleyElementsKind(kind) : GetPackedElementsKind(kind); + + literals->set(0, Smi::FromInt(kind)); + literals->set(1, *element_values); + + constant_elements_ = literals; + set_is_simple(is_simple); + if (depth != NULL) *depth = depth_acc; +} + + +Handle MaterializedLiteral::GetBoilerplateValue(Expression* expression, + Isolate* isolate) { + if (expression->AsLiteral() != NULL) { + return expression->AsLiteral()->value(); + } + if (CompileTimeValue::IsCompileTimeValue(expression)) { + return CompileTimeValue::GetValue(isolate, expression); + } + return isolate->factory()->uninitialized_value(); +} + + +void MaterializedLiteral::BuildConstants(Isolate* isolate, int* depth) { + if (IsArrayLiteral()) { + return AsArrayLiteral()->BuildConstantElements(isolate, depth); + } + if (IsObjectLiteral()) { + return AsObjectLiteral()->BuildConstantProperties(isolate, depth); + } + ASSERT(IsRegExpLiteral()); +} + + void TargetCollector::AddTarget(Label* target, Zone* zone) { // Add the label to the collector, but discard duplicates. int length = targets_.length(); diff --git a/src/ast.h b/src/ast.h index b4f7348eee..42f6c8bd93 100644 --- a/src/ast.h +++ b/src/ast.h @@ -1409,27 +1409,35 @@ class MaterializedLiteral : public Expression { int literal_index() { return literal_index_; } - // A materialized literal is simple if the values consist of only - // constants and simple object and array literals. - bool is_simple() const { return is_simple_; } - - int depth() const { return depth_; } - protected: MaterializedLiteral(Isolate* isolate, int literal_index, - bool is_simple, - int depth, int pos) : Expression(isolate, pos), literal_index_(literal_index), - is_simple_(is_simple), - depth_(depth) {} + is_simple_(false) {} + + // A materialized literal is simple if the values consist of only + // constants and simple object and array literals. + bool is_simple() const { return is_simple_; } + void set_is_simple(bool is_simple) { is_simple_ = is_simple; } + friend class CompileTimeValue; + + // Populate the constant properties/elements fixed array. + void BuildConstants(Isolate* isolate, int* depth); + friend class ArrayLiteral; + friend class ObjectLiteral; + + // If the expression is a literal, return the literal value; + // if the expression is a materialized literal and is simple return a + // compile time value as encoded by CompileTimeValue::GetValue(). + // Otherwise, return undefined literal as the placeholder + // in the object literal boilerplate. + Handle GetBoilerplateValue(Expression* expression, Isolate* isolate); private: int literal_index_; bool is_simple_; - int depth_; }; @@ -1493,6 +1501,12 @@ class ObjectLiteral V8_FINAL : public MaterializedLiteral { bool may_store_doubles() const { return may_store_doubles_; } bool has_function() const { return has_function_; } + // Decide if a property should be in the object boilerplate. + static bool IsBoilerplateProperty(Property* property); + + // Populate the constant properties fixed array. + void BuildConstantProperties(Isolate* isolate, int* depth = NULL); + // Mark all computed expressions that are bound to a key that // is shadowed by a later occurrence of the same key. For the // marked expressions, no store code is emitted. @@ -1512,25 +1526,22 @@ class ObjectLiteral V8_FINAL : public MaterializedLiteral { protected: ObjectLiteral(Isolate* isolate, - Handle constant_properties, ZoneList* properties, int literal_index, - bool is_simple, - bool fast_elements, - int depth, - bool may_store_doubles, + int boilerplate_properties, bool has_function, int pos) - : MaterializedLiteral(isolate, literal_index, is_simple, depth, pos), - constant_properties_(constant_properties), + : MaterializedLiteral(isolate, literal_index, pos), properties_(properties), - fast_elements_(fast_elements), - may_store_doubles_(may_store_doubles), + boilerplate_properties_(boilerplate_properties), + fast_elements_(false), + may_store_doubles_(false), has_function_(has_function) {} private: Handle constant_properties_; ZoneList* properties_; + int boilerplate_properties_; bool fast_elements_; bool may_store_doubles_; bool has_function_; @@ -1551,7 +1562,7 @@ class RegExpLiteral V8_FINAL : public MaterializedLiteral { Handle flags, int literal_index, int pos) - : MaterializedLiteral(isolate, literal_index, false, 1, pos), + : MaterializedLiteral(isolate, literal_index, pos), pattern_(pattern), flags_(flags) {} @@ -1575,16 +1586,15 @@ class ArrayLiteral V8_FINAL : public MaterializedLiteral { return BailoutId(first_element_id_.ToInt() + i); } + // Populate the constant elements fixed array. + void BuildConstantElements(Isolate* isolate, int* depth = NULL); + protected: ArrayLiteral(Isolate* isolate, - Handle constant_elements, ZoneList* values, int literal_index, - bool is_simple, - int depth, int pos) - : MaterializedLiteral(isolate, literal_index, is_simple, depth, pos), - constant_elements_(constant_elements), + : MaterializedLiteral(isolate, literal_index, pos), values_(values), first_element_id_(ReserveIdRange(isolate, values->length())) {} @@ -3066,18 +3076,14 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED { } ObjectLiteral* NewObjectLiteral( - Handle constant_properties, ZoneList* properties, int literal_index, - bool is_simple, - bool fast_elements, - int depth, - bool may_store_doubles, + int boilerplate_properties, bool has_function, int pos) { ObjectLiteral* lit = new(zone_) ObjectLiteral( - isolate_, constant_properties, properties, literal_index, - is_simple, fast_elements, depth, may_store_doubles, has_function, pos); + isolate_, properties, literal_index, boilerplate_properties, + has_function, pos); VISIT_AND_RETURN(ObjectLiteral, lit) } @@ -3099,15 +3105,11 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED { VISIT_AND_RETURN(RegExpLiteral, lit); } - ArrayLiteral* NewArrayLiteral(Handle constant_elements, - ZoneList* values, + ArrayLiteral* NewArrayLiteral(ZoneList* values, int literal_index, - bool is_simple, - int depth, int pos) { ArrayLiteral* lit = new(zone_) ArrayLiteral( - isolate_, constant_elements, values, literal_index, is_simple, - depth, pos); + isolate_, values, literal_index, pos); VISIT_AND_RETURN(ArrayLiteral, lit) } diff --git a/src/hydrogen.cc b/src/hydrogen.cc index d6b97a8a15..307595256c 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -4310,6 +4310,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { ASSERT(!HasStackOverflow()); ASSERT(current_block() != NULL); ASSERT(current_block()->HasPredecessor()); + expr->BuildConstantProperties(isolate()); Handle closure = function_state()->compilation_info()->closure(); HInstruction* literal; @@ -4431,6 +4432,7 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { ASSERT(!HasStackOverflow()); ASSERT(current_block() != NULL); ASSERT(current_block()->HasPredecessor()); + expr->BuildConstantElements(isolate()); ZoneList* subexprs = expr->values(); int length = subexprs->length(); HInstruction* literal; diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 82d23e7791..b7ddeac0e4 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -1574,6 +1574,9 @@ void FullCodeGenerator::EmitAccessor(Expression* expression) { void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { Comment cmnt(masm_, "[ ObjectLiteral"); + + int depth = 1; + expr->BuildConstantProperties(isolate(), &depth); Handle constant_properties = expr->constant_properties(); int flags = expr->fast_elements() ? ObjectLiteral::kFastElements @@ -1583,7 +1586,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { : ObjectLiteral::kNoFlags; int properties_count = constant_properties->length() / 2; if ((FLAG_track_double_fields && expr->may_store_doubles()) || - expr->depth() > 1 || Serializer::enabled() || + depth > 1 || Serializer::enabled() || flags != ObjectLiteral::kFastElements || properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) { __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); @@ -1702,6 +1705,8 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { Comment cmnt(masm_, "[ ArrayLiteral"); + int depth = 1; + expr->BuildConstantElements(isolate(), &depth); ZoneList* subexprs = expr->values(); int length = subexprs->length(); Handle constant_elements = expr->constant_elements(); @@ -1728,8 +1733,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { DONT_TRACK_ALLOCATION_SITE, length); __ CallStub(&stub); - } else if (expr->depth() > 1 || - Serializer::enabled() || + } else if (depth > 1 || Serializer::enabled() || length > FastCloneShallowArrayStub::kMaximumClonedLength) { __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset)); diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc index b217e06db4..6947ca8781 100644 --- a/src/mips/full-codegen-mips.cc +++ b/src/mips/full-codegen-mips.cc @@ -1644,6 +1644,9 @@ void FullCodeGenerator::EmitAccessor(Expression* expression) { void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { Comment cmnt(masm_, "[ ObjectLiteral"); + + int depth = 1; + expr->BuildConstantProperties(isolate(), &depth); Handle constant_properties = expr->constant_properties(); __ lw(a3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); __ lw(a3, FieldMemOperand(a3, JSFunction::kLiteralsOffset)); @@ -1658,7 +1661,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ li(a0, Operand(Smi::FromInt(flags))); int properties_count = constant_properties->length() / 2; if ((FLAG_track_double_fields && expr->may_store_doubles()) || - expr->depth() > 1 || Serializer::enabled() || + depth > 1 || Serializer::enabled() || flags != ObjectLiteral::kFastElements || properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) { __ Push(a3, a2, a1, a0); @@ -1777,6 +1780,8 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { Comment cmnt(masm_, "[ ArrayLiteral"); + int depth = 1; + expr->BuildConstantElements(isolate(), &depth); ZoneList* subexprs = expr->values(); int length = subexprs->length(); @@ -1803,8 +1808,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { __ CallStub(&stub); __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1, a1, a2); - } else if (expr->depth() > 1 || - Serializer::enabled() || + } else if (depth > 1 || Serializer::enabled() || length > FastCloneShallowArrayStub::kMaximumClonedLength) { __ Push(a3, a2, a1); __ CallRuntime(Runtime::kCreateArrayLiteral, 3); diff --git a/src/parser.cc b/src/parser.cc index 837d46fb83..0b1bf63f5d 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -3660,61 +3660,7 @@ Expression* Parser::ParseArrayLiteral(bool* ok) { // Update the scope information before the pre-parsing bailout. int literal_index = current_function_state_->NextMaterializedLiteralIndex(); - // Allocate a fixed array to hold all the object literals. - Handle array = - isolate()->factory()->NewJSArray(0, FAST_HOLEY_SMI_ELEMENTS); - isolate()->factory()->SetElementsCapacityAndLength( - array, values->length(), values->length()); - - // Fill in the literals. - Heap* heap = isolate()->heap(); - bool is_simple = true; - int depth = 1; - bool is_holey = false; - for (int i = 0, n = values->length(); i < n; i++) { - MaterializedLiteral* m_literal = values->at(i)->AsMaterializedLiteral(); - if (m_literal != NULL && m_literal->depth() + 1 > depth) { - depth = m_literal->depth() + 1; - } - Handle boilerplate_value = GetBoilerplateValue(values->at(i)); - if (boilerplate_value->IsTheHole()) { - is_holey = true; - } else if (boilerplate_value->IsUninitialized()) { - is_simple = false; - JSObject::SetOwnElement( - array, i, handle(Smi::FromInt(0), isolate()), kNonStrictMode); - } else { - JSObject::SetOwnElement(array, i, boilerplate_value, kNonStrictMode); - } - } - - Handle element_values(array->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 && - array->HasFastSmiOrObjectElements()) { - element_values->set_map(heap->fixed_cow_array_map()); - } - - // Remember both the literal's constant values as well as the ElementsKind - // in a 2-element FixedArray. - Handle literals = isolate()->factory()->NewFixedArray(2, TENURED); - - ElementsKind kind = array->GetElementsKind(); - kind = is_holey ? GetHoleyElementsKind(kind) : GetPackedElementsKind(kind); - - literals->set(0, Smi::FromInt(kind)); - literals->set(1, *element_values); - - return factory()->NewArrayLiteral( - literals, values, literal_index, is_simple, depth, pos); -} - - -bool Parser::IsBoilerplateProperty(ObjectLiteral::Property* property) { - return property != NULL && - property->kind() != ObjectLiteral::Property::PROTOTYPE; + return factory()->NewArrayLiteral(values, literal_index, pos); } @@ -3761,89 +3707,6 @@ Handle CompileTimeValue::GetElements(Handle value) { } -Handle Parser::GetBoilerplateValue(Expression* expression) { - if (expression->AsLiteral() != NULL) { - return expression->AsLiteral()->value(); - } - if (CompileTimeValue::IsCompileTimeValue(expression)) { - return CompileTimeValue::GetValue(isolate(), expression); - } - return isolate()->factory()->uninitialized_value(); -} - - -void Parser::BuildObjectLiteralConstantProperties( - ZoneList* properties, - Handle constant_properties, - bool* is_simple, - bool* fast_elements, - int* depth, - bool* may_store_doubles) { - int position = 0; - // Accumulate the value in local variables and store it at the end. - bool is_simple_acc = true; - int depth_acc = 1; - uint32_t max_element_index = 0; - uint32_t elements = 0; - for (int i = 0; i < properties->length(); i++) { - ObjectLiteral::Property* property = properties->at(i); - if (!IsBoilerplateProperty(property)) { - is_simple_acc = false; - continue; - } - MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral(); - if (m_literal != NULL && m_literal->depth() >= depth_acc) { - depth_acc = m_literal->depth() + 1; - } - - // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined - // value for COMPUTED properties, the real value is filled in at - // runtime. The enumeration order is maintained. - Handle key = property->key()->value(); - Handle value = GetBoilerplateValue(property->value()); - - // Ensure objects that may, at any point in time, contain fields with double - // representation are always treated as nested objects. This is true for - // computed fields (value is undefined), and smi and double literals - // (value->IsNumber()). - // TODO(verwaest): Remove once we can store them inline. - if (FLAG_track_double_fields && - (value->IsNumber() || value->IsUninitialized())) { - *may_store_doubles = true; - } - - is_simple_acc = is_simple_acc && !value->IsUninitialized(); - - // Keep track of the number of elements in the object literal and - // the largest element index. If the largest element index is - // much larger than the number of elements, creating an object - // literal with fast elements will be a waste of space. - uint32_t element_index = 0; - if (key->IsString() - && Handle::cast(key)->AsArrayIndex(&element_index) - && element_index > max_element_index) { - max_element_index = element_index; - elements++; - } else if (key->IsSmi()) { - int key_value = Smi::cast(*key)->value(); - if (key_value > 0 - && static_cast(key_value) > max_element_index) { - max_element_index = key_value; - } - elements++; - } - - // Add name, value pair to the fixed array. - constant_properties->set(position++, *key); - constant_properties->set(position++, *value); - } - *fast_elements = - (max_element_index <= 32) || ((2 * elements) >= max_element_index); - *is_simple = is_simple_acc; - *depth = depth_acc; -} - - Expression* Parser::ParseObjectLiteral(bool* ok) { // ObjectLiteral :: // '{' ( @@ -3912,7 +3775,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { // Specification only allows zero parameters for get and one for set. ObjectLiteral::Property* property = factory()->NewObjectLiteralProperty(is_getter, value, next_pos); - if (IsBoilerplateProperty(property)) { + if (ObjectLiteral::IsBoilerplateProperty(property)) { number_of_boilerplate_properties++; } properties->Add(property, zone()); @@ -3984,7 +3847,9 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { } // Count CONSTANT or COMPUTED properties to maintain the enumeration order. - if (IsBoilerplateProperty(property)) number_of_boilerplate_properties++; + if (ObjectLiteral::IsBoilerplateProperty(property)) { + number_of_boilerplate_properties++; + } properties->Add(property, zone()); // TODO(1240767): Consider allowing trailing comma. @@ -4000,26 +3865,9 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { // Computation of literal_index must happen before pre parse bailout. int literal_index = current_function_state_->NextMaterializedLiteralIndex(); - Handle constant_properties = isolate()->factory()->NewFixedArray( - number_of_boilerplate_properties * 2, TENURED); - - bool is_simple = true; - bool fast_elements = true; - int depth = 1; - bool may_store_doubles = false; - BuildObjectLiteralConstantProperties(properties, - constant_properties, - &is_simple, - &fast_elements, - &depth, - &may_store_doubles); - return factory()->NewObjectLiteral(constant_properties, - properties, + return factory()->NewObjectLiteral(properties, literal_index, - is_simple, - fast_elements, - depth, - may_store_doubles, + number_of_boilerplate_properties, has_function, pos); } diff --git a/src/parser.h b/src/parser.h index 79ce68b615..f5ad31151f 100644 --- a/src/parser.h +++ b/src/parser.h @@ -653,25 +653,6 @@ class Parser : public ParserBase { Expression* ParseObjectLiteral(bool* ok); Expression* ParseRegExpLiteral(bool seen_equal, bool* ok); - // Populate the constant properties fixed array for a materialized object - // literal. - void BuildObjectLiteralConstantProperties( - ZoneList* properties, - Handle constants, - bool* is_simple, - bool* fast_elements, - int* depth, - bool* may_store_doubles); - - // Decide if a property should be in the object boilerplate. - bool IsBoilerplateProperty(ObjectLiteral::Property* property); - // If the expression is a literal, return the literal value; - // if the expression is a materialized literal and is simple return a - // compile time value as encoded by CompileTimeValue::GetValue(). - // Otherwise, return undefined literal as the placeholder - // in the object literal boilerplate. - Handle GetBoilerplateValue(Expression* expression); - // Initialize the components of a for-in / for-of statement. void InitializeForEachStatement(ForEachStatement* stmt, Expression* each, diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 2e988c8b7c..468ed8c23f 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -1595,6 +1595,9 @@ void FullCodeGenerator::EmitAccessor(Expression* expression) { void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { Comment cmnt(masm_, "[ ObjectLiteral"); + + int depth = 1; + expr->BuildConstantProperties(isolate(), &depth); Handle constant_properties = expr->constant_properties(); int flags = expr->fast_elements() ? ObjectLiteral::kFastElements @@ -1604,7 +1607,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { : ObjectLiteral::kNoFlags; int properties_count = constant_properties->length() / 2; if ((FLAG_track_double_fields && expr->may_store_doubles()) || - expr->depth() > 1 || Serializer::enabled() || + depth > 1 || Serializer::enabled() || flags != ObjectLiteral::kFastElements || properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) { __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); @@ -1723,6 +1726,8 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { Comment cmnt(masm_, "[ ArrayLiteral"); + int depth = 1; + expr->BuildConstantElements(isolate(), &depth); ZoneList* subexprs = expr->values(); int length = subexprs->length(); Handle constant_elements = expr->constant_elements(); @@ -1749,8 +1754,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { DONT_TRACK_ALLOCATION_SITE, length); __ CallStub(&stub); - } else if (expr->depth() > 1 || - Serializer::enabled() || + } else if (depth > 1 || Serializer::enabled() || length > FastCloneShallowArrayStub::kMaximumClonedLength) { __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));