Reland "[runtime] Refactor TransitionsAccessor"
This is a reland of c927ada76c
Fix: Recalculate encoding after an allocation (that can potentially
trigger GC) in EnsureHasFullTransitionArray.
Original change's description:
> [runtime] Refactor TransitionsAccessor
>
> Problems:
> - The class uses a bare Map field, but some methods can trigger GC
> causing it to have a potential dangling pointer in case of map
> compaction.
> - Some methods invalidate the object state and should not be used again.
> - Complicate logic with a no_gc and a gc aware constructors. Some
> methods can only be called if the object is constructed with a
> particular constructor (e.g, Insert and PutPrototypeTransition).
>
> Note: Most usages of this class is done by constructing an object and
> calling a single method:
> `TransitionAccessor(...).Method(...)`
> So we can easily change them to a static method.
>
> This CL:
> 1. Adds DISALLOW_GARBAGE_COLLECTION to the class.
> 2. Makes methods that can trigger GC static.
> 3. Creates static helper functions that wrap the class in a different
> scope, since TransitionsAccessor now forces the scope to disallow gc.
> 4. Removes now unnecessary "Reload" logic.
>
> Bug: chromium:1295133, v8:12578
> Change-Id: I85484e7235fbd5e69894e26f5e1c491c6f69635e
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3450416
> Reviewed-by: Dominik Inführ <dinfuehr@chromium.org>
> Reviewed-by: Toon Verwaest <verwaest@chromium.org>
> Commit-Queue: Victor Gomes <victorgomes@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#79051}
Bug: chromium:1295133, v8:12578
Change-Id: If3880c2480433b78567870c8d14508d6ad9eccbd
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3460405
Reviewed-by: Dominik Inführ <dinfuehr@chromium.org>
Auto-Submit: Victor Gomes <victorgomes@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79069}
This commit is contained in:
parent
af78745f2e
commit
24ff6e28c7
@ -1119,10 +1119,9 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition(
|
||||
PropertyAttributes attrs) const {
|
||||
// Check if the {map} has a data transition with the given {name}.
|
||||
Map transition =
|
||||
TransitionsAccessor(isolate(), map.object(), true)
|
||||
TransitionsAccessor(isolate(), *map.object(), true)
|
||||
.SearchTransition(*name.object(), PropertyKind::kData, attrs);
|
||||
if (transition.is_null()) return Invalid();
|
||||
|
||||
base::Optional<MapRef> maybe_transition_map =
|
||||
TryMakeRef(broker(), transition);
|
||||
if (!maybe_transition_map.has_value()) return Invalid();
|
||||
|
@ -563,8 +563,7 @@ int InstanceSizeWithMinSlack(JSHeapBroker* broker, MapRef map) {
|
||||
DCHECK(map.object()->GetBackPointer().IsUndefined(broker->isolate()));
|
||||
|
||||
static constexpr bool kConcurrentAccess = true;
|
||||
TransitionsAccessor(broker->isolate(), *map.object(), &no_gc,
|
||||
kConcurrentAccess)
|
||||
TransitionsAccessor(broker->isolate(), *map.object(), kConcurrentAccess)
|
||||
.TraverseTransitionTree([&](Map m) {
|
||||
maps.push_back(broker->CanonicalPersistentHandle(m));
|
||||
});
|
||||
|
@ -520,11 +520,9 @@ void Map::MapVerify(Isolate* isolate) {
|
||||
}
|
||||
}
|
||||
SLOW_DCHECK(instance_descriptors(isolate).IsSortedNoDuplicates());
|
||||
DisallowGarbageCollection no_gc;
|
||||
SLOW_DCHECK(TransitionsAccessor(isolate, *this).IsSortedNoDuplicates());
|
||||
SLOW_DCHECK(
|
||||
TransitionsAccessor(isolate, *this, &no_gc).IsSortedNoDuplicates());
|
||||
SLOW_DCHECK(TransitionsAccessor(isolate, *this, &no_gc)
|
||||
.IsConsistentWithBackPointers());
|
||||
TransitionsAccessor(isolate, *this).IsConsistentWithBackPointers());
|
||||
// Only JSFunction maps have has_prototype_slot() bit set and constructible
|
||||
// JSFunction objects must have prototype slot.
|
||||
CHECK_IMPLIES(has_prototype_slot(),
|
||||
|
@ -2592,8 +2592,7 @@ void Map::MapPrint(std::ostream& os) {
|
||||
// the isolate to iterate over the transitions.
|
||||
if (!IsReadOnlyHeapObject(*this)) {
|
||||
Isolate* isolate = GetIsolateFromWritableObject(*this);
|
||||
DisallowGarbageCollection no_gc;
|
||||
TransitionsAccessor transitions(isolate, *this, &no_gc);
|
||||
TransitionsAccessor transitions(isolate, *this);
|
||||
int nof_transitions = transitions.NumberOfTransitions();
|
||||
if (nof_transitions > 0) {
|
||||
os << "\n - transitions #" << nof_transitions << ": ";
|
||||
@ -2780,14 +2779,13 @@ void TransitionsAccessor::PrintTransitionTree(
|
||||
descriptors.PrintDescriptorDetails(os, descriptor,
|
||||
PropertyDetails::kForTransitions);
|
||||
}
|
||||
TransitionsAccessor transitions(isolate_, target, no_gc);
|
||||
TransitionsAccessor transitions(isolate_, target);
|
||||
transitions.PrintTransitionTree(os, level + 1, no_gc);
|
||||
}
|
||||
}
|
||||
|
||||
void JSObject::PrintTransitions(std::ostream& os) {
|
||||
DisallowGarbageCollection no_gc;
|
||||
TransitionsAccessor ta(GetIsolate(), map(), &no_gc);
|
||||
TransitionsAccessor ta(GetIsolate(), map());
|
||||
if (ta.NumberOfTransitions() == 0) return;
|
||||
os << "\n - transitions";
|
||||
ta.PrintTransitions(os);
|
||||
@ -2891,9 +2889,8 @@ V8_EXPORT_PRIVATE extern void _v8_internal_Print_TransitionTree(void* object) {
|
||||
printf("Please provide a valid Map\n");
|
||||
} else {
|
||||
#if defined(DEBUG) || defined(OBJECT_PRINT)
|
||||
i::DisallowGarbageCollection no_gc;
|
||||
i::Map map = i::Map::unchecked_cast(o);
|
||||
i::TransitionsAccessor transitions(i::Isolate::Current(), map, &no_gc);
|
||||
i::TransitionsAccessor transitions(i::Isolate::Current(), map);
|
||||
transitions.PrintTransitionTree();
|
||||
#endif
|
||||
}
|
||||
|
@ -2535,7 +2535,7 @@ void MarkCompactCollector::ClearPotentialSimpleMapTransition(Map dead_target) {
|
||||
Map parent = Map::cast(potential_parent);
|
||||
DisallowGarbageCollection no_gc_obviously;
|
||||
if (non_atomic_marking_state()->IsBlackOrGrey(parent) &&
|
||||
TransitionsAccessor(isolate(), parent, &no_gc_obviously)
|
||||
TransitionsAccessor(isolate(), parent)
|
||||
.HasSimpleTransitionTo(dead_target)) {
|
||||
ClearPotentialSimpleMapTransition(parent, dead_target);
|
||||
}
|
||||
|
@ -486,14 +486,13 @@ Handle<Object> JsonParser<Char>::BuildJsonObject(
|
||||
descriptor_index)),
|
||||
isolate_);
|
||||
} else {
|
||||
DisallowGarbageCollection no_gc;
|
||||
TransitionsAccessor transitions(isolate(), *map, &no_gc);
|
||||
TransitionsAccessor transitions(isolate(), *map);
|
||||
expected = transitions.ExpectedTransitionKey();
|
||||
if (!expected.is_null()) {
|
||||
// Directly read out the target while reading out the key, otherwise it
|
||||
// might die while building the string below.
|
||||
target = TransitionsAccessor(isolate(), *map, &no_gc)
|
||||
.ExpectedTransitionTarget();
|
||||
target =
|
||||
TransitionsAccessor(isolate(), *map).ExpectedTransitionTarget();
|
||||
}
|
||||
}
|
||||
|
||||
@ -505,7 +504,7 @@ Handle<Object> JsonParser<Char>::BuildJsonObject(
|
||||
map = ParentOfDescriptorOwner(isolate_, map, feedback, descriptor);
|
||||
feedback_descriptors = 0;
|
||||
}
|
||||
if (!TransitionsAccessor(isolate(), map)
|
||||
if (!TransitionsAccessor(isolate(), *map)
|
||||
.FindTransitionToField(key)
|
||||
.ToHandle(&target)) {
|
||||
break;
|
||||
|
@ -3230,7 +3230,8 @@ void JSObject::MigrateToMap(Isolate* isolate, Handle<JSObject> object,
|
||||
old_map->set_owns_descriptors(false);
|
||||
DCHECK(old_map->is_abandoned_prototype_map());
|
||||
// Ensure that no transition was inserted for prototype migrations.
|
||||
DCHECK_EQ(0, TransitionsAccessor(isolate, old_map).NumberOfTransitions());
|
||||
DCHECK_EQ(0,
|
||||
TransitionsAccessor(isolate, *old_map).NumberOfTransitions());
|
||||
DCHECK(new_map->GetBackPointer(isolate).IsUndefined(isolate));
|
||||
DCHECK(object->map(isolate) != *old_map);
|
||||
}
|
||||
@ -4202,10 +4203,10 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition(
|
||||
|
||||
Handle<Map> old_map(object->map(), isolate);
|
||||
old_map = Map::Update(isolate, old_map);
|
||||
TransitionsAccessor transitions(isolate, old_map);
|
||||
Map transition = transitions.SearchSpecial(*transition_marker);
|
||||
if (!transition.is_null()) {
|
||||
Handle<Map> transition_map(transition, isolate);
|
||||
Handle<Map> transition_map;
|
||||
MaybeHandle<Map> maybe_transition_map =
|
||||
TransitionsAccessor::SearchSpecial(isolate, old_map, *transition_marker);
|
||||
if (maybe_transition_map.ToHandle(&transition_map)) {
|
||||
DCHECK(transition_map->has_dictionary_elements() ||
|
||||
transition_map->has_typed_array_elements() ||
|
||||
transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS ||
|
||||
@ -4215,7 +4216,7 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition(
|
||||
new_element_dictionary = CreateElementDictionary(isolate, object);
|
||||
}
|
||||
JSObject::MigrateToMap(isolate, object, transition_map);
|
||||
} else if (transitions.CanHaveMoreTransitions()) {
|
||||
} else if (TransitionsAccessor::CanHaveMoreTransitions(isolate, old_map)) {
|
||||
// Create a new descriptor array with the appropriate property attributes
|
||||
Handle<Map> new_map = Map::CopyForPreventExtensions(
|
||||
isolate, old_map, attrs, transition_marker, "CopyForPreventExtensions");
|
||||
|
@ -768,8 +768,7 @@ void Map::SetBackPointer(HeapObject value, WriteBarrierMode mode) {
|
||||
|
||||
// static
|
||||
Map Map::ElementsTransitionMap(Isolate* isolate, ConcurrencyMode cmode) {
|
||||
DisallowGarbageCollection no_gc;
|
||||
return TransitionsAccessor(isolate, *this, &no_gc,
|
||||
return TransitionsAccessor(isolate, *this,
|
||||
cmode == ConcurrencyMode::kConcurrent)
|
||||
.SearchSpecial(ReadOnlyRoots(isolate).elements_transition_symbol());
|
||||
}
|
||||
|
@ -277,7 +277,7 @@ Handle<Map> MapUpdater::UpdateImpl() {
|
||||
}
|
||||
DCHECK_EQ(kEnd, state_);
|
||||
if (FLAG_fast_map_update) {
|
||||
TransitionsAccessor(isolate_, old_map_).SetMigrationTarget(*result_map_);
|
||||
TransitionsAccessor::SetMigrationTarget(isolate_, old_map_, *result_map_);
|
||||
}
|
||||
return result_map_;
|
||||
}
|
||||
@ -304,7 +304,7 @@ IntegrityLevelTransitionInfo DetectIntegrityLevelTransitions(
|
||||
// be the last one in the transition tree).
|
||||
DCHECK(!map.is_extensible());
|
||||
Map previous = Map::cast(map.GetBackPointer(isolate));
|
||||
TransitionsAccessor last_transitions(isolate, previous, no_gc, is_concurrent);
|
||||
TransitionsAccessor last_transitions(isolate, previous, is_concurrent);
|
||||
if (!last_transitions.HasIntegrityLevelTransitionTo(
|
||||
map, &info.integrity_level_symbol, &info.integrity_level)) {
|
||||
// The last transition was not integrity level transition - just bail out.
|
||||
@ -322,7 +322,7 @@ IntegrityLevelTransitionInfo DetectIntegrityLevelTransitions(
|
||||
// with integrity level transitions, just bail out.
|
||||
while (!source_map.is_extensible()) {
|
||||
previous = Map::cast(source_map.GetBackPointer(isolate));
|
||||
TransitionsAccessor transitions(isolate, previous, no_gc, is_concurrent);
|
||||
TransitionsAccessor transitions(isolate, previous, is_concurrent);
|
||||
if (!transitions.HasIntegrityLevelTransitionTo(source_map)) {
|
||||
return info;
|
||||
}
|
||||
@ -390,7 +390,7 @@ base::Optional<Map> MapUpdater::TryUpdateNoLock(Isolate* isolate, Map old_map,
|
||||
|
||||
if (info.has_integrity_level_transition) {
|
||||
// Now replay the integrity level transition.
|
||||
result = TransitionsAccessor(isolate, result, &no_gc,
|
||||
result = TransitionsAccessor(isolate, result,
|
||||
cmode == ConcurrencyMode::kConcurrent)
|
||||
.SearchSpecial(info.integrity_level_symbol);
|
||||
}
|
||||
@ -423,14 +423,13 @@ MapUpdater::State MapUpdater::Normalize(const char* reason) {
|
||||
// static
|
||||
void MapUpdater::CompleteInobjectSlackTracking(Isolate* isolate,
|
||||
Map initial_map) {
|
||||
DisallowGarbageCollection no_gc;
|
||||
// Has to be an initial map.
|
||||
DCHECK(initial_map.GetBackPointer().IsUndefined(isolate));
|
||||
|
||||
const int slack = initial_map.ComputeMinObjectSlack(isolate);
|
||||
DCHECK_GE(slack, 0);
|
||||
|
||||
TransitionsAccessor transitions(isolate, initial_map, &no_gc);
|
||||
TransitionsAccessor transitions(isolate, initial_map);
|
||||
TransitionsAccessor::TraverseCallback callback;
|
||||
if (slack != 0) {
|
||||
// Resize the initial map and all maps in its transition tree.
|
||||
@ -518,7 +517,7 @@ bool MapUpdater::TrySaveIntegrityLevelTransitions() {
|
||||
Handle<Map> previous =
|
||||
handle(Map::cast(old_map_->GetBackPointer()), isolate_);
|
||||
Symbol integrity_level_symbol;
|
||||
TransitionsAccessor last_transitions(isolate_, previous);
|
||||
TransitionsAccessor last_transitions(isolate_, *previous);
|
||||
if (!last_transitions.HasIntegrityLevelTransitionTo(
|
||||
*old_map_, &integrity_level_symbol, &integrity_level_)) {
|
||||
// The last transition was not integrity level transition - just bail out.
|
||||
@ -538,7 +537,7 @@ bool MapUpdater::TrySaveIntegrityLevelTransitions() {
|
||||
while (!integrity_source_map_->is_extensible()) {
|
||||
previous =
|
||||
handle(Map::cast(integrity_source_map_->GetBackPointer()), isolate_);
|
||||
TransitionsAccessor transitions(isolate_, previous);
|
||||
TransitionsAccessor transitions(isolate_, *previous);
|
||||
if (!transitions.HasIntegrityLevelTransitionTo(*integrity_source_map_)) {
|
||||
return false;
|
||||
}
|
||||
@ -641,12 +640,11 @@ MapUpdater::State MapUpdater::FindTargetMap() {
|
||||
int root_nof = root_map_->NumberOfOwnDescriptors();
|
||||
for (InternalIndex i : InternalIndex::Range(root_nof, old_nof_)) {
|
||||
PropertyDetails old_details = GetDetails(i);
|
||||
Map transition = TransitionsAccessor(isolate_, target_map_)
|
||||
.SearchTransition(GetKey(i), old_details.kind(),
|
||||
old_details.attributes());
|
||||
if (transition.is_null()) break;
|
||||
Handle<Map> tmp_map(transition, isolate_);
|
||||
|
||||
Handle<Map> tmp_map;
|
||||
MaybeHandle<Map> maybe_tmp_map = TransitionsAccessor::SearchTransition(
|
||||
isolate_, target_map_, GetKey(i), old_details.kind(),
|
||||
old_details.attributes());
|
||||
if (!maybe_tmp_map.ToHandle(&tmp_map)) break;
|
||||
Handle<DescriptorArray> tmp_descriptors(
|
||||
tmp_map->instance_descriptors(isolate_), isolate_);
|
||||
|
||||
@ -727,10 +725,9 @@ MapUpdater::State MapUpdater::FindTargetMap() {
|
||||
}
|
||||
|
||||
// We try to replay the integrity level transition here.
|
||||
Map transition = TransitionsAccessor(isolate_, target_map_)
|
||||
.SearchSpecial(*integrity_level_symbol_);
|
||||
if (!transition.is_null()) {
|
||||
result_map_ = handle(transition, isolate_);
|
||||
MaybeHandle<Map> maybe_transition = TransitionsAccessor::SearchSpecial(
|
||||
isolate_, target_map_, *integrity_level_symbol_);
|
||||
if (maybe_transition.ToHandle(&result_map_)) {
|
||||
state_ = kEnd;
|
||||
return state_; // Done.
|
||||
}
|
||||
@ -739,11 +736,11 @@ MapUpdater::State MapUpdater::FindTargetMap() {
|
||||
// Find the last compatible target map in the transition tree.
|
||||
for (InternalIndex i : InternalIndex::Range(target_nof, old_nof_)) {
|
||||
PropertyDetails old_details = GetDetails(i);
|
||||
Map transition = TransitionsAccessor(isolate_, target_map_)
|
||||
.SearchTransition(GetKey(i), old_details.kind(),
|
||||
old_details.attributes());
|
||||
if (transition.is_null()) break;
|
||||
Handle<Map> tmp_map(transition, isolate_);
|
||||
Handle<Map> tmp_map;
|
||||
MaybeHandle<Map> maybe_tmp_map = TransitionsAccessor::SearchTransition(
|
||||
isolate_, target_map_, GetKey(i), old_details.kind(),
|
||||
old_details.attributes());
|
||||
if (!maybe_tmp_map.ToHandle(&tmp_map)) break;
|
||||
Handle<DescriptorArray> tmp_descriptors(
|
||||
tmp_map->instance_descriptors(isolate_), isolate_);
|
||||
#ifdef DEBUG
|
||||
@ -933,15 +930,13 @@ Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() {
|
||||
}
|
||||
|
||||
Handle<Map> MapUpdater::FindSplitMap(Handle<DescriptorArray> descriptors) {
|
||||
DisallowGarbageCollection no_gc;
|
||||
|
||||
int root_nof = root_map_->NumberOfOwnDescriptors();
|
||||
Map current = *root_map_;
|
||||
for (InternalIndex i : InternalIndex::Range(root_nof, old_nof_)) {
|
||||
Name name = descriptors->GetKey(i);
|
||||
PropertyDetails details = descriptors->GetDetails(i);
|
||||
Map next =
|
||||
TransitionsAccessor(isolate_, current, &no_gc)
|
||||
TransitionsAccessor(isolate_, current)
|
||||
.SearchTransition(name, details.kind(), details.attributes());
|
||||
if (next.is_null()) break;
|
||||
DescriptorArray next_descriptors = next.instance_descriptors(isolate_);
|
||||
@ -981,21 +976,20 @@ MapUpdater::State MapUpdater::ConstructNewMap() {
|
||||
}
|
||||
InternalIndex split_index(split_nof);
|
||||
PropertyDetails split_details = GetDetails(split_index);
|
||||
TransitionsAccessor transitions(isolate_, split_map);
|
||||
|
||||
// Invalidate a transition target at |key|.
|
||||
Handle<Map> maybe_transition(
|
||||
transitions.SearchTransition(GetKey(split_index), split_details.kind(),
|
||||
split_details.attributes()),
|
||||
isolate_);
|
||||
if (!maybe_transition->is_null()) {
|
||||
maybe_transition->DeprecateTransitionTree(isolate_);
|
||||
MaybeHandle<Map> maybe_transition = TransitionsAccessor::SearchTransition(
|
||||
isolate_, split_map, GetKey(split_index), split_details.kind(),
|
||||
split_details.attributes());
|
||||
if (!maybe_transition.is_null()) {
|
||||
maybe_transition.ToHandleChecked()->DeprecateTransitionTree(isolate_);
|
||||
}
|
||||
|
||||
// If |maybe_transition| is not nullptr then the transition array already
|
||||
// contains entry for given descriptor. This means that the transition
|
||||
// could be inserted regardless of whether transitions array is full or not.
|
||||
if (maybe_transition->is_null() && !transitions.CanHaveMoreTransitions()) {
|
||||
if (maybe_transition.is_null() &&
|
||||
!TransitionsAccessor::CanHaveMoreTransitions(isolate_, split_map)) {
|
||||
return Normalize("Normalize_CantHaveMoreTransitions");
|
||||
}
|
||||
|
||||
@ -1056,8 +1050,7 @@ MapUpdater::State MapUpdater::ConstructNewMap() {
|
||||
MapUpdater::State MapUpdater::ConstructNewMapWithIntegrityLevelTransition() {
|
||||
DCHECK_EQ(kAtIntegrityLevelSource, state_);
|
||||
|
||||
TransitionsAccessor transitions(isolate_, target_map_);
|
||||
if (!transitions.CanHaveMoreTransitions()) {
|
||||
if (!TransitionsAccessor::CanHaveMoreTransitions(isolate_, target_map_)) {
|
||||
return Normalize("Normalize_CantHaveMoreTransitions");
|
||||
}
|
||||
|
||||
@ -1127,7 +1120,6 @@ void MapUpdater::UpdateFieldType(Isolate* isolate, Handle<Map> map,
|
||||
const MaybeObjectHandle& new_wrapped_type) {
|
||||
DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeak());
|
||||
// We store raw pointers in the queue, so no allocations are allowed.
|
||||
DisallowGarbageCollection no_gc;
|
||||
PropertyDetails details =
|
||||
map->instance_descriptors(isolate).GetDetails(descriptor);
|
||||
if (details.location() != PropertyLocation::kField) return;
|
||||
@ -1144,7 +1136,7 @@ void MapUpdater::UpdateFieldType(Isolate* isolate, Handle<Map> map,
|
||||
Map current = backlog.front();
|
||||
backlog.pop();
|
||||
|
||||
TransitionsAccessor transitions(isolate, current, &no_gc);
|
||||
TransitionsAccessor transitions(isolate, current);
|
||||
int num_transitions = transitions.NumberOfTransitions();
|
||||
for (int i = 0; i < num_transitions; ++i) {
|
||||
Map target = transitions.GetTarget(i);
|
||||
|
@ -557,8 +557,7 @@ bool Map::HasOutOfObjectProperties() const {
|
||||
|
||||
void Map::DeprecateTransitionTree(Isolate* isolate) {
|
||||
if (is_deprecated()) return;
|
||||
DisallowGarbageCollection no_gc;
|
||||
TransitionsAccessor transitions(isolate, *this, &no_gc);
|
||||
TransitionsAccessor transitions(isolate, *this);
|
||||
int num_transitions = transitions.NumberOfTransitions();
|
||||
for (int i = 0; i < num_transitions; ++i) {
|
||||
transitions.GetTarget(i).DeprecateTransitionTree(isolate);
|
||||
@ -645,7 +644,7 @@ Map SearchMigrationTarget(Isolate* isolate, Map old_map) {
|
||||
|
||||
Map target = old_map;
|
||||
do {
|
||||
target = TransitionsAccessor(isolate, target, &no_gc).GetMigrationTarget();
|
||||
target = TransitionsAccessor(isolate, target).GetMigrationTarget();
|
||||
} while (!target.is_null() && target.is_deprecated());
|
||||
if (target.is_null()) return Map();
|
||||
|
||||
@ -693,8 +692,7 @@ MaybeHandle<Map> Map::TryUpdate(Isolate* isolate, Handle<Map> old_map) {
|
||||
isolate, *old_map, ConcurrencyMode::kNotConcurrent);
|
||||
if (!new_map.has_value()) return MaybeHandle<Map>();
|
||||
if (FLAG_fast_map_update) {
|
||||
TransitionsAccessor(isolate, *old_map, &no_gc)
|
||||
.SetMigrationTarget(new_map.value());
|
||||
TransitionsAccessor::SetMigrationTarget(isolate, old_map, new_map.value());
|
||||
}
|
||||
return handle(new_map.value(), isolate);
|
||||
}
|
||||
@ -716,7 +714,7 @@ Map Map::TryReplayPropertyTransitions(Isolate* isolate, Map old_map,
|
||||
for (InternalIndex i : InternalIndex::Range(root_nof, old_nof)) {
|
||||
PropertyDetails old_details = old_descriptors.GetDetails(i);
|
||||
Map transition =
|
||||
TransitionsAccessor(isolate, new_map, &no_gc, is_concurrent)
|
||||
TransitionsAccessor(isolate, new_map, is_concurrent)
|
||||
.SearchTransition(old_descriptors.GetKey(i), old_details.kind(),
|
||||
old_details.attributes());
|
||||
if (transition.is_null()) return Map();
|
||||
@ -1404,7 +1402,7 @@ void Map::ConnectTransition(Isolate* isolate, Handle<Map> parent,
|
||||
LOG(isolate, MapEvent("Transition", parent, child, "prototype", name));
|
||||
}
|
||||
} else {
|
||||
TransitionsAccessor(isolate, parent).Insert(name, child, flag);
|
||||
TransitionsAccessor::Insert(isolate, parent, name, child, flag);
|
||||
if (FLAG_log_maps) {
|
||||
LOG(isolate, MapEvent("Transition", parent, child, "", name));
|
||||
}
|
||||
@ -1432,7 +1430,7 @@ Handle<Map> Map::CopyReplaceDescriptors(Isolate* isolate, Handle<Map> map,
|
||||
result->InitializeDescriptors(isolate, *descriptors);
|
||||
} else {
|
||||
if (flag == INSERT_TRANSITION &&
|
||||
TransitionsAccessor(isolate, map).CanHaveMoreTransitions()) {
|
||||
TransitionsAccessor::CanHaveMoreTransitions(isolate, map)) {
|
||||
result->InitializeDescriptors(isolate, *descriptors);
|
||||
|
||||
DCHECK(!maybe_name.is_null());
|
||||
@ -1544,7 +1542,7 @@ Handle<Map> Map::CopyAsElementsKind(Isolate* isolate, Handle<Map> map,
|
||||
|
||||
bool insert_transition =
|
||||
flag == INSERT_TRANSITION &&
|
||||
TransitionsAccessor(isolate, map).CanHaveMoreTransitions() &&
|
||||
TransitionsAccessor::CanHaveMoreTransitions(isolate, map) &&
|
||||
maybe_elements_transition_map.is_null();
|
||||
|
||||
if (insert_transition) {
|
||||
@ -1578,10 +1576,10 @@ Handle<Map> Map::AsLanguageMode(Isolate* isolate, Handle<Map> initial_map,
|
||||
DCHECK_EQ(LanguageMode::kStrict, shared_info->language_mode());
|
||||
Handle<Symbol> transition_symbol =
|
||||
isolate->factory()->strict_function_transition_symbol();
|
||||
Map maybe_transition = TransitionsAccessor(isolate, initial_map)
|
||||
.SearchSpecial(*transition_symbol);
|
||||
MaybeHandle<Map> maybe_transition = TransitionsAccessor::SearchSpecial(
|
||||
isolate, initial_map, *transition_symbol);
|
||||
if (!maybe_transition.is_null()) {
|
||||
return handle(maybe_transition, isolate);
|
||||
return maybe_transition.ToHandleChecked();
|
||||
}
|
||||
initial_map->NotifyLeafMapLayoutChange(isolate);
|
||||
|
||||
@ -1595,7 +1593,7 @@ Handle<Map> Map::AsLanguageMode(Isolate* isolate, Handle<Map> initial_map,
|
||||
map->set_prototype(initial_map->prototype());
|
||||
map->set_construction_counter(initial_map->construction_counter());
|
||||
|
||||
if (TransitionsAccessor(isolate, initial_map).CanHaveMoreTransitions()) {
|
||||
if (TransitionsAccessor::CanHaveMoreTransitions(isolate, initial_map)) {
|
||||
Map::ConnectTransition(isolate, initial_map, map, transition_symbol,
|
||||
SPECIAL_TRANSITION);
|
||||
}
|
||||
@ -1807,11 +1805,10 @@ Handle<Map> Map::TransitionToDataProperty(Isolate* isolate, Handle<Map> map,
|
||||
// Migrate to the newest map before storing the property.
|
||||
map = Update(isolate, map);
|
||||
|
||||
Map maybe_transition =
|
||||
TransitionsAccessor(isolate, map)
|
||||
.SearchTransition(*name, PropertyKind::kData, attributes);
|
||||
if (!maybe_transition.is_null()) {
|
||||
Handle<Map> transition(maybe_transition, isolate);
|
||||
MaybeHandle<Map> maybe_transition = TransitionsAccessor::SearchTransition(
|
||||
isolate, map, *name, PropertyKind::kData, attributes);
|
||||
Handle<Map> transition;
|
||||
if (maybe_transition.ToHandle(&transition)) {
|
||||
InternalIndex descriptor = transition->LastAdded();
|
||||
|
||||
DCHECK_EQ(attributes, transition->instance_descriptors(isolate)
|
||||
@ -1903,11 +1900,10 @@ Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map,
|
||||
? KEEP_INOBJECT_PROPERTIES
|
||||
: CLEAR_INOBJECT_PROPERTIES;
|
||||
|
||||
Map maybe_transition =
|
||||
TransitionsAccessor(isolate, map)
|
||||
.SearchTransition(*name, PropertyKind::kAccessor, attributes);
|
||||
if (!maybe_transition.is_null()) {
|
||||
Handle<Map> transition(maybe_transition, isolate);
|
||||
MaybeHandle<Map> maybe_transition = TransitionsAccessor::SearchTransition(
|
||||
isolate, map, *name, PropertyKind::kAccessor, attributes);
|
||||
Handle<Map> transition;
|
||||
if (maybe_transition.ToHandle(&transition)) {
|
||||
DescriptorArray descriptors = transition->instance_descriptors(isolate);
|
||||
InternalIndex last_descriptor = transition->LastAdded();
|
||||
DCHECK(descriptors.GetKey(last_descriptor).Equals(*name));
|
||||
@ -2000,7 +1996,7 @@ Handle<Map> Map::CopyAddDescriptor(Isolate* isolate, Handle<Map> map,
|
||||
// Share descriptors only if map owns descriptors and it not an initial map.
|
||||
if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
|
||||
!map->GetBackPointer().IsUndefined(isolate) &&
|
||||
TransitionsAccessor(isolate, map).CanHaveMoreTransitions()) {
|
||||
TransitionsAccessor::CanHaveMoreTransitions(isolate, map)) {
|
||||
return ShareDescriptor(isolate, map, descriptors, descriptor);
|
||||
}
|
||||
|
||||
@ -2152,12 +2148,11 @@ bool Map::EquivalentToForNormalization(const Map other,
|
||||
}
|
||||
|
||||
int Map::ComputeMinObjectSlack(Isolate* isolate) {
|
||||
DisallowGarbageCollection no_gc;
|
||||
// Has to be an initial map.
|
||||
DCHECK(GetBackPointer().IsUndefined(isolate));
|
||||
|
||||
int slack = UnusedPropertyFields();
|
||||
TransitionsAccessor transitions(isolate, *this, &no_gc);
|
||||
TransitionsAccessor transitions(isolate, *this);
|
||||
TransitionsAccessor::TraverseCallback callback = [&](Map map) {
|
||||
slack = std::min(slack, map.UnusedPropertyFields());
|
||||
};
|
||||
@ -2283,11 +2278,11 @@ void Map::StartInobjectSlackTracking() {
|
||||
Handle<Map> Map::TransitionToPrototype(Isolate* isolate, Handle<Map> map,
|
||||
Handle<HeapObject> prototype) {
|
||||
Handle<Map> new_map =
|
||||
TransitionsAccessor(isolate, map).GetPrototypeTransition(prototype);
|
||||
TransitionsAccessor::GetPrototypeTransition(isolate, map, prototype);
|
||||
if (new_map.is_null()) {
|
||||
new_map = Copy(isolate, map, "TransitionToPrototype");
|
||||
TransitionsAccessor(isolate, map)
|
||||
.PutPrototypeTransition(prototype, new_map);
|
||||
TransitionsAccessor::PutPrototypeTransition(isolate, map, prototype,
|
||||
new_map);
|
||||
Map::SetPrototype(isolate, new_map, prototype);
|
||||
}
|
||||
return new_map;
|
||||
|
@ -17,9 +17,23 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// static
|
||||
TransitionArray TransitionsAccessor::GetTransitionArray(
|
||||
Isolate* isolate, MaybeObject raw_transitions) {
|
||||
DCHECK_EQ(kFullTransitionArray, GetEncoding(isolate, raw_transitions));
|
||||
USE(isolate);
|
||||
return TransitionArray::cast(raw_transitions.GetHeapObjectAssumeStrong());
|
||||
}
|
||||
|
||||
// static
|
||||
TransitionArray TransitionsAccessor::GetTransitionArray(Isolate* isolate,
|
||||
Handle<Map> map) {
|
||||
MaybeObject raw_transitions = map->raw_transitions(isolate, kAcquireLoad);
|
||||
return GetTransitionArray(isolate, raw_transitions);
|
||||
}
|
||||
|
||||
TransitionArray TransitionsAccessor::transitions() {
|
||||
DCHECK_EQ(kFullTransitionArray, encoding());
|
||||
return TransitionArray::cast(raw_transitions_->GetHeapObjectAssumeStrong());
|
||||
return GetTransitionArray(isolate_, raw_transitions_);
|
||||
}
|
||||
|
||||
OBJECT_CONSTRUCTORS_IMPL(TransitionArray, WeakFixedArray)
|
||||
@ -193,26 +207,13 @@ int TransitionArray::SearchName(Name name, bool concurrent_search,
|
||||
}
|
||||
|
||||
TransitionsAccessor::TransitionsAccessor(Isolate* isolate, Map map,
|
||||
DisallowGarbageCollection* no_gc,
|
||||
bool concurrent_access)
|
||||
: isolate_(isolate), map_(map), concurrent_access_(concurrent_access) {
|
||||
Initialize();
|
||||
USE(no_gc);
|
||||
}
|
||||
|
||||
TransitionsAccessor::TransitionsAccessor(Isolate* isolate, Handle<Map> map,
|
||||
bool concurrent_access)
|
||||
: isolate_(isolate),
|
||||
map_handle_(map),
|
||||
map_(*map),
|
||||
map_(map),
|
||||
raw_transitions_(map.raw_transitions(isolate_, kAcquireLoad)),
|
||||
encoding_(GetEncoding(isolate_, raw_transitions_)),
|
||||
concurrent_access_(concurrent_access) {
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void TransitionsAccessor::Reload() {
|
||||
DCHECK(!map_handle_.is_null());
|
||||
map_ = *map_handle_;
|
||||
Initialize();
|
||||
DCHECK_IMPLIES(encoding_ == kMigrationTarget, map_.is_deprecated());
|
||||
}
|
||||
|
||||
int TransitionsAccessor::Capacity() { return transitions().Capacity(); }
|
||||
@ -239,13 +240,36 @@ TransitionsAccessor::Encoding TransitionsAccessor::GetEncoding(
|
||||
}
|
||||
}
|
||||
|
||||
void TransitionsAccessor::Initialize() {
|
||||
raw_transitions_ = map_.raw_transitions(isolate_, kAcquireLoad);
|
||||
encoding_ = GetEncoding(isolate_, raw_transitions_);
|
||||
DCHECK_IMPLIES(encoding_ == kMigrationTarget, map_.is_deprecated());
|
||||
#if DEBUG
|
||||
needs_reload_ = false;
|
||||
#endif
|
||||
// static
|
||||
TransitionsAccessor::Encoding TransitionsAccessor::GetEncoding(
|
||||
Isolate* isolate, TransitionArray array) {
|
||||
return GetEncoding(isolate, MaybeObject::FromObject(array));
|
||||
}
|
||||
|
||||
// static
|
||||
TransitionsAccessor::Encoding TransitionsAccessor::GetEncoding(
|
||||
Isolate* isolate, Handle<Map> map) {
|
||||
MaybeObject raw_transitions = map->raw_transitions(isolate, kAcquireLoad);
|
||||
return GetEncoding(isolate, raw_transitions);
|
||||
}
|
||||
|
||||
// static
|
||||
MaybeHandle<Map> TransitionsAccessor::SearchTransition(
|
||||
Isolate* isolate, Handle<Map> map, Name name, PropertyKind kind,
|
||||
PropertyAttributes attributes) {
|
||||
Map result = TransitionsAccessor(isolate, *map)
|
||||
.SearchTransition(name, kind, attributes);
|
||||
if (result.is_null()) return MaybeHandle<Map>();
|
||||
return MaybeHandle<Map>(result, isolate);
|
||||
}
|
||||
|
||||
// static
|
||||
MaybeHandle<Map> TransitionsAccessor::SearchSpecial(Isolate* isolate,
|
||||
Handle<Map> map,
|
||||
Symbol name) {
|
||||
Map result = TransitionsAccessor(isolate, *map).SearchSpecial(name);
|
||||
if (result.is_null()) return MaybeHandle<Map>();
|
||||
return MaybeHandle<Map>(result, isolate);
|
||||
}
|
||||
|
||||
int TransitionArray::number_of_transitions() const {
|
||||
|
@ -12,10 +12,13 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
Map TransitionsAccessor::GetSimpleTransition() {
|
||||
switch (encoding()) {
|
||||
// static
|
||||
Map TransitionsAccessor::GetSimpleTransition(Isolate* isolate,
|
||||
Handle<Map> map) {
|
||||
MaybeObject raw_transitions = map->raw_transitions(isolate, kAcquireLoad);
|
||||
switch (GetEncoding(isolate, raw_transitions)) {
|
||||
case kWeakRef:
|
||||
return Map::cast(raw_transitions_->GetHeapObjectAssumeWeak());
|
||||
return Map::cast(raw_transitions->GetHeapObjectAssumeWeak());
|
||||
default:
|
||||
return Map();
|
||||
}
|
||||
@ -34,56 +37,56 @@ bool TransitionsAccessor::HasSimpleTransitionTo(Map map) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void TransitionsAccessor::Insert(Handle<Name> name, Handle<Map> target,
|
||||
// static
|
||||
void TransitionsAccessor::Insert(Isolate* isolate, Handle<Map> map,
|
||||
Handle<Name> name, Handle<Map> target,
|
||||
SimpleTransitionFlag flag) {
|
||||
DCHECK(!concurrent_access_);
|
||||
DCHECK(!map_handle_.is_null());
|
||||
DCHECK_NE(kPrototypeInfo, encoding());
|
||||
target->SetBackPointer(map_);
|
||||
Encoding encoding = GetEncoding(isolate, map);
|
||||
DCHECK_NE(kPrototypeInfo, encoding);
|
||||
target->SetBackPointer(*map);
|
||||
|
||||
// If the map doesn't have any transitions at all yet, install the new one.
|
||||
if (encoding() == kUninitialized || encoding() == kMigrationTarget) {
|
||||
if (encoding == kUninitialized || encoding == kMigrationTarget) {
|
||||
if (flag == SIMPLE_PROPERTY_TRANSITION) {
|
||||
ReplaceTransitions(HeapObjectReference::Weak(*target));
|
||||
ReplaceTransitions(isolate, map, HeapObjectReference::Weak(*target));
|
||||
return;
|
||||
}
|
||||
// If the flag requires a full TransitionArray, allocate one.
|
||||
Handle<TransitionArray> result =
|
||||
isolate_->factory()->NewTransitionArray(1, 0);
|
||||
isolate->factory()->NewTransitionArray(1, 0);
|
||||
result->Set(0, *name, HeapObjectReference::Weak(*target));
|
||||
ReplaceTransitions(MaybeObject::FromObject(*result));
|
||||
Reload();
|
||||
DCHECK_EQ(kFullTransitionArray, encoding());
|
||||
ReplaceTransitions(isolate, map, result);
|
||||
DCHECK_EQ(kFullTransitionArray, GetEncoding(isolate, *result));
|
||||
return;
|
||||
}
|
||||
|
||||
if (encoding() == kWeakRef) {
|
||||
Map simple_transition = GetSimpleTransition();
|
||||
if (encoding == kWeakRef) {
|
||||
Map simple_transition = GetSimpleTransition(isolate, map);
|
||||
DCHECK(!simple_transition.is_null());
|
||||
|
||||
if (flag == SIMPLE_PROPERTY_TRANSITION) {
|
||||
Name key = GetSimpleTransitionKey(simple_transition);
|
||||
PropertyDetails old_details = GetSimpleTargetDetails(simple_transition);
|
||||
PropertyDetails old_details =
|
||||
simple_transition.GetLastDescriptorDetails(isolate);
|
||||
PropertyDetails new_details = GetTargetDetails(*name, *target);
|
||||
if (key.Equals(*name) && old_details.kind() == new_details.kind() &&
|
||||
old_details.attributes() == new_details.attributes()) {
|
||||
ReplaceTransitions(HeapObjectReference::Weak(*target));
|
||||
ReplaceTransitions(isolate, map, HeapObjectReference::Weak(*target));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise allocate a full TransitionArray with slack for a new entry.
|
||||
Handle<Map> map(simple_transition, isolate_);
|
||||
Handle<TransitionArray> result =
|
||||
isolate_->factory()->NewTransitionArray(1, 1);
|
||||
// Reload state; allocations might have caused it to be cleared.
|
||||
Reload();
|
||||
simple_transition = GetSimpleTransition();
|
||||
isolate->factory()->NewTransitionArray(1, 1);
|
||||
|
||||
// Reload `simple_transition`. Allocations might have caused it to be
|
||||
// cleared.
|
||||
simple_transition = GetSimpleTransition(isolate, map);
|
||||
if (simple_transition.is_null()) {
|
||||
result->Set(0, *name, HeapObjectReference::Weak(*target));
|
||||
ReplaceTransitions(MaybeObject::FromObject(*result));
|
||||
Reload();
|
||||
DCHECK_EQ(kFullTransitionArray, encoding());
|
||||
ReplaceTransitions(isolate, map, result);
|
||||
DCHECK_EQ(kFullTransitionArray, GetEncoding(isolate, *result));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -116,28 +119,27 @@ void TransitionsAccessor::Insert(Handle<Name> name, Handle<Map> target,
|
||||
result->SetRawTarget(insertion_index, HeapObjectReference::Weak(*target));
|
||||
|
||||
SLOW_DCHECK(result->IsSortedNoDuplicates());
|
||||
ReplaceTransitions(MaybeObject::FromObject(*result));
|
||||
Reload();
|
||||
DCHECK_EQ(kFullTransitionArray, encoding());
|
||||
ReplaceTransitions(isolate, map, result);
|
||||
DCHECK_EQ(kFullTransitionArray, GetEncoding(isolate, *result));
|
||||
return;
|
||||
}
|
||||
|
||||
// At this point, we know that the map has a full TransitionArray.
|
||||
DCHECK_EQ(kFullTransitionArray, encoding());
|
||||
DCHECK_EQ(kFullTransitionArray, encoding);
|
||||
|
||||
int number_of_transitions = 0;
|
||||
int new_nof = 0;
|
||||
int insertion_index = kNotFound;
|
||||
const bool is_special_transition = flag == SPECIAL_TRANSITION;
|
||||
DCHECK_EQ(is_special_transition,
|
||||
IsSpecialTransition(ReadOnlyRoots(isolate_), *name));
|
||||
IsSpecialTransition(ReadOnlyRoots(isolate), *name));
|
||||
PropertyDetails details = is_special_transition
|
||||
? PropertyDetails::Empty()
|
||||
: GetTargetDetails(*name, *target);
|
||||
|
||||
{
|
||||
DisallowGarbageCollection no_gc;
|
||||
TransitionArray array = transitions();
|
||||
TransitionArray array = GetTransitionArray(isolate, map);
|
||||
number_of_transitions = array.number_of_transitions();
|
||||
|
||||
int index =
|
||||
@ -148,7 +150,7 @@ void TransitionsAccessor::Insert(Handle<Name> name, Handle<Map> target,
|
||||
// If an existing entry was found, overwrite it and return.
|
||||
if (index != kNotFound) {
|
||||
base::SharedMutexGuard<base::kExclusive> shared_mutex_guard(
|
||||
isolate_->full_transition_array_access());
|
||||
isolate->full_transition_array_access());
|
||||
array.SetRawTarget(index, HeapObjectReference::Weak(*target));
|
||||
return;
|
||||
}
|
||||
@ -161,7 +163,7 @@ void TransitionsAccessor::Insert(Handle<Name> name, Handle<Map> target,
|
||||
// If there is enough capacity, insert new entry into the existing array.
|
||||
if (new_nof <= array.Capacity()) {
|
||||
base::SharedMutexGuard<base::kExclusive> shared_mutex_guard(
|
||||
isolate_->full_transition_array_access());
|
||||
isolate->full_transition_array_access());
|
||||
array.SetNumberOfTransitions(new_nof);
|
||||
for (int i = number_of_transitions; i > insertion_index; --i) {
|
||||
array.SetKey(i, array.GetKey(i - 1));
|
||||
@ -175,16 +177,15 @@ void TransitionsAccessor::Insert(Handle<Name> name, Handle<Map> target,
|
||||
}
|
||||
|
||||
// We're gonna need a bigger TransitionArray.
|
||||
Handle<TransitionArray> result = isolate_->factory()->NewTransitionArray(
|
||||
Handle<TransitionArray> result = isolate->factory()->NewTransitionArray(
|
||||
new_nof,
|
||||
Map::SlackForArraySize(number_of_transitions, kMaxNumberOfTransitions));
|
||||
|
||||
// The map's transition array may have shrunk during the allocation above as
|
||||
// it was weakly traversed, though it is guaranteed not to disappear. Trim the
|
||||
// result copy if needed, and recompute variables.
|
||||
Reload();
|
||||
DisallowGarbageCollection no_gc;
|
||||
TransitionArray array = transitions();
|
||||
TransitionArray array = GetTransitionArray(isolate, map);
|
||||
if (array.number_of_transitions() != number_of_transitions) {
|
||||
DCHECK_LT(array.number_of_transitions(), number_of_transitions);
|
||||
|
||||
@ -217,7 +218,7 @@ void TransitionsAccessor::Insert(Handle<Name> name, Handle<Map> target,
|
||||
}
|
||||
|
||||
SLOW_DCHECK(result->IsSortedNoDuplicates());
|
||||
ReplaceTransitions(MaybeObject::FromObject(*result));
|
||||
ReplaceTransitions(isolate, map, result);
|
||||
}
|
||||
|
||||
Map TransitionsAccessor::SearchTransition(Name name, PropertyKind kind,
|
||||
@ -305,10 +306,14 @@ void TransitionsAccessor::ForEachTransitionTo(
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
bool TransitionsAccessor::CanHaveMoreTransitions() {
|
||||
if (map_.is_dictionary_map()) return false;
|
||||
if (encoding() == kFullTransitionArray) {
|
||||
return transitions().number_of_transitions() < kMaxNumberOfTransitions;
|
||||
// static
|
||||
bool TransitionsAccessor::CanHaveMoreTransitions(Isolate* isolate,
|
||||
Handle<Map> map) {
|
||||
if (map->is_dictionary_map()) return false;
|
||||
MaybeObject raw_transitions = map->raw_transitions(isolate, kAcquireLoad);
|
||||
if (GetEncoding(isolate, raw_transitions) == kFullTransitionArray) {
|
||||
return GetTransitionArray(isolate, raw_transitions)
|
||||
.number_of_transitions() < kMaxNumberOfTransitions;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -375,31 +380,33 @@ Handle<WeakFixedArray> TransitionArray::GrowPrototypeTransitionArray(
|
||||
return array;
|
||||
}
|
||||
|
||||
void TransitionsAccessor::PutPrototypeTransition(Handle<Object> prototype,
|
||||
// static
|
||||
void TransitionsAccessor::PutPrototypeTransition(Isolate* isolate,
|
||||
Handle<Map> map,
|
||||
Handle<Object> prototype,
|
||||
Handle<Map> target_map) {
|
||||
DCHECK(HeapObject::cast(*prototype).map().IsMap());
|
||||
// Don't cache prototype transition if this map is either shared, or a map of
|
||||
// a prototype.
|
||||
if (map_.is_prototype_map()) return;
|
||||
if (map_.is_dictionary_map() || !FLAG_cache_prototype_transitions) return;
|
||||
if (map->is_prototype_map()) return;
|
||||
if (map->is_dictionary_map() || !FLAG_cache_prototype_transitions) return;
|
||||
|
||||
const int header = TransitionArray::kProtoTransitionHeaderSize;
|
||||
|
||||
Handle<WeakFixedArray> cache(GetPrototypeTransitions(), isolate_);
|
||||
Handle<WeakFixedArray> cache(GetPrototypeTransitions(isolate, map), isolate);
|
||||
int capacity = cache->length() - header;
|
||||
int transitions = TransitionArray::NumberOfPrototypeTransitions(*cache) + 1;
|
||||
|
||||
base::SharedMutexGuard<base::kExclusive> scope(
|
||||
isolate_->full_transition_array_access());
|
||||
isolate->full_transition_array_access());
|
||||
|
||||
if (transitions > capacity) {
|
||||
// Grow the array if compacting it doesn't free space.
|
||||
if (!TransitionArray::CompactPrototypeTransitionArray(isolate_, *cache)) {
|
||||
if (!TransitionArray::CompactPrototypeTransitionArray(isolate, *cache)) {
|
||||
if (capacity == TransitionArray::kMaxCachedPrototypeTransitions) return;
|
||||
cache = TransitionArray::GrowPrototypeTransitionArray(
|
||||
cache, 2 * transitions, isolate_);
|
||||
Reload();
|
||||
SetPrototypeTransitions(cache);
|
||||
cache, 2 * transitions, isolate);
|
||||
SetPrototypeTransitions(isolate, map, cache);
|
||||
}
|
||||
}
|
||||
|
||||
@ -411,10 +418,11 @@ void TransitionsAccessor::PutPrototypeTransition(Handle<Object> prototype,
|
||||
TransitionArray::SetNumberOfPrototypeTransitions(*cache, last + 1);
|
||||
}
|
||||
|
||||
// static
|
||||
Handle<Map> TransitionsAccessor::GetPrototypeTransition(
|
||||
Handle<Object> prototype) {
|
||||
Isolate* isolate, Handle<Map> map, Handle<Object> prototype) {
|
||||
DisallowGarbageCollection no_gc;
|
||||
WeakFixedArray cache = GetPrototypeTransitions();
|
||||
WeakFixedArray cache = GetPrototypeTransitions(isolate, map);
|
||||
int length = TransitionArray::NumberOfPrototypeTransitions(cache);
|
||||
for (int i = 0; i < length; i++) {
|
||||
MaybeObject target =
|
||||
@ -422,21 +430,28 @@ Handle<Map> TransitionsAccessor::GetPrototypeTransition(
|
||||
DCHECK(target->IsWeakOrCleared());
|
||||
HeapObject heap_object;
|
||||
if (target->GetHeapObjectIfWeak(&heap_object)) {
|
||||
Map map = Map::cast(heap_object);
|
||||
if (map.prototype() == *prototype) {
|
||||
return handle(map, isolate_);
|
||||
Map target_map = Map::cast(heap_object);
|
||||
if (target_map.prototype() == *prototype) {
|
||||
return handle(target_map, isolate);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Handle<Map>();
|
||||
}
|
||||
|
||||
WeakFixedArray TransitionsAccessor::GetPrototypeTransitions() {
|
||||
if (encoding() != kFullTransitionArray ||
|
||||
!transitions().HasPrototypeTransitions()) {
|
||||
return ReadOnlyRoots(isolate_).empty_weak_fixed_array();
|
||||
// static
|
||||
WeakFixedArray TransitionsAccessor::GetPrototypeTransitions(Isolate* isolate,
|
||||
Handle<Map> map) {
|
||||
MaybeObject raw_transitions = map->raw_transitions(isolate, kAcquireLoad);
|
||||
if (GetEncoding(isolate, raw_transitions) != kFullTransitionArray) {
|
||||
return ReadOnlyRoots(isolate).empty_weak_fixed_array();
|
||||
}
|
||||
return transitions().GetPrototypeTransitions();
|
||||
TransitionArray transition_array =
|
||||
GetTransitionArray(isolate, raw_transitions);
|
||||
if (!transition_array.HasPrototypeTransitions()) {
|
||||
return ReadOnlyRoots(isolate).empty_weak_fixed_array();
|
||||
}
|
||||
return transition_array.GetPrototypeTransitions();
|
||||
}
|
||||
|
||||
// static
|
||||
@ -461,14 +476,15 @@ int TransitionsAccessor::NumberOfTransitions() {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void TransitionsAccessor::SetMigrationTarget(Map migration_target) {
|
||||
// static
|
||||
void TransitionsAccessor::SetMigrationTarget(Isolate* isolate, Handle<Map> map,
|
||||
Map migration_target) {
|
||||
// We only cache the migration target for maps with empty transitions for GC's
|
||||
// sake.
|
||||
if (encoding() != kUninitialized) return;
|
||||
DCHECK(map_.is_deprecated());
|
||||
map_.set_raw_transitions(MaybeObject::FromObject(migration_target),
|
||||
if (GetEncoding(isolate, map) != kUninitialized) return;
|
||||
DCHECK(map->is_deprecated());
|
||||
map->set_raw_transitions(MaybeObject::FromObject(migration_target),
|
||||
kReleaseStore);
|
||||
MarkNeedsReload();
|
||||
}
|
||||
|
||||
Map TransitionsAccessor::GetMigrationTarget() {
|
||||
@ -478,44 +494,60 @@ Map TransitionsAccessor::GetMigrationTarget() {
|
||||
return Map();
|
||||
}
|
||||
|
||||
void TransitionsAccessor::ReplaceTransitions(MaybeObject new_transitions) {
|
||||
if (encoding() == kFullTransitionArray) {
|
||||
// static
|
||||
void TransitionsAccessor::ReplaceTransitions(Isolate* isolate, Handle<Map> map,
|
||||
MaybeObject new_transitions) {
|
||||
#if DEBUG
|
||||
TransitionArray old_transitions = transitions();
|
||||
if (GetEncoding(isolate, map) == kFullTransitionArray) {
|
||||
CheckNewTransitionsAreConsistent(
|
||||
old_transitions, new_transitions->GetHeapObjectAssumeStrong());
|
||||
DCHECK(old_transitions != new_transitions->GetHeapObjectAssumeStrong());
|
||||
#endif
|
||||
isolate, map, new_transitions->GetHeapObjectAssumeStrong());
|
||||
DCHECK_NE(GetTransitionArray(isolate, map),
|
||||
new_transitions->GetHeapObjectAssumeStrong());
|
||||
}
|
||||
map_.set_raw_transitions(new_transitions, kReleaseStore);
|
||||
MarkNeedsReload();
|
||||
#endif
|
||||
map->set_raw_transitions(new_transitions, kReleaseStore);
|
||||
USE(isolate);
|
||||
}
|
||||
|
||||
// static
|
||||
void TransitionsAccessor::ReplaceTransitions(
|
||||
Isolate* isolate, Handle<Map> map,
|
||||
Handle<TransitionArray> new_transitions) {
|
||||
ReplaceTransitions(isolate, map, MaybeObject::FromObject(*new_transitions));
|
||||
}
|
||||
|
||||
// static
|
||||
void TransitionsAccessor::SetPrototypeTransitions(
|
||||
Isolate* isolate, Handle<Map> map,
|
||||
Handle<WeakFixedArray> proto_transitions) {
|
||||
EnsureHasFullTransitionArray();
|
||||
transitions().SetPrototypeTransitions(*proto_transitions);
|
||||
EnsureHasFullTransitionArray(isolate, map);
|
||||
GetTransitionArray(isolate, map->raw_transitions(isolate, kAcquireLoad))
|
||||
.SetPrototypeTransitions(*proto_transitions);
|
||||
}
|
||||
|
||||
void TransitionsAccessor::EnsureHasFullTransitionArray() {
|
||||
if (encoding() == kFullTransitionArray) return;
|
||||
// static
|
||||
void TransitionsAccessor::EnsureHasFullTransitionArray(Isolate* isolate,
|
||||
Handle<Map> map) {
|
||||
Encoding encoding =
|
||||
GetEncoding(isolate, map->raw_transitions(isolate, kAcquireLoad));
|
||||
if (encoding == kFullTransitionArray) return;
|
||||
int nof =
|
||||
(encoding() == kUninitialized || encoding() == kMigrationTarget) ? 0 : 1;
|
||||
Handle<TransitionArray> result = isolate_->factory()->NewTransitionArray(nof);
|
||||
Reload(); // Reload after possible GC.
|
||||
(encoding == kUninitialized || encoding == kMigrationTarget) ? 0 : 1;
|
||||
Handle<TransitionArray> result = isolate->factory()->NewTransitionArray(nof);
|
||||
// Reload encoding after possible GC.
|
||||
encoding = GetEncoding(isolate, map->raw_transitions(isolate, kAcquireLoad));
|
||||
if (nof == 1) {
|
||||
if (encoding() == kUninitialized) {
|
||||
if (encoding == kUninitialized) {
|
||||
// If allocation caused GC and cleared the target, trim the new array.
|
||||
result->SetNumberOfTransitions(0);
|
||||
} else {
|
||||
// Otherwise populate the new array.
|
||||
Handle<Map> target(GetSimpleTransition(), isolate_);
|
||||
Name key = GetSimpleTransitionKey(*target);
|
||||
result->Set(0, key, HeapObjectReference::Weak(*target));
|
||||
Map target = GetSimpleTransition(isolate, map);
|
||||
Name key = GetSimpleTransitionKey(target);
|
||||
result->Set(0, key, HeapObjectReference::Weak(target));
|
||||
}
|
||||
}
|
||||
ReplaceTransitions(MaybeObject::FromObject(*result));
|
||||
Reload(); // Reload after replacing transitions.
|
||||
ReplaceTransitions(isolate, map, result);
|
||||
}
|
||||
|
||||
void TransitionsAccessor::TraverseTransitionTreeInternal(
|
||||
@ -575,18 +607,21 @@ void TransitionsAccessor::TraverseTransitionTreeInternal(
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void TransitionsAccessor::CheckNewTransitionsAreConsistent(
|
||||
TransitionArray old_transitions, Object transitions) {
|
||||
// static
|
||||
void TransitionsAccessor::CheckNewTransitionsAreConsistent(Isolate* isolate,
|
||||
Handle<Map> map,
|
||||
Object transitions) {
|
||||
// This function only handles full transition arrays.
|
||||
DCHECK_EQ(kFullTransitionArray, encoding());
|
||||
TransitionArray old_transitions = GetTransitionArray(isolate, map);
|
||||
DCHECK_EQ(kFullTransitionArray, GetEncoding(isolate, old_transitions));
|
||||
TransitionArray new_transitions = TransitionArray::cast(transitions);
|
||||
for (int i = 0; i < old_transitions.number_of_transitions(); i++) {
|
||||
Map target = old_transitions.GetTarget(i);
|
||||
if (target.instance_descriptors(isolate_) ==
|
||||
map_.instance_descriptors(isolate_)) {
|
||||
if (target.instance_descriptors(isolate) ==
|
||||
map->instance_descriptors(isolate)) {
|
||||
Name key = old_transitions.GetKey(i);
|
||||
int new_target_index;
|
||||
if (IsSpecialTransition(ReadOnlyRoots(isolate_), key)) {
|
||||
if (IsSpecialTransition(ReadOnlyRoots(isolate), key)) {
|
||||
new_target_index = new_transitions.SearchSpecial(Symbol::cast(key));
|
||||
} else {
|
||||
PropertyDetails details = GetTargetDetails(key, target);
|
||||
|
@ -50,20 +50,23 @@ class V8_EXPORT_PRIVATE TransitionsAccessor {
|
||||
// in background threads. It acquires a reader lock for critical paths, as
|
||||
// well as blocking the accessor from modifying the TransitionsArray.
|
||||
inline TransitionsAccessor(Isolate* isolate, Map map,
|
||||
DisallowGarbageCollection* no_gc,
|
||||
bool concurrent_access = false);
|
||||
inline TransitionsAccessor(Isolate* isolate, Handle<Map> map,
|
||||
bool concurrent_access = false);
|
||||
|
||||
// Insert a new transition into |map|'s transition array, extending it
|
||||
// as necessary.
|
||||
// Requires the constructor that takes a Handle<Map> to have been used.
|
||||
// This TransitionsAccessor instance is unusable after this operation.
|
||||
void Insert(Handle<Name> name, Handle<Map> target, SimpleTransitionFlag flag);
|
||||
// as necessary. This can trigger GC.
|
||||
static void Insert(Isolate* isolate, Handle<Map> map, Handle<Name> name,
|
||||
Handle<Map> target, SimpleTransitionFlag flag);
|
||||
|
||||
Map SearchTransition(Name name, PropertyKind kind,
|
||||
PropertyAttributes attributes);
|
||||
static inline MaybeHandle<Map> SearchTransition(
|
||||
Isolate* isolate, Handle<Map> map, Name name, PropertyKind kind,
|
||||
PropertyAttributes attributes);
|
||||
|
||||
Map SearchSpecial(Symbol name);
|
||||
static inline MaybeHandle<Map> SearchSpecial(Isolate* isolate,
|
||||
Handle<Map> map, Symbol name);
|
||||
|
||||
// Returns true for non-property transitions like elements kind, or
|
||||
// or frozen/sealed transitions.
|
||||
static bool IsSpecialTransition(ReadOnlyRoots roots, Name name);
|
||||
@ -92,11 +95,12 @@ class V8_EXPORT_PRIVATE TransitionsAccessor {
|
||||
// object space. Otherwise ClearNonLiveReferences would leak memory while
|
||||
// applying in-place right trimming.
|
||||
static const int kMaxNumberOfTransitions = 1024 + 512;
|
||||
bool CanHaveMoreTransitions();
|
||||
inline Name GetKey(int transition_number);
|
||||
inline Map GetTarget(int transition_number);
|
||||
static inline PropertyDetails GetTargetDetails(Name name, Map target);
|
||||
|
||||
static bool CanHaveMoreTransitions(Isolate* isolate, Handle<Map> map);
|
||||
|
||||
static bool IsMatchingMap(Map target, Name name, PropertyKind kind,
|
||||
PropertyAttributes attributes);
|
||||
|
||||
@ -124,15 +128,20 @@ class V8_EXPORT_PRIVATE TransitionsAccessor {
|
||||
// prototype is set, rather than creating a new map every time. The
|
||||
// transitions are in the form of a map where the keys are prototype objects
|
||||
// and the values are the maps they transition to.
|
||||
void PutPrototypeTransition(Handle<Object> prototype, Handle<Map> target_map);
|
||||
Handle<Map> GetPrototypeTransition(Handle<Object> prototype);
|
||||
// PutPrototypeTransition can trigger GC.
|
||||
static void PutPrototypeTransition(Isolate* isolate, Handle<Map>,
|
||||
Handle<Object> prototype,
|
||||
Handle<Map> target_map);
|
||||
static Handle<Map> GetPrototypeTransition(Isolate* isolate, Handle<Map> map,
|
||||
Handle<Object> prototype);
|
||||
|
||||
// During the first-time Map::Update and Map::TryUpdate, the migration target
|
||||
// map could be cached in the raw_transitions slot of the old map that is
|
||||
// deprecated from the map transition tree. The next time old map is updated,
|
||||
// we will check this cache slot as a shortcut to get the migration target
|
||||
// map.
|
||||
void SetMigrationTarget(Map migration_target);
|
||||
static void SetMigrationTarget(Isolate* isolate, Handle<Map> map,
|
||||
Map migration_target);
|
||||
Map GetMigrationTarget();
|
||||
|
||||
#if DEBUG || OBJECT_PRINT
|
||||
@ -143,8 +152,9 @@ class V8_EXPORT_PRIVATE TransitionsAccessor {
|
||||
DisallowGarbageCollection* no_gc);
|
||||
#endif
|
||||
#if DEBUG
|
||||
void CheckNewTransitionsAreConsistent(TransitionArray old_transitions,
|
||||
Object transitions);
|
||||
static void CheckNewTransitionsAreConsistent(Isolate* isolate,
|
||||
Handle<Map> map,
|
||||
Object transitions);
|
||||
bool IsConsistentWithBackPointers();
|
||||
bool IsSortedNoDuplicates();
|
||||
#endif
|
||||
@ -159,17 +169,14 @@ class V8_EXPORT_PRIVATE TransitionsAccessor {
|
||||
kFullTransitionArray,
|
||||
};
|
||||
|
||||
inline void Reload();
|
||||
|
||||
inline Encoding encoding() {
|
||||
DCHECK(!needs_reload_);
|
||||
return encoding_;
|
||||
}
|
||||
inline Encoding encoding() { return encoding_; }
|
||||
|
||||
inline int Capacity();
|
||||
|
||||
inline TransitionArray transitions();
|
||||
|
||||
DISALLOW_GARBAGE_COLLECTION(no_gc_)
|
||||
|
||||
private:
|
||||
friend class MarkCompactCollector; // For HasSimpleTransitionTo.
|
||||
friend class third_party_heap::Impl;
|
||||
@ -177,44 +184,44 @@ class V8_EXPORT_PRIVATE TransitionsAccessor {
|
||||
|
||||
static inline Encoding GetEncoding(Isolate* isolate,
|
||||
MaybeObject raw_transitions);
|
||||
static inline Encoding GetEncoding(Isolate* isolate, TransitionArray array);
|
||||
static inline Encoding GetEncoding(Isolate* isolate, Handle<Map> map);
|
||||
|
||||
inline PropertyDetails GetSimpleTargetDetails(Map transition);
|
||||
static inline TransitionArray GetTransitionArray(Isolate* isolate,
|
||||
MaybeObject raw_transitions);
|
||||
static inline TransitionArray GetTransitionArray(Isolate* isolate,
|
||||
Handle<Map> map);
|
||||
|
||||
static inline Map GetSimpleTransition(Isolate* isolate, Handle<Map> map);
|
||||
static inline Name GetSimpleTransitionKey(Map transition);
|
||||
inline PropertyDetails GetSimpleTargetDetails(Map transition);
|
||||
|
||||
static inline Map GetTargetFromRaw(MaybeObject raw);
|
||||
|
||||
void MarkNeedsReload() {
|
||||
#if DEBUG
|
||||
needs_reload_ = true;
|
||||
#endif
|
||||
}
|
||||
static void EnsureHasFullTransitionArray(Isolate* isolate, Handle<Map> map);
|
||||
static void SetPrototypeTransitions(Isolate* isolate, Handle<Map> map,
|
||||
Handle<WeakFixedArray> proto_transitions);
|
||||
static WeakFixedArray GetPrototypeTransitions(Isolate* isolate,
|
||||
Handle<Map> map);
|
||||
|
||||
inline void Initialize();
|
||||
static inline void ReplaceTransitions(Isolate* isolate, Handle<Map> map,
|
||||
MaybeObject new_transitions);
|
||||
static inline void ReplaceTransitions(
|
||||
Isolate* isolate, Handle<Map> map,
|
||||
Handle<TransitionArray> new_transitions);
|
||||
|
||||
inline Map GetSimpleTransition();
|
||||
bool HasSimpleTransitionTo(Map map);
|
||||
|
||||
void ReplaceTransitions(MaybeObject new_transitions);
|
||||
|
||||
inline Map GetTargetMapFromWeakRef();
|
||||
|
||||
void EnsureHasFullTransitionArray();
|
||||
void SetPrototypeTransitions(Handle<WeakFixedArray> proto_transitions);
|
||||
WeakFixedArray GetPrototypeTransitions();
|
||||
|
||||
void TraverseTransitionTreeInternal(const TraverseCallback& callback,
|
||||
DisallowGarbageCollection* no_gc);
|
||||
|
||||
Isolate* isolate_;
|
||||
Handle<Map> map_handle_;
|
||||
Map map_;
|
||||
MaybeObject raw_transitions_;
|
||||
Encoding encoding_;
|
||||
bool concurrent_access_;
|
||||
#if DEBUG
|
||||
bool needs_reload_;
|
||||
#endif
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(TransitionsAccessor);
|
||||
};
|
||||
|
@ -2218,11 +2218,16 @@ Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties(
|
||||
// transition was found.
|
||||
Handle<Object> key;
|
||||
Handle<Map> target;
|
||||
TransitionsAccessor transitions(isolate_, map);
|
||||
Handle<String> expected_key = transitions.ExpectedTransitionKey();
|
||||
Handle<String> expected_key;
|
||||
{
|
||||
TransitionsAccessor transitions(isolate_, *map);
|
||||
expected_key = transitions.ExpectedTransitionKey();
|
||||
if (!expected_key.is_null()) {
|
||||
target = transitions.ExpectedTransitionTarget();
|
||||
}
|
||||
}
|
||||
if (!expected_key.is_null() && ReadExpectedString(expected_key)) {
|
||||
key = expected_key;
|
||||
target = transitions.ExpectedTransitionTarget();
|
||||
} else {
|
||||
if (!ReadObject().ToHandle(&key) || !IsValidObjectKey(*key, isolate_)) {
|
||||
return Nothing<uint32_t>();
|
||||
@ -2231,7 +2236,7 @@ Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties(
|
||||
key =
|
||||
isolate_->factory()->InternalizeString(Handle<String>::cast(key));
|
||||
// Don't reuse |transitions| because it could be stale.
|
||||
transitioning = TransitionsAccessor(isolate_, map)
|
||||
transitioning = TransitionsAccessor(isolate_, *map)
|
||||
.FindTransitionToField(Handle<String>::cast(key))
|
||||
.ToHandle(&target);
|
||||
} else {
|
||||
|
@ -117,7 +117,7 @@ void GeneralizeAllTransitionsToFieldAsMutable(Isolate* isolate, Handle<Map> map,
|
||||
// Collect all outgoing field transitions.
|
||||
{
|
||||
DisallowGarbageCollection no_gc;
|
||||
TransitionsAccessor transitions(isolate, *map, &no_gc);
|
||||
TransitionsAccessor transitions(isolate, *map);
|
||||
transitions.ForEachTransitionTo(
|
||||
*name,
|
||||
[&](Map target) {
|
||||
|
@ -2880,8 +2880,7 @@ TEST(OptimizedAllocationArrayLiterals) {
|
||||
}
|
||||
|
||||
static int CountMapTransitions(i::Isolate* isolate, Map map) {
|
||||
DisallowGarbageCollection no_gc;
|
||||
return TransitionsAccessor(isolate, map, &no_gc).NumberOfTransitions();
|
||||
return TransitionsAccessor(isolate, map).NumberOfTransitions();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1122,7 +1122,7 @@ TEST(TransitionLookup) {
|
||||
|
||||
// Ensure we didn't overflow transition array and therefore all the
|
||||
// combinations of cases are covered.
|
||||
CHECK(TransitionsAccessor(isolate, root_map).CanHaveMoreTransitions());
|
||||
CHECK(TransitionsAccessor::CanHaveMoreTransitions(isolate, root_map));
|
||||
|
||||
// Now try querying keys.
|
||||
bool positive_lookup_tested = false;
|
||||
|
@ -40,7 +40,7 @@ class ConcurrentSearchThread : public v8::base::Thread {
|
||||
|
||||
background_thread_started_->Signal();
|
||||
|
||||
CHECK_EQ(TransitionsAccessor(CcTest::i_isolate(), map_, true)
|
||||
CHECK_EQ(TransitionsAccessor(CcTest::i_isolate(), *map_, true)
|
||||
.SearchTransition(*name_, PropertyKind::kData, NONE),
|
||||
result_map_ ? **result_map_ : Map());
|
||||
}
|
||||
@ -74,11 +74,11 @@ class ConcurrentSearchOnOutdatedAccessorThread final
|
||||
LocalHeap local_heap(heap_, ThreadKind::kBackground, std::move(ph_));
|
||||
UnparkedScope scope(&local_heap);
|
||||
|
||||
TransitionsAccessor accessor(CcTest::i_isolate(), map_, true);
|
||||
background_thread_started_->Signal();
|
||||
main_thread_finished_->Wait();
|
||||
|
||||
CHECK_EQ(accessor.SearchTransition(*name_, PropertyKind::kData, NONE),
|
||||
CHECK_EQ(TransitionsAccessor(CcTest::i_isolate(), *map_, true)
|
||||
.SearchTransition(*name_, PropertyKind::kData, NONE),
|
||||
result_map_ ? **result_map_ : Map());
|
||||
}
|
||||
|
||||
@ -102,7 +102,7 @@ TEST(FullFieldTransitions_OnlySearch) {
|
||||
attributes, PropertyConstness::kMutable,
|
||||
Representation::Tagged(), OMIT_TRANSITION)
|
||||
.ToHandleChecked();
|
||||
TransitionsAccessor(isolate, map0).Insert(name, map1, PROPERTY_TRANSITION);
|
||||
TransitionsAccessor::Insert(isolate, map0, name, map1, PROPERTY_TRANSITION);
|
||||
{
|
||||
TestTransitionsAccessor transitions(isolate, map0);
|
||||
CHECK(transitions.IsFullTransitionArrayEncoding());
|
||||
@ -124,8 +124,9 @@ TEST(FullFieldTransitions_OnlySearch) {
|
||||
|
||||
background_thread_started.Wait();
|
||||
|
||||
CHECK_EQ(*map1, TransitionsAccessor(isolate, map0)
|
||||
.SearchTransition(*name, kind, attributes));
|
||||
CHECK_EQ(*map1, *TransitionsAccessor::SearchTransition(isolate, map0, *name,
|
||||
kind, attributes)
|
||||
.ToHandleChecked());
|
||||
|
||||
thread->Join();
|
||||
}
|
||||
@ -154,7 +155,7 @@ TEST(FullFieldTransitions) {
|
||||
attributes, PropertyConstness::kMutable,
|
||||
Representation::Tagged(), OMIT_TRANSITION)
|
||||
.ToHandleChecked();
|
||||
TransitionsAccessor(isolate, map0).Insert(name1, map1, PROPERTY_TRANSITION);
|
||||
TransitionsAccessor::Insert(isolate, map0, name1, map1, PROPERTY_TRANSITION);
|
||||
{
|
||||
TestTransitionsAccessor transitions(isolate, map0);
|
||||
CHECK(transitions.IsFullTransitionArrayEncoding());
|
||||
@ -176,11 +177,13 @@ TEST(FullFieldTransitions) {
|
||||
|
||||
background_thread_started.Wait();
|
||||
|
||||
CHECK_EQ(*map1, TransitionsAccessor(isolate, map0)
|
||||
.SearchTransition(*name1, kind, attributes));
|
||||
TransitionsAccessor(isolate, map0).Insert(name2, map2, PROPERTY_TRANSITION);
|
||||
CHECK_EQ(*map2, TransitionsAccessor(isolate, map0)
|
||||
.SearchTransition(*name2, kind, attributes));
|
||||
CHECK_EQ(*map1, *TransitionsAccessor::SearchTransition(isolate, map0, *name1,
|
||||
kind, attributes)
|
||||
.ToHandleChecked());
|
||||
TransitionsAccessor::Insert(isolate, map0, name2, map2, PROPERTY_TRANSITION);
|
||||
CHECK_EQ(*map2, *TransitionsAccessor::SearchTransition(isolate, map0, *name2,
|
||||
kind, attributes)
|
||||
.ToHandleChecked());
|
||||
|
||||
thread->Join();
|
||||
}
|
||||
@ -210,8 +213,8 @@ TEST(WeakRefToFullFieldTransitions) {
|
||||
attributes, PropertyConstness::kMutable,
|
||||
Representation::Tagged(), OMIT_TRANSITION)
|
||||
.ToHandleChecked();
|
||||
TransitionsAccessor(isolate, map0)
|
||||
.Insert(name1, map1, SIMPLE_PROPERTY_TRANSITION);
|
||||
TransitionsAccessor::Insert(isolate, map0, name1, map1,
|
||||
SIMPLE_PROPERTY_TRANSITION);
|
||||
{
|
||||
TestTransitionsAccessor transitions(isolate, map0);
|
||||
CHECK(transitions.IsWeakRefEncoding());
|
||||
@ -233,16 +236,18 @@ TEST(WeakRefToFullFieldTransitions) {
|
||||
|
||||
background_thread_started.Wait();
|
||||
|
||||
CHECK_EQ(*map1, TransitionsAccessor(isolate, map0)
|
||||
.SearchTransition(*name1, kind, attributes));
|
||||
TransitionsAccessor(isolate, map0)
|
||||
.Insert(name2, map2, SIMPLE_PROPERTY_TRANSITION);
|
||||
CHECK_EQ(*map1, *TransitionsAccessor::SearchTransition(isolate, map0, *name1,
|
||||
kind, attributes)
|
||||
.ToHandleChecked());
|
||||
TransitionsAccessor::Insert(isolate, map0, name2, map2,
|
||||
SIMPLE_PROPERTY_TRANSITION);
|
||||
{
|
||||
TestTransitionsAccessor transitions(isolate, map0);
|
||||
CHECK(transitions.IsFullTransitionArrayEncoding());
|
||||
}
|
||||
CHECK_EQ(*map2, TransitionsAccessor(isolate, map0)
|
||||
.SearchTransition(*name2, kind, attributes));
|
||||
CHECK_EQ(*map2, *TransitionsAccessor::SearchTransition(isolate, map0, *name2,
|
||||
kind, attributes)
|
||||
.ToHandleChecked());
|
||||
|
||||
thread->Join();
|
||||
}
|
||||
@ -278,8 +283,8 @@ TEST(FullFieldTransitions_withSlack) {
|
||||
attributes, PropertyConstness::kMutable,
|
||||
Representation::Tagged(), OMIT_TRANSITION)
|
||||
.ToHandleChecked();
|
||||
TransitionsAccessor(isolate, map0).Insert(name1, map1, PROPERTY_TRANSITION);
|
||||
TransitionsAccessor(isolate, map0).Insert(name2, map2, PROPERTY_TRANSITION);
|
||||
TransitionsAccessor::Insert(isolate, map0, name1, map1, PROPERTY_TRANSITION);
|
||||
TransitionsAccessor::Insert(isolate, map0, name2, map2, PROPERTY_TRANSITION);
|
||||
{
|
||||
TestTransitionsAccessor transitions(isolate, map0);
|
||||
CHECK(transitions.IsFullTransitionArrayEncoding());
|
||||
@ -301,19 +306,22 @@ TEST(FullFieldTransitions_withSlack) {
|
||||
|
||||
background_thread_started.Wait();
|
||||
|
||||
CHECK_EQ(*map1, TransitionsAccessor(isolate, map0)
|
||||
.SearchTransition(*name1, kind, attributes));
|
||||
CHECK_EQ(*map2, TransitionsAccessor(isolate, map0)
|
||||
.SearchTransition(*name2, kind, attributes));
|
||||
CHECK_EQ(*map1, *TransitionsAccessor::SearchTransition(isolate, map0, *name1,
|
||||
kind, attributes)
|
||||
.ToHandleChecked());
|
||||
CHECK_EQ(*map2, *TransitionsAccessor::SearchTransition(isolate, map0, *name2,
|
||||
kind, attributes)
|
||||
.ToHandleChecked());
|
||||
{
|
||||
// Check that we have enough slack for the 3rd insertion into the
|
||||
// TransitionArray.
|
||||
TestTransitionsAccessor transitions(isolate, map0);
|
||||
CHECK_GE(transitions.Capacity(), 3);
|
||||
}
|
||||
TransitionsAccessor(isolate, map0).Insert(name3, map3, PROPERTY_TRANSITION);
|
||||
CHECK_EQ(*map3, TransitionsAccessor(isolate, map0)
|
||||
.SearchTransition(*name3, kind, attributes));
|
||||
TransitionsAccessor::Insert(isolate, map0, name3, map3, PROPERTY_TRANSITION);
|
||||
CHECK_EQ(*map3, *TransitionsAccessor::SearchTransition(isolate, map0, *name3,
|
||||
kind, attributes)
|
||||
.ToHandleChecked());
|
||||
|
||||
thread->Join();
|
||||
}
|
||||
@ -359,9 +367,10 @@ TEST(UninitializedToFullFieldTransitions) {
|
||||
|
||||
background_thread_started.Wait();
|
||||
|
||||
TransitionsAccessor(isolate, map0).Insert(name1, map1, PROPERTY_TRANSITION);
|
||||
CHECK_EQ(*map1, TransitionsAccessor(isolate, map0)
|
||||
.SearchTransition(*name1, kind, attributes));
|
||||
TransitionsAccessor::Insert(isolate, map0, name1, map1, PROPERTY_TRANSITION);
|
||||
CHECK_EQ(*map1, *TransitionsAccessor::SearchTransition(isolate, map0, *name1,
|
||||
kind, attributes)
|
||||
.ToHandleChecked());
|
||||
{
|
||||
TestTransitionsAccessor transitions(isolate, map0);
|
||||
CHECK(transitions.IsFullTransitionArrayEncoding());
|
||||
@ -395,7 +404,7 @@ TEST(FullFieldTransitions_BackgroundSearchOldPointer) {
|
||||
attributes, PropertyConstness::kMutable,
|
||||
Representation::Tagged(), OMIT_TRANSITION)
|
||||
.ToHandleChecked();
|
||||
TransitionsAccessor(isolate, map0).Insert(name1, map1, PROPERTY_TRANSITION);
|
||||
TransitionsAccessor::Insert(isolate, map0, name1, map1, PROPERTY_TRANSITION);
|
||||
{
|
||||
TestTransitionsAccessor transitions(isolate, map0);
|
||||
CHECK(transitions.IsFullTransitionArrayEncoding());
|
||||
@ -420,17 +429,19 @@ TEST(FullFieldTransitions_BackgroundSearchOldPointer) {
|
||||
|
||||
background_thread_started.Wait();
|
||||
|
||||
CHECK_EQ(*map1, TransitionsAccessor(isolate, map0)
|
||||
.SearchTransition(*name1, kind, attributes));
|
||||
CHECK_EQ(*map1, *TransitionsAccessor::SearchTransition(isolate, map0, *name1,
|
||||
kind, attributes)
|
||||
.ToHandleChecked());
|
||||
{
|
||||
// Check that we do not have enough slack for the 2nd insertion into the
|
||||
// TransitionArray.
|
||||
TestTransitionsAccessor transitions(isolate, map0);
|
||||
CHECK_EQ(transitions.Capacity(), 1);
|
||||
}
|
||||
TransitionsAccessor(isolate, map0).Insert(name2, map2, PROPERTY_TRANSITION);
|
||||
CHECK_EQ(*map2, TransitionsAccessor(isolate, map0)
|
||||
.SearchTransition(*name2, kind, attributes));
|
||||
TransitionsAccessor::Insert(isolate, map0, name2, map2, PROPERTY_TRANSITION);
|
||||
CHECK_EQ(*map2, *TransitionsAccessor::SearchTransition(isolate, map0, *name2,
|
||||
kind, attributes)
|
||||
.ToHandleChecked());
|
||||
main_thread_finished.Signal();
|
||||
|
||||
thread->Join();
|
||||
|
@ -66,8 +66,7 @@ static Handle<AccessorPair> CreateAccessorPair(bool with_getter,
|
||||
|
||||
// Check cached migration target map after Map::Update() and Map::TryUpdate()
|
||||
static void CheckMigrationTarget(Isolate* isolate, Map old_map, Map new_map) {
|
||||
Map target = TransitionsAccessor(isolate, handle(old_map, isolate))
|
||||
.GetMigrationTarget();
|
||||
Map target = TransitionsAccessor(isolate, old_map).GetMigrationTarget();
|
||||
if (target.is_null()) return;
|
||||
CHECK_EQ(new_map, target);
|
||||
CHECK_EQ(MapUpdater::TryUpdateNoLock(isolate, old_map,
|
||||
@ -391,10 +390,10 @@ class Expectations {
|
||||
heap_type);
|
||||
|
||||
Handle<String> name = CcTest::MakeName("prop", property_index);
|
||||
Map target = TransitionsAccessor(isolate_, map)
|
||||
.SearchTransition(*name, PropertyKind::kData, attributes);
|
||||
MaybeHandle<Map> target = TransitionsAccessor::SearchTransition(
|
||||
isolate_, map, *name, PropertyKind::kData, attributes);
|
||||
CHECK(!target.is_null());
|
||||
return handle(target, isolate_);
|
||||
return target.ToHandleChecked();
|
||||
}
|
||||
|
||||
Handle<Map> AddAccessorConstant(Handle<Map> map,
|
||||
@ -2065,10 +2064,10 @@ TEST(ReconfigurePropertySplitMapTransitionsOverflow) {
|
||||
}
|
||||
|
||||
Handle<String> name = CcTest::MakeName("prop", i);
|
||||
Map target = TransitionsAccessor(isolate, map2)
|
||||
.SearchTransition(*name, PropertyKind::kData, NONE);
|
||||
MaybeHandle<Map> target = TransitionsAccessor::SearchTransition(
|
||||
isolate, map2, *name, PropertyKind::kData, NONE);
|
||||
CHECK(!target.is_null());
|
||||
map2 = handle(target, isolate);
|
||||
map2 = target.ToHandleChecked();
|
||||
}
|
||||
|
||||
map2 = ReconfigureProperty(isolate, map2, InternalIndex(kSplitProp),
|
||||
@ -2090,14 +2089,14 @@ TEST(ReconfigurePropertySplitMapTransitionsOverflow) {
|
||||
|
||||
// Fill in transition tree of |map2| so that it can't have more transitions.
|
||||
for (int i = 0; i < TransitionsAccessor::kMaxNumberOfTransitions; i++) {
|
||||
CHECK(TransitionsAccessor(isolate, map2).CanHaveMoreTransitions());
|
||||
CHECK(TransitionsAccessor::CanHaveMoreTransitions(isolate, map2));
|
||||
Handle<String> name = CcTest::MakeName("foo", i);
|
||||
Map::CopyWithField(isolate, map2, name, any_type, NONE,
|
||||
PropertyConstness::kMutable, Representation::Smi(),
|
||||
INSERT_TRANSITION)
|
||||
.ToHandleChecked();
|
||||
}
|
||||
CHECK(!TransitionsAccessor(isolate, map2).CanHaveMoreTransitions());
|
||||
CHECK(!TransitionsAccessor::CanHaveMoreTransitions(isolate, map2));
|
||||
|
||||
// Try to update |map|, since there is no place for propX transition at |map2|
|
||||
// |map| should become normalized.
|
||||
@ -3094,7 +3093,7 @@ TEST(DeletePropertyGeneralizesConstness) {
|
||||
|
||||
// |new_parent_map| must have exactly one outgoing transition to |new_map|.
|
||||
{
|
||||
TransitionsAccessor ta(isolate, new_parent_map);
|
||||
TransitionsAccessor ta(isolate, *new_parent_map);
|
||||
CHECK_EQ(ta.NumberOfTransitions(), 1);
|
||||
CHECK_EQ(ta.GetTarget(0), *new_map);
|
||||
}
|
||||
|
@ -45,19 +45,22 @@ TEST(TransitionArray_SimpleFieldTransitions) {
|
||||
CHECK(map0->raw_transitions()->IsSmi());
|
||||
|
||||
{
|
||||
TestTransitionsAccessor transitions(isolate, map0);
|
||||
transitions.Insert(name1, map1, SIMPLE_PROPERTY_TRANSITION);
|
||||
TransitionsAccessor::Insert(isolate, map0, name1, map1,
|
||||
SIMPLE_PROPERTY_TRANSITION);
|
||||
}
|
||||
{
|
||||
TestTransitionsAccessor transitions(isolate, map0);
|
||||
CHECK(transitions.IsWeakRefEncoding());
|
||||
CHECK_EQ(*map1, transitions.SearchTransition(*name1, PropertyKind::kData,
|
||||
attributes));
|
||||
CHECK_EQ(1, transitions.NumberOfTransitions());
|
||||
CHECK_EQ(*name1, transitions.GetKey(0));
|
||||
CHECK_EQ(*map1, transitions.GetTarget(0));
|
||||
{
|
||||
TestTransitionsAccessor transitions(isolate, map0);
|
||||
CHECK(transitions.IsWeakRefEncoding());
|
||||
CHECK_EQ(*map1, transitions.SearchTransition(*name1, PropertyKind::kData,
|
||||
attributes));
|
||||
CHECK_EQ(1, transitions.NumberOfTransitions());
|
||||
CHECK_EQ(*name1, transitions.GetKey(0));
|
||||
CHECK_EQ(*map1, transitions.GetTarget(0));
|
||||
}
|
||||
|
||||
transitions.Insert(name2, map2, SIMPLE_PROPERTY_TRANSITION);
|
||||
TransitionsAccessor::Insert(isolate, map0, name2, map2,
|
||||
SIMPLE_PROPERTY_TRANSITION);
|
||||
}
|
||||
{
|
||||
TestTransitionsAccessor transitions(isolate, map0);
|
||||
@ -105,19 +108,22 @@ TEST(TransitionArray_FullFieldTransitions) {
|
||||
CHECK(map0->raw_transitions()->IsSmi());
|
||||
|
||||
{
|
||||
TestTransitionsAccessor transitions(isolate, map0);
|
||||
transitions.Insert(name1, map1, PROPERTY_TRANSITION);
|
||||
TransitionsAccessor::Insert(isolate, map0, name1, map1,
|
||||
PROPERTY_TRANSITION);
|
||||
}
|
||||
{
|
||||
TestTransitionsAccessor transitions(isolate, map0);
|
||||
CHECK(transitions.IsFullTransitionArrayEncoding());
|
||||
CHECK_EQ(*map1, transitions.SearchTransition(*name1, PropertyKind::kData,
|
||||
attributes));
|
||||
CHECK_EQ(1, transitions.NumberOfTransitions());
|
||||
CHECK_EQ(*name1, transitions.GetKey(0));
|
||||
CHECK_EQ(*map1, transitions.GetTarget(0));
|
||||
{
|
||||
TestTransitionsAccessor transitions(isolate, map0);
|
||||
CHECK(transitions.IsFullTransitionArrayEncoding());
|
||||
CHECK_EQ(*map1, transitions.SearchTransition(*name1, PropertyKind::kData,
|
||||
attributes));
|
||||
CHECK_EQ(1, transitions.NumberOfTransitions());
|
||||
CHECK_EQ(*name1, transitions.GetKey(0));
|
||||
CHECK_EQ(*map1, transitions.GetTarget(0));
|
||||
}
|
||||
|
||||
transitions.Insert(name2, map2, PROPERTY_TRANSITION);
|
||||
TransitionsAccessor::Insert(isolate, map0, name2, map2,
|
||||
PROPERTY_TRANSITION);
|
||||
}
|
||||
{
|
||||
TestTransitionsAccessor transitions(isolate, map0);
|
||||
@ -166,10 +172,10 @@ TEST(TransitionArray_DifferentFieldNames) {
|
||||
names[i] = name;
|
||||
maps[i] = map;
|
||||
|
||||
TransitionsAccessor(isolate, map0).Insert(name, map, PROPERTY_TRANSITION);
|
||||
TransitionsAccessor::Insert(isolate, map0, name, map, PROPERTY_TRANSITION);
|
||||
}
|
||||
|
||||
TransitionsAccessor transitions(isolate, map0);
|
||||
TransitionsAccessor transitions(isolate, *map0);
|
||||
for (int i = 0; i < PROPS_COUNT; i++) {
|
||||
CHECK_EQ(*maps[i], transitions.SearchTransition(
|
||||
*names[i], PropertyKind::kData, attributes));
|
||||
@ -214,11 +220,11 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributesSimple) {
|
||||
.ToHandleChecked();
|
||||
attr_maps[i] = map;
|
||||
|
||||
TransitionsAccessor(isolate, map0).Insert(name, map, PROPERTY_TRANSITION);
|
||||
TransitionsAccessor::Insert(isolate, map0, name, map, PROPERTY_TRANSITION);
|
||||
}
|
||||
|
||||
// Ensure that transitions for |name| field are valid.
|
||||
TransitionsAccessor transitions(isolate, map0);
|
||||
TransitionsAccessor transitions(isolate, *map0);
|
||||
for (int i = 0; i < ATTRS_COUNT; i++) {
|
||||
PropertyAttributes attributes = static_cast<PropertyAttributes>(i);
|
||||
CHECK_EQ(*attr_maps[i], transitions.SearchTransition(
|
||||
@ -258,7 +264,7 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributes) {
|
||||
names[i] = name;
|
||||
maps[i] = map;
|
||||
|
||||
TransitionsAccessor(isolate, map0).Insert(name, map, PROPERTY_TRANSITION);
|
||||
TransitionsAccessor::Insert(isolate, map0, name, map, PROPERTY_TRANSITION);
|
||||
}
|
||||
|
||||
const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1;
|
||||
@ -277,11 +283,11 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributes) {
|
||||
.ToHandleChecked();
|
||||
attr_maps[i] = map;
|
||||
|
||||
TransitionsAccessor(isolate, map0).Insert(name, map, PROPERTY_TRANSITION);
|
||||
TransitionsAccessor::Insert(isolate, map0, name, map, PROPERTY_TRANSITION);
|
||||
}
|
||||
|
||||
// Ensure that transitions for |name| field are valid.
|
||||
TransitionsAccessor transitions(isolate, map0);
|
||||
TransitionsAccessor transitions(isolate, *map0);
|
||||
for (int i = 0; i < ATTRS_COUNT; i++) {
|
||||
PropertyAttributes attr = static_cast<PropertyAttributes>(i);
|
||||
CHECK_EQ(*attr_maps[i],
|
||||
|
@ -12,11 +12,10 @@ namespace internal {
|
||||
|
||||
class TestTransitionsAccessor : public TransitionsAccessor {
|
||||
public:
|
||||
TestTransitionsAccessor(Isolate* isolate, Map map,
|
||||
DisallowGarbageCollection* no_gc)
|
||||
: TransitionsAccessor(isolate, map, no_gc) {}
|
||||
TestTransitionsAccessor(Isolate* isolate, Handle<Map> map)
|
||||
TestTransitionsAccessor(Isolate* isolate, Map map)
|
||||
: TransitionsAccessor(isolate, map) {}
|
||||
TestTransitionsAccessor(Isolate* isolate, Handle<Map> map)
|
||||
: TransitionsAccessor(isolate, *map) {}
|
||||
|
||||
// Expose internals for tests.
|
||||
bool IsUninitializedEncoding() { return encoding() == kUninitialized; }
|
||||
|
Loading…
Reference in New Issue
Block a user