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.