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
This commit is contained in:
parent
e2ccac2279
commit
d46a9900ee
@ -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;
|
||||
}
|
||||
|
20
src/ast.h
20
src/ast.h
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the functions literal and return the boilerplate.
|
||||
literals->set(literals_index, *boilerplate);
|
||||
return boilerplate;
|
||||
}
|
||||
|
||||
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, *result);;
|
||||
|
||||
return *result;
|
||||
}
|
||||
|
||||
|
||||
|
63
test/mjsunit/object-literal.js
Normal file
63
test/mjsunit/object-literal.js
Normal file
@ -0,0 +1,63 @@
|
||||
// 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);
|
Loading…
Reference in New Issue
Block a user