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
This commit is contained in:
parent
ad3478bb2f
commit
acac89008d
@ -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<FixedArray> 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<Expression*>* subexprs = expr->values();
|
||||
int length = subexprs->length();
|
||||
Handle<FixedArray> 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);
|
||||
|
163
src/ast.cc
163
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<FixedArray> 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<Object> key = property->key()->value();
|
||||
Handle<Object> 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<String>::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<uint32_t>(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<JSArray> 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<Object> 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<FixedArrayBase> 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<FixedArray> 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<Object> 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();
|
||||
|
80
src/ast.h
80
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<Object> 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<FixedArray> constant_properties,
|
||||
ZoneList<Property*>* 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<FixedArray> constant_properties_;
|
||||
ZoneList<Property*>* 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<String> 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<FixedArray> constant_elements,
|
||||
ZoneList<Expression*>* 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<FixedArray> constant_properties,
|
||||
ZoneList<ObjectLiteral::Property*>* 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<FixedArray> constant_elements,
|
||||
ZoneList<Expression*>* values,
|
||||
ArrayLiteral* NewArrayLiteral(ZoneList<Expression*>* 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)
|
||||
}
|
||||
|
||||
|
@ -4310,6 +4310,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
ASSERT(!HasStackOverflow());
|
||||
ASSERT(current_block() != NULL);
|
||||
ASSERT(current_block()->HasPredecessor());
|
||||
expr->BuildConstantProperties(isolate());
|
||||
Handle<JSFunction> 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<Expression*>* subexprs = expr->values();
|
||||
int length = subexprs->length();
|
||||
HInstruction* literal;
|
||||
|
@ -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<FixedArray> 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<Expression*>* subexprs = expr->values();
|
||||
int length = subexprs->length();
|
||||
Handle<FixedArray> 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));
|
||||
|
@ -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<FixedArray> 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<Expression*>* 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);
|
||||
|
166
src/parser.cc
166
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<JSArray> 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<Object> 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<FixedArrayBase> 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<FixedArray> 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<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) {
|
||||
}
|
||||
|
||||
|
||||
Handle<Object> 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<ObjectLiteral::Property*>* properties,
|
||||
Handle<FixedArray> 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<Object> key = property->key()->value();
|
||||
Handle<Object> 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<String>::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<uint32_t>(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<FixedArray> 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);
|
||||
}
|
||||
|
19
src/parser.h
19
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<ObjectLiteral::Property*>* properties,
|
||||
Handle<FixedArray> 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<Object> GetBoilerplateValue(Expression* expression);
|
||||
|
||||
// Initialize the components of a for-in / for-of statement.
|
||||
void InitializeForEachStatement(ForEachStatement* stmt,
|
||||
Expression* each,
|
||||
|
@ -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<FixedArray> 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<Expression*>* subexprs = expr->values();
|
||||
int length = subexprs->length();
|
||||
Handle<FixedArray> 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));
|
||||
|
Loading…
Reference in New Issue
Block a user