Commit aa9948f3 authored by Clemens Backes's avatar Clemens Backes Committed by Commit Bot

Revert "Reland "[runtime] Amortize descriptor array growing for fast-mode prototypes""

This reverts commit 71f9c117.

Reason for revert: Seems to cause several TSan flakes, e.g. https://ci.chromium.org/p/v8/builders/ci/V8%20Linux64%20TSAN%20-%20concurrent%20marking/12926

Original change's description:
> Reland "[runtime] Amortize descriptor array growing for fast-mode prototypes"
> 
> This is a reland of 2de2d3dc
> 
> Original change's description:
> > [runtime] Amortize descriptor array growing for fast-mode prototypes
> >
> > This avoids an O(n^2) algorithm that creates an equal amount of garbage.
> > Even though the actual final descriptor array might be a little bigger,
> > it reduces peak memory usage by allocating less.
> >
> > Bug: b:148346655
> > Change-Id: I984159d36e9e0b37c19bc81afc90c94c9a9d168a
> > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2135728
> > Commit-Queue: Toon Verwaest <verwaest@chromium.org>
> > Reviewed-by: Igor Sheludko <ishell@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#67031}
> 
> Bug: b:148346655, v8:10339
> Change-Id: I24436d8f49dc1fe527c4f6558db1abcba323b6f8
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2139215
> Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
> Reviewed-by: Igor Sheludko <ishell@chromium.org>
> Auto-Submit: Toon Verwaest <verwaest@chromium.org>
> Commit-Queue: Igor Sheludko <ishell@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#67475}

TBR=ulan@chromium.org,ishell@chromium.org,verwaest@chromium.org

Change-Id: I6fa02d0c89557eae33b792c1fe62c9c15eb0f7c7
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: b:148346655, v8:10339
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2172749Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67478}
parent faf3d4c8
...@@ -439,12 +439,8 @@ void Map::MapVerify(Isolate* isolate) { ...@@ -439,12 +439,8 @@ void Map::MapVerify(Isolate* isolate) {
if (GetBackPointer().IsUndefined(isolate)) { if (GetBackPointer().IsUndefined(isolate)) {
// Root maps must not have descriptors in the descriptor array that do not // Root maps must not have descriptors in the descriptor array that do not
// belong to the map. // belong to the map.
int nof = instance_descriptors().number_of_descriptors(); CHECK_EQ(NumberOfOwnDescriptors(),
if (IsDetached(isolate)) { instance_descriptors().number_of_descriptors());
CHECK(base::IsInRange(NumberOfOwnDescriptors(), 0, nof));
} else {
CHECK_EQ(NumberOfOwnDescriptors(), nof);
}
} else { } else {
// If there is a parent map it must be non-stable. // If there is a parent map it must be non-stable.
Map parent = Map::cast(GetBackPointer()); Map parent = Map::cast(GetBackPointer());
......
...@@ -407,14 +407,7 @@ int MarkingVisitorBase<ConcreteVisitor, MarkingState>::VisitMap(Map meta_map, ...@@ -407,14 +407,7 @@ int MarkingVisitorBase<ConcreteVisitor, MarkingState>::VisitMap(Map meta_map,
DescriptorArray descriptors = map.synchronized_instance_descriptors(); DescriptorArray descriptors = map.synchronized_instance_descriptors();
size += MarkDescriptorArrayBlack(map, descriptors); size += MarkDescriptorArrayBlack(map, descriptors);
int number_of_own_descriptors = map.NumberOfOwnDescriptors(); int number_of_own_descriptors = map.NumberOfOwnDescriptors();
if (map.IsDetached(heap_->isolate())) { if (number_of_own_descriptors) {
// Mark all descriptors in detached maps. Descriptor arrays are reused as
// objects transition between maps, and its possible that a newer map dies
// before an older map. Marking all descriptors through each map
// guarantees that we don't end up with dangling references that we don't
// clear since there are no explicit transitions.
VisitDescriptors(descriptors, descriptors.number_of_descriptors());
} else if (number_of_own_descriptors) {
// It is possible that the concurrent marker observes the // It is possible that the concurrent marker observes the
// number_of_own_descriptors out of sync with the descriptors. In that // number_of_own_descriptors out of sync with the descriptors. In that
// case the marking write barrier for the descriptor array will ensure // case the marking write barrier for the descriptor array will ensure
......
...@@ -838,7 +838,7 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { ...@@ -838,7 +838,7 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() {
Map maybe_feedback = JSObject::cast(*element_stack.back()).map(); Map maybe_feedback = JSObject::cast(*element_stack.back()).map();
// Don't consume feedback from objects with a map that's detached // Don't consume feedback from objects with a map that's detached
// from the transition tree. // from the transition tree.
if (!maybe_feedback.IsDetached(isolate_)) { if (!maybe_feedback.GetBackPointer().IsUndefined(isolate_)) {
feedback = handle(maybe_feedback, isolate_); feedback = handle(maybe_feedback, isolate_);
if (feedback->is_deprecated()) { if (feedback->is_deprecated()) {
feedback = Map::Update(isolate_, feedback); feedback = Map::Update(isolate_, feedback);
......
...@@ -123,12 +123,6 @@ bool Map::CanHaveFastTransitionableElementsKind() const { ...@@ -123,12 +123,6 @@ bool Map::CanHaveFastTransitionableElementsKind() const {
return CanHaveFastTransitionableElementsKind(instance_type()); return CanHaveFastTransitionableElementsKind(instance_type());
} }
bool Map::IsDetached(Isolate* isolate) const {
if (is_prototype_map()) return true;
return instance_type() == JS_OBJECT_TYPE && NumberOfOwnDescriptors() > 0 &&
GetBackPointer().IsUndefined(isolate);
}
// static // static
void Map::GeneralizeIfCanHaveTransitionableFastElementsKind( void Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
Isolate* isolate, InstanceType instance_type, Isolate* isolate, InstanceType instance_type,
......
...@@ -658,7 +658,7 @@ Map Map::FindRootMap(Isolate* isolate) const { ...@@ -658,7 +658,7 @@ Map Map::FindRootMap(Isolate* isolate) const {
if (back.IsUndefined(isolate)) { if (back.IsUndefined(isolate)) {
// Initial map must not contain descriptors in the descriptors array // Initial map must not contain descriptors in the descriptors array
// that do not belong to the map. // that do not belong to the map.
DCHECK_LE(result.NumberOfOwnDescriptors(), DCHECK_EQ(result.NumberOfOwnDescriptors(),
result.instance_descriptors().number_of_descriptors()); result.instance_descriptors().number_of_descriptors());
return result; return result;
} }
...@@ -1221,7 +1221,7 @@ Map Map::FindElementsKindTransitionedMap(Isolate* isolate, ...@@ -1221,7 +1221,7 @@ Map Map::FindElementsKindTransitionedMap(Isolate* isolate,
DisallowHeapAllocation no_allocation; DisallowHeapAllocation no_allocation;
DisallowDeoptimization no_deoptimization(isolate); DisallowDeoptimization no_deoptimization(isolate);
if (IsDetached(isolate)) return Map(); if (is_prototype_map()) return Map();
ElementsKind kind = elements_kind(); ElementsKind kind = elements_kind();
bool packed = IsFastPackedElementsKind(kind); bool packed = IsFastPackedElementsKind(kind);
...@@ -1354,7 +1354,7 @@ static Handle<Map> AddMissingElementsTransitions(Isolate* isolate, ...@@ -1354,7 +1354,7 @@ static Handle<Map> AddMissingElementsTransitions(Isolate* isolate,
ElementsKind kind = map->elements_kind(); ElementsKind kind = map->elements_kind();
TransitionFlag flag; TransitionFlag flag;
if (map->IsDetached(isolate)) { if (map->is_prototype_map()) {
flag = OMIT_TRANSITION; flag = OMIT_TRANSITION;
} else { } else {
flag = INSERT_TRANSITION; flag = INSERT_TRANSITION;
...@@ -1721,14 +1721,14 @@ void Map::ConnectTransition(Isolate* isolate, Handle<Map> parent, ...@@ -1721,14 +1721,14 @@ void Map::ConnectTransition(Isolate* isolate, Handle<Map> parent,
child->may_have_interesting_symbols()); child->may_have_interesting_symbols());
if (!parent->GetBackPointer().IsUndefined(isolate)) { if (!parent->GetBackPointer().IsUndefined(isolate)) {
parent->set_owns_descriptors(false); parent->set_owns_descriptors(false);
} else if (!parent->IsDetached(isolate)) { } else {
// |parent| is initial map and it must not contain descriptors in the // |parent| is initial map and it must not contain descriptors in the
// descriptors array that do not belong to the map. // descriptors array that do not belong to the map.
DCHECK_EQ(parent->NumberOfOwnDescriptors(), DCHECK_EQ(parent->NumberOfOwnDescriptors(),
parent->instance_descriptors().number_of_descriptors()); parent->instance_descriptors().number_of_descriptors());
} }
if (parent->IsDetached(isolate)) { if (parent->is_prototype_map()) {
DCHECK(child->IsDetached(isolate)); DCHECK(child->is_prototype_map());
if (FLAG_trace_maps) { if (FLAG_trace_maps) {
LOG(isolate, MapEvent("Transition", parent, child, "prototype", name)); LOG(isolate, MapEvent("Transition", parent, child, "prototype", name));
} }
...@@ -1755,9 +1755,7 @@ Handle<Map> Map::CopyReplaceDescriptors( ...@@ -1755,9 +1755,7 @@ Handle<Map> Map::CopyReplaceDescriptors(
result->set_may_have_interesting_symbols(true); result->set_may_have_interesting_symbols(true);
} }
if (map->is_prototype_map()) { if (!map->is_prototype_map()) {
result->InitializeDescriptors(isolate, *descriptors, *layout_descriptor);
} else {
if (flag == INSERT_TRANSITION && if (flag == INSERT_TRANSITION &&
TransitionsAccessor(isolate, map).CanHaveMoreTransitions()) { TransitionsAccessor(isolate, map).CanHaveMoreTransitions()) {
result->InitializeDescriptors(isolate, *descriptors, *layout_descriptor); result->InitializeDescriptors(isolate, *descriptors, *layout_descriptor);
...@@ -1768,11 +1766,19 @@ Handle<Map> Map::CopyReplaceDescriptors( ...@@ -1768,11 +1766,19 @@ Handle<Map> Map::CopyReplaceDescriptors(
descriptors->GeneralizeAllFields(); descriptors->GeneralizeAllFields();
result->InitializeDescriptors(isolate, *descriptors, result->InitializeDescriptors(isolate, *descriptors,
LayoutDescriptor::FastPointerLayout()); LayoutDescriptor::FastPointerLayout());
// If we were trying to insert a transition but failed because there are
// too many transitions already, mark the object as a prototype to avoid
// tracking transitions from the detached map.
if (flag == INSERT_TRANSITION) {
result->set_is_prototype_map(true);
}
} }
} else {
result->InitializeDescriptors(isolate, *descriptors, *layout_descriptor);
} }
if (FLAG_trace_maps && if (FLAG_trace_maps &&
// Mirror conditions above that did not call ConnectTransition(). // Mirror conditions above that did not call ConnectTransition().
(map->IsDetached(isolate) || (map->is_prototype_map() ||
!(flag == INSERT_TRANSITION && !(flag == INSERT_TRANSITION &&
TransitionsAccessor(isolate, map).CanHaveMoreTransitions()))) { TransitionsAccessor(isolate, map).CanHaveMoreTransitions()))) {
LOG(isolate, MapEvent("ReplaceDescriptors", map, result, reason, LOG(isolate, MapEvent("ReplaceDescriptors", map, result, reason,
...@@ -1954,7 +1960,7 @@ Handle<Map> Map::AsLanguageMode(Isolate* isolate, Handle<Map> initial_map, ...@@ -1954,7 +1960,7 @@ Handle<Map> Map::AsLanguageMode(Isolate* isolate, Handle<Map> initial_map,
} }
Handle<Map> Map::CopyForElementsTransition(Isolate* isolate, Handle<Map> map) { Handle<Map> Map::CopyForElementsTransition(Isolate* isolate, Handle<Map> map) {
DCHECK(!map->IsDetached(isolate)); DCHECK(!map->is_prototype_map());
Handle<Map> new_map = CopyDropDescriptors(isolate, map); Handle<Map> new_map = CopyDropDescriptors(isolate, map);
if (map->owns_descriptors()) { if (map->owns_descriptors()) {
...@@ -2155,7 +2161,7 @@ Handle<Map> Map::TransitionToDataProperty(Isolate* isolate, Handle<Map> map, ...@@ -2155,7 +2161,7 @@ Handle<Map> Map::TransitionToDataProperty(Isolate* isolate, Handle<Map> map,
StoreOrigin store_origin) { StoreOrigin store_origin) {
RuntimeCallTimerScope stats_scope( RuntimeCallTimerScope stats_scope(
isolate, isolate,
map->IsDetached(isolate) map->is_prototype_map()
? RuntimeCallCounterId::kPrototypeMap_TransitionToDataProperty ? RuntimeCallCounterId::kPrototypeMap_TransitionToDataProperty
: RuntimeCallCounterId::kMap_TransitionToDataProperty); : RuntimeCallCounterId::kMap_TransitionToDataProperty);
...@@ -2269,7 +2275,7 @@ Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map, ...@@ -2269,7 +2275,7 @@ Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map,
PropertyAttributes attributes) { PropertyAttributes attributes) {
RuntimeCallTimerScope stats_scope( RuntimeCallTimerScope stats_scope(
isolate, isolate,
map->IsDetached(isolate) map->is_prototype_map()
? RuntimeCallCounterId::kPrototypeMap_TransitionToAccessorProperty ? RuntimeCallCounterId::kPrototypeMap_TransitionToAccessorProperty
: RuntimeCallCounterId::kMap_TransitionToAccessorProperty); : RuntimeCallCounterId::kMap_TransitionToAccessorProperty);
...@@ -2384,64 +2390,19 @@ Handle<Map> Map::CopyAddDescriptor(Isolate* isolate, Handle<Map> map, ...@@ -2384,64 +2390,19 @@ Handle<Map> Map::CopyAddDescriptor(Isolate* isolate, Handle<Map> map,
return ShareDescriptor(isolate, map, descriptors, descriptor); return ShareDescriptor(isolate, map, descriptors, descriptor);
} }
Handle<DescriptorArray> new_descriptors; int nof = map->NumberOfOwnDescriptors();
Handle<LayoutDescriptor> new_layout_descriptor; Handle<DescriptorArray> new_descriptors =
if (map->IsDetached(isolate)) { DescriptorArray::CopyUpTo(isolate, descriptors, nof, 1);
if (descriptors->number_of_slack_descriptors() == 0) { new_descriptors->Append(descriptor);
int old_size = descriptors->number_of_descriptors();
if (old_size == 0) {
new_descriptors = DescriptorArray::Allocate(isolate, 0, 1);
} else {
int slack = SlackForArraySize(old_size, kMaxNumberOfDescriptors);
EnsureDescriptorSlack(isolate, map, slack);
new_descriptors = handle(map->instance_descriptors(), isolate);
}
} else {
new_descriptors = descriptors;
}
new_layout_descriptor =
FLAG_unbox_double_fields
? LayoutDescriptor::ShareAppend(isolate, map,
descriptor->GetDetails())
: handle(LayoutDescriptor::FastPointerLayout(), isolate);
} else {
int nof = map->NumberOfOwnDescriptors();
new_descriptors = DescriptorArray::CopyUpTo(isolate, descriptors, nof, 1);
new_layout_descriptor =
FLAG_unbox_double_fields
? LayoutDescriptor::New(isolate, map, new_descriptors, nof + 1)
: handle(LayoutDescriptor::FastPointerLayout(), isolate);
}
Handle<Map> result = CopyDropDescriptors(isolate, map);
if (descriptor->GetKey()->IsInterestingSymbol()) {
result->set_may_have_interesting_symbols(true);
}
{
DisallowHeapAllocation no_gc;
new_descriptors->Append(descriptor);
result->InitializeDescriptors(isolate, *new_descriptors,
*new_layout_descriptor);
}
if (flag == INSERT_TRANSITION &&
TransitionsAccessor(isolate, map).CanHaveMoreTransitions()) {
ConnectTransition(isolate, map, result, descriptor->GetKey(),
SIMPLE_PROPERTY_TRANSITION);
}
if (FLAG_trace_maps && Handle<LayoutDescriptor> new_layout_descriptor =
// Mirror conditions above that did not call ConnectTransition(). FLAG_unbox_double_fields
(map->IsDetached(isolate) || ? LayoutDescriptor::New(isolate, map, new_descriptors, nof + 1)
!(flag == INSERT_TRANSITION && : handle(LayoutDescriptor::FastPointerLayout(), isolate);
TransitionsAccessor(isolate, map).CanHaveMoreTransitions()))) {
LOG(isolate, MapEvent("ReplaceDescriptors", map, result,
"CopyAddDescriptor", descriptor->GetKey()));
}
return result; return CopyReplaceDescriptors(
isolate, map, new_descriptors, new_layout_descriptor, flag,
descriptor->GetKey(), "CopyAddDescriptor", SIMPLE_PROPERTY_TRANSITION);
} }
Handle<Map> Map::CopyInsertDescriptor(Isolate* isolate, Handle<Map> map, Handle<Map> Map::CopyInsertDescriptor(Isolate* isolate, Handle<Map> map,
......
...@@ -422,11 +422,6 @@ class Map : public HeapObject { ...@@ -422,11 +422,6 @@ class Map : public HeapObject {
inline bool has_sealed_elements() const; inline bool has_sealed_elements() const;
inline bool has_frozen_elements() const; inline bool has_frozen_elements() const;
// Weakly checks whether a map is detached from all transition trees. If this
// returns true, the map is guaranteed to be detached. If it returns false,
// there is no guarantee it is attached.
inline bool IsDetached(Isolate* isolate) const;
// Returns true if the current map doesn't have DICTIONARY_ELEMENTS but if a // Returns true if the current map doesn't have DICTIONARY_ELEMENTS but if a
// map with DICTIONARY_ELEMENTS was found in the prototype chain. // map with DICTIONARY_ELEMENTS was found in the prototype chain.
bool DictionaryElementsInPrototypeChainOnly(Isolate* isolate); bool DictionaryElementsInPrototypeChainOnly(Isolate* isolate);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment