Author: olehougaard
Date: Fri Mar  6 01:38:17 2009
New Revision: 1432

Added:
    branches/bleeding_edge/test/mjsunit/object-literal.js
Modified:
    branches/bleeding_edge/src/ast.cc
    branches/bleeding_edge/src/ast.h
    branches/bleeding_edge/src/codegen-ia32.cc
    branches/bleeding_edge/src/parser.cc
    branches/bleeding_edge/src/runtime.cc

Log:
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

Modified: branches/bleeding_edge/src/ast.cc
==============================================================================
--- branches/bleeding_edge/src/ast.cc   (original)
+++ branches/bleeding_edge/src/ast.cc   Fri Mar  6 01:38:17 2009
@@ -135,6 +135,8 @@
    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;
    }

Modified: branches/bleeding_edge/src/ast.h
==============================================================================
--- branches/bleeding_edge/src/ast.h    (original)
+++ branches/bleeding_edge/src/ast.h    Fri Mar  6 01:38:17 2009
@@ -129,6 +129,7 @@
    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 @@
     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 @@

    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 @@
    }
    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_;
  };



Modified: branches/bleeding_edge/src/codegen-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/codegen-ia32.cc  (original)
+++ branches/bleeding_edge/src/codegen-ia32.cc  Fri Mar  6 01:38:17 2009
@@ -3432,7 +3432,10 @@
    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));

Modified: branches/bleeding_edge/src/parser.cc
==============================================================================
--- branches/bleeding_edge/src/parser.cc        (original)
+++ branches/bleeding_edge/src/parser.cc        Fri Mar  6 01:38:17 2009
@@ -158,10 +158,13 @@

    // 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 @@
  }


-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 @@
    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);
  }



Modified: branches/bleeding_edge/src/runtime.cc
==============================================================================
--- branches/bleeding_edge/src/runtime.cc       (original)
+++ branches/bleeding_edge/src/runtime.cc       Fri Mar  6 01:38:17 2009
@@ -131,14 +131,9 @@
  }


-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 @@
      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 @@
        // 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;
  }



Added: branches/bleeding_edge/test/mjsunit/object-literal.js
==============================================================================
--- (empty file)
+++ branches/bleeding_edge/test/mjsunit/object-literal.js       Fri Mar  6  
01:38:17 2009
@@ -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);

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to