Reviewers: Toon Verwaest,

Message:
Another piece of https://codereview.chromium.org/908213002/ that can be reviewed
on its own. PTAL.

Description:
Populate PrototypeInfo with prototype_object value

But only if --track-prototype-users, which is still off by default.
This is the next step towards prototype chain check elimination.

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

Base URL: https://chromium.googlesource.com/v8/v8.git@master

Affected files (+75, -20 lines):
  M src/bootstrapper.cc
  M src/factory.h
  M src/factory.cc
  M src/objects.h
  M src/objects.cc
  M src/objects-debug.cc
  M src/objects-inl.h
  M src/transitions.cc


Index: src/bootstrapper.cc
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 097437e7c1e8723e1189feb46eb9a2289a0f67b8..b121d3e1d6aebd74b6bdf9bb8ab1972f15b11cda 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -487,6 +487,7 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
                                 "EmptyObjectPrototype");
     map->set_is_prototype_map(true);
     object_function_prototype->set_map(*map);
+    Map::SetPrototypeObject(map, object_function_prototype, isolate);

native_context()->set_initial_object_prototype(*object_function_prototype); // For bootstrapping set the array prototype to be the same as the object @@ -512,6 +513,7 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
   Map::SetPrototype(empty_function_map, object_function_prototype);
   empty_function_map->set_is_prototype_map(true);
   empty_function->set_map(*empty_function_map);
+  Map::SetPrototypeObject(empty_function_map, empty_function, isolate);

   // --- E m p t y ---
   Handle<String> source = factory->NewStringFromStaticChars("() {}");
@@ -1127,6 +1129,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> global_object,
                                  Smi::FromInt(0),
                                  SKIP_WRITE_BARRIER);  // It's a Smi.
     proto_map->set_is_prototype_map(true);
+    Map::SetPrototypeObject(proto_map, proto, isolate);
     Map::SetPrototype(initial_map, proto);
     factory->SetRegExpIrregexpData(Handle<JSRegExp>::cast(proto),
JSRegExp::IRREGEXP, factory->empty_string(),
Index: src/factory.cc
diff --git a/src/factory.cc b/src/factory.cc
index ae3a46f811240703364e819d6b96f8efce705b8e..83815f2d0de891341369a3ced747c24f4d567ada 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -51,11 +51,10 @@ Handle<Box> Factory::NewBox(Handle<Object> value) {
 }


-Handle<PrototypeInfo> Factory::NewPrototypeInfo(
-    Handle<JSObject> prototype_obj) {
+Handle<PrototypeInfo> Factory::NewPrototypeInfo() {
   Handle<PrototypeInfo> result =
       Handle<PrototypeInfo>::cast(NewStruct(PROTOTYPE_INFO_TYPE));
-  result->set_prototype_object(*prototype_obj);
+  result->set_prototype_object(Smi::FromInt(0));
   result->set_prototype_users(Smi::FromInt(0));
   result->set_validity_cell(Smi::FromInt(0));
   return result;
Index: src/factory.h
diff --git a/src/factory.h b/src/factory.h
index aabb0ed20d2274c212419ffbbd41a14cb0d61d0e..6e51b6f2c7583a92322e4e7e2f71dad028e8e2f3 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -59,7 +59,7 @@ class Factory FINAL {
   Handle<Box> NewBox(Handle<Object> value);

   // Create a new PrototypeInfo struct.
-  Handle<PrototypeInfo> NewPrototypeInfo(Handle<JSObject> prototype_obj);
+  Handle<PrototypeInfo> NewPrototypeInfo();

   // Create a pre-tenured empty AccessorPair.
   Handle<AccessorPair> NewAccessorPair();
Index: src/objects-debug.cc
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index ed1a53cfff39f9b17eb73f36f234bd60801c0ce6..397c27950e41701851d39cf33af47d38c27724cc 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -882,13 +882,13 @@ void Box::BoxVerify() {

 void PrototypeInfo::PrototypeInfoVerify() {
   CHECK(IsPrototypeInfo());
-  CHECK(prototype_object()->IsJSObject());
+  CHECK(prototype_object()->IsJSObject() || prototype_object()->IsSmi());
   if (prototype_users()->IsWeakFixedArray()) {
     WeakFixedArray::cast(prototype_users())->FixedArrayVerify();
   } else {
     CHECK(prototype_users()->IsSmi());
   }
-  CHECK(validity_cell()->IsCell() || validity_cell()->IsCell());
+  CHECK(validity_cell()->IsCell() || validity_cell()->IsSmi());
 }


Index: src/objects-inl.h
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 6e3e969f093c2be5e801b29310d4c01a69006d8a..781d8d615001d15dee483ee1c9a835047b6539d8 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -5444,7 +5444,7 @@ ACCESSORS(ExecutableAccessorInfo, data, Object, kDataOffset)

 ACCESSORS(Box, value, Object, kValueOffset)

-ACCESSORS(PrototypeInfo, prototype_object, JSObject, kPrototypeObjectOffset)
+ACCESSORS(PrototypeInfo, prototype_object, Object, kPrototypeObjectOffset)
 ACCESSORS(PrototypeInfo, prototype_users, Object, kPrototypeUsersOffset)
 ACCESSORS(PrototypeInfo, validity_cell, Object, kValidityCellOffset)

Index: src/objects.cc
diff --git a/src/objects.cc b/src/objects.cc
index 28a7ce623bfb35d8eae2c880c01ed033858e05a5..931ef0a0a9896ff80c2df17410d9ea471ad9c233 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -9905,7 +9905,8 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
     JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
                                   "NormalizeAsPrototype");
   }
-  Handle<Map> previous_map(object->map());
+  Isolate* isolate = object->GetIsolate();
+  Handle<Map> previous_map(object->map(), isolate);
   if (!object->HasFastProperties()) {
     JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
   }
@@ -9921,8 +9922,7 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object, // from the same context if undetectable from JS. This is to avoid keeping
       // memory alive unnecessarily.
       if (!constructor->shared()->IsApiFunction() &&
-          object->class_name() ==
-              object->GetIsolate()->heap()->Object_string()) {
+          object->class_name() == isolate->heap()->Object_string()) {
         Context* context = constructor->context()->native_context();
         JSFunction* object_function = context->object_function();
         object->map()->SetConstructor(object_function);
@@ -9930,6 +9930,8 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
     }
     object->map()->set_is_prototype_map(true);
   }
+  Handle<Map> new_map(object->map(), isolate);
+  Map::SetPrototypeObject(new_map, object, isolate);
 }


@@ -9948,14 +9950,10 @@ void JSObject::RegisterPrototypeUser(Handle<JSObject> prototype,
   if (prototype->IsJSGlobalProxy()) {
prototype = handle(JSObject::cast(prototype->map()->prototype()), isolate);
   }
-  Handle<PrototypeInfo> proto_info;
-  Object* maybe_proto_info = prototype->map()->prototype_info();
-  if (maybe_proto_info->IsPrototypeInfo()) {
-    proto_info = handle(PrototypeInfo::cast(maybe_proto_info), isolate);
-  } else {
-    proto_info = isolate->factory()->NewPrototypeInfo(prototype);
-    prototype->map()->set_prototype_info(*proto_info);
-  }
+  Handle<Map> proto_map(prototype->map(), isolate);
+  Handle<PrototypeInfo> proto_info =
+      Map::GetOrCreatePrototypeInfo(proto_map, isolate);
+  proto_info->set_prototype_object(*prototype);
   Handle<Object> maybe_registry(proto_info->prototype_users(), isolate);
Handle<WeakFixedArray> new_array = WeakFixedArray::Add(maybe_registry, user);
   if (!maybe_registry.is_identical_to(new_array)) {
@@ -9983,6 +9981,45 @@ void JSObject::UnregisterPrototypeUser(Handle<JSObject> prototype,


 // static
+Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> map,
+                                                    Isolate* isolate) {
+  Object* maybe_proto_info = map->prototype_info();
+  if (maybe_proto_info->IsPrototypeInfo()) {
+    return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
+  }
+ Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
+  map->set_prototype_info(*proto_info);
+  return proto_info;
+}
+
+
+// static
+void Map::SetPrototypeObject(Handle<Map> map, Handle<JSObject> prototype_obj,
+                             Isolate* isolate) {
+  if (!FLAG_track_prototype_users) return;
+ Handle<PrototypeInfo> proto_info = GetOrCreatePrototypeInfo(map, isolate);
+  proto_info->set_prototype_object(*prototype_obj);
+}
+
+
+Object* Map::GetPrototypeObject() {
+  DisallowHeapAllocation no_handlification_required;
+  if (!is_prototype_map()) return Smi::FromInt(0);
+  Object* maybe_prototype_info = prototype_info();
+  if (!maybe_prototype_info->IsPrototypeInfo()) return Smi::FromInt(0);
+  PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_prototype_info);
+  Object* maybe_obj = proto_info->prototype_object();
+  if (maybe_obj->IsSmi()) return maybe_obj;
+  JSObject* object = JSObject::cast(maybe_obj);
+  if (object->map() != this) {
+    proto_info->set_prototype_object(Smi::FromInt(0));
+    return Smi::FromInt(0);
+  }
+  return object;
+}
+
+
+// static
 void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype,
                        PrototypeOptimizationMode proto_mode) {
   if (map->prototype()->IsJSObject() && FLAG_track_prototype_users) {
Index: src/objects.h
diff --git a/src/objects.h b/src/objects.h
index d604b8b580f3219fa3fedbd4923aad0c5d6212df..8c2271d33178048644b42670d0a12fd4d3e04f37 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -5775,6 +5775,9 @@ class DependentCode: public FixedArray {
 };


+class PrototypeInfo;
+
+
 // All heap objects have a Map that describes their structure.
 //  A Map contains information about:
 //  - Size information about the object
@@ -5982,6 +5985,16 @@ class Map: public HeapObject {
   // [prototype_info]: Per-prototype metadata. Aliased with transitions
   // (which prototype maps don't have).
   DECL_ACCESSORS(prototype_info, Object)
+  static Handle<PrototypeInfo> GetOrCreatePrototypeInfo(Handle<Map> map,
+                                                        Isolate* isolate);
+ // [prototype object]: points from a prototype map (which is never shared)
+  // to the object using it. Can be a Smi if the map is no longer used by a
+ // prototype object. Always use the GetPrototypeObject() getter, which zaps
+  // invalid references on the fly; the raw value is in the prototype_info.
+  static void SetPrototypeObject(Handle<Map> map,
+                                 Handle<JSObject> prototype_obj,
+                                 Isolate* isolate);
+  Object* GetPrototypeObject();

   Map* FindRootMap();
   Map* FindFieldOwner(int descriptor);
@@ -6553,8 +6566,9 @@ class Box : public Struct {
 // Container for metadata stored on each prototype map.
 class PrototypeInfo : public Struct {
  public:
- // [prototype_object]: The object using the map holding this PrototypeInfo.
-  DECL_ACCESSORS(prototype_object, JSObject)
+ // [prototype_object]: The object using the map holding this PrototypeInfo,
+  // or Smi(0) if uninitialized.
+  DECL_ACCESSORS(prototype_object, Object)
// [prototype_users]: WeakFixedArray containing maps using this prototype,
   // or Smi(0) if uninitialized.
   DECL_ACCESSORS(prototype_users, Object)
Index: src/transitions.cc
diff --git a/src/transitions.cc b/src/transitions.cc
index 2e65e387de74e05be69951495c5d3255ae04ba30..9fe9e8656447163d9fffcc2a5a8dce9400e2d3e7 100644
--- a/src/transitions.cc
+++ b/src/transitions.cc
@@ -316,6 +316,8 @@ void TransitionArray::SetNumberOfPrototypeTransitions(
 int TransitionArray::NumberOfTransitions(Object* raw_transitions) {
   if (CanStoreSimpleTransition(raw_transitions)) return 0;
   if (IsSimpleTransition(raw_transitions)) return 1;
+  // Prototype maps don't have transitions.
+  if (raw_transitions->IsPrototypeInfo()) return 0;
   DCHECK(IsFullTransitionArray(raw_transitions));
   return TransitionArray::cast(raw_transitions)->number_of_transitions();
 }


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