[vm/compiler] Fix assertion when assigning type to a Phi in ComputeSSA

Fixes https://github.com/dart-lang/sdk/issues/43682

Change-Id: I6b123ac5ba153b1f4177148341619419c3058684
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/166304
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_promotion.dart b/pkg/front_end/lib/src/fasta/type_inference/type_promotion.dart
index af42f14..2ae32bf 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_promotion.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_promotion.dart
@@ -377,9 +377,7 @@
           factMap[variable],
           isCheck.functionNestingLevel,
           isCheck.checkedType,
-          []
-            ..addAll(isCheck._blockingScopes)
-            ..add(_currentScope));
+          [...isCheck._blockingScopes, _currentScope]);
       factMap[variable] = facts;
       _factCacheState = facts;
     }
diff --git a/runtime/tests/vm/dart/regress_43682_test.dart b/runtime/tests/vm/dart/regress_43682_test.dart
new file mode 100644
index 0000000..63ef705
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_43682_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2020, 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 --optimization_counter_threshold=20
+
+// Verifies that SSA construction doesn't crash when handling a Phi
+// corresponding to an expression temp in case of OSR with non-empty
+// expression stack.
+// Regression test for https://github.com/dart-lang/sdk/issues/43682.
+
+import 'package:expect/expect.dart';
+
+class Foo {
+  List<Object> data;
+  Foo(this.data);
+}
+
+Map<String, Foo> foo(List<Object> objects) {
+  Map<String, Foo> map = {};
+  // OSR happens during '...objects' spread, and Foo instance is already
+  // allocated and remains on the stack during OSR.
+  // OSR Phi corresponding to that value is stored into 'foo' local and
+  // then loaded from it, but it doesn't correspond to 'foo' environment slot.
+  final foo = new Foo([...objects]);
+  map['hi'] = foo;
+  return map;
+}
+
+main() {
+  Expect.equals(30, foo(List.filled(30, Object()))['hi']!.data.length);
+}
diff --git a/runtime/tests/vm/dart_2/regress_43682_test.dart b/runtime/tests/vm/dart_2/regress_43682_test.dart
new file mode 100644
index 0000000..15924b1
--- /dev/null
+++ b/runtime/tests/vm/dart_2/regress_43682_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2020, 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 --optimization_counter_threshold=20
+
+// Verifies that SSA construction doesn't crash when handling a Phi
+// corresponding to an expression temp in case of OSR with non-empty
+// expression stack.
+// Regression test for https://github.com/dart-lang/sdk/issues/43682.
+
+import 'package:expect/expect.dart';
+
+class Foo {
+  List<Object> data;
+  Foo(this.data);
+}
+
+Map<String, Foo> foo(List<Object> objects) {
+  Map<String, Foo> map = {};
+  // OSR happens during '...objects' spread, and Foo instance is already
+  // allocated and remains on the stack during OSR.
+  // OSR Phi corresponding to that value is stored into 'foo' local and
+  // then loaded from it, but it doesn't correspond to 'foo' environment slot.
+  final foo = new Foo([...objects]);
+  map['hi'] = foo;
+  return map;
+}
+
+main() {
+  Expect.equals(30, foo(List.filled(30, Object()))['hi'].data.length);
+}
diff --git a/runtime/vm/compiler/backend/flow_graph.cc b/runtime/vm/compiler/backend/flow_graph.cc
index 9196b2d..82430b4 100644
--- a/runtime/vm/compiler/backend/flow_graph.cc
+++ b/runtime/vm/compiler/backend/flow_graph.cc
@@ -1453,13 +1453,23 @@
           // there as incoming value by renaming or it was stored there by
           // StoreLocal which took this Phi from another local via LoadLocal,
           // to which this reasoning applies recursively.
+          //
           // This means that we are guaranteed to process LoadLocal for a
-          // matching variable first.
+          // matching variable first, unless there was an OSR with a non-empty
+          // expression stack. In the latter case, Phi inserted by
+          // FlowGraph::AddSyntheticPhis for expression temp will not have an
+          // assigned type and may be accessed by StoreLocal and subsequent
+          // LoadLocal.
+          //
           if (!phi->HasType()) {
-            ASSERT((index < phi->block()->phis()->length()) &&
-                   ((*phi->block()->phis())[index] == phi));
-            phi->UpdateType(
-                CompileType::FromAbstractType(load->local().type()));
+            // Check if phi corresponds to the same slot.
+            auto* phis = phi->block()->phis();
+            if ((index < phis->length()) && (*phis)[index] == phi) {
+              phi->UpdateType(
+                  CompileType::FromAbstractType(load->local().type()));
+            } else {
+              ASSERT(IsCompiledForOsr() && (phi->block()->stack_depth() > 0));
+            }
           }
         }
         break;