Commit 239bfc96 authored by Ross McIlroy's avatar Ross McIlroy Committed by Commit Bot

[Turboprop] Support migration of deprecated maps in dynamic check maps

Adds support for generating code to migrate instances if a map
is a migration target, to dynamic check maps.

BUG=v8:10582

Change-Id: Id26d95491869fc68a5633398d230237eb88648d9
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2575058Reviewed-by: 's avatarMythri Alle <mythria@chromium.org>
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71658}
parent 371d7dbc
...@@ -286,6 +286,9 @@ class EffectControlLinearizer { ...@@ -286,6 +286,9 @@ class EffectControlLinearizer {
void MigrateInstanceOrDeopt(Node* value, Node* value_map, Node* frame_state, void MigrateInstanceOrDeopt(Node* value, Node* value_map, Node* frame_state,
FeedbackSource const& feedback_source, FeedbackSource const& feedback_source,
DeoptimizeReason reason); DeoptimizeReason reason);
// Tries to migrate |value| if its map |value_map| is deprecated, but doesn't
// deopt on failure.
void TryMigrateInstance(Node* value, Node* value_map);
bool should_maintain_schedule() const { bool should_maintain_schedule() const {
return maintain_schedule_ == MaintainSchedule::kMaintain; return maintain_schedule_ == MaintainSchedule::kMaintain;
...@@ -1883,31 +1886,61 @@ void EffectControlLinearizer::LowerCheckMaps(Node* node, Node* frame_state) { ...@@ -1883,31 +1886,61 @@ void EffectControlLinearizer::LowerCheckMaps(Node* node, Node* frame_state) {
} }
} }
void EffectControlLinearizer::TryMigrateInstance(Node* value, Node* value_map) {
auto done = __ MakeLabel();
// If map is not deprecated the migration attempt does not make sense.
Node* bitfield3 = __ LoadField(AccessBuilder::ForMapBitField3(), value_map);
Node* is_not_deprecated = __ Word32Equal(
__ Word32And(bitfield3,
__ Int32Constant(Map::Bits3::IsDeprecatedBit::kMask)),
__ Int32Constant(0));
__ GotoIf(is_not_deprecated, &done);
Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow;
Runtime::FunctionId id = Runtime::kTryMigrateInstance;
auto call_descriptor = Linkage::GetRuntimeCallDescriptor(
graph()->zone(), id, 1, properties, CallDescriptor::kNoFlags);
__ Call(call_descriptor, __ CEntryStubConstant(1), value,
__ ExternalConstant(ExternalReference::Create(id)),
__ Int32Constant(1), __ NoContextConstant());
__ Goto(&done);
__ Bind(&done);
}
void EffectControlLinearizer::LowerDynamicCheckMaps(Node* node, void EffectControlLinearizer::LowerDynamicCheckMaps(Node* node,
Node* frame_state) { Node* frame_state) {
DynamicCheckMapsParameters const& p = DynamicCheckMapsParameters const& p =
DynamicCheckMapsParametersOf(node->op()); DynamicCheckMapsParametersOf(node->op());
Node* actual_value = node->InputAt(0); Node* value = node->InputAt(0);
FeedbackSource const& feedback = p.feedback(); FeedbackSource const& feedback = p.feedback();
Node* slot_index = __ IntPtrConstant(feedback.index()); Node* slot_index = __ IntPtrConstant(feedback.index());
Node* actual_value_map = __ LoadField(AccessBuilder::ForMap(), actual_value); Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
Node* actual_handler = Node* actual_handler =
p.handler()->IsSmi() p.handler()->IsSmi()
? __ SmiConstant(Smi::ToInt(*p.handler())) ? __ SmiConstant(Smi::ToInt(*p.handler()))
: __ HeapConstant(Handle<HeapObject>::cast(p.handler())); : __ HeapConstant(Handle<HeapObject>::cast(p.handler()));
// TODO(rmcilroy) Add support to perform the instance migration of deprecated
// maps if the map might need migration.
auto done = __ MakeLabel(); auto done = __ MakeLabel();
ZoneHandleSet<Map> maps = p.maps(); ZoneHandleSet<Map> maps = p.maps();
size_t const map_count = maps.size(); size_t const map_count = maps.size();
for (size_t i = 0; i < map_count; ++i) { for (size_t i = 0; i < map_count; ++i) {
Node* map = __ HeapConstant(maps[i]); Node* map = __ HeapConstant(maps[i]);
Node* check = __ TaggedEqual(actual_value_map, map); Node* check = __ TaggedEqual(value_map, map);
if (i == map_count - 1) { if (i == map_count - 1) {
__ DynamicCheckMapsWithDeoptUnless(check, slot_index, actual_value_map, if (p.flags() & CheckMapsFlag::kTryMigrateInstance) {
auto migrate = __ MakeDeferredLabel();
__ BranchWithCriticalSafetyCheck(check, &done, &migrate);
__ Bind(&migrate);
TryMigrateInstance(value, value_map);
// Reload the current map of the {value} before performing the dynanmic
// map check.
value_map = __ LoadField(AccessBuilder::ForMap(), value);
}
__ DynamicCheckMapsWithDeoptUnless(check, slot_index, value_map,
actual_handler, frame_state); actual_handler, frame_state);
__ Goto(&done); __ Goto(&done);
} else { } else {
......
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --turboprop --turbo-dynamic-map-checks
// Flags: --opt --no-always-opt --deopt-every-n-times=0
function b(a) { return a; }
function f(o, should_bailout) {
b(o.a);
let did_bailout = (%GetOptimizationStatus(f) &
V8OptimizationStatus.kTopmostFrameIsTurboFanned) == 0;
assertEquals(should_bailout, did_bailout);
}
var o = {a:10, b:20, c:30};
var o1 = {a:10, b:20, c:30};
var o2 = {a:10, b:20, c:30};
// Make o's map a migration target.
o1.b = 10.23;
o.a;
%PrepareFunctionForOptimization(f);
f(o, true);
%OptimizeFunctionOnNextCall(f);
f(o, false);
assertOptimized(f);
// Deprecate o's new map again and update the feedback vector but don't migrate
// o.
o1.c = 20.23;
f(o1, true);
assertOptimized(f);
// We migrates o's map without deopting or bailing out.
f(o, false);
f(o1, false);
f(o2, false);
assertOptimized(f);
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