Fasterify JSObject::UnregisterPrototypeUser
When a (prototype) map registers as a user of its own prototype, it now remembers the index in that prototype's registry where it is listed. This remembered index is used on un-registration to find the right slot to clear without walking the entire registry. Compaction of the registry must update all entries' remembered indices. BUG=chromium:517778,chromium:517406 LOG=n R=yangguo@chromium.org Review URL: https://codereview.chromium.org/1276353004 Cr-Commit-Position: refs/heads/master@{#30079}
This commit is contained in:
parent
6ea0d55dfb
commit
1e65e20189
@ -55,6 +55,7 @@ Handle<PrototypeInfo> Factory::NewPrototypeInfo() {
|
||||
Handle<PrototypeInfo> result =
|
||||
Handle<PrototypeInfo>::cast(NewStruct(PROTOTYPE_INFO_TYPE));
|
||||
result->set_prototype_users(WeakFixedArray::Empty());
|
||||
result->set_registry_slot(PrototypeInfo::UNREGISTERED);
|
||||
result->set_validity_cell(Smi::FromInt(0));
|
||||
result->set_constructor_name(Smi::FromInt(0));
|
||||
return result;
|
||||
|
@ -4963,6 +4963,7 @@ ACCESSORS(ExecutableAccessorInfo, data, Object, kDataOffset)
|
||||
ACCESSORS(Box, value, Object, kValueOffset)
|
||||
|
||||
ACCESSORS(PrototypeInfo, prototype_users, Object, kPrototypeUsersOffset)
|
||||
SMI_ACCESSORS(PrototypeInfo, registry_slot, kRegistrySlotOffset)
|
||||
ACCESSORS(PrototypeInfo, validity_cell, Object, kValidityCellOffset)
|
||||
ACCESSORS(PrototypeInfo, constructor_name, Object, kConstructorNameOffset)
|
||||
|
||||
|
@ -967,6 +967,7 @@ void Box::BoxPrint(std::ostream& os) { // NOLINT
|
||||
void PrototypeInfo::PrototypeInfoPrint(std::ostream& os) { // NOLINT
|
||||
HeapObject::PrintHeader(os, "PrototypeInfo");
|
||||
os << "\n - prototype users: " << Brief(prototype_users());
|
||||
os << "\n - registry slot: " << registry_slot();
|
||||
os << "\n - validity cell: " << Brief(validity_cell());
|
||||
os << "\n - constructor name: " << Brief(constructor_name());
|
||||
os << "\n";
|
||||
|
236
src/objects.cc
236
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;
|
||||
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()));
|
||||
}
|
||||
|
||||
current_user = handle(proto->map(), isolate);
|
||||
current_user_info = proto_info;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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()));
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -9879,6 +9877,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) {
|
||||
@ -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.
|
||||
|
@ -1906,13 +1906,15 @@ class JSObject: public JSReceiver {
|
||||
PrototypeOptimizationMode mode);
|
||||
static void ReoptimizeIfPrototype(Handle<JSObject> object);
|
||||
static void LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate);
|
||||
static bool RegisterPrototypeUserIfNotRegistered(Handle<JSObject> prototype,
|
||||
Handle<HeapObject> user,
|
||||
Isolate* isolate);
|
||||
static bool UnregisterPrototypeUser(Handle<JSObject> prototype,
|
||||
Handle<HeapObject> user);
|
||||
static bool UnregisterPrototypeUser(Handle<Map> user, Isolate* isolate);
|
||||
static void InvalidatePrototypeChains(Map* map);
|
||||
|
||||
// Alternative implementation of WeakFixedArray::NullCallback.
|
||||
class PrototypeRegistryCompactionCallback {
|
||||
public:
|
||||
static void Callback(Object* value, int old_index, int new_index);
|
||||
};
|
||||
|
||||
// Retrieve interceptors.
|
||||
InterceptorInfo* GetNamedInterceptor();
|
||||
InterceptorInfo* GetIndexedInterceptor();
|
||||
@ -2531,17 +2533,22 @@ class FixedDoubleArray: public FixedArrayBase {
|
||||
|
||||
class WeakFixedArray : public FixedArray {
|
||||
public:
|
||||
enum SearchForDuplicates { kAlwaysAdd, kAddIfNotFound };
|
||||
|
||||
// If |maybe_array| is not a WeakFixedArray, a fresh one will be allocated.
|
||||
static Handle<WeakFixedArray> Add(
|
||||
Handle<Object> maybe_array, Handle<HeapObject> value,
|
||||
SearchForDuplicates search_for_duplicates = kAlwaysAdd,
|
||||
bool* was_present = NULL);
|
||||
// This function does not check if the value exists already, callers must
|
||||
// ensure this themselves if necessary.
|
||||
static Handle<WeakFixedArray> Add(Handle<Object> maybe_array,
|
||||
Handle<HeapObject> value,
|
||||
int* assigned_index = NULL);
|
||||
|
||||
// Returns true if an entry was found and removed.
|
||||
bool Remove(Handle<HeapObject> value);
|
||||
|
||||
class NullCallback {
|
||||
public:
|
||||
static void Callback(Object* value, int old_index, int new_index) {}
|
||||
};
|
||||
|
||||
template <class CompactionCallback>
|
||||
void Compact();
|
||||
|
||||
inline Object* Get(int index) const;
|
||||
@ -5467,6 +5474,8 @@ class Map: public HeapObject {
|
||||
// the given prototype's map).
|
||||
static Handle<PrototypeInfo> GetOrCreatePrototypeInfo(
|
||||
Handle<JSObject> prototype, Isolate* isolate);
|
||||
static Handle<PrototypeInfo> GetOrCreatePrototypeInfo(
|
||||
Handle<Map> prototype_map, Isolate* isolate);
|
||||
|
||||
// [prototype chain validity cell]: Associated with a prototype object,
|
||||
// stored in that object's map's PrototypeInfo, indicates that prototype
|
||||
@ -6036,9 +6045,15 @@ class Box : public Struct {
|
||||
// Container for metadata stored on each prototype map.
|
||||
class PrototypeInfo : public Struct {
|
||||
public:
|
||||
static const int UNREGISTERED = -1;
|
||||
|
||||
// [prototype_users]: WeakFixedArray containing maps using this prototype,
|
||||
// or Smi(0) if uninitialized.
|
||||
DECL_ACCESSORS(prototype_users, Object)
|
||||
// [registry_slot]: Slot in prototype's user registry where this user
|
||||
// is stored. Returns UNREGISTERED if this prototype has not been registered.
|
||||
inline int registry_slot() const;
|
||||
inline void set_registry_slot(int slot);
|
||||
// [validity_cell]: Cell containing the validity bit for prototype chains
|
||||
// going through this object, or Smi(0) if uninitialized.
|
||||
DECL_ACCESSORS(validity_cell, Object)
|
||||
@ -6052,7 +6067,8 @@ class PrototypeInfo : public Struct {
|
||||
DECLARE_VERIFIER(PrototypeInfo)
|
||||
|
||||
static const int kPrototypeUsersOffset = HeapObject::kHeaderSize;
|
||||
static const int kValidityCellOffset = kPrototypeUsersOffset + kPointerSize;
|
||||
static const int kRegistrySlotOffset = kPrototypeUsersOffset + kPointerSize;
|
||||
static const int kValidityCellOffset = kRegistrySlotOffset + kPointerSize;
|
||||
static const int kConstructorNameOffset = kValidityCellOffset + kPointerSize;
|
||||
static const int kSize = kConstructorNameOffset + kPointerSize;
|
||||
|
||||
|
@ -1926,7 +1926,23 @@ void Serializer::ObjectSerializer::Serialize() {
|
||||
if (object_->IsPrototypeInfo()) {
|
||||
Object* prototype_users = PrototypeInfo::cast(object_)->prototype_users();
|
||||
if (prototype_users->IsWeakFixedArray()) {
|
||||
WeakFixedArray::cast(prototype_users)->Compact();
|
||||
WeakFixedArray* array = WeakFixedArray::cast(prototype_users);
|
||||
array->Compact<JSObject::PrototypeRegistryCompactionCallback>();
|
||||
}
|
||||
}
|
||||
// Compaction of a prototype users list can require the registered users
|
||||
// to update their remembered slots. That doesn't work if those users
|
||||
// have already been serialized themselves. So if this object is a
|
||||
// registered user, compact its prototype's user list now.
|
||||
if (object_->IsMap()) {
|
||||
Map* map = Map::cast(object_);
|
||||
if (map->is_prototype_map() && map->prototype_info()->IsPrototypeInfo() &&
|
||||
PrototypeInfo::cast(map->prototype_info())->registry_slot() !=
|
||||
PrototypeInfo::UNREGISTERED) {
|
||||
JSObject* proto = JSObject::cast(map->prototype());
|
||||
PrototypeInfo* info = PrototypeInfo::cast(proto->map()->prototype_info());
|
||||
WeakFixedArray* array = WeakFixedArray::cast(info->prototype_users());
|
||||
array->Compact<JSObject::PrototypeRegistryCompactionCallback>();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1936,7 +1952,8 @@ void Serializer::ObjectSerializer::Serialize() {
|
||||
Script::cast(object_)->set_line_ends(undefined);
|
||||
Object* shared_list = Script::cast(object_)->shared_function_infos();
|
||||
if (shared_list->IsWeakFixedArray()) {
|
||||
WeakFixedArray::cast(shared_list)->Compact();
|
||||
WeakFixedArray::cast(shared_list)
|
||||
->Compact<WeakFixedArray::NullCallback>();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5954,7 +5954,7 @@ TEST(WeakFixedArray) {
|
||||
Handle<HeapNumber> number = CcTest::i_isolate()->factory()->NewHeapNumber(1);
|
||||
Handle<WeakFixedArray> array = WeakFixedArray::Add(Handle<Object>(), number);
|
||||
array->Remove(number);
|
||||
array->Compact();
|
||||
array->Compact<WeakFixedArray::NullCallback>();
|
||||
WeakFixedArray::Add(array, number);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user