Commit c285380c authored by Shiyu Zhang's avatar Shiyu Zhang Committed by Commit Bot

Create a fast path to get migration target when updating map

During map updating, store the pointer to new map in the
raw_transitions slot of the old map that is deprecated from map
transition tree. Thus, we can get the migration target directly
instead of TryReplayPropertyTransitions when updating map.

This can improve Speedometer2.0 Elm-TodoMVC case by ~5% on ATOM
Chromebook and ~9% on big-core Ubuntu.

Change-Id: I56f9ce5183bbdd567b964890f623ef0ceed9b7db
Reviewed-on: https://chromium-review.googlesource.com/1233433
Commit-Queue: Shiyu Zhang <shiyu.zhang@intel.com>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56303}
parent 0b9f6476
...@@ -170,6 +170,7 @@ Handle<Map> MapUpdater::Update() { ...@@ -170,6 +170,7 @@ Handle<Map> MapUpdater::Update() {
if (FindTargetMap() == kEnd) return result_map_; if (FindTargetMap() == kEnd) return result_map_;
ConstructNewMap(); ConstructNewMap();
DCHECK_EQ(kEnd, state_); DCHECK_EQ(kEnd, state_);
TransitionsAccessor(isolate_, old_map_).SetMigrationTarget(*result_map_);
return result_map_; return result_map_;
} }
......
...@@ -2386,6 +2386,7 @@ void TransitionsAccessor::PrintTransitions(std::ostream& os) { // NOLINT ...@@ -2386,6 +2386,7 @@ void TransitionsAccessor::PrintTransitions(std::ostream& os) { // NOLINT
switch (encoding()) { switch (encoding()) {
case kPrototypeInfo: case kPrototypeInfo:
case kUninitialized: case kUninitialized:
case kMigrationTarget:
return; return;
case kWeakRef: { case kWeakRef: {
Map* target = Map::cast(raw_transitions_->GetHeapObjectAssumeWeak()); Map* target = Map::cast(raw_transitions_->GetHeapObjectAssumeWeak());
......
...@@ -4882,6 +4882,25 @@ Handle<Map> Map::ReconfigureElementsKind(Isolate* isolate, Handle<Map> map, ...@@ -4882,6 +4882,25 @@ Handle<Map> Map::ReconfigureElementsKind(Isolate* isolate, Handle<Map> map,
return mu.ReconfigureElementsKind(new_elements_kind); return mu.ReconfigureElementsKind(new_elements_kind);
} }
namespace {
Map* SearchMigrationTarget(Isolate* isolate, Map* old_map) {
DisallowHeapAllocation no_allocation;
DisallowDeoptimization no_deoptimization(isolate);
Map* target = old_map;
do {
target = TransitionsAccessor(isolate, target, &no_allocation)
.GetMigrationTarget();
} while (target != nullptr && target->is_deprecated());
SLOW_DCHECK(target == nullptr ||
Map::TryUpdateSlow(isolate, old_map) == nullptr ||
Map::TryUpdateSlow(isolate, old_map) == target);
return target;
}
} // namespace
// TODO(ishell): Move TryUpdate() and friends to MapUpdater
// static // static
MaybeHandle<Map> Map::TryUpdate(Isolate* isolate, Handle<Map> old_map) { MaybeHandle<Map> Map::TryUpdate(Isolate* isolate, Handle<Map> old_map) {
DisallowHeapAllocation no_allocation; DisallowHeapAllocation no_allocation;
...@@ -4889,6 +4908,22 @@ MaybeHandle<Map> Map::TryUpdate(Isolate* isolate, Handle<Map> old_map) { ...@@ -4889,6 +4908,22 @@ MaybeHandle<Map> Map::TryUpdate(Isolate* isolate, Handle<Map> old_map) {
if (!old_map->is_deprecated()) return old_map; if (!old_map->is_deprecated()) return old_map;
Map* target_map = SearchMigrationTarget(isolate, *old_map);
if (target_map != nullptr) {
return handle(target_map, isolate);
}
Map* new_map = TryUpdateSlow(isolate, *old_map);
if (new_map == nullptr) return MaybeHandle<Map>();
TransitionsAccessor(isolate, *old_map, &no_allocation)
.SetMigrationTarget(new_map);
return handle(new_map, isolate);
}
Map* Map::TryUpdateSlow(Isolate* isolate, Map* old_map) {
DisallowHeapAllocation no_allocation;
DisallowDeoptimization no_deoptimization(isolate);
// Check the state of the root map. // Check the state of the root map.
Map* root_map = old_map->FindRootMap(isolate); Map* root_map = old_map->FindRootMap(isolate);
if (root_map->is_deprecated()) { if (root_map->is_deprecated()) {
...@@ -4897,23 +4932,21 @@ MaybeHandle<Map> Map::TryUpdate(Isolate* isolate, Handle<Map> old_map) { ...@@ -4897,23 +4932,21 @@ MaybeHandle<Map> Map::TryUpdate(Isolate* isolate, Handle<Map> old_map) {
DCHECK(constructor->initial_map()->is_dictionary_map()); DCHECK(constructor->initial_map()->is_dictionary_map());
if (constructor->initial_map()->elements_kind() != if (constructor->initial_map()->elements_kind() !=
old_map->elements_kind()) { old_map->elements_kind()) {
return MaybeHandle<Map>(); return nullptr;
} }
return handle(constructor->initial_map(), constructor->GetIsolate()); return constructor->initial_map();
} }
if (!old_map->EquivalentToForTransition(root_map)) return MaybeHandle<Map>(); if (!old_map->EquivalentToForTransition(root_map)) return nullptr;
ElementsKind from_kind = root_map->elements_kind(); ElementsKind from_kind = root_map->elements_kind();
ElementsKind to_kind = old_map->elements_kind(); ElementsKind to_kind = old_map->elements_kind();
if (from_kind != to_kind) { if (from_kind != to_kind) {
// Try to follow existing elements kind transitions. // Try to follow existing elements kind transitions.
root_map = root_map->LookupElementsTransitionMap(isolate, to_kind); root_map = root_map->LookupElementsTransitionMap(isolate, to_kind);
if (root_map == nullptr) return MaybeHandle<Map>(); if (root_map == nullptr) return nullptr;
// From here on, use the map with correct elements kind as root map. // From here on, use the map with correct elements kind as root map.
} }
Map* new_map = root_map->TryReplayPropertyTransitions(isolate, *old_map); return root_map->TryReplayPropertyTransitions(isolate, old_map);
if (new_map == nullptr) return MaybeHandle<Map>();
return handle(new_map, isolate);
} }
Map* Map::TryReplayPropertyTransitions(Isolate* isolate, Map* old_map) { Map* Map::TryReplayPropertyTransitions(Isolate* isolate, Map* old_map) {
...@@ -4995,6 +5028,10 @@ Map* Map::TryReplayPropertyTransitions(Isolate* isolate, Map* old_map) { ...@@ -4995,6 +5028,10 @@ Map* Map::TryReplayPropertyTransitions(Isolate* isolate, Map* old_map) {
// static // static
Handle<Map> Map::Update(Isolate* isolate, Handle<Map> map) { Handle<Map> Map::Update(Isolate* isolate, Handle<Map> map) {
if (!map->is_deprecated()) return map; if (!map->is_deprecated()) return map;
Map* target_map = SearchMigrationTarget(isolate, *map);
if (target_map != nullptr) {
return handle(target_map, isolate);
}
MapUpdater mu(isolate, map); MapUpdater mu(isolate, map);
return mu.Update(); return mu.Update();
} }
......
...@@ -632,6 +632,7 @@ class Map : public HeapObject { ...@@ -632,6 +632,7 @@ class Map : public HeapObject {
// is found. // is found.
static MaybeHandle<Map> TryUpdate(Isolate* isolate, static MaybeHandle<Map> TryUpdate(Isolate* isolate,
Handle<Map> map) V8_WARN_UNUSED_RESULT; Handle<Map> map) V8_WARN_UNUSED_RESULT;
static Map* TryUpdateSlow(Isolate* isolate, Map* map) V8_WARN_UNUSED_RESULT;
// Returns a non-deprecated version of the input. This method may deprecate // Returns a non-deprecated version of the input. This method may deprecate
// existing maps along the way if encodings conflict. Not for use while // existing maps along the way if encodings conflict. Not for use while
......
...@@ -65,6 +65,7 @@ Name* TransitionsAccessor::GetKey(int transition_number) { ...@@ -65,6 +65,7 @@ Name* TransitionsAccessor::GetKey(int transition_number) {
switch (encoding()) { switch (encoding()) {
case kPrototypeInfo: case kPrototypeInfo:
case kUninitialized: case kUninitialized:
case kMigrationTarget:
UNREACHABLE(); UNREACHABLE();
return nullptr; return nullptr;
case kWeakRef: { case kWeakRef: {
...@@ -118,6 +119,7 @@ Map* TransitionsAccessor::GetTarget(int transition_number) { ...@@ -118,6 +119,7 @@ Map* TransitionsAccessor::GetTarget(int transition_number) {
switch (encoding()) { switch (encoding()) {
case kPrototypeInfo: case kPrototypeInfo:
case kUninitialized: case kUninitialized:
case kMigrationTarget:
UNREACHABLE(); UNREACHABLE();
return nullptr; return nullptr;
case kWeakRef: case kWeakRef:
......
...@@ -21,9 +21,12 @@ void TransitionsAccessor::Initialize() { ...@@ -21,9 +21,12 @@ void TransitionsAccessor::Initialize() {
} else if (raw_transitions_->GetHeapObjectIfStrong(&heap_object)) { } else if (raw_transitions_->GetHeapObjectIfStrong(&heap_object)) {
if (heap_object->IsTransitionArray()) { if (heap_object->IsTransitionArray()) {
encoding_ = kFullTransitionArray; encoding_ = kFullTransitionArray;
} else { } else if (heap_object->IsPrototypeInfo()) {
DCHECK(heap_object->IsPrototypeInfo());
encoding_ = kPrototypeInfo; encoding_ = kPrototypeInfo;
} else {
DCHECK(map_->is_deprecated());
DCHECK(heap_object->IsMap());
encoding_ = kMigrationTarget;
} }
} else { } else {
UNREACHABLE(); UNREACHABLE();
...@@ -48,6 +51,7 @@ bool TransitionsAccessor::HasSimpleTransitionTo(Map* map) { ...@@ -48,6 +51,7 @@ bool TransitionsAccessor::HasSimpleTransitionTo(Map* map) {
return raw_transitions_->GetHeapObjectAssumeWeak() == map; return raw_transitions_->GetHeapObjectAssumeWeak() == map;
case kPrototypeInfo: case kPrototypeInfo:
case kUninitialized: case kUninitialized:
case kMigrationTarget:
case kFullTransitionArray: case kFullTransitionArray:
return false; return false;
} }
...@@ -212,6 +216,7 @@ Map* TransitionsAccessor::SearchTransition(Name* name, PropertyKind kind, ...@@ -212,6 +216,7 @@ Map* TransitionsAccessor::SearchTransition(Name* name, PropertyKind kind,
switch (encoding()) { switch (encoding()) {
case kPrototypeInfo: case kPrototypeInfo:
case kUninitialized: case kUninitialized:
case kMigrationTarget:
return nullptr; return nullptr;
case kWeakRef: { case kWeakRef: {
Map* map = Map::cast(raw_transitions_->GetHeapObjectAssumeWeak()); Map* map = Map::cast(raw_transitions_->GetHeapObjectAssumeWeak());
...@@ -264,6 +269,7 @@ Handle<String> TransitionsAccessor::ExpectedTransitionKey() { ...@@ -264,6 +269,7 @@ Handle<String> TransitionsAccessor::ExpectedTransitionKey() {
switch (encoding()) { switch (encoding()) {
case kPrototypeInfo: case kPrototypeInfo:
case kUninitialized: case kUninitialized:
case kMigrationTarget:
case kFullTransitionArray: case kFullTransitionArray:
return Handle<String>::null(); return Handle<String>::null();
case kWeakRef: { case kWeakRef: {
...@@ -430,6 +436,7 @@ int TransitionsAccessor::NumberOfTransitions() { ...@@ -430,6 +436,7 @@ int TransitionsAccessor::NumberOfTransitions() {
switch (encoding()) { switch (encoding()) {
case kPrototypeInfo: case kPrototypeInfo:
case kUninitialized: case kUninitialized:
case kMigrationTarget:
return 0; return 0;
case kWeakRef: case kWeakRef:
return 1; return 1;
...@@ -440,6 +447,18 @@ int TransitionsAccessor::NumberOfTransitions() { ...@@ -440,6 +447,18 @@ int TransitionsAccessor::NumberOfTransitions() {
return 0; // Make GCC happy. return 0; // Make GCC happy.
} }
void TransitionsAccessor::SetMigrationTarget(Map* migration_target) {
DCHECK(map_->is_deprecated());
ReplaceTransitions(MaybeObject::FromObject(migration_target));
}
Map* TransitionsAccessor::GetMigrationTarget() {
if (encoding() == kMigrationTarget) {
return map_->raw_transitions()->cast<Map>();
}
return nullptr;
}
void TransitionArray::Zap(Isolate* isolate) { void TransitionArray::Zap(Isolate* isolate) {
MemsetPointer( MemsetPointer(
data_start() + kPrototypeTransitionsIndex, data_start() + kPrototypeTransitionsIndex,
...@@ -474,7 +493,8 @@ void TransitionsAccessor::SetPrototypeTransitions( ...@@ -474,7 +493,8 @@ void TransitionsAccessor::SetPrototypeTransitions(
void TransitionsAccessor::EnsureHasFullTransitionArray() { void TransitionsAccessor::EnsureHasFullTransitionArray() {
if (encoding() == kFullTransitionArray) return; if (encoding() == kFullTransitionArray) return;
int nof = encoding() == kUninitialized ? 0 : 1; int nof =
(encoding() == kUninitialized || encoding() == kMigrationTarget) ? 0 : 1;
Handle<TransitionArray> result = isolate_->factory()->NewTransitionArray(nof); Handle<TransitionArray> result = isolate_->factory()->NewTransitionArray(nof);
Reload(); // Reload after possible GC. Reload(); // Reload after possible GC.
if (nof == 1) { if (nof == 1) {
...@@ -497,6 +517,7 @@ void TransitionsAccessor::TraverseTransitionTreeInternal( ...@@ -497,6 +517,7 @@ void TransitionsAccessor::TraverseTransitionTreeInternal(
switch (encoding()) { switch (encoding()) {
case kPrototypeInfo: case kPrototypeInfo:
case kUninitialized: case kUninitialized:
case kMigrationTarget:
break; break;
case kWeakRef: { case kWeakRef: {
Map* simple_target = Map* simple_target =
......
...@@ -106,6 +106,14 @@ class TransitionsAccessor { ...@@ -106,6 +106,14 @@ class TransitionsAccessor {
void PutPrototypeTransition(Handle<Object> prototype, Handle<Map> target_map); void PutPrototypeTransition(Handle<Object> prototype, Handle<Map> target_map);
Handle<Map> GetPrototypeTransition(Handle<Object> prototype); Handle<Map> GetPrototypeTransition(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);
Map* GetMigrationTarget();
#if DEBUG || OBJECT_PRINT #if DEBUG || OBJECT_PRINT
void PrintTransitions(std::ostream& os); void PrintTransitions(std::ostream& os);
static void PrintOneTransition(std::ostream& os, Name* key, Map* target); static void PrintOneTransition(std::ostream& os, Name* key, Map* target);
...@@ -125,6 +133,7 @@ class TransitionsAccessor { ...@@ -125,6 +133,7 @@ class TransitionsAccessor {
enum Encoding { enum Encoding {
kPrototypeInfo, kPrototypeInfo,
kUninitialized, kUninitialized,
kMigrationTarget,
kWeakRef, kWeakRef,
kFullTransitionArray, kFullTransitionArray,
}; };
......
...@@ -78,6 +78,14 @@ static Handle<AccessorPair> CreateAccessorPair(bool with_getter, ...@@ -78,6 +78,14 @@ static Handle<AccessorPair> CreateAccessorPair(bool with_getter,
return pair; return pair;
} }
// 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();
if (!target) return;
CHECK_EQ(new_map, target);
CHECK_EQ(Map::TryUpdateSlow(isolate, old_map), target);
}
class Expectations { class Expectations {
static const int MAX_PROPERTIES = 10; static const int MAX_PROPERTIES = 10;
...@@ -707,6 +715,7 @@ static void TestGeneralizeField(int detach_property_at_index, ...@@ -707,6 +715,7 @@ static void TestGeneralizeField(int detach_property_at_index,
// Update all deprecated maps and check that they are now the same. // Update all deprecated maps and check that they are now the same.
Handle<Map> updated_map = Map::Update(isolate, map); Handle<Map> updated_map = Map::Update(isolate, map);
CHECK_EQ(*new_map, *updated_map); CHECK_EQ(*new_map, *updated_map);
CheckMigrationTarget(isolate, *map, *updated_map);
} }
static void TestGeneralizeField(const CRFTData& from, const CRFTData& to, static void TestGeneralizeField(const CRFTData& from, const CRFTData& to,
...@@ -967,9 +976,11 @@ TEST(GeneralizeFieldWithAccessorProperties) { ...@@ -967,9 +976,11 @@ TEST(GeneralizeFieldWithAccessorProperties) {
// Update all deprecated maps and check that they are now the same. // Update all deprecated maps and check that they are now the same.
Handle<Map> updated_map = Map::Update(isolate, map); Handle<Map> updated_map = Map::Update(isolate, map);
CHECK_EQ(*active_map, *updated_map); CHECK_EQ(*active_map, *updated_map);
CheckMigrationTarget(isolate, *map, *updated_map);
for (int i = 0; i < kPropCount; i++) { for (int i = 0; i < kPropCount; i++) {
updated_map = Map::Update(isolate, maps[i]); updated_map = Map::Update(isolate, maps[i]);
CHECK_EQ(*active_map, *updated_map); CHECK_EQ(*active_map, *updated_map);
CheckMigrationTarget(isolate, *maps[i], *updated_map);
} }
} }
...@@ -1060,6 +1071,7 @@ static void TestReconfigureDataFieldAttribute_GeneralizeField( ...@@ -1060,6 +1071,7 @@ static void TestReconfigureDataFieldAttribute_GeneralizeField(
// Update deprecated |map|, it should become |new_map|. // Update deprecated |map|, it should become |new_map|.
Handle<Map> updated_map = Map::Update(isolate, map); Handle<Map> updated_map = Map::Update(isolate, map);
CHECK_EQ(*new_map, *updated_map); CHECK_EQ(*new_map, *updated_map);
CheckMigrationTarget(isolate, *map, *updated_map);
} }
// This test ensures that trivial field generalization (from HeapObject to // This test ensures that trivial field generalization (from HeapObject to
...@@ -1370,6 +1382,7 @@ struct CheckDeprecated { ...@@ -1370,6 +1382,7 @@ struct CheckDeprecated {
// Update deprecated |map|, it should become |new_map|. // Update deprecated |map|, it should become |new_map|.
Handle<Map> updated_map = Map::Update(isolate, map); Handle<Map> updated_map = Map::Update(isolate, map);
CHECK_EQ(*new_map, *updated_map); CHECK_EQ(*new_map, *updated_map);
CheckMigrationTarget(isolate, *map, *updated_map);
} }
}; };
...@@ -1828,6 +1841,7 @@ static void TestReconfigureElementsKind_GeneralizeField( ...@@ -1828,6 +1841,7 @@ static void TestReconfigureElementsKind_GeneralizeField(
// Update deprecated |map|, it should become |new_map|. // Update deprecated |map|, it should become |new_map|.
Handle<Map> updated_map = Map::Update(isolate, map); Handle<Map> updated_map = Map::Update(isolate, map);
CHECK_EQ(*new_map, *updated_map); CHECK_EQ(*new_map, *updated_map);
CheckMigrationTarget(isolate, *map, *updated_map);
// Ensure Map::FindElementsKindTransitionedMap() is able to find the // Ensure Map::FindElementsKindTransitionedMap() is able to find the
// transitioned map. // transitioned map.
...@@ -2339,9 +2353,11 @@ static void TestGeneralizeFieldWithSpecialTransition(TestConfig& config, ...@@ -2339,9 +2353,11 @@ static void TestGeneralizeFieldWithSpecialTransition(TestConfig& config,
// Update all deprecated maps and check that they are now the same. // Update all deprecated maps and check that they are now the same.
Handle<Map> updated_map = Map::Update(isolate, map); Handle<Map> updated_map = Map::Update(isolate, map);
CHECK_EQ(*active_map, *updated_map); CHECK_EQ(*active_map, *updated_map);
CheckMigrationTarget(isolate, *map, *updated_map);
for (int i = 0; i < kPropCount; i++) { for (int i = 0; i < kPropCount; i++) {
updated_map = Map::Update(isolate, maps[i]); updated_map = Map::Update(isolate, maps[i]);
CHECK_EQ(*active_map, *updated_map); CHECK_EQ(*active_map, *updated_map);
CheckMigrationTarget(isolate, *maps[i], *updated_map);
} }
} }
...@@ -2623,6 +2639,7 @@ struct FieldGeneralizationChecker { ...@@ -2623,6 +2639,7 @@ struct FieldGeneralizationChecker {
CHECK_NE(*map1, *map2); CHECK_NE(*map1, *map2);
Handle<Map> updated_map = Map::Update(isolate, map1); Handle<Map> updated_map = Map::Update(isolate, map1);
CHECK_EQ(*map2, *updated_map); CHECK_EQ(*map2, *updated_map);
CheckMigrationTarget(isolate, *map1, *updated_map);
expectations2.SetDataField(descriptor_, attributes_, constness_, expectations2.SetDataField(descriptor_, attributes_, constness_,
representation_, heap_type_); representation_, heap_type_);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment