Version 2.14.0-169.0.dev
Merge commit 'af957d95786b33901ea7d0260ab286a964fe8318' into 'dev'
diff --git a/DEPS b/DEPS
index accfc1b..f0269ec 100644
--- a/DEPS
+++ b/DEPS
@@ -142,7 +142,7 @@
"pool_rev": "7abe634002a1ba8a0928eded086062f1307ccfae",
"process_rev": "56ece43b53b64c63ae51ec184b76bd5360c28d0b",
"protobuf_rev": "0d03fd588df69e9863e2a2efc0059dee8f18d5b2",
- "pub_rev": "def32ceb1d660552eaec24839d377199aea5a569",
+ "pub_rev": "11c2a0978e66fbc2c182dc6a8174db1a3651276c",
"pub_semver_rev": "f50d80ef10c4b2fa5f4c8878036a4d9342c0cc82",
"resource_rev": "6b79867d0becf5395e5819a75720963b8298e9a7",
"root_certificates_rev": "7e5ec82c99677a2e5b95ce296c4d68b0d3378ed8",
diff --git a/runtime/tests/vm/dart/deopt/restart_call_on_deopt_regress_46070_test.dart b/runtime/tests/vm/dart/deopt/restart_call_on_deopt_regress_46070_test.dart
new file mode 100644
index 0000000..959c792
--- /dev/null
+++ b/runtime/tests/vm/dart/deopt/restart_call_on_deopt_regress_46070_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--deterministic --deoptimize-on-runtime-call-every=3 --optimization-counter-threshold=10
+
+main() {
+ final l = <int>[1, 2, 3, 4, 5];
+ for (int i = 0; i < 1000; ++i) {
+ if (sumIt(l) != 15) throw 'failed';
+ }
+}
+
+@pragma('vm:never-inline')
+int sumIt(dynamic arg) {
+ int sum = 0;
+ for (int i = 0; i < 5; ++i) {
+ final l = arg as List<int>;
+ sum += l[i];
+ }
+ return sum;
+}
diff --git a/runtime/tests/vm/dart_2/deopt/restart_call_on_deopt_regress_46070_test.dart b/runtime/tests/vm/dart_2/deopt/restart_call_on_deopt_regress_46070_test.dart
new file mode 100644
index 0000000..959c792
--- /dev/null
+++ b/runtime/tests/vm/dart_2/deopt/restart_call_on_deopt_regress_46070_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--deterministic --deoptimize-on-runtime-call-every=3 --optimization-counter-threshold=10
+
+main() {
+ final l = <int>[1, 2, 3, 4, 5];
+ for (int i = 0; i < 1000; ++i) {
+ if (sumIt(l) != 15) throw 'failed';
+ }
+}
+
+@pragma('vm:never-inline')
+int sumIt(dynamic arg) {
+ int sum = 0;
+ for (int i = 0; i < 5; ++i) {
+ final l = arg as List<int>;
+ sum += l[i];
+ }
+ return sum;
+}
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index bc3bf363..0094d89 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -501,10 +501,20 @@
if ((deopt_id != DeoptId::kNone) && !FLAG_precompiled_mode) {
// Marks either the continuation point in unoptimized code or the
// deoptimization point in optimized code, after call.
- const intptr_t deopt_id_after = DeoptId::ToDeoptAfter(deopt_id);
if (is_optimizing()) {
- AddDeoptIndexAtCall(deopt_id_after, env);
+ ASSERT(env != nullptr);
+ // Note that we may lazy-deopt to the same IR instruction in unoptimized
+ // code or to another IR instruction (e.g. if LICM hoisted an instruction
+ // it will lazy-deopt to a Goto).
+ // If we happen to deopt to the beginning of an instruction in unoptimized
+ // code, we'll use the before deopt-id, otherwise the after deopt-id.
+ const intptr_t dest_deopt_id = env->LazyDeoptToBeforeDeoptId()
+ ? deopt_id
+ : DeoptId::ToDeoptAfter(deopt_id);
+ AddDeoptIndexAtCall(dest_deopt_id, env);
} else {
+ ASSERT(env == nullptr);
+ const intptr_t deopt_id_after = DeoptId::ToDeoptAfter(deopt_id);
// Add deoptimization continuation point after the call and before the
// arguments are removed.
AddCurrentDescriptor(UntaggedPcDescriptors::kDeopt, deopt_id_after,
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 55da50a..0986d22 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -5742,6 +5742,7 @@
length, fixed_parameter_count_, LazyDeoptPruneCount(), parsed_function_,
(outer_ == NULL) ? NULL : outer_->DeepCopy(zone));
copy->SetDeoptId(DeoptIdBits::decode(bitfield_));
+ copy->SetLazyDeoptToBeforeDeoptId(LazyDeoptToBeforeDeoptId());
if (locations_ != NULL) {
Location* new_locations = zone->Alloc<Location>(length);
copy->set_locations(new_locations);
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index a0b3cd1..b41c986 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -9423,6 +9423,14 @@
return LazyDeoptPruningBits::decode(bitfield_);
}
+ bool LazyDeoptToBeforeDeoptId() const {
+ return LazyDeoptToBeforeDeoptId::decode(bitfield_);
+ }
+
+ void MarkAsLazyDeoptToBeforeDeoptId() {
+ bitfield_ = LazyDeoptToBeforeDeoptId::update(true, bitfield_);
+ }
+
Environment* GetLazyDeoptEnv(Zone* zone) {
const intptr_t num_args_to_prune = LazyDeoptPruneCount();
if (num_args_to_prune == 0) return this;
@@ -9501,11 +9509,13 @@
friend class FlowGraphDeserializer; // For constructor and deopt_id_.
class LazyDeoptPruningBits : public BitField<uintptr_t, uintptr_t, 0, 8> {};
+ class LazyDeoptToBeforeDeoptId
+ : public BitField<uintptr_t, bool, LazyDeoptPruningBits::kNextBit, 1> {};
class DeoptIdBits
: public BitField<uintptr_t,
intptr_t,
- LazyDeoptPruningBits::kNextBit,
- kBitsPerWord - LazyDeoptPruningBits::kNextBit,
+ LazyDeoptToBeforeDeoptId::kNextBit,
+ kBitsPerWord - LazyDeoptToBeforeDeoptId::kNextBit,
/*sign_extend=*/true> {};
Environment(intptr_t length,
@@ -9516,6 +9526,7 @@
: values_(length),
fixed_parameter_count_(fixed_parameter_count),
bitfield_(DeoptIdBits::encode(DeoptId::kNone) |
+ LazyDeoptToBeforeDeoptId::encode(false) |
LazyDeoptPruningBits::encode(lazy_deopt_pruning_count)),
parsed_function_(parsed_function),
outer_(outer) {}
@@ -9526,6 +9537,9 @@
void SetLazyDeoptPruneCount(intptr_t value) {
bitfield_ = LazyDeoptPruningBits::update(value, bitfield_);
}
+ void SetLazyDeoptToBeforeDeoptId(bool value) {
+ bitfield_ = LazyDeoptToBeforeDeoptId::update(value, bitfield_);
+ }
GrowableArray<Value*> values_;
Location* locations_ = nullptr;
diff --git a/runtime/vm/compiler/backend/inliner.cc b/runtime/vm/compiler/backend/inliner.cc
index 5c8dcc8..d576993 100644
--- a/runtime/vm/compiler/backend/inliner.cc
+++ b/runtime/vm/compiler/backend/inliner.cc
@@ -2657,6 +2657,11 @@
Symbols::Value(), call->deopt_id());
cursor = flow_graph->AppendTo(cursor, assert_value, call->env(),
FlowGraph::kValue);
+ // The environment is that of the InstanceCall([]=, ..., <env>).
+ // A lazy-deopt of the inserted AssertAssignable must continue in
+ // unoptimzed code.
+ // => We will re-try this []= call in unoptimized code.
+ assert_value->env()->MarkAsLazyDeoptToBeforeDeoptId();
}
}
diff --git a/runtime/vm/compiler/backend/redundancy_elimination.cc b/runtime/vm/compiler/backend/redundancy_elimination.cc
index 5cbc45e..bda4322 100644
--- a/runtime/vm/compiler/backend/redundancy_elimination.cc
+++ b/runtime/vm/compiler/backend/redundancy_elimination.cc
@@ -1368,6 +1368,9 @@
GotoInstr* last = pre_header->last_instruction()->AsGoto();
// Using kind kEffect will not assign a fresh ssa temporary index.
flow_graph()->InsertBefore(last, current, last->env(), FlowGraph::kEffect);
+ // If the hoisted instruction lazy-deopts, it should continue at the start of
+ // the Goto (of which we copy the deopt-id from).
+ current->env()->MarkAsLazyDeoptToBeforeDeoptId();
current->CopyDeoptIdFrom(*last);
}
diff --git a/tools/VERSION b/tools/VERSION
index 2d5a96a..be9c9e0 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 168
+PRERELEASE 169
PRERELEASE_PATCH 0
\ No newline at end of file