Index: src/ast.cc |
diff --git a/src/ast.cc b/src/ast.cc |
index 843f8c89600d66d5e201064d75643fa6802a04c8..9deb71d0afeb9667a586c0600756d01be9db983c 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<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(); |