[vm/compiler] Ensure allocate instructions have correctly pruned lazy deopt environment

Since allocation instructions can throw OOM exceptions, they require
deopt information. In general it's rather hard to test that this deopt
information is correct.

In order to test this, this CL makes those IR instructions support lazy
deopt and add tests that exercise this deopt sequence, thereby ensuring
the deoptimization environment is correct.

Issue https://github.com/dart-lang/sdk/issues/45213

TEST=New vm/dart_2/isolates/deopt/*_test.

Change-Id: I6a02dcf5a0c47636f1f0aa4cd8cc0d2b4f032ca0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/192687
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
diff --git a/runtime/tests/vm/dart/deopt/allocate_array_test.dart b/runtime/tests/vm/dart/deopt/allocate_array_test.dart
new file mode 100644
index 0000000..eb06336
--- /dev/null
+++ b/runtime/tests/vm/dart/deopt/allocate_array_test.dart
@@ -0,0 +1,17 @@
+// 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=--disable-dart-dev --no-inline-alloc --use-slow-path --deoptimize-on-runtime-call-every=1 --deterministic --optimization-counter-threshold=1 --deoptimize-on-runtime-call-name-filter=AllocateArray
+
+main() {
+  for (int i = 0; i < 20; ++i) {
+    final list = foo(1);
+    if (list[0] != 42) throw 'a';
+  }
+}
+
+@pragma('vm:never-inline')
+List foo(int a) {
+  return List<dynamic>.filled(a, null)..[0] = 42;
+}
diff --git a/runtime/tests/vm/dart/deopt/allocate_context_test.dart b/runtime/tests/vm/dart/deopt/allocate_context_test.dart
new file mode 100644
index 0000000..c52abc0
--- /dev/null
+++ b/runtime/tests/vm/dart/deopt/allocate_context_test.dart
@@ -0,0 +1,21 @@
+// 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=--disable-dart-dev --no-inline-alloc --use-slow-path --deoptimize-on-runtime-call-every=1 --deterministic --optimization-counter-threshold=1 --deoptimize-on-runtime-call-name-filter=AllocateContext
+
+main() {
+  for (int i = 0; i < 20; ++i) {
+    final fun = foo(1);
+    if (fun(1) != 3) throw 'a';
+    if (fun(2) != 6) throw 'b';
+  }
+}
+
+@pragma('vm:never-inline')
+int Function(int) foo(int a) {
+  int b = 1;
+  return (int c) {
+    return a++ + b++ + c;
+  };
+}
diff --git a/runtime/tests/vm/dart/deopt/allocate_object_test.dart b/runtime/tests/vm/dart/deopt/allocate_object_test.dart
new file mode 100644
index 0000000..efcd883
--- /dev/null
+++ b/runtime/tests/vm/dart/deopt/allocate_object_test.dart
@@ -0,0 +1,27 @@
+// 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=--disable-dart-dev --no-inline-alloc --use-slow-path --deoptimize-on-runtime-call-every=1 --deterministic --optimization-counter-threshold=1 --deoptimize-on-runtime-call-name-filter=AllocateObject
+
+main() {
+  for (int i = 0; i < 20; ++i) {
+    final foo = bar(1);
+    if (foo.fun(1) != 3) throw 'a';
+    if (foo.fun(2) != 6) throw 'b';
+  }
+}
+
+@pragma('vm:never-inline')
+Foo bar(int a) {
+  int b = 1;
+  return Foo(a, (int c) {
+    return a++ + b++ + c++;
+  });
+}
+
+class Foo {
+  final int value;
+  final int Function(int) fun;
+  Foo(this.value, this.fun);
+}
diff --git a/runtime/tests/vm/dart/deopt/allocate_typed_data_test.dart b/runtime/tests/vm/dart/deopt/allocate_typed_data_test.dart
new file mode 100644
index 0000000..6556661
--- /dev/null
+++ b/runtime/tests/vm/dart/deopt/allocate_typed_data_test.dart
@@ -0,0 +1,19 @@
+// 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=--disable-dart-dev --no-inline-alloc --use-slow-path --deoptimize-on-runtime-call-every=1 --deterministic --optimization-counter-threshold=1 --deoptimize-on-runtime-call-name-filter=AllocateTypedData
+
+import 'dart:typed_data';
+
+main() {
+  for (int i = 0; i < 20; ++i) {
+    final foo = bar(1);
+    if (foo[0] != 42) throw 'a';
+  }
+}
+
+@pragma('vm:never-inline')
+Uint32List bar(int a) {
+  return Uint32List(1)..[0] = 42;
+}
diff --git a/runtime/tests/vm/dart/deopt/clone_context_test.dart b/runtime/tests/vm/dart/deopt/clone_context_test.dart
new file mode 100644
index 0000000..5320404
--- /dev/null
+++ b/runtime/tests/vm/dart/deopt/clone_context_test.dart
@@ -0,0 +1,20 @@
+// 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=--disable-dart-dev --no-inline-alloc --use-slow-path --deoptimize-on-runtime-call-every=1 --deterministic --optimization-counter-threshold=1 --deoptimize-on-runtime-call-name-filter=CloneContext
+
+main() {
+  for (int i = 0; i < 20; ++i) {
+    if (foo(1)[1]() != 2) throw 'a';
+  }
+}
+
+@pragma('vm:never-inline')
+List foo(int a) {
+  final l = <int Function()>[];
+  for (int i = 0; i < 10; ++i) {
+    l.add(() => a + i);
+  }
+  return l;
+}
diff --git a/runtime/tests/vm/dart_2/deopt/allocate_array_test.dart b/runtime/tests/vm/dart_2/deopt/allocate_array_test.dart
new file mode 100644
index 0000000..eb06336
--- /dev/null
+++ b/runtime/tests/vm/dart_2/deopt/allocate_array_test.dart
@@ -0,0 +1,17 @@
+// 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=--disable-dart-dev --no-inline-alloc --use-slow-path --deoptimize-on-runtime-call-every=1 --deterministic --optimization-counter-threshold=1 --deoptimize-on-runtime-call-name-filter=AllocateArray
+
+main() {
+  for (int i = 0; i < 20; ++i) {
+    final list = foo(1);
+    if (list[0] != 42) throw 'a';
+  }
+}
+
+@pragma('vm:never-inline')
+List foo(int a) {
+  return List<dynamic>.filled(a, null)..[0] = 42;
+}
diff --git a/runtime/tests/vm/dart_2/deopt/allocate_context_test.dart b/runtime/tests/vm/dart_2/deopt/allocate_context_test.dart
new file mode 100644
index 0000000..c52abc0
--- /dev/null
+++ b/runtime/tests/vm/dart_2/deopt/allocate_context_test.dart
@@ -0,0 +1,21 @@
+// 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=--disable-dart-dev --no-inline-alloc --use-slow-path --deoptimize-on-runtime-call-every=1 --deterministic --optimization-counter-threshold=1 --deoptimize-on-runtime-call-name-filter=AllocateContext
+
+main() {
+  for (int i = 0; i < 20; ++i) {
+    final fun = foo(1);
+    if (fun(1) != 3) throw 'a';
+    if (fun(2) != 6) throw 'b';
+  }
+}
+
+@pragma('vm:never-inline')
+int Function(int) foo(int a) {
+  int b = 1;
+  return (int c) {
+    return a++ + b++ + c;
+  };
+}
diff --git a/runtime/tests/vm/dart_2/deopt/allocate_object_test.dart b/runtime/tests/vm/dart_2/deopt/allocate_object_test.dart
new file mode 100644
index 0000000..efcd883
--- /dev/null
+++ b/runtime/tests/vm/dart_2/deopt/allocate_object_test.dart
@@ -0,0 +1,27 @@
+// 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=--disable-dart-dev --no-inline-alloc --use-slow-path --deoptimize-on-runtime-call-every=1 --deterministic --optimization-counter-threshold=1 --deoptimize-on-runtime-call-name-filter=AllocateObject
+
+main() {
+  for (int i = 0; i < 20; ++i) {
+    final foo = bar(1);
+    if (foo.fun(1) != 3) throw 'a';
+    if (foo.fun(2) != 6) throw 'b';
+  }
+}
+
+@pragma('vm:never-inline')
+Foo bar(int a) {
+  int b = 1;
+  return Foo(a, (int c) {
+    return a++ + b++ + c++;
+  });
+}
+
+class Foo {
+  final int value;
+  final int Function(int) fun;
+  Foo(this.value, this.fun);
+}
diff --git a/runtime/tests/vm/dart_2/deopt/allocate_typed_data_test.dart b/runtime/tests/vm/dart_2/deopt/allocate_typed_data_test.dart
new file mode 100644
index 0000000..6556661
--- /dev/null
+++ b/runtime/tests/vm/dart_2/deopt/allocate_typed_data_test.dart
@@ -0,0 +1,19 @@
+// 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=--disable-dart-dev --no-inline-alloc --use-slow-path --deoptimize-on-runtime-call-every=1 --deterministic --optimization-counter-threshold=1 --deoptimize-on-runtime-call-name-filter=AllocateTypedData
+
+import 'dart:typed_data';
+
+main() {
+  for (int i = 0; i < 20; ++i) {
+    final foo = bar(1);
+    if (foo[0] != 42) throw 'a';
+  }
+}
+
+@pragma('vm:never-inline')
+Uint32List bar(int a) {
+  return Uint32List(1)..[0] = 42;
+}
diff --git a/runtime/tests/vm/dart_2/deopt/clone_context_test.dart b/runtime/tests/vm/dart_2/deopt/clone_context_test.dart
new file mode 100644
index 0000000..5320404
--- /dev/null
+++ b/runtime/tests/vm/dart_2/deopt/clone_context_test.dart
@@ -0,0 +1,20 @@
+// 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=--disable-dart-dev --no-inline-alloc --use-slow-path --deoptimize-on-runtime-call-every=1 --deterministic --optimization-counter-threshold=1 --deoptimize-on-runtime-call-name-filter=CloneContext
+
+main() {
+  for (int i = 0; i < 20; ++i) {
+    if (foo(1)[1]() != 2) throw 'a';
+  }
+}
+
+@pragma('vm:never-inline')
+List foo(int a) {
+  final l = <int Function()>[];
+  for (int i = 0; i < 10; ++i) {
+    l.add(() => a + i);
+  }
+  return l;
+}
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 045bb9e..7a787a9 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -1020,7 +1020,7 @@
   const Code& stub = Code::ZoneHandle(
       compiler->zone(), StubCode::GetAllocationStubForTypedData(class_id()));
   compiler->GenerateStubCall(source(), stub, UntaggedPcDescriptors::kOther,
-                             locs());
+                             locs(), deopt_id());
 }
 
 bool StoreInstanceFieldInstr::IsUnboxedStore() const {
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 3cb915c..bca05d1 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -6063,6 +6063,16 @@
     // Any allocation instruction may throw an OutOfMemory error.
     return true;
   }
+  virtual bool ComputeCanDeoptimize() const { return false; }
+  virtual bool ComputeCanDeoptimizeAfterCall() const {
+    // We test that allocation instructions have correct deopt environment
+    // (which is needed in case OOM is thrown) by actually deoptimizing
+    // optimized code in allocation slow paths.
+    return !CompilerState::Current().is_aot();
+  }
+  virtual intptr_t NumberOfInputsConsumedBeforeCall() const {
+    return InputCount();
+  }
 
   DEFINE_INSTRUCTION_TYPE_CHECK(Allocation);
 
@@ -6128,8 +6138,6 @@
     return type_arguments_;
   }
 
-  virtual bool ComputeCanDeoptimize() const { return false; }
-
   virtual bool HasUnknownSideEffects() const { return false; }
 
   virtual bool WillAllocateNewOrRemembered() const {
@@ -6167,8 +6175,6 @@
 
   intptr_t num_context_variables() const { return num_context_variables_; }
 
-  virtual bool ComputeCanDeoptimize() const { return false; }
-
   virtual bool HasUnknownSideEffects() const { return false; }
 
   virtual bool WillAllocateNewOrRemembered() const {
@@ -6326,12 +6332,6 @@
   Value* element_type() const { return inputs_[kElementTypePos]; }
   virtual Value* num_elements() const { return inputs_[kLengthPos]; }
 
-  // Throw needs environment, which is created only if instruction can
-  // deoptimize.
-  virtual bool ComputeCanDeoptimize() const {
-    return !CompilerState::Current().is_aot();
-  }
-
   virtual bool HasUnknownSideEffects() const { return false; }
 
   virtual bool WillAllocateNewOrRemembered() const {
@@ -6363,12 +6363,6 @@
   classid_t class_id() const { return class_id_; }
   virtual Value* num_elements() const { return inputs_[kLengthPos]; }
 
-  // Throw needs environment, which is created only if instruction can
-  // deoptimize.
-  virtual bool ComputeCanDeoptimize() const {
-    return !CompilerState::Current().is_aot();
-  }
-
   virtual bool HasUnknownSideEffects() const { return false; }
 
   virtual bool WillAllocateNewOrRemembered() const {
@@ -6813,9 +6807,16 @@
   DECLARE_INSTRUCTION(CloneContext)
   virtual CompileType ComputeType() const;
 
-  virtual bool ComputeCanDeoptimize() const {
+  virtual bool ComputeCanDeoptimize() const { return false; }
+  virtual bool ComputeCanDeoptimizeAfterCall() const {
+    // We test that allocation instructions have correct deopt environment
+    // (which is needed in case OOM is thrown) by actually deoptimizing
+    // optimized code in allocation slow paths.
     return !CompilerState::Current().is_aot();
   }
+  virtual intptr_t NumberOfInputsConsumedBeforeCall() const {
+    return InputCount();
+  }
 
   virtual bool HasUnknownSideEffects() const { return false; }
 
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 02b811a..53ca92a 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -3487,12 +3487,17 @@
 
     compiler->SaveLiveRegisters(locs);
 
+    auto slow_path_env = compiler->SlowPathEnvironmentFor(
+        instruction(), /*num_slow_path_args=*/0);
+    ASSERT(slow_path_env != nullptr);
+
     auto object_store = compiler->isolate_group()->object_store();
     const auto& allocate_context_stub = Code::ZoneHandle(
         compiler->zone(), object_store->allocate_context_stub());
     __ LoadImmediate(R1, instruction()->num_context_variables());
     compiler->GenerateStubCall(instruction()->source(), allocate_context_stub,
-                               UntaggedPcDescriptors::kOther, locs);
+                               UntaggedPcDescriptors::kOther, locs,
+                               instruction()->deopt_id(), slow_path_env);
     ASSERT(instruction()->locs()->out(0).reg() == R0);
     compiler->RestoreLiveRegisters(instruction()->locs());
     __ b(exit_label());
@@ -3547,7 +3552,7 @@
       Code::ZoneHandle(compiler->zone(), object_store->allocate_context_stub());
   __ LoadImmediate(R1, num_context_variables());
   compiler->GenerateStubCall(source(), allocate_context_stub,
-                             UntaggedPcDescriptors::kOther, locs());
+                             UntaggedPcDescriptors::kOther, locs(), deopt_id());
 }
 
 LocationSummary* CloneContextInstr::MakeLocationSummary(Zone* zone,
@@ -3569,7 +3574,8 @@
   const auto& clone_context_stub =
       Code::ZoneHandle(compiler->zone(), object_store->clone_context_stub());
   compiler->GenerateStubCall(source(), clone_context_stub,
-                             /*kind=*/UntaggedPcDescriptors::kOther, locs());
+                             /*kind=*/UntaggedPcDescriptors::kOther, locs(),
+                             deopt_id());
 }
 
 LocationSummary* CatchBlockEntryInstr::MakeLocationSummary(Zone* zone,
@@ -7846,7 +7852,7 @@
   const Code& stub = Code::ZoneHandle(
       compiler->zone(), StubCode::GetAllocationStubForClass(cls()));
   compiler->GenerateStubCall(source(), stub, UntaggedPcDescriptors::kOther,
-                             locs());
+                             locs(), deopt_id());
 }
 
 void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index 170d8e6..8cae728 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -3062,13 +3062,18 @@
 
     compiler->SaveLiveRegisters(locs);
 
+    auto slow_path_env = compiler->SlowPathEnvironmentFor(
+        instruction(), /*num_slow_path_args=*/0);
+    ASSERT(slow_path_env != nullptr);
+
     auto object_store = compiler->isolate_group()->object_store();
     const auto& allocate_context_stub = Code::ZoneHandle(
         compiler->zone(), object_store->allocate_context_stub());
 
     __ LoadImmediate(R1, instruction()->num_context_variables());
     compiler->GenerateStubCall(instruction()->source(), allocate_context_stub,
-                               UntaggedPcDescriptors::kOther, locs);
+                               UntaggedPcDescriptors::kOther, locs,
+                               instruction()->deopt_id(), slow_path_env);
     ASSERT(instruction()->locs()->out(0).reg() == R0);
     compiler->RestoreLiveRegisters(instruction()->locs());
     __ b(exit_label());
@@ -3122,7 +3127,7 @@
       Code::ZoneHandle(compiler->zone(), object_store->allocate_context_stub());
   __ LoadImmediate(R1, num_context_variables());
   compiler->GenerateStubCall(source(), allocate_context_stub,
-                             UntaggedPcDescriptors::kOther, locs());
+                             UntaggedPcDescriptors::kOther, locs(), deopt_id());
 }
 
 LocationSummary* CloneContextInstr::MakeLocationSummary(Zone* zone,
@@ -3144,7 +3149,8 @@
   const auto& clone_context_stub =
       Code::ZoneHandle(compiler->zone(), object_store->clone_context_stub());
   compiler->GenerateStubCall(source(), clone_context_stub,
-                             /*kind=*/UntaggedPcDescriptors::kOther, locs());
+                             /*kind=*/UntaggedPcDescriptors::kOther, locs(),
+                             deopt_id());
 }
 
 LocationSummary* CatchBlockEntryInstr::MakeLocationSummary(Zone* zone,
@@ -6905,7 +6911,7 @@
   const Code& stub = Code::ZoneHandle(
       compiler->zone(), StubCode::GetAllocationStubForClass(cls()));
   compiler->GenerateStubCall(source(), stub, UntaggedPcDescriptors::kOther,
-                             locs());
+                             locs(), deopt_id());
 }
 
 void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc
index 3381064..c7c46fc 100644
--- a/runtime/vm/compiler/backend/il_ia32.cc
+++ b/runtime/vm/compiler/backend/il_ia32.cc
@@ -2812,10 +2812,15 @@
 
     compiler->SaveLiveRegisters(locs);
 
+    auto slow_path_env = compiler->SlowPathEnvironmentFor(
+        instruction(), /*num_slow_path_args=*/0);
+    ASSERT(slow_path_env != nullptr);
+
     __ movl(EDX, compiler::Immediate(instruction()->num_context_variables()));
     compiler->GenerateStubCall(instruction()->source(),
                                StubCode::AllocateContext(),
-                               UntaggedPcDescriptors::kOther, locs);
+                               UntaggedPcDescriptors::kOther, locs,
+                               instruction()->deopt_id(), slow_path_env);
     ASSERT(instruction()->locs()->out(0).reg() == EAX);
     compiler->RestoreLiveRegisters(instruction()->locs());
     __ jmp(exit_label());
@@ -2867,7 +2872,7 @@
 
   __ movl(EDX, compiler::Immediate(num_context_variables()));
   compiler->GenerateStubCall(source(), StubCode::AllocateContext(),
-                             UntaggedPcDescriptors::kOther, locs());
+                             UntaggedPcDescriptors::kOther, locs(), deopt_id());
 }
 
 LocationSummary* CloneContextInstr::MakeLocationSummary(Zone* zone,
@@ -2886,7 +2891,8 @@
   ASSERT(locs()->out(0).reg() == EAX);
 
   compiler->GenerateStubCall(source(), StubCode::CloneContext(),
-                             /*kind=*/UntaggedPcDescriptors::kOther, locs());
+                             /*kind=*/UntaggedPcDescriptors::kOther, locs(),
+                             deopt_id());
 }
 
 LocationSummary* CatchBlockEntryInstr::MakeLocationSummary(Zone* zone,
@@ -6797,7 +6803,7 @@
   const Code& stub = Code::ZoneHandle(
       compiler->zone(), StubCode::GetAllocationStubForClass(cls()));
   compiler->GenerateStubCall(source(), stub, UntaggedPcDescriptors::kOther,
-                             locs());
+                             locs(), deopt_id());
 }
 
 void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index f755d79..d3264b1 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -3145,6 +3145,10 @@
 
     compiler->SaveLiveRegisters(locs);
 
+    auto slow_path_env = compiler->SlowPathEnvironmentFor(
+        instruction(), /*num_slow_path_args=*/0);
+    ASSERT(slow_path_env != nullptr);
+
     auto object_store = compiler->isolate_group()->object_store();
     const auto& allocate_context_stub = Code::ZoneHandle(
         compiler->zone(), object_store->allocate_context_stub());
@@ -3152,8 +3156,10 @@
     __ LoadImmediate(
         R10, compiler::Immediate(instruction()->num_context_variables()));
     compiler->GenerateStubCall(instruction()->source(), allocate_context_stub,
-                               UntaggedPcDescriptors::kOther, locs);
+                               UntaggedPcDescriptors::kOther, locs,
+                               instruction()->deopt_id(), slow_path_env);
     ASSERT(instruction()->locs()->out(0).reg() == RAX);
+
     compiler->RestoreLiveRegisters(instruction()->locs());
     __ jmp(exit_label());
   }
@@ -3207,7 +3213,7 @@
 
   __ LoadImmediate(R10, compiler::Immediate(num_context_variables()));
   compiler->GenerateStubCall(source(), allocate_context_stub,
-                             UntaggedPcDescriptors::kOther, locs());
+                             UntaggedPcDescriptors::kOther, locs(), deopt_id());
 }
 
 LocationSummary* CloneContextInstr::MakeLocationSummary(Zone* zone,
@@ -3229,7 +3235,8 @@
   const auto& clone_context_stub =
       Code::ZoneHandle(compiler->zone(), object_store->clone_context_stub());
   compiler->GenerateStubCall(source(), clone_context_stub,
-                             /*kind=*/UntaggedPcDescriptors::kOther, locs());
+                             /*kind=*/UntaggedPcDescriptors::kOther, locs(),
+                             deopt_id());
 }
 
 LocationSummary* CatchBlockEntryInstr::MakeLocationSummary(Zone* zone,
@@ -7329,7 +7336,7 @@
   const Code& stub = Code::ZoneHandle(
       compiler->zone(), StubCode::GetAllocationStubForClass(cls()));
   compiler->GenerateStubCall(source(), stub, UntaggedPcDescriptors::kOther,
-                             locs());
+                             locs(), deopt_id());
 }
 
 void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {