Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index a1f34cb95d7e86f02ce7d95da679b85a2ede8e11..4164df55d8db6723e2177182dfaa0ce26800960e 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -1026,7 +1026,7 @@ Object* FunctionTemplateInfo::GetCompatibleReceiver(Isolate* isolate, |
FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type); |
// Check the receiver. |
for (PrototypeIterator iter(isolate, JSObject::cast(receiver), |
- PrototypeIterator::START_AT_RECEIVER, |
+ kStartAtReceiver, |
PrototypeIterator::END_AT_NON_HIDDEN); |
!iter.IsAtEnd(); iter.Advance()) { |
if (signature->IsTemplateFor(iter.GetCurrent())) return iter.GetCurrent(); |
@@ -1484,7 +1484,7 @@ void JSObject::SetNormalizedProperty(Handle<JSObject> object, |
Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate, |
Handle<JSReceiver> object, |
Handle<Object> proto) { |
- PrototypeIterator iter(isolate, object, PrototypeIterator::START_AT_RECEIVER); |
+ PrototypeIterator iter(isolate, object, kStartAtReceiver); |
while (true) { |
if (!iter.AdvanceFollowingProxies()) return Nothing<bool>(); |
if (iter.IsAtEnd()) return Just(false); |
@@ -11862,6 +11862,26 @@ static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) { |
return false; |
} |
+// static |
+void JSObject::MakePrototypesFast(Handle<Object> receiver, |
+ WhereToStart where_to_start, |
+ Isolate* isolate) { |
+ if (!receiver->IsJSReceiver()) return; |
+ for (PrototypeIterator iter(isolate, Handle<JSReceiver>::cast(receiver), |
+ where_to_start); |
+ !iter.IsAtEnd(); iter.Advance()) { |
+ Handle<Object> current = PrototypeIterator::GetCurrent(iter); |
+ if (!current->IsJSObject()) return; |
+ Handle<JSObject> current_obj = Handle<JSObject>::cast(current); |
+ Map* current_map = current_obj->map(); |
+ if (current_map->is_prototype_map() && |
+ !current_map->should_be_fast_prototype_map()) { |
+ Handle<Map> map(current_map); |
+ Map::SetShouldBeFastPrototypeMap(map, true, isolate); |
+ JSObject::OptimizeAsPrototype(current_obj, FAST_PROTOTYPE); |
+ } |
+ } |
+} |
// static |
void JSObject::OptimizeAsPrototype(Handle<JSObject> object, |
@@ -11873,10 +11893,12 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object, |
"NormalizeAsPrototype"); |
} |
Handle<Map> previous_map(object->map()); |
- if (!object->HasFastProperties()) { |
- JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype"); |
- } |
- if (!object->map()->is_prototype_map()) { |
+ if (object->map()->is_prototype_map()) { |
+ if (object->map()->should_be_fast_prototype_map() && |
+ !object->HasFastProperties()) { |
+ JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype"); |
+ } |
+ } else { |
if (object->map() == *previous_map) { |
Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype"); |
JSObject::MigrateToMap(object, new_map); |
@@ -11904,6 +11926,7 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object, |
// static |
void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) { |
if (!object->map()->is_prototype_map()) return; |
+ if (!object->map()->should_be_fast_prototype_map()) return; |
OptimizeAsPrototype(object, FAST_PROTOTYPE); |
} |
@@ -12045,6 +12068,15 @@ Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map, |
return proto_info; |
} |
+// static |
+void Map::SetShouldBeFastPrototypeMap(Handle<Map> map, bool value, |
+ Isolate* isolate) { |
+ if (value == false && !map->prototype_info()->IsPrototypeInfo()) { |
+ // "False" is the implicit default value, so there's nothing to do. |
+ return; |
+ } |
+ GetOrCreatePrototypeInfo(map, isolate)->set_should_be_fast_map(value); |
+} |
// static |
Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map, |
@@ -13041,9 +13073,8 @@ void JSFunction::CalculateInstanceSizeForDerivedClass( |
int* instance_size, int* in_object_properties) { |
Isolate* isolate = GetIsolate(); |
int expected_nof_properties = 0; |
- for (PrototypeIterator iter(isolate, this, |
- PrototypeIterator::START_AT_RECEIVER); |
- !iter.IsAtEnd(); iter.Advance()) { |
+ for (PrototypeIterator iter(isolate, this, kStartAtReceiver); !iter.IsAtEnd(); |
+ iter.Advance()) { |
JSReceiver* current = iter.GetCurrent<JSReceiver>(); |
if (!current->IsJSFunction()) break; |
JSFunction* func = JSFunction::cast(current); |
@@ -14867,8 +14898,7 @@ Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object, |
if (from_javascript) { |
// Find the first object in the chain whose prototype object is not |
// hidden. |
- PrototypeIterator iter(isolate, real_receiver, |
- PrototypeIterator::START_AT_PROTOTYPE, |
+ PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype, |
PrototypeIterator::END_AT_NON_HIDDEN); |
while (!iter.IsAtEnd()) { |
// Casting to JSObject is fine because hidden prototypes are never |
@@ -14901,7 +14931,7 @@ Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object, |
// new prototype chain. |
if (value->IsJSReceiver()) { |
for (PrototypeIterator iter(isolate, JSReceiver::cast(*value), |
- PrototypeIterator::START_AT_RECEIVER); |
+ kStartAtReceiver); |
!iter.IsAtEnd(); iter.Advance()) { |
if (iter.GetCurrent<JSReceiver>() == *object) { |
// Cycle detected. |