Commit d46a9900 authored by olehougaard's avatar olehougaard

Optimizing nested, constant object literals (like JSON objects) by building...

Optimizing nested, constant object literals (like JSON objects) by building one large object template for the entire object instead of one for each sub-object.
Review URL: http://codereview.chromium.org/39184

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1432 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent e2ccac22
......@@ -135,6 +135,8 @@ ObjectLiteral::Property::Property(Literal* key, Expression* value) {
Object* k = *key->handle();
if (k->IsSymbol() && Heap::Proto_symbol()->Equals(String::cast(k))) {
kind_ = PROTOTYPE;
} else if (value_->AsObjectLiteral() != NULL) {
kind_ = OBJECT_LITERAL;
} else {
kind_ = value_->AsLiteral() == NULL ? COMPUTED : CONSTANT;
}
......
......@@ -129,6 +129,7 @@ class Node: public ZoneObject {
virtual BinaryOperation* AsBinaryOperation() { return NULL; }
virtual Assignment* AsAssignment() { return NULL; }
virtual FunctionLiteral* AsFunctionLiteral() { return NULL; }
virtual ObjectLiteral* AsObjectLiteral() { return NULL; }
void set_statement_pos(int statement_pos) { statement_pos_ = statement_pos; }
int statement_pos() const { return statement_pos_; }
......@@ -651,10 +652,11 @@ class ObjectLiteral: public MaterializedLiteral {
public:
enum Kind {
CONSTANT, // Property with constant value (at compile time).
COMPUTED, // Property with computed value (at execution time).
CONSTANT, // Property with constant value (at compile time).
COMPUTED, // Property with computed value (at execution time).
OBJECT_LITERAL, // Property value is an object literal.
GETTER, SETTER, // Property is an accessor function.
PROTOTYPE // Property is __proto__.
PROTOTYPE // Property is __proto__.
};
Property(Literal* key, Expression* value);
......@@ -672,12 +674,15 @@ class ObjectLiteral: public MaterializedLiteral {
ObjectLiteral(Handle<FixedArray> constant_properties,
ZoneList<Property*>* properties,
int literal_index)
int literal_index,
bool is_simple)
: MaterializedLiteral(literal_index),
constant_properties_(constant_properties),
properties_(properties) {
properties_(properties),
is_simple_(is_simple) {
}
virtual ObjectLiteral* AsObjectLiteral() { return this; }
virtual void Accept(AstVisitor* v);
Handle<FixedArray> constant_properties() const {
......@@ -685,9 +690,14 @@ class ObjectLiteral: public MaterializedLiteral {
}
ZoneList<Property*>* properties() const { return properties_; }
// An object literal is simple if the values consist of only
// constants and simple object literals.
bool is_simple() const { return is_simple_; }
private:
Handle<FixedArray> constant_properties_;
ZoneList<Property*>* properties_;
bool is_simple_;
};
......
......@@ -3432,7 +3432,10 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
for (int i = 0; i < node->properties()->length(); i++) {
ObjectLiteral::Property* property = node->properties()->at(i);
switch (property->kind()) {
case ObjectLiteral::Property::CONSTANT: break;
case ObjectLiteral::Property::CONSTANT:
break;
case ObjectLiteral::Property::OBJECT_LITERAL:
if (property->value()->AsObjectLiteral()->is_simple()) break;
case ObjectLiteral::Property::COMPUTED: {
Handle<Object> key(property->key()->handle());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
......
......@@ -158,10 +158,13 @@ class Parser {
// Decide if a property should be the object boilerplate.
bool IsBoilerplateProperty(ObjectLiteral::Property* property);
// If the property is CONSTANT type, it returns the literal value,
// otherwise, it return undefined literal as the placeholder
// If the property is CONSTANT type, return the literal value;
// if the property is OBJECT_LITERAL and the object literal is
// simple return a fixed array containing the keys and values of the
// object literal.
// Otherwise, return undefined literal as the placeholder
// in the object literal boilerplate.
Literal* GetBoilerplateValue(ObjectLiteral::Property* property);
Handle<Object> GetBoilerplateValue(ObjectLiteral::Property* property);
enum FunctionLiteralType {
EXPRESSION,
......@@ -3083,10 +3086,16 @@ bool Parser::IsBoilerplateProperty(ObjectLiteral::Property* property) {
}
Literal* Parser::GetBoilerplateValue(ObjectLiteral::Property* property) {
Handle<Object> Parser::GetBoilerplateValue(ObjectLiteral::Property* property) {
if (property->kind() == ObjectLiteral::Property::CONSTANT)
return property->value()->AsLiteral();
return GetLiteralUndefined();
return property->value()->AsLiteral()->handle();
if (property->kind() == ObjectLiteral::Property::OBJECT_LITERAL) {
ObjectLiteral* object_literal = property->value()->AsObjectLiteral();
if (object_literal->is_simple()) {
return object_literal->constant_properties();
}
}
return Factory::undefined_value();
}
......@@ -3181,24 +3190,30 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
Handle<FixedArray> constant_properties =
Factory::NewFixedArray(number_of_boilerplate_properties * 2, TENURED);
int position = 0;
bool is_simple = true;
for (int i = 0; i < properties.length(); i++) {
ObjectLiteral::Property* property = properties.at(i);
if (!IsBoilerplateProperty(property)) continue;
if (!IsBoilerplateProperty(property)) {
is_simple = false;
continue;
}
// 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()->handle();
Literal* literal = GetBoilerplateValue(property);
Handle<Object> value = GetBoilerplateValue(property);
is_simple = is_simple && !value->IsUndefined();
// Add name, value pair to the fixed array.
constant_properties->set(position++, *key);
constant_properties->set(position++, *literal->handle());
constant_properties->set(position++, *value);
}
return new ObjectLiteral(constant_properties,
properties.elements(),
literal_index);
literal_index,
is_simple);
}
......
......@@ -131,14 +131,9 @@ static Handle<Map> ComputeObjectLiteralMap(
}
static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) {
HandleScope scope;
ASSERT(args.length() == 3);
// Copy the arguments.
Handle<FixedArray> literals = args.at<FixedArray>(0);
int literals_index = Smi::cast(args[1])->value();
Handle<FixedArray> constant_properties = args.at<FixedArray>(2);
static Handle<Object> CreateObjectLiteralBoilerplate(
Handle<FixedArray> literals,
Handle<FixedArray> constant_properties) {
// Get the global context from the literals array. This is the
// context in which the function was created and we use the object
// function from this context to create the object literal. We do
......@@ -161,6 +156,12 @@ static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) {
for (int index = 0; index < length; index +=2) {
Handle<Object> key(constant_properties->get(index+0));
Handle<Object> value(constant_properties->get(index+1));
if (value->IsFixedArray()) {
// The value contains the constant_properties of a
// simple object literal.
Handle<FixedArray> array = Handle<FixedArray>::cast(value);
value = CreateObjectLiteralBoilerplate(literals, array);
}
Handle<Object> result;
uint32_t element_index = 0;
if (key->IsSymbol()) {
......@@ -185,14 +186,31 @@ static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) {
// exception, the exception is converted to an empty handle in
// the handle based operations. In that case, we need to
// convert back to an exception.
if (result.is_null()) return Failure::Exception();
if (result.is_null()) return result;
}
}
return boilerplate;
}
static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) {
HandleScope scope;
ASSERT(args.length() == 3);
// Copy the arguments.
Handle<FixedArray> literals = args.at<FixedArray>(0);
int literals_index = Smi::cast(args[1])->value();
Handle<FixedArray> constant_properties = args.at<FixedArray>(2);
Handle<Object> result =
CreateObjectLiteralBoilerplate(literals, constant_properties);
if (result.is_null()) return Failure::Exception();
// Update the functions literal and return the boilerplate.
literals->set(literals_index, *boilerplate);
literals->set(literals_index, *result);;
return *boilerplate;
return *result;
}
......
// Copyright 2009 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.
var obj = {
a: 7,
b: { x: 12, y: 24 },
c: 'Zebra'
}
assertEquals(7, obj.a);
assertEquals(12, obj.b.x);
assertEquals(24, obj.b.y);
assertEquals('Zebra', obj.c);
var z = 24;
var obj2 = {
a: 7,
b: { x: 12, y: z },
c: 'Zebra'
}
assertEquals(7, obj2.a);
assertEquals(12, obj2.b.x);
assertEquals(24, obj2.b.y);
assertEquals('Zebra', obj2.c);
var arr = [];
for (var i = 0; i < 2; i++) {
arr[i] = {
a: 7,
b: { x: 12, y: 24 },
c: 'Zebra'
}
}
arr[0].a = 2;
assertEquals(2, arr[0].a);
assertEquals(7, arr[1].a);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment