Reviewers: Igor Sheludko,

Message:
PTAL

Description:
Mark as prototype only after instantiating the function

BUG=

Please review this at https://codereview.chromium.org/447293002/

SVN Base: https://v8.googlecode.com/svn/branches/bleeding_edge

Affected files (+44, -47 lines):
  M src/bootstrapper.cc
  M src/factory.cc
  M src/objects.h
  M src/objects.cc
  M src/objects-inl.h
  M test/mjsunit/dictionary-properties.js
  M test/mjsunit/fast-prototype.js


Index: src/bootstrapper.cc
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 5ce58a7e153d20d0761c82dbea00bb8ffb6b17b1..44803f8968bc9b761d5f5a9e386e09c2351f2676 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -480,8 +480,7 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
     Handle<JSFunction> object_fun = factory->NewFunction(object_name);
     Handle<Map> object_function_map =
         factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
-    object_fun->set_initial_map(*object_function_map);
-    object_function_map->set_constructor(*object_fun);
+    JSFunction::SetInitialMap(object_fun, object_function_map);
     object_function_map->set_unused_property_fields(
         JSObject::kInitialGlobalObjectUnusedPropertiesCount);

@@ -1211,8 +1210,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> global_object,
     native_context()->set_sloppy_arguments_map(*map);

     DCHECK(!function->has_initial_map());
-    function->set_initial_map(*map);
-    map->set_constructor(*function);
+    JSFunction::SetInitialMap(function, map);

     DCHECK(map->inobject_properties() > Heap::kArgumentsCalleeIndex);
     DCHECK(map->inobject_properties() > Heap::kArgumentsLengthIndex);
@@ -1336,8 +1334,7 @@ void Genesis::InstallTypedArray(
       JS_TYPED_ARRAY_TYPE,
       JSTypedArray::kSizeWithInternalFields,
       elements_kind);
-  result->set_initial_map(*initial_map);
-  initial_map->set_constructor(*result);
+  JSFunction::SetInitialMap(result, initial_map);
   *fun = result;

ElementsKind external_kind = GetNextTransitionElementsKind(elements_kind);
@@ -1658,7 +1655,7 @@ Handle<JSFunction> Genesis::InstallInternalArray(
   Handle<Map> original_map(array_function->initial_map());
   Handle<Map> initial_map = Map::Copy(original_map);
   initial_map->set_elements_kind(elements_kind);
-  array_function->set_initial_map(*initial_map);
+  JSFunction::SetInitialMap(array_function, initial_map);

   // Make "length" magic on instances.
   Map::EnsureDescriptorSlack(initial_map, 1);
Index: src/factory.cc
diff --git a/src/factory.cc b/src/factory.cc
index e3a19a1e4ba988a0b19b00219e8ed50d83cb3a23..a52b95719db05276362f7325ec32be751b37d87a 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -1268,11 +1268,6 @@ Handle<JSFunction> Factory::NewFunction(Handle<String> name,
       ? isolate()->sloppy_function_with_readonly_prototype_map()
       : isolate()->sloppy_function_map();
   Handle<JSFunction> result = NewFunction(map, name, code);
-  if (!prototype->IsTheHole()) {
-    Handle<JSObject> js_proto = Handle<JSObject>::cast(prototype);
-    Handle<Map> new_map = Map::CopyAsPrototypeMap(handle(js_proto->map()));
-    JSObject::MigrateToMap(js_proto, new_map);
-  }
   result->set_prototype_or_initial_map(*prototype);
   return result;
 }
@@ -1293,9 +1288,9 @@ Handle<JSFunction> Factory::NewFunction(Handle<String> name,
   if (prototype->IsTheHole() && !function->shared()->is_generator()) {
     prototype = NewFunctionPrototype(function);
   }
+
   initial_map->set_prototype(*prototype);
-  function->set_initial_map(*initial_map);
-  initial_map->set_constructor(*function);
+  JSFunction::SetInitialMap(function, initial_map);

   return function;
 }
@@ -1323,7 +1318,7 @@ Handle<JSObject> Factory::NewFunctionPrototype(Handle<JSFunction> function) {
     // maps between prototypes of different constructors.
     Handle<JSFunction> object_function(native_context->object_function());
     DCHECK(object_function->has_initial_map());
- new_map = Map::CopyAsPrototypeMap(handle(object_function->initial_map()));
+    new_map = handle(object_function->initial_map());
   }

   Handle<JSObject> prototype = NewJSObjectFromMap(new_map);
Index: src/objects-inl.h
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 7729c2018dd5bc3e5e0308f619cc996aae1654d3..cfac520acc6092074855baece99b4e1cf0f7decc 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -4451,8 +4451,8 @@ bool Map::is_extensible() {
 }


-void Map::mark_prototype_map() {
-  set_bit_field2(IsPrototypeMapBits::update(bit_field2(), true));
+void Map::set_is_prototype_map(bool value) {
+  set_bit_field2(IsPrototypeMapBits::update(bit_field2(), value));
 }

 bool Map::is_prototype_map() {
@@ -5940,11 +5940,6 @@ Map* JSFunction::initial_map() {
 }


-void JSFunction::set_initial_map(Map* value) {
-  set_prototype_or_initial_map(value);
-}
-
-
 bool JSFunction::has_initial_map() {
   return prototype_or_initial_map()->IsMap();
 }
Index: src/objects.cc
diff --git a/src/objects.cc b/src/objects.cc
index abf135bfbcfe94772160fd16c5a4e01601d7816f..723ce4cea3d929764668e8d95d91527dc1658caf 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -7239,14 +7239,6 @@ Handle<Map> Map::CopyForObserved(Handle<Map> map) {
 }


-Handle<Map> Map::CopyAsPrototypeMap(Handle<Map> map) {
-  if (map->is_prototype_map()) return map;
-  Handle<Map> result = Copy(map);
-  result->mark_prototype_map();
-  return result;
-}
-
-
 Handle<Map> Map::Copy(Handle<Map> map) {
   Handle<DescriptorArray> descriptors(map->instance_descriptors());
   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
@@ -9874,17 +9866,6 @@ void JSFunction::SetInstancePrototype(Handle<JSFunction> function,

   DCHECK(value->IsJSReceiver());

- // First some logic for the map of the prototype to make sure it is in fast
-  // mode.
-  if (value->IsJSObject()) {
-    Handle<JSObject> js_proto = Handle<JSObject>::cast(value);
-    JSObject::OptimizeAsPrototype(js_proto);
-    if (js_proto->HasFastProperties()) {
- Handle<Map> new_map = Map::CopyAsPrototypeMap(handle(js_proto->map()));
-      JSObject::MigrateToMap(js_proto, new_map);
-    }
-  }
-
// Now some logic for the maps of the objects that are created by using this
   // function as a constructor.
   if (function->has_initial_map()) {
@@ -9908,7 +9889,7 @@ void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
       CacheInitialJSArrayMaps(handle(native_context, isolate), new_map);
     }

-    function->set_initial_map(*new_map);
+    JSFunction::SetInitialMap(function, new_map);

     // Deoptimize all code that embeds the previous initial map.
     initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
@@ -9975,6 +9956,34 @@ bool JSFunction::RemovePrototype() {
 }


+void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map) {
+  if (map->prototype()->IsJSObject()) {
+    Handle<JSObject> js_proto = handle(JSObject::cast(map->prototype()));
+    if (!js_proto->map()->is_prototype_map() &&
+        !js_proto->map()->IsGlobalObjectMap() &&
+        !js_proto->map()->IsJSGlobalProxyMap()) {
+      // Normalize and turn fast again to make all functions CONSTANT
+      // properties.
+      if (!js_proto->GetIsolate()->bootstrapper()->IsActive()) {
+ JSObject::NormalizeProperties(js_proto, KEEP_INOBJECT_PROPERTIES, 0);
+      }
+      if (!js_proto->HasFastProperties()) {
+        JSObject::MigrateSlowToFast(js_proto, 0);
+        js_proto->ObjectVerify();
+      }
+      if (js_proto->HasFastProperties()) {
+        Handle<Map> new_map = Map::Copy(handle(js_proto->map()));
+        JSObject::MigrateToMap(js_proto, new_map);
+        js_proto->map()->set_is_prototype_map(true);
+        js_proto->ObjectVerify();
+      }
+    }
+  }
+  function->set_prototype_or_initial_map(*map);
+  map->set_constructor(*function);
+}
+
+
 void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
   if (function->has_initial_map()) return;
   Isolate* isolate = function->GetIsolate();
@@ -10008,8 +10017,7 @@ void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
   DCHECK(map->has_fast_object_elements());

   // Finally link initial map and constructor function.
-  function->set_initial_map(*map);
-  map->set_constructor(*function);
+  JSFunction::SetInitialMap(function, map);

   if (!function->shared()->is_generator()) {
     function->StartInobjectSlackTracking();
Index: src/objects.h
diff --git a/src/objects.h b/src/objects.h
index 43c92a403bf7d08de99485ce2e41f95914c71661..1464a4d86b9fb582bdbbaf5546415d60fea0c7a2 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -6206,7 +6206,7 @@ class Map: public HeapObject {

   inline void set_is_extensible(bool value);
   inline bool is_extensible();
-  inline void mark_prototype_map();
+  inline void set_is_prototype_map(bool value);
   inline bool is_prototype_map();

   inline void set_elements_kind(ElementsKind elements_kind) {
@@ -6541,7 +6541,6 @@ class Map: public HeapObject {
   // Returns a copy of the map, with all transitions dropped from the
   // instance descriptors.
   static Handle<Map> Copy(Handle<Map> map);
-  static Handle<Map> CopyAsPrototypeMap(Handle<Map> map);
   static Handle<Map> Create(Handle<JSFunction> constructor,
                             int extra_inobject_properties);

@@ -7782,7 +7781,7 @@ class JSFunction: public JSObject {

   // The initial map for an object created by this constructor.
   inline Map* initial_map();
-  inline void set_initial_map(Map* value);
+  static void SetInitialMap(Handle<JSFunction> function, Handle<Map> map);
   inline bool has_initial_map();
   static void EnsureHasInitialMap(Handle<JSFunction> function);

Index: test/mjsunit/dictionary-properties.js
diff --git a/test/mjsunit/dictionary-properties.js b/test/mjsunit/dictionary-properties.js index 9563f3a178fb78b5ea67cdf6a77c56d441f7176b..0659268bac2357d5a024ed341218fa2e465a59dc 100644
--- a/test/mjsunit/dictionary-properties.js
+++ b/test/mjsunit/dictionary-properties.js
@@ -39,6 +39,7 @@ function SlowPrototype() {
 SlowPrototype.prototype.bar = 2;
 SlowPrototype.prototype.baz = 3;
 delete SlowPrototype.prototype.baz;
+new SlowPrototype;

 // Prototypes stay fast even after deleting properties.
 assertTrue(%HasFastProperties(SlowPrototype.prototype));
Index: test/mjsunit/fast-prototype.js
diff --git a/test/mjsunit/fast-prototype.js b/test/mjsunit/fast-prototype.js
index 55a0faae805341b16804deeef6e53e7a49dfc1cd..98647612f6ddcc5b1ed1d1caa82c81b5ac718d4a 100644
--- a/test/mjsunit/fast-prototype.js
+++ b/test/mjsunit/fast-prototype.js
@@ -50,6 +50,8 @@ function DoProtoMagic(proto, set__proto__) {
     (new Sub()).__proto__ = proto;
   } else {
     Sub.prototype = proto;
+    // Need to instantiate Sub to mark .prototype as prototype.
+    new Sub();
   }
 }



--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to