Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index f7d0fd5b65fc5fa923c7dfbccf9cda42128a6795..b7947fa748195dde30c11d2fc6a70ee3b2a7ec59 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -1885,11 +1885,12 @@ void Map::ConnectElementsTransition(Handle<Map> parent, Handle<Map> child) { |
} |
-void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) { |
+void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map, |
+ int expected_additional_properties) { |
if (object->map() == *new_map) return; |
+ Handle<Map> old_map(object->map()); |
if (object->HasFastProperties()) { |
if (!new_map->is_dictionary_map()) { |
- Handle<Map> old_map(object->map()); |
MigrateFastToFast(object, new_map); |
if (old_map->is_prototype_map()) { |
// Clear out the old descriptor array to avoid problems to sharing |
@@ -1903,16 +1904,20 @@ void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) { |
DCHECK(new_map->GetBackPointer()->IsUndefined()); |
} |
} else { |
- MigrateFastToSlow(object, new_map, 0); |
+ MigrateFastToSlow(object, new_map, expected_additional_properties); |
} |
} else { |
- // For slow-to-fast migrations JSObject::TransformToFastProperties() |
+ // For slow-to-fast migrations JSObject::MigrateSlowToFast() |
// must be used instead. |
CHECK(new_map->is_dictionary_map()); |
// Slow-to-slow migration is trivial. |
object->set_map(*new_map); |
} |
+ if (old_map->is_prototype_map()) { |
+ new_map->set_prototype_info(old_map->prototype_info()); |
+ old_map->set_prototype_info(Smi::FromInt(0)); |
+ } |
} |
@@ -4515,7 +4520,7 @@ void JSObject::NormalizeProperties(Handle<JSObject> object, |
Handle<Map> map(object->map()); |
Handle<Map> new_map = Map::Normalize(map, mode, reason); |
- MigrateFastToSlow(object, new_map, expected_additional_properties); |
+ MigrateToMap(object, new_map, expected_additional_properties); |
} |
@@ -9888,6 +9893,7 @@ static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) { |
} |
+// static |
void JSObject::OptimizeAsPrototype(Handle<JSObject> object, |
PrototypeOptimizationMode mode) { |
if (object->IsGlobalObject()) return; |
@@ -9897,14 +9903,12 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object, |
JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0, |
"NormalizeAsPrototype"); |
} |
- bool has_just_copied_map = false; |
+ Handle<Map> previous_map(object->map()); |
if (!object->HasFastProperties()) { |
JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype"); |
- has_just_copied_map = true; |
} |
- if (mode == FAST_PROTOTYPE && object->HasFastProperties() && |
- !object->map()->is_prototype_map()) { |
- if (!has_just_copied_map) { |
+ if (!object->map()->is_prototype_map()) { |
+ if (object->map() == *previous_map) { |
Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype"); |
JSObject::MigrateToMap(object, new_map); |
} |
@@ -9927,39 +9931,54 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object, |
} |
+// static |
void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) { |
if (!object->map()->is_prototype_map()) return; |
OptimizeAsPrototype(object, FAST_PROTOTYPE); |
} |
+// static |
void JSObject::RegisterPrototypeUser(Handle<JSObject> prototype, |
Handle<HeapObject> user) { |
DCHECK(FLAG_track_prototype_users); |
Isolate* isolate = prototype->GetIsolate(); |
- Handle<Name> symbol = isolate->factory()->prototype_users_symbol(); |
- |
- // Get prototype users array, create it if it doesn't exist yet. |
- Handle<Object> maybe_array = |
- JSObject::GetProperty(prototype, symbol).ToHandleChecked(); |
- |
- Handle<WeakFixedArray> new_array = WeakFixedArray::Add(maybe_array, user); |
- if (!maybe_array.is_identical_to(new_array)) { |
- JSObject::SetOwnPropertyIgnoreAttributes(prototype, symbol, new_array, |
- DONT_ENUM).Assert(); |
+ if (prototype->IsJSGlobalProxy()) { |
+ PrototypeIterator iter(isolate, prototype); |
+ prototype = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); |
+ } |
+ 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->map()->set_prototype_info(*proto_info); |
+ } |
+ 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)) { |
+ proto_info->set_prototype_users(*new_array); |
} |
} |
+// static |
void JSObject::UnregisterPrototypeUser(Handle<JSObject> prototype, |
Handle<HeapObject> user) { |
Isolate* isolate = prototype->GetIsolate(); |
- Handle<Name> symbol = isolate->factory()->prototype_users_symbol(); |
- |
- Handle<Object> maybe_array = |
- JSObject::GetProperty(prototype, symbol).ToHandleChecked(); |
- if (!maybe_array->IsWeakFixedArray()) return; |
- Handle<WeakFixedArray>::cast(maybe_array)->Remove(user); |
+ 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; |
+ Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info), |
+ isolate); |
+ Object* maybe_registry = proto_info->prototype_users(); |
+ if (!maybe_registry->IsWeakFixedArray()) return; |
+ WeakFixedArray::cast(maybe_registry)->Remove(user); |
} |
@@ -9985,7 +10004,6 @@ void Map::SetPrototype(Handle<Object> prototype, |
bool Map::ShouldRegisterAsPrototypeUser(Handle<JSObject> prototype) { |
if (!FLAG_track_prototype_users) return false; |
if (this->is_prototype_map()) return true; |
- if (this->is_dictionary_map()) return false; |
Object* back = GetBackPointer(); |
if (!back->IsMap()) return true; |
if (Map::cast(back)->prototype() != *prototype) return true; |
@@ -9993,14 +10011,6 @@ bool Map::ShouldRegisterAsPrototypeUser(Handle<JSObject> prototype) { |
} |
-bool Map::CanUseOptimizationsBasedOnPrototypeRegistry() { |
- if (!FLAG_track_prototype_users) return false; |
- if (this->is_prototype_map()) return true; |
- if (GetBackPointer()->IsMap()) return true; |
- return false; |
-} |
- |
- |
Handle<Object> CacheInitialJSArrayMaps( |
Handle<Context> native_context, Handle<Map> initial_map) { |
// Replace all of the cached initial array maps in the native context with |