[VM runtime] Add transition before checking for error after interpreting call.

Change-Id: I6030f17ae9ebb937231f5766f4477cf7127dcc33
Reviewed-on: https://dart-review.googlesource.com/73289
Commit-Queue: Régis Crelier <regis@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index c5b9eba..3731a08 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -2722,7 +2722,7 @@
   return reinterpret_cast<uword>(RuntimeEntry::InterpretCall);
 }
 
-// Interpret a function call. Should be called only for uncompiled functions.
+// Interpret a function call. Should be called only for non-jitted functions.
 // argc indicates the number of arguments, including the type arguments.
 // argv points to the first argument.
 // If argc < 0, arguments are passed at decreasing memory addresses from argv.
@@ -2737,6 +2737,9 @@
   uword exit_fp = thread->top_exit_frame_info();
   ASSERT(exit_fp != 0);
   ASSERT(thread == Thread::Current());
+  // Caller is InterpretCall stub called from generated code.
+  // We stay in "in generated code" execution state when interpreting code.
+  ASSERT(thread->execution_state() == Thread::kThreadInGenerated);
   ASSERT(!Function::HasCode(function));
   ASSERT(Function::HasBytecode(function));
   ASSERT(interpreter != NULL);
@@ -2744,7 +2747,12 @@
   const Object& result = Object::Handle(
       thread->zone(), interpreter->Call(function, argdesc, argc, argv, thread));
   DEBUG_ASSERT(thread->top_exit_frame_info() == exit_fp);
-  CheckResultError(result);
+  if (result.IsError()) {
+    // Propagating an error may cause allocation. Check if we need to block for
+    // a safepoint by switching to "in VM" execution state.
+    TransitionGeneratedToVM transition(thread);
+    Exceptions::PropagateError(Error::Cast(result));
+  }
   return result.raw();
 #else
   UNREACHABLE();