Avoid some recursion in InvalidatePrototypeChains

We can walk linear prototype chains using iteration instead of
recursion, reducing the likelihood (though not excluding the
possibility) that large prototype-relation graphs will run into
a stack overflow.
This partial mitigation should be performance neutral.

Bug: v8:10522
Change-Id: Ia266efe38a9cc52fe6ab2189066f45c4566f3596
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2245591
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68530}
This commit is contained in:
Jakob Kummerow 2020-06-24 18:19:52 +02:00 committed by Commit Bot
parent 4239880777
commit fdaa6c286e

View File

@ -4395,24 +4395,36 @@ void InvalidateOnePrototypeValidityCellInternal(Map map) {
}
void InvalidatePrototypeChainsInternal(Map map) {
InvalidateOnePrototypeValidityCellInternal(map);
// We handle linear prototype chains by looping, and multiple children
// by recursion, in order to reduce the likelihood of running into stack
// overflows. So, conceptually, the outer loop iterates the depth of the
// prototype tree, and the inner loop iterates the breadth of a node.
Map next_map;
for (; !map.is_null(); map = next_map, next_map = Map()) {
InvalidateOnePrototypeValidityCellInternal(map);
Object maybe_proto_info = map.prototype_info();
if (!maybe_proto_info.IsPrototypeInfo()) return;
PrototypeInfo proto_info = PrototypeInfo::cast(maybe_proto_info);
if (!proto_info.prototype_users().IsWeakArrayList()) {
return;
}
WeakArrayList prototype_users =
WeakArrayList::cast(proto_info.prototype_users());
// For now, only maps register themselves as users.
for (int i = PrototypeUsers::kFirstIndex; i < prototype_users.length(); ++i) {
HeapObject heap_object;
if (prototype_users.Get(i)->GetHeapObjectIfWeak(&heap_object) &&
heap_object.IsMap()) {
// Walk the prototype chain (backwards, towards leaf objects) if
// necessary.
InvalidatePrototypeChainsInternal(Map::cast(heap_object));
Object maybe_proto_info = map.prototype_info();
if (!maybe_proto_info.IsPrototypeInfo()) return;
PrototypeInfo proto_info = PrototypeInfo::cast(maybe_proto_info);
if (!proto_info.prototype_users().IsWeakArrayList()) {
return;
}
WeakArrayList prototype_users =
WeakArrayList::cast(proto_info.prototype_users());
// For now, only maps register themselves as users.
for (int i = PrototypeUsers::kFirstIndex; i < prototype_users.length();
++i) {
HeapObject heap_object;
if (prototype_users.Get(i)->GetHeapObjectIfWeak(&heap_object) &&
heap_object.IsMap()) {
// Walk the prototype chain (backwards, towards leaf objects) if
// necessary.
if (next_map.is_null()) {
next_map = Map::cast(heap_object);
} else {
InvalidatePrototypeChainsInternal(Map::cast(heap_object));
}
}
}
}
}