[VM interpreter] Propagate error from invoked compiled function to interpreter caller.

Change-Id: Ie72cbca424ff843f16a276c6877bd7d428aa8e8c
Reviewed-on: https://dart-review.googlesource.com/75424
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Régis Crelier <regis@google.com>
diff --git a/runtime/vm/interpreter.cc b/runtime/vm/interpreter.cc
index 9650957..3c4cfb1 100644
--- a/runtime/vm/interpreter.cc
+++ b/runtime/vm/interpreter.cc
@@ -923,19 +923,35 @@
   **SP = result;
   pp_ = InterpreterHelpers::FrameCode(*FP)->ptr()->object_pool_;
 
-  // It is legit to call the constructor of an error object, however a
-  // result of class UnhandledException must be propagated.
-  if (result->IsHeapObject() &&
-      result->GetClassId() == kUnhandledExceptionCid) {
-    (*SP)[0] = UnhandledException::RawCast(result)->ptr()->exception_;
-    (*SP)[1] = UnhandledException::RawCast(result)->ptr()->stacktrace_;
-    (*SP)[2] = 0;  // Space for result.
-    Exit(thread, *FP, *SP + 3, *pc);
-    NativeArguments args(thread, 2, *SP, *SP + 2);
-    if (!InvokeRuntime(thread, this, DRT_ReThrow, args)) {
+  // If the result is an error (not a Dart instance), it must either be rethrown
+  // (in the case of an unhandled exception) or it must be returned to the
+  // caller of the interpreter to be propagated.
+  if (result->IsHeapObject()) {
+    const intptr_t result_cid = result->GetClassId();
+    if (result_cid == kUnhandledExceptionCid) {
+      (*SP)[0] = UnhandledException::RawCast(result)->ptr()->exception_;
+      (*SP)[1] = UnhandledException::RawCast(result)->ptr()->stacktrace_;
+      (*SP)[2] = 0;  // Space for result.
+      Exit(thread, *FP, *SP + 3, *pc);
+      NativeArguments args(thread, 2, *SP, *SP + 2);
+      if (!InvokeRuntime(thread, this, DRT_ReThrow, args)) {
+        return false;
+      }
+      UNREACHABLE();
+    }
+    if (RawObject::IsErrorClassId(result_cid)) {
+      // Unwind to entry frame.
+      fp_ = *FP;
+      pc_ = reinterpret_cast<uword>(SavedCallerPC(fp_));
+      while ((pc_ & 2) == 0) {
+        fp_ = SavedCallerFP(fp_);
+        pc_ = reinterpret_cast<uword>(SavedCallerPC(fp_));
+      }
+      // Pop entry frame.
+      fp_ = SavedCallerFP(fp_);
+      special_[KernelBytecode::kExceptionSpecialIndex] = result;
       return false;
     }
-    UNREACHABLE();
   }
   return true;
 }