Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(553)

Unified Diff: src/objects.cc

Issue 1276353004: Fasterify JSObject::UnregisterPrototypeUser (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: fix compaction<->serialization interaction Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/objects.cc
diff --git a/src/objects.cc b/src/objects.cc
index 12c8d17c383974a20b587f12012e319f26281c6c..75726793b4fae7d0c89168dbbaf7b50d5bdd35c9 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -1895,6 +1895,33 @@ bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
}
+static void UpdatePrototypeUserRegistration(Handle<Map> old_map,
+ Handle<Map> new_map,
+ Isolate* isolate) {
+ if (!FLAG_track_prototype_users) return;
+ if (!old_map->is_prototype_map()) return;
+ DCHECK(new_map->is_prototype_map());
+ bool was_registered = JSObject::UnregisterPrototypeUser(old_map, isolate);
+ new_map->set_prototype_info(old_map->prototype_info());
+ old_map->set_prototype_info(Smi::FromInt(0));
+ if (FLAG_trace_prototype_users) {
+ PrintF("Moving prototype_info %p from map %p to map %p.\n",
+ reinterpret_cast<void*>(new_map->prototype_info()),
+ reinterpret_cast<void*>(*old_map),
+ reinterpret_cast<void*>(*new_map));
+ }
+ if (was_registered) {
+ if (new_map->prototype_info()->IsPrototypeInfo()) {
+ // The new map isn't registered with its prototype yet; reflect this fact
+ // in the PrototypeInfo it just inherited from the old map.
+ PrototypeInfo::cast(new_map->prototype_info())
+ ->set_registry_slot(PrototypeInfo::UNREGISTERED);
+ }
+ JSObject::LazyRegisterPrototypeUser(new_map, isolate);
+ }
+}
+
+
void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
int expected_additional_properties) {
if (object->map() == *new_map) return;
@@ -1908,16 +1935,7 @@ void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
// when a map on a prototype chain is registered with its prototype, then
// all prototypes further up the chain are also registered with their
// respective prototypes.
- Object* maybe_old_prototype = old_map->prototype();
- if (FLAG_track_prototype_users && old_map->is_prototype_map() &&
- maybe_old_prototype->IsJSObject()) {
- Handle<JSObject> old_prototype(JSObject::cast(maybe_old_prototype));
- bool was_registered =
- JSObject::UnregisterPrototypeUser(old_prototype, old_map);
- if (was_registered) {
- JSObject::LazyRegisterPrototypeUser(new_map, new_map->GetIsolate());
- }
- }
+ UpdatePrototypeUserRegistration(old_map, new_map, new_map->GetIsolate());
if (object->HasFastProperties()) {
if (!new_map->is_dictionary_map()) {
@@ -1950,20 +1968,7 @@ void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
// state now: the new map might have a new elements_kind, but the object's
// elements pointer hasn't been updated yet. Callers will fix this, but in
// the meantime, (indirectly) calling JSObjectVerify() must be avoided.
- DisallowHeapAllocation no_object_verification;
-
- if (old_map->is_prototype_map() && FLAG_track_prototype_users) {
- DCHECK(new_map->is_prototype_map());
- DCHECK(object->map() == *new_map);
- new_map->set_prototype_info(old_map->prototype_info());
- old_map->set_prototype_info(Smi::FromInt(0));
- if (FLAG_trace_prototype_users) {
- PrintF("Moving prototype_info %p from map %p to map %p.\n",
- reinterpret_cast<void*>(new_map->prototype_info()),
- reinterpret_cast<void*>(*old_map),
- reinterpret_cast<void*>(*new_map));
- }
- }
+ // When adding code here, add a DisallowHeapAllocation too.
}
@@ -4769,27 +4774,7 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object,
Handle<Map> new_map = Map::CopyDropDescriptors(old_map);
new_map->set_dictionary_map(false);
- if (old_map->is_prototype_map() && FLAG_track_prototype_users) {
- DCHECK(new_map->is_prototype_map());
-
- Object* maybe_old_prototype = old_map->prototype();
- if (maybe_old_prototype->IsJSObject()) {
- Handle<JSObject> old_prototype(JSObject::cast(maybe_old_prototype));
- bool was_registered =
- JSObject::UnregisterPrototypeUser(old_prototype, old_map);
- if (was_registered) {
- JSObject::LazyRegisterPrototypeUser(new_map, isolate);
- }
- }
- new_map->set_prototype_info(old_map->prototype_info());
- old_map->set_prototype_info(Smi::FromInt(0));
- if (FLAG_trace_prototype_users) {
- PrintF("Moving prototype_info %p from map %p to map %p.\n",
- reinterpret_cast<void*>(new_map->prototype_info()),
- reinterpret_cast<void*>(*old_map),
- reinterpret_cast<void*>(*new_map));
- }
- }
+ UpdatePrototypeUserRegistration(old_map, new_map, isolate);
#if TRACE_MAPS
if (FLAG_trace_maps) {
@@ -7938,59 +7923,46 @@ void WeakFixedArray::Set(Handle<WeakFixedArray> array, int index,
// static
-Handle<WeakFixedArray> WeakFixedArray::Add(
- Handle<Object> maybe_array, Handle<HeapObject> value,
- SearchForDuplicates search_for_duplicates, bool* was_present) {
+Handle<WeakFixedArray> WeakFixedArray::Add(Handle<Object> maybe_array,
+ Handle<HeapObject> value,
+ int* assigned_index) {
Handle<WeakFixedArray> array =
(maybe_array.is_null() || !maybe_array->IsWeakFixedArray())
? Allocate(value->GetIsolate(), 1, Handle<WeakFixedArray>::null())
: Handle<WeakFixedArray>::cast(maybe_array);
- if (was_present != NULL) *was_present = false;
- if (search_for_duplicates == kAddIfNotFound) {
- for (int i = 0; i < array->Length(); ++i) {
- if (array->Get(i) == *value) {
- if (was_present != NULL) *was_present = true;
- return array;
- }
- }
-#if 0 // Enable this if you want to check your search_for_duplicates flags.
- } else {
- for (int i = 0; i < array->Length(); ++i) {
- DCHECK_NE(*value, array->Get(i));
- }
-#endif
- }
-
// Try to store the new entry if there's room. Optimize for consecutive
// accesses.
int first_index = array->last_used_index();
- if (array->Length() > 0) {
+ int length = array->Length();
+ if (length > 0) {
for (int i = first_index;;) {
if (array->IsEmptySlot((i))) {
WeakFixedArray::Set(array, i, value);
+ if (assigned_index != NULL) *assigned_index = i;
return array;
}
if (FLAG_trace_weak_arrays) {
PrintF("[WeakFixedArray: searching for free slot]\n");
}
- i = (i + 1) % array->Length();
+ i = (i + 1) % length;
if (i == first_index) break;
}
}
// No usable slot found, grow the array.
- int new_length =
- array->Length() == 0 ? 1 : array->Length() + (array->Length() >> 1) + 4;
+ int new_length = length == 0 ? 1 : length + (length >> 1) + 4;
Handle<WeakFixedArray> new_array =
Allocate(array->GetIsolate(), new_length, array);
if (FLAG_trace_weak_arrays) {
PrintF("[WeakFixedArray: growing to size %d ]\n", new_length);
}
- WeakFixedArray::Set(new_array, array->Length(), value);
+ WeakFixedArray::Set(new_array, length, value);
+ if (assigned_index != NULL) *assigned_index = length;
return new_array;
}
+template <class CompactionCallback>
void WeakFixedArray::Compact() {
FixedArray* array = FixedArray::cast(this);
int new_length = kFirstIndex;
@@ -7998,6 +7970,9 @@ void WeakFixedArray::Compact() {
Object* element = array->get(i);
if (element->IsSmi()) continue;
if (WeakCell::cast(element)->cleared()) continue;
+ Object* value = WeakCell::cast(element)->value();
+ CompactionCallback::Callback(value, i - kFirstIndex,
+ new_length - kFirstIndex);
array->set(new_length++, element);
}
array->Shrink(new_length);
@@ -8005,6 +7980,23 @@ void WeakFixedArray::Compact() {
}
+void JSObject::PrototypeRegistryCompactionCallback::Callback(Object* value,
+ int old_index,
+ int new_index) {
+ DCHECK(value->IsMap() && Map::cast(value)->is_prototype_map());
+ Map* map = Map::cast(value);
+ DCHECK(map->prototype_info()->IsPrototypeInfo());
+ PrototypeInfo* proto_info = PrototypeInfo::cast(map->prototype_info());
+ DCHECK_EQ(old_index, proto_info->registry_slot());
+ proto_info->set_registry_slot(new_index);
+}
+
+
+template void WeakFixedArray::Compact<WeakFixedArray::NullCallback>();
+template void
+WeakFixedArray::Compact<JSObject::PrototypeRegistryCompactionCallback>();
+
+
bool WeakFixedArray::Remove(Handle<HeapObject> value) {
if (Length() == 0) return false;
// Optimize for the most recently added element to be removed again.
@@ -8012,8 +8004,7 @@ bool WeakFixedArray::Remove(Handle<HeapObject> value) {
for (int i = first_index;;) {
if (Get(i) == *value) {
Clear(i);
- // Users of WeakFixedArray should make sure that there are no duplicates,
- // they can use Add(..., kAddIfNotFound) if necessary.
+ // Users of WeakFixedArray should make sure that there are no duplicates.
return true;
}
i = (i + 1) % Length();
@@ -9758,67 +9749,74 @@ void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
DCHECK(user->is_prototype_map());
Handle<Map> current_user = user;
+ Handle<PrototypeInfo> current_user_info =
+ Map::GetOrCreatePrototypeInfo(user, isolate);
for (PrototypeIterator iter(user); !iter.IsAtEnd(); iter.Advance()) {
+ // Walk up the prototype chain as far as links haven't been registered yet.
+ if (current_user_info->registry_slot() != PrototypeInfo::UNREGISTERED) {
+ break;
+ }
Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter);
if (maybe_proto->IsJSGlobalProxy()) continue;
// Proxies on the prototype chain are not supported.
if (maybe_proto->IsJSProxy()) return;
Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto);
- bool just_registered =
- RegisterPrototypeUserIfNotRegistered(proto, current_user, isolate);
- // Walk up the prototype chain as far as links haven't been registered yet.
- if (!just_registered) break;
- current_user = handle(proto->map(), isolate);
- }
-}
-
+ Handle<PrototypeInfo> proto_info =
+ Map::GetOrCreatePrototypeInfo(proto, isolate);
+ Handle<Object> maybe_registry(proto_info->prototype_users(), isolate);
+ int slot = 0;
+ Handle<WeakFixedArray> new_array =
+ WeakFixedArray::Add(maybe_registry, current_user, &slot);
+ current_user_info->set_registry_slot(slot);
+ if (!maybe_registry.is_identical_to(new_array)) {
+ proto_info->set_prototype_users(*new_array);
+ }
+ if (FLAG_trace_prototype_users) {
+ PrintF("Registering %p as a user of prototype %p (map=%p).\n",
+ reinterpret_cast<void*>(*current_user),
+ reinterpret_cast<void*>(*proto),
+ reinterpret_cast<void*>(proto->map()));
+ }
-// Returns true if the user was not yet registered.
-// static
-bool JSObject::RegisterPrototypeUserIfNotRegistered(Handle<JSObject> prototype,
- Handle<HeapObject> user,
- Isolate* isolate) {
- Handle<PrototypeInfo> proto_info =
- Map::GetOrCreatePrototypeInfo(prototype, isolate);
- Handle<Object> maybe_registry(proto_info->prototype_users(), isolate);
- bool was_present = false;
- Handle<WeakFixedArray> new_array = WeakFixedArray::Add(
- maybe_registry, user, WeakFixedArray::kAddIfNotFound, &was_present);
- if (!maybe_registry.is_identical_to(new_array)) {
- proto_info->set_prototype_users(*new_array);
- }
- if (FLAG_trace_prototype_users && !was_present) {
- PrintF("Registering %p as a user of prototype %p (map=%p).\n",
- reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype),
- reinterpret_cast<void*>(prototype->map()));
+ current_user = handle(proto->map(), isolate);
+ current_user_info = proto_info;
}
- return !was_present;
}
// Can be called regardless of whether |user| was actually registered with
// |prototype|. Returns true when there was a registration.
// static
-bool JSObject::UnregisterPrototypeUser(Handle<JSObject> prototype,
- Handle<HeapObject> user) {
- Isolate* isolate = prototype->GetIsolate();
+bool JSObject::UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate) {
+ DCHECK(user->is_prototype_map());
+ // If it doesn't have a PrototypeInfo, it was never registered.
+ if (!user->prototype_info()->IsPrototypeInfo()) return false;
+ // If it doesn't have a prototype, it can't be registered.
+ if (!user->prototype()->IsJSObject()) return false;
+ Handle<JSObject> prototype(JSObject::cast(user->prototype()), isolate);
+ Handle<PrototypeInfo> user_info =
+ Map::GetOrCreatePrototypeInfo(user, isolate);
+ int slot = user_info->registry_slot();
+ if (slot == PrototypeInfo::UNREGISTERED) return false;
if (prototype->IsJSGlobalProxy()) {
PrototypeIterator iter(isolate, prototype);
prototype = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
}
DCHECK(prototype->map()->is_prototype_map());
Object* maybe_proto_info = prototype->map()->prototype_info();
- if (!maybe_proto_info->IsPrototypeInfo()) return false;
+ // User knows its registry slot, prototype info and user registry must exist.
+ DCHECK(maybe_proto_info->IsPrototypeInfo());
Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info),
isolate);
Object* maybe_registry = proto_info->prototype_users();
- if (!maybe_registry->IsWeakFixedArray()) return false;
- bool result = WeakFixedArray::cast(maybe_registry)->Remove(user);
- if (FLAG_trace_prototype_users && result) {
+ DCHECK(maybe_registry->IsWeakFixedArray());
+ DCHECK(WeakFixedArray::cast(maybe_registry)->Get(slot) == *user);
+ WeakFixedArray::cast(maybe_registry)->Clear(slot);
+ if (FLAG_trace_prototype_users) {
PrintF("Unregistering %p as a user of prototype %p.\n",
reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype));
}
- return result;
+ return true;
}
@@ -9880,6 +9878,19 @@ Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype,
// static
+Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map,
+ Isolate* isolate) {
+ Object* maybe_proto_info = prototype_map->prototype_info();
+ if (maybe_proto_info->IsPrototypeInfo()) {
+ return handle(PrototypeInfo::cast(maybe_proto_info), isolate);
+ }
+ Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo();
+ prototype_map->set_prototype_info(*proto_info);
+ return proto_info;
+}
+
+
+// static
Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
Isolate* isolate) {
Handle<Object> maybe_prototype(map->prototype(), isolate);
@@ -10370,13 +10381,14 @@ void SharedFunctionInfo::SetScript(Handle<SharedFunctionInfo> shared,
Handle<Script> script = Handle<Script>::cast(script_object);
Handle<Object> list(script->shared_function_infos(), shared->GetIsolate());
#ifdef DEBUG
- bool found = false;
- list = WeakFixedArray::Add(list, shared, WeakFixedArray::kAddIfNotFound,
- &found);
- CHECK(!found);
-#else
- list = WeakFixedArray::Add(list, shared, WeakFixedArray::kAlwaysAdd);
+ if (list->IsWeakFixedArray()) {
+ Handle<WeakFixedArray> array = Handle<WeakFixedArray>::cast(list);
+ for (int i = 0; i < array->Length(); ++i) {
+ DCHECK(array->Get(i) != *shared);
+ }
+ }
#endif // DEBUG
+ list = WeakFixedArray::Add(list, shared);
script->set_shared_function_infos(*list);
}
// Finally set new script.
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698