[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}
This commit is contained in:
Victor Gomes 2022-02-11 15:02:17 +01:00 committed by V8 LUCI CQ
parent 5e6a64b515
commit c927ada76c
21 changed files with 402 additions and 340 deletions

View File

@ -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();

View File

@ -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));
});

View File

@ -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(),

View File

@ -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
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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");

View File

@ -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());
}

View File

@ -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);

View File

@ -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;

View File

@ -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 {

View File

@ -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,58 @@ 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);
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 +605,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);

View File

@ -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);
};

View File

@ -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 {

View File

@ -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) {

View File

@ -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();
}

View File

@ -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;

View File

@ -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();

View File

@ -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);
}

View File

@ -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],

View File

@ -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; }