Revision: 7283
Author:   [email protected]
Date:     Mon Mar 21 05:25:31 2011
Log: Optimize calls to object literal properties that are initialized with a function literal.

This allows fast calls and inlining of functions like:

var o = {f: function() { return "foo"; }}
o.f();


Object literals that contain function literals are initially created a dictionary mode object and only transformed to fast properties once all properties are computed and added. This allows us to create constant function properties for functions declared inside the object literal. Function literals inside object literals are marked for
pretenuring so that they work as contant function properties.

Object literals without functions should just function as before.

Review URL: http://codereview.chromium.org/6240012
http://code.google.com/p/v8/source/detail?r=7283

Modified:
 /branches/bleeding_edge/src/arm/full-codegen-arm.cc
 /branches/bleeding_edge/src/arm/lithium-arm.cc
 /branches/bleeding_edge/src/arm/lithium-arm.h
 /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
 /branches/bleeding_edge/src/ast.h
 /branches/bleeding_edge/src/handles.cc
 /branches/bleeding_edge/src/handles.h
 /branches/bleeding_edge/src/hydrogen-instructions.h
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/lithium-ia32.cc
 /branches/bleeding_edge/src/ia32/lithium-ia32.h
 /branches/bleeding_edge/src/parser.cc
 /branches/bleeding_edge/src/runtime.cc
 /branches/bleeding_edge/src/x64/full-codegen-x64.cc
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
 /branches/bleeding_edge/src/x64/lithium-x64.cc
 /branches/bleeding_edge/src/x64/lithium-x64.h

=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Fri Mar 18 13:35:07 2011 +++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Mon Mar 21 05:25:31 2011
@@ -1397,7 +1397,13 @@
   __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
   __ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
   __ mov(r1, Operand(expr->constant_properties()));
-  __ mov(r0, Operand(Smi::FromInt(expr->fast_elements() ? 1 : 0)));
+  int flags = expr->fast_elements()
+      ? ObjectLiteral::kFastElements
+      : ObjectLiteral::kNoFlags;
+  flags |= expr->has_function()
+      ? ObjectLiteral::kHasFunction
+      : ObjectLiteral::kNoFlags;
+  __ mov(r0, Operand(Smi::FromInt(flags)));
   __ Push(r3, r2, r1, r0);
   if (expr->depth() > 1) {
     __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
@@ -1475,6 +1481,13 @@
         break;
     }
   }
+
+  if (expr->has_function()) {
+    ASSERT(result_saved);
+    __ ldr(r0, MemOperand(sp));
+    __ push(r0);
+    __ CallRuntime(Runtime::kToFastProperties, 1);
+  }

   if (result_saved) {
     context()->PlugTOS();
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc      Fri Mar 18 13:35:07 2011
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc      Mon Mar 21 05:25:31 2011
@@ -1994,6 +1994,13 @@
LAccessArgumentsAt* result = new LAccessArgumentsAt(arguments, length, index);
   return AssignEnvironment(DefineAsRegister(result));
 }
+
+
+LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
+  LOperand* object = UseFixed(instr->value(), r0);
+  LToFastProperties* result = new LToFastProperties(object);
+  return MarkAsCall(DefineFixed(result, r0), instr);
+}


 LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.h       Fri Mar 18 13:35:07 2011
+++ /branches/bleeding_edge/src/arm/lithium-arm.h       Mon Mar 21 05:25:31 2011
@@ -155,6 +155,7 @@
   V(SubI)                                       \
   V(TaggedToI)                                  \
   V(Throw)                                      \
+  V(ToFastProperties)                           \
   V(Typeof)                                     \
   V(TypeofIs)                                   \
   V(TypeofIsAndBranch)                          \
@@ -1767,6 +1768,17 @@
 };


+class LToFastProperties: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LToFastProperties(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(ToFastProperties, "to-fast-properties")
+  DECLARE_HYDROGEN_ACCESSOR(ToFastProperties)
+};
+
+
 class LTypeof: public LTemplateInstruction<1, 1, 0> {
  public:
   explicit LTypeof(LOperand* value) {
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Fri Mar 18 13:35:07 2011 +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Mon Mar 21 05:25:31 2011
@@ -3672,6 +3672,13 @@
     CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr);
   }
 }
+
+
+void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
+  ASSERT(ToRegister(instr->InputAt(0)).is(r0));
+  __ push(r0);
+  CallRuntime(Runtime::kToFastProperties, 1, instr);
+}


 void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
=======================================
--- /branches/bleeding_edge/src/ast.h   Mon Mar 21 04:57:59 2011
+++ /branches/bleeding_edge/src/ast.h   Mon Mar 21 05:25:31 2011
@@ -985,11 +985,13 @@
                 int literal_index,
                 bool is_simple,
                 bool fast_elements,
-                int depth)
+                int depth,
+                bool has_function)
       : MaterializedLiteral(literal_index, is_simple, depth),
         constant_properties_(constant_properties),
         properties_(properties),
-        fast_elements_(fast_elements) {}
+        fast_elements_(fast_elements),
+        has_function_(has_function) {}

   DECLARE_NODE_TYPE(ObjectLiteral)

@@ -1000,16 +1002,24 @@

   bool fast_elements() const { return fast_elements_; }

+  bool has_function() { return has_function_; }

   // 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.
   void CalculateEmitStore();

+  enum Flags {
+    kNoFlags = 0,
+    kFastElements = 1,
+    kHasFunction = 1 << 1
+  };
+
  private:
   Handle<FixedArray> constant_properties_;
   ZoneList<Property*>* properties_;
   bool fast_elements_;
+  bool has_function_;
 };


=======================================
--- /branches/bleeding_edge/src/handles.cc      Fri Mar 18 13:35:07 2011
+++ /branches/bleeding_edge/src/handles.cc      Mon Mar 21 05:25:31 2011
@@ -957,35 +957,5 @@
   info.SetOptimizing(osr_ast_id);
   return CompileLazyHelper(&info, flag);
 }
-
-
-OptimizedObjectForAddingMultipleProperties::
-OptimizedObjectForAddingMultipleProperties(Handle<JSObject> object,
- int expected_additional_properties,
-                                           bool condition) {
-  object_ = object;
- if (condition && object_->HasFastProperties() && !object->IsJSGlobalProxy()) {
-    // Normalize the properties of object to avoid n^2 behavior
- // when extending the object multiple properties. Indicate the number of
-    // properties to be added.
-    unused_property_fields_ = object->map()->unused_property_fields();
-    NormalizeProperties(object_,
-                        KEEP_INOBJECT_PROPERTIES,
-                        expected_additional_properties);
-    has_been_transformed_ = true;
-
-  } else {
-    has_been_transformed_ = false;
-  }
-}
-
-
-OptimizedObjectForAddingMultipleProperties::
-~OptimizedObjectForAddingMultipleProperties() {
-  // Reoptimize the object to allow fast property access.
-  if (has_been_transformed_) {
-    TransformToFastProperties(object_, unused_property_fields_);
-  }
-}

 } }  // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/handles.h       Fri Mar 18 13:35:07 2011
+++ /branches/bleeding_edge/src/handles.h       Mon Mar 21 05:25:31 2011
@@ -367,25 +367,6 @@
 #endif
 };

-
-// ----------------------------------------------------------------------------
-
-
-// Stack allocated wrapper call for optimizing adding multiple
-// properties to an object.
-class OptimizedObjectForAddingMultipleProperties BASE_EMBEDDED {
- public:
-  OptimizedObjectForAddingMultipleProperties(Handle<JSObject> object,
-                                             int expected_property_count,
-                                             bool condition = true);
-  ~OptimizedObjectForAddingMultipleProperties();
- private:
- bool has_been_transformed_; // Tells whether the object has been transformed.
-  int unused_property_fields_;  // Captures the unused number of field.
-  Handle<JSObject> object_;    // The object being optimized.
-};
-
-
 } }  // namespace v8::internal

 #endif  // V8_HANDLES_H_
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Fri Mar 18 13:35:07 2011 +++ /branches/bleeding_edge/src/hydrogen-instructions.h Mon Mar 21 05:25:31 2011
@@ -156,6 +156,7 @@
   V(Sub)                                       \
   V(Test)                                      \
   V(Throw)                                     \
+  V(ToFastProperties)                          \
   V(Typeof)                                    \
   V(TypeofIs)                                  \
   V(UnaryMathOperation)                        \
@@ -3382,10 +3383,12 @@
                  Handle<FixedArray> constant_properties,
                  bool fast_elements,
                  int literal_index,
-                 int depth)
+                 int depth,
+                 bool has_function)
       : HMaterializedLiteral<1>(literal_index, depth),
         constant_properties_(constant_properties),
-        fast_elements_(fast_elements) {
+        fast_elements_(fast_elements),
+        has_function_(has_function) {
     SetOperandAt(0, context);
   }

@@ -3394,6 +3397,7 @@
     return constant_properties_;
   }
   bool fast_elements() const { return fast_elements_; }
+  bool has_function() const { return has_function_; }

   virtual Representation RequiredInputRepresentation(int index) const {
     return Representation::Tagged();
@@ -3404,6 +3408,7 @@
  private:
   Handle<FixedArray> constant_properties_;
   bool fast_elements_;
+  bool has_function_;
 };


@@ -3467,6 +3472,24 @@
 };


+class HToFastProperties: public HUnaryOperation {
+ public:
+  explicit HToFastProperties(HValue* value) : HUnaryOperation(value) {
+    // This instruction is not marked as having side effects, but
+    // changes the map of the input operand. Use it only when creating
+    // object literals.
+    ASSERT(value->IsObjectLiteral());
+    set_representation(Representation::Tagged());
+  }
+
+  virtual Representation RequiredInputRepresentation(int index) const {
+    return Representation::Tagged();
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(ToFastProperties, "to_fast_properties")
+};
+
+
 class HValueOf: public HUnaryOperation {
  public:
   explicit HValueOf(HValue* value) : HUnaryOperation(value) {
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Mon Mar 21 04:57:59 2011
+++ /branches/bleeding_edge/src/hydrogen.cc     Mon Mar 21 05:25:31 2011
@@ -2905,7 +2905,8 @@
expr->constant_properties(),
                                                 expr->fast_elements(),
                                                 expr->literal_index(),
-                                                expr->depth()));
+                                                expr->depth(),
+                                                expr->has_function()));
   // The object is expected in the bailout environment during computation
   // of the property values and is the value of the entire expression.
   PushAndAdd(literal);
@@ -2946,7 +2947,19 @@
       default: UNREACHABLE();
     }
   }
-  ast_context()->ReturnValue(Pop());
+
+  if (expr->has_function()) {
+    // Return the result of the transformation to fast properties
+    // instead of the original since this operation changes the map
+    // of the object. This makes sure that the original object won't
+    // be used by other optimized code before it is transformed
+    // (e.g. because of code motion).
+    HToFastProperties* result = new HToFastProperties(Pop());
+    AddInstruction(result);
+    ast_context()->ReturnValue(result);
+  } else {
+    ast_context()->ReturnValue(Pop());
+  }
 }


=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Fri Mar 18 13:35:07 2011 +++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Mon Mar 21 05:25:31 2011
@@ -1343,7 +1343,13 @@
   __ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
   __ push(Immediate(Smi::FromInt(expr->literal_index())));
   __ push(Immediate(expr->constant_properties()));
-  __ push(Immediate(Smi::FromInt(expr->fast_elements() ? 1 : 0)));
+  int flags = expr->fast_elements()
+      ? ObjectLiteral::kFastElements
+      : ObjectLiteral::kNoFlags;
+  flags |= expr->has_function()
+      ? ObjectLiteral::kHasFunction
+      : ObjectLiteral::kNoFlags;
+  __ push(Immediate(Smi::FromInt(flags)));
   if (expr->depth() > 1) {
     __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
   } else {
@@ -1414,6 +1420,12 @@
       default: UNREACHABLE();
     }
   }
+
+  if (expr->has_function()) {
+    ASSERT(result_saved);
+    __ push(Operand(esp, 0));
+    __ CallRuntime(Runtime::kToFastProperties, 1);
+  }

   if (result_saved) {
     context()->PlugTOS();
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Fri Mar 18 13:35:07 2011 +++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Mon Mar 21 05:25:31 2011
@@ -3676,7 +3676,13 @@
   __ push(FieldOperand(eax, JSFunction::kLiteralsOffset));
   __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
   __ push(Immediate(instr->hydrogen()->constant_properties()));
- __ push(Immediate(Smi::FromInt(instr->hydrogen()->fast_elements() ? 1 : 0)));
+  int flags = instr->hydrogen()->fast_elements()
+      ? ObjectLiteral::kFastElements
+      : ObjectLiteral::kNoFlags;
+  flags |= instr->hydrogen()->has_function()
+      ? ObjectLiteral::kHasFunction
+      : ObjectLiteral::kNoFlags;
+  __ push(Immediate(Smi::FromInt(flags)));

   // Pick the right runtime function to call.
   if (instr->hydrogen()->depth() > 1) {
@@ -3685,6 +3691,13 @@
     CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr);
   }
 }
+
+
+void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
+  ASSERT(ToRegister(instr->InputAt(0)).is(eax));
+  __ push(eax);
+  CallRuntime(Runtime::kToFastProperties, 1, instr);
+}


 void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.cc Fri Mar 18 13:35:07 2011 +++ /branches/bleeding_edge/src/ia32/lithium-ia32.cc Mon Mar 21 05:25:31 2011
@@ -2028,6 +2028,13 @@
LAccessArgumentsAt* result = new LAccessArgumentsAt(arguments, length, index);
   return AssignEnvironment(DefineAsRegister(result));
 }
+
+
+LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
+  LOperand* object = UseFixed(instr->value(), eax);
+  LToFastProperties* result = new LToFastProperties(object);
+  return MarkAsCall(DefineFixed(result, eax), instr);
+}


 LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.h     Fri Mar 18 13:35:07 2011
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.h     Mon Mar 21 05:25:31 2011
@@ -157,6 +157,7 @@
   V(SubI)                                       \
   V(TaggedToI)                                  \
   V(Throw)                                      \
+  V(ToFastProperties)                           \
   V(Typeof)                                     \
   V(TypeofIs)                                   \
   V(TypeofIsAndBranch)                          \
@@ -1847,6 +1848,17 @@
 };


+class LToFastProperties: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LToFastProperties(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(ToFastProperties, "to-fast-properties")
+  DECLARE_HYDROGEN_ACCESSOR(ToFastProperties)
+};
+
+
 class LTypeof: public LTemplateInstruction<1, 1, 0> {
  public:
   explicit LTypeof(LOperand* value) {
=======================================
--- /branches/bleeding_edge/src/parser.cc       Fri Mar 18 13:35:07 2011
+++ /branches/bleeding_edge/src/parser.cc       Mon Mar 21 05:25:31 2011
@@ -3340,6 +3340,7 @@
   ZoneList<ObjectLiteral::Property*>* properties =
       new ZoneList<ObjectLiteral::Property*>(4);
   int number_of_boilerplate_properties = 0;
+  bool has_function = false;

   ObjectLiteralPropertyChecker checker(this, top_scope_->is_strict_mode());

@@ -3427,6 +3428,13 @@

     ObjectLiteral::Property* property =
         new ObjectLiteral::Property(key, value);
+
+ // Mark object literals that contain function literals and pretenure the
+    // literal so it can be added as a constant function property.
+    if (value->AsFunctionLiteral() != NULL) {
+      has_function = true;
+      value->AsFunctionLiteral()->set_pretenure(true);
+    }

// Count CONSTANT or COMPUTED properties to maintain the enumeration order. if (IsBoilerplateProperty(property)) number_of_boilerplate_properties++;
@@ -3463,7 +3471,8 @@
                            literal_index,
                            is_simple,
                            fast_elements,
-                           depth);
+                           depth,
+                           has_function);
 }


=======================================
--- /branches/bleeding_edge/src/runtime.cc      Fri Mar 18 16:55:11 2011
+++ /branches/bleeding_edge/src/runtime.cc      Mon Mar 21 05:25:31 2011
@@ -304,7 +304,8 @@
     Isolate* isolate,
     Handle<FixedArray> literals,
     Handle<FixedArray> constant_properties,
-    bool should_have_fast_elements) {
+    bool should_have_fast_elements,
+    bool has_function_literal) {
   // 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
@@ -314,70 +315,90 @@
   Handle<Context> context =
       Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));

-  bool is_result_from_cache;
-  Handle<Map> map = ComputeObjectLiteralMap(context,
-                                            constant_properties,
-                                            &is_result_from_cache);
+  // In case we have function literals, we want the object to be in
+  // slow properties mode for now. We don't go in the map cache because
+  // maps with constant functions can't be shared if the functions are
+  // not the same (which is the common case).
+  bool is_result_from_cache = false;
+  Handle<Map> map = has_function_literal
+      ? Handle<Map>(context->object_function()->initial_map())
+      : ComputeObjectLiteralMap(context,
+                                constant_properties,
+                                &is_result_from_cache);

Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);

   // Normalize the elements of the boilerplate to save space if needed.
   if (!should_have_fast_elements) NormalizeElements(boilerplate);

-  {  // Add the constant properties to the boilerplate.
-    int length = constant_properties->length();
-    OptimizedObjectForAddingMultipleProperties opt(boilerplate,
-                                                   length / 2,
-                                                   !is_result_from_cache);
-    for (int index = 0; index < length; index +=2) {
-      Handle<Object> key(constant_properties->get(index+0), isolate);
-      Handle<Object> value(constant_properties->get(index+1), isolate);
-      if (value->IsFixedArray()) {
-        // The value contains the constant_properties of a
-        // simple object literal.
-        Handle<FixedArray> array = Handle<FixedArray>::cast(value);
-        value = CreateLiteralBoilerplate(isolate, literals, array);
-        if (value.is_null()) return value;
-      }
-      Handle<Object> result;
-      uint32_t element_index = 0;
-      if (key->IsSymbol()) {
-        if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
-          // Array index as string (uint32).
-          result = SetOwnElement(boilerplate,
-                                 element_index,
-                                 value,
-                                 kNonStrictMode);
-        } else {
-          Handle<String> name(String::cast(*key));
-          ASSERT(!name->AsArrayIndex(&element_index));
-          result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
-                                                    value, NONE);
-        }
-      } else if (key->ToArrayIndex(&element_index)) {
-        // Array index (uint32).
+  // Add the constant properties to the boilerplate.
+  int length = constant_properties->length();
+  bool should_transform =
+      !is_result_from_cache && boilerplate->HasFastProperties();
+  if (should_transform || has_function_literal) {
+    // Normalize the properties of object to avoid n^2 behavior
+ // when extending the object multiple properties. Indicate the number of
+    // properties to be added.
+    NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
+  }
+
+  for (int index = 0; index < length; index +=2) {
+    Handle<Object> key(constant_properties->get(index+0), isolate);
+    Handle<Object> value(constant_properties->get(index+1), isolate);
+    if (value->IsFixedArray()) {
+      // The value contains the constant_properties of a
+      // simple object or array literal.
+      Handle<FixedArray> array = Handle<FixedArray>::cast(value);
+      value = CreateLiteralBoilerplate(isolate, literals, array);
+      if (value.is_null()) return value;
+    }
+    Handle<Object> result;
+    uint32_t element_index = 0;
+    if (key->IsSymbol()) {
+      if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
+        // Array index as string (uint32).
         result = SetOwnElement(boilerplate,
                                element_index,
                                value,
                                kNonStrictMode);
       } else {
-        // Non-uint32 number.
-        ASSERT(key->IsNumber());
-        double num = key->Number();
-        char arr[100];
-        Vector<char> buffer(arr, ARRAY_SIZE(arr));
-        const char* str = DoubleToCString(num, buffer);
-        Handle<String> name =
-            isolate->factory()->NewStringFromAscii(CStrVector(str));
+        Handle<String> name(String::cast(*key));
+        ASSERT(!name->AsArrayIndex(&element_index));
         result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
                                                   value, NONE);
       }
-      // If setting the property on the boilerplate throws an
-      // 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 result;
-    }
+    } else if (key->ToArrayIndex(&element_index)) {
+      // Array index (uint32).
+      result = SetOwnElement(boilerplate,
+                             element_index,
+                             value,
+                             kNonStrictMode);
+    } else {
+      // Non-uint32 number.
+      ASSERT(key->IsNumber());
+      double num = key->Number();
+      char arr[100];
+      Vector<char> buffer(arr, ARRAY_SIZE(arr));
+      const char* str = DoubleToCString(num, buffer);
+      Handle<String> name =
+          isolate->factory()->NewStringFromAscii(CStrVector(str));
+      result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
+                                                value, NONE);
+    }
+    // If setting the property on the boilerplate throws an
+    // 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 result;
+  }
+
+  // Transform to fast properties if necessary. For object literals with
+  // containing function literals we defer this operation until after all
+  // computed properties have been assigned so that we can generate
+  // constant function properties.
+  if (should_transform && !has_function_literal) {
+    TransformToFastProperties(boilerplate,
+ boilerplate->map()->unused_property_fields());
   }

   return boilerplate;
@@ -410,7 +431,7 @@
     for (int i = 0; i < content->length(); i++) {
       if (content->get(i)->IsFixedArray()) {
         // The value contains the constant_properties of a
-        // simple object literal.
+        // simple object or array literal.
         Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
         Handle<Object> result =
             CreateLiteralBoilerplate(isolate, literals, fa);
@@ -431,11 +452,20 @@
     Handle<FixedArray> literals,
     Handle<FixedArray> array) {
   Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
+  const bool kHasNoFunctionLiteral = false;
   switch (CompileTimeValue::GetType(array)) {
     case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
- return CreateObjectLiteralBoilerplate(isolate, literals, elements, true);
+      return CreateObjectLiteralBoilerplate(isolate,
+                                            literals,
+                                            elements,
+                                            true,
+                                            kHasNoFunctionLiteral);
     case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
- return CreateObjectLiteralBoilerplate(isolate, literals, elements, false);
+      return CreateObjectLiteralBoilerplate(isolate,
+                                            literals,
+                                            elements,
+                                            false,
+                                            kHasNoFunctionLiteral);
     case CompileTimeValue::ARRAY_LITERAL:
       return CreateArrayLiteralBoilerplate(isolate, literals, elements);
     default:
@@ -476,8 +506,9 @@
   CONVERT_ARG_CHECKED(FixedArray, literals, 0);
   CONVERT_SMI_CHECKED(literals_index, args[1]);
   CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
-  CONVERT_SMI_CHECKED(fast_elements, args[3]);
-  bool should_have_fast_elements = fast_elements == 1;
+  CONVERT_SMI_CHECKED(flags, args[3]);
+ bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
+  bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;

   // Check if boilerplate exists. If not, create it first.
   Handle<Object> boilerplate(literals->get(literals_index), isolate);
@@ -485,7 +516,8 @@
     boilerplate = CreateObjectLiteralBoilerplate(isolate,
                                                  literals,
                                                  constant_properties,
- should_have_fast_elements);
+                                                 should_have_fast_elements,
+                                                 has_function_literal);
     if (boilerplate.is_null()) return Failure::Exception();
     // Update the functions literal and return the boilerplate.
     literals->set(literals_index, *boilerplate);
@@ -502,8 +534,9 @@
   CONVERT_ARG_CHECKED(FixedArray, literals, 0);
   CONVERT_SMI_CHECKED(literals_index, args[1]);
   CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
-  CONVERT_SMI_CHECKED(fast_elements, args[3]);
-  bool should_have_fast_elements = fast_elements == 1;
+  CONVERT_SMI_CHECKED(flags, args[3]);
+ bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
+  bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;

   // Check if boilerplate exists. If not, create it first.
   Handle<Object> boilerplate(literals->get(literals_index), isolate);
@@ -511,7 +544,8 @@
     boilerplate = CreateObjectLiteralBoilerplate(isolate,
                                                  literals,
                                                  constant_properties,
- should_have_fast_elements);
+                                                 should_have_fast_elements,
+                                                 has_function_literal);
     if (boilerplate.is_null()) return Failure::Exception();
     // Update the functions literal and return the boilerplate.
     literals->set(literals_index, *boilerplate);
=======================================
--- /branches/bleeding_edge/src/x64/full-codegen-x64.cc Fri Mar 18 13:35:07 2011 +++ /branches/bleeding_edge/src/x64/full-codegen-x64.cc Mon Mar 21 05:25:31 2011
@@ -1361,7 +1361,13 @@
   __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset));
   __ Push(Smi::FromInt(expr->literal_index()));
   __ Push(expr->constant_properties());
-  __ Push(Smi::FromInt(expr->fast_elements() ? 1 : 0));
+  int flags = expr->fast_elements()
+      ? ObjectLiteral::kFastElements
+      : ObjectLiteral::kNoFlags;
+  flags |= expr->has_function()
+      ? ObjectLiteral::kHasFunction
+      : ObjectLiteral::kNoFlags;
+  __ Push(Smi::FromInt(flags));
   if (expr->depth() > 1) {
     __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
   } else {
@@ -1430,6 +1436,12 @@
         break;
     }
   }
+
+  if (expr->has_function()) {
+    ASSERT(result_saved);
+    __ push(Operand(rsp, 0));
+    __ CallRuntime(Runtime::kToFastProperties, 1);
+  }

   if (result_saved) {
     context()->PlugTOS();
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Fri Mar 18 13:35:07 2011 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Mon Mar 21 05:25:31 2011
@@ -3485,6 +3485,13 @@
     CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr);
   }
 }
+
+
+void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
+  ASSERT(ToRegister(instr->InputAt(0)).is(rax));
+  __ push(rax);
+  CallRuntime(Runtime::kToFastProperties, 1, instr);
+}


 void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.cc      Fri Mar 18 13:35:07 2011
+++ /branches/bleeding_edge/src/x64/lithium-x64.cc      Mon Mar 21 05:25:31 2011
@@ -1988,6 +1988,13 @@
LAccessArgumentsAt* result = new LAccessArgumentsAt(arguments, length, index);
   return AssignEnvironment(DefineAsRegister(result));
 }
+
+
+LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
+  LOperand* object = UseFixed(instr->value(), rax);
+  LToFastProperties* result = new LToFastProperties(object);
+  return MarkAsCall(DefineFixed(result, rax), instr);
+}


 LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.h       Fri Mar 18 13:35:07 2011
+++ /branches/bleeding_edge/src/x64/lithium-x64.h       Mon Mar 21 05:25:31 2011
@@ -154,6 +154,7 @@
   V(StringLength)                               \
   V(SubI)                                       \
   V(TaggedToI)                                  \
+  V(ToFastProperties)                           \
   V(Throw)                                      \
   V(Typeof)                                     \
   V(TypeofIs)                                   \
@@ -1762,6 +1763,17 @@
 };


+class LToFastProperties: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LToFastProperties(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(ToFastProperties, "to-fast-properties")
+  DECLARE_HYDROGEN_ACCESSOR(ToFastProperties)
+};
+
+
 class LTypeof: public LTemplateInstruction<1, 1, 0> {
  public:
   explicit LTypeof(LOperand* value) {

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

Reply via email to