[vm] Make [ReloadOperationScope] a macro instead of a class

The [ReloadOperationScope] has [StackResource]s as fields and is itself
a [StackResource] which is problemantic if unwinding happens manually.

So we'll make it a macro that expands to the 3 fields instead.

TEST=ci

Change-Id: I3fb7bec7ca87193c83ec34908f9a43c5db005900
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/302201
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
diff --git a/runtime/vm/heap/safepoint_test.cc b/runtime/vm/heap/safepoint_test.cc
index 6ece798..0f08b45 100644
--- a/runtime/vm/heap/safepoint_test.cc
+++ b/runtime/vm/heap/safepoint_test.cc
@@ -465,13 +465,13 @@
       wait_for_sync(1);  // Wait for threads to exit safepoint
       { DeoptSafepointOperationScope safepoint_operation(thread); }
       wait_for_sync(2);  // Wait for threads to exit safepoint
-      { ReloadOperationScope reload(thread); }
+      { RELOAD_OPERATION_SCOPE(thread); }
       wait_for_sync(3);  // Wait for threads to exit safepoint
       { GcSafepointOperationScope safepoint_operation(thread); }
       wait_for_sync(4);  // Wait for threads to exit safepoint
       { DeoptSafepointOperationScope safepoint_operation(thread); }
       wait_for_sync(5);  // Wait for threads to exit safepoint
-      { ReloadOperationScope reload(thread); }
+      { RELOAD_OPERATION_SCOPE(thread); }
     }
     for (intptr_t i = 0; i < kTaskCount; i++) {
       threads[i]->MarkAndNotify(CheckinTask::kPleaseExit);
@@ -698,9 +698,7 @@
   explicit ReloadTask(std::shared_ptr<Data> data) : StateMachineTask(data) {}
 
  protected:
-  virtual void RunInternal() {
-    ReloadOperationScope reload_operation_scope(thread_);
-  }
+  virtual void RunInternal() { RELOAD_OPERATION_SCOPE(thread_); }
 };
 
 ISOLATE_UNIT_TEST_CASE(Reload_AtReloadSafepoint) {
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 663b325..5b38e98 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -1902,7 +1902,7 @@
 
   // Ensure all isolates inside the isolate group are paused at a place where we
   // can safely do a reload.
-  ReloadOperationScope reload_operation(Thread::Current());
+  RELOAD_OPERATION_SCOPE(Thread::Current());
 
   auto class_table = IsolateGroup::Current()->class_table();
   std::shared_ptr<IsolateGroupReloadContext> group_reload_context(
@@ -1931,7 +1931,7 @@
 
   // Ensure all isolates inside the isolate group are paused at a place where we
   // can safely do a reload.
-  ReloadOperationScope reload_operation(Thread::Current());
+  RELOAD_OPERATION_SCOPE(Thread::Current());
 
   auto class_table = IsolateGroup::Current()->class_table();
   std::shared_ptr<IsolateGroupReloadContext> group_reload_context(
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index 2d3d684..972ba23 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -2830,16 +2830,6 @@
   }
 }
 
-ReloadOperationScope::ReloadOperationScope(Thread* thread)
-    : StackResource(thread),
-      stop_bg_compiler_(thread),
-      allow_reload_(thread),
-      safepoint_operation_(thread) {
-  ASSERT(!thread->IsInNoReloadScope());
-  ASSERT(thread->current_safepoint_level() ==
-         SafepointLevel::kGCAndDeoptAndReload);
-}
-
 #endif  // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
 
 }  // namespace dart
diff --git a/runtime/vm/isolate_reload.h b/runtime/vm/isolate_reload.h
index 397ece8..93de727 100644
--- a/runtime/vm/isolate_reload.h
+++ b/runtime/vm/isolate_reload.h
@@ -440,27 +440,23 @@
 
 // Ensures all other mutators are stopped at a well-defined place where reload
 // is allowed.
-class ReloadOperationScope : public StackResource {
- public:
-  explicit ReloadOperationScope(Thread* thread);
-  ~ReloadOperationScope() {}
-
- private:
-  // As the background compiler is a mutator it participates in safepoint
-  // operations. Though the BG compiler won't check into reload safepoint
-  // requests - as it's not a well-defined place to do reload.
-  // So we ensure the background compiler is stopped before we get all other
-  // mutators to reload safepoints.
-  NoBackgroundCompilerScope stop_bg_compiler_;
-
-  // This will enable the current thread to perform reload operations (as well
-  // as check-in with other thread's reload operations).
-  ReloadParticipationScope allow_reload_;
-
-  // The actual reload operation that will ensure all other mutators are stopped
-  // at well-defined places where reload can happen.
-  ReloadSafepointOperationScope safepoint_operation_;
-};
+#define RELOAD_OPERATION_SCOPE(thread_expr)                                    \
+  auto _thread_ = (thread_expr);                                               \
+                                                                               \
+  /* As the background compiler is a mutator it participates in safepoint */   \
+  /* operations. Though the BG compiler won't check into reload safepoint */   \
+  /* requests - as it's not a well-defined place to do reload.            */   \
+  /* So we ensure the background compiler is stopped before we get all    */   \
+  /* other mutators to reload safepoints.                                 */   \
+  NoBackgroundCompilerScope _stop_bg_compiler_(_thread_);                      \
+                                                                               \
+  /* This will enable the current thread to perform reload operations (as */   \
+  /* well as check-in with other thread's reload operations).             */   \
+  ReloadParticipationScope _allow_reload_(_thread_);                           \
+                                                                               \
+  /* The actual reload operation that will ensure all other mutators are */    \
+  /* stopped at well-defined places where reload can happen.             */    \
+  ReloadSafepointOperationScope _safepoint_operation_(_thread_);
 
 }  // namespace dart
 
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 4d6305b..053be27 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -639,7 +639,7 @@
     // at event-loop boundary (or shutting down). We participate in reload in
     // those scenarios.
     //
-    // (It may be that an active [ReloadOperationScope] sent an OOB message to
+    // (It may be that an active [RELOAD_OPERATION_SCOPE] sent an OOB message to
     // this isolate but it didn't handle the OOB due to shutting down, so we'll
     // still have to update the reloading thread that it's ok to continue)
     RawReloadParticipationScope enable_reload(thread);
diff --git a/runtime/vm/thread_stack_resource.h b/runtime/vm/thread_stack_resource.h
index 4d04625..8a4b669 100644
--- a/runtime/vm/thread_stack_resource.h
+++ b/runtime/vm/thread_stack_resource.h
@@ -5,6 +5,7 @@
 #ifndef RUNTIME_VM_THREAD_STACK_RESOURCE_H_
 #define RUNTIME_VM_THREAD_STACK_RESOURCE_H_
 
+#include <type_traits>
 #include <utility>
 
 #include "vm/allocation.h"
@@ -34,6 +35,7 @@
 template <typename T, typename... Args>
 class AsThreadStackResource : public ThreadStackResource {
  public:
+  static_assert(!std::is_base_of<StackResource, T>::value);
   AsThreadStackResource(Thread* thread, Args&&... args)
       : ThreadStackResource(thread),
         member_(thread, std::forward<Args>(args)...) {}