[dart_runner] Stop after unhandled exception and set return code.

Bug: FL-47
Change-Id: I733703e7ad7631bb304ce80bfb1dc073eab4a238
diff --git a/dart_message_handler.cc b/dart_message_handler.cc
index 851f52c..2263315 100644
--- a/dart_message_handler.cc
+++ b/dart_message_handler.cc
@@ -20,21 +20,16 @@
       isolate_had_uncaught_exception_error_(false),
       isolate_had_fatal_error_(false),
       isolate_last_error_(kNoError),
-      task_dispatcher_(nullptr),
-      message_epilogue_(nullptr) {}
+      task_dispatcher_(nullptr) {}
 
 DartMessageHandler::~DartMessageHandler() {
   task_dispatcher_ = nullptr;
-  message_epilogue_ = nullptr;
 }
 
-void DartMessageHandler::Initialize(TaskDispatcher dispatcher,
-                                    std::function<void()> message_epilogue) {
+void DartMessageHandler::Initialize(TaskDispatcher dispatcher) {
   // Only can be called once.
-  TONIC_CHECK(!task_dispatcher_);
+  TONIC_CHECK(!task_dispatcher_ && dispatcher);
   task_dispatcher_ = dispatcher;
-  message_epilogue_ = message_epilogue;
-  TONIC_CHECK(task_dispatcher_);
   Dart_SetMessageNotifyCallback(MessageNotifyCallback);
 }
 
@@ -97,10 +92,12 @@
       Dart_SetPausedOnStart(false);
       // We've resumed, handle normal messages that are in the queue.
       result = Dart_HandleMessage();
-      if (message_epilogue_) {
-        message_epilogue_();
-      }
       error = LogIfError(result);
+      dart_state->MessageEpilogue(result);
+      if (!Dart_CurrentIsolate()) {
+        isolate_exited_ = true;
+        return;
+      }
     }
   } else if (Dart_IsPausedOnExit()) {
     // We are paused on isolate exit. Only handle service messages until we are
@@ -115,9 +112,6 @@
   } else {
     // We are processing messages normally.
     result = Dart_HandleMessage();
-    if (message_epilogue_) {
-      message_epilogue_();
-    }
     // If the Dart program has set a return code, then it is intending to shut
     // down by way of a fatal error, and so there is no need to emit a log
     // message.
@@ -127,6 +121,11 @@
     } else {
       error = LogIfError(result);
     }
+    dart_state->MessageEpilogue(result);
+    if (!Dart_CurrentIsolate()) {
+      isolate_exited_ = true;
+      return;
+    }
   }
 
   if (error) {
diff --git a/dart_message_handler.h b/dart_message_handler.h
index d217186..7ce7e38 100644
--- a/dart_message_handler.h
+++ b/dart_message_handler.h
@@ -22,8 +22,7 @@
   ~DartMessageHandler();
 
   // Messages for the current isolate will be scheduled on |runner|.
-  void Initialize(TaskDispatcher dispatcher,
-                  std::function<void()> message_epilogue = nullptr);
+  void Initialize(TaskDispatcher dispatcher);
 
   // Handle an unhandled error. If the error is fatal then shut down the
   // isolate. The message handler's isolate must be the current isolate.
@@ -57,7 +56,6 @@
   bool isolate_had_fatal_error_;
   DartErrorHandleType isolate_last_error_;
   TaskDispatcher task_dispatcher_;
-  std::function<void()> message_epilogue_;
 
  private:
   static void MessageNotifyCallback(Dart_Isolate dest_isolate);
diff --git a/dart_microtask_queue.cc b/dart_microtask_queue.cc
index c69e041..d102de0 100644
--- a/dart_microtask_queue.cc
+++ b/dart_microtask_queue.cc
@@ -80,6 +80,9 @@
         if (error != kNoError) {
           last_error_ = error;
         }
+        dart_state->MessageEpilogue(result);
+        if (!Dart_CurrentIsolate())
+            return;
       }
     }
   }
diff --git a/dart_state.cc b/dart_state.cc
index 3c0c8bd..886a16f 100644
--- a/dart_state.cc
+++ b/dart_state.cc
@@ -16,11 +16,13 @@
 
 DartState::Scope::~Scope() {}
 
-DartState::DartState(int dirfd)
+DartState::DartState(int dirfd, std::function<void(Dart_Handle)> message_epilogue)
     : isolate_(nullptr),
       class_library_(new DartClassLibrary),
       message_handler_(new DartMessageHandler()),
-      file_loader_(new FileLoader(dirfd)) {}
+      file_loader_(new FileLoader(dirfd)),
+      message_epilogue_(message_epilogue),
+      weak_factory_(this) {}
 
 DartState::~DartState() {}
 
diff --git a/dart_state.h b/dart_state.h
index 18aad93..2eedff2 100644
--- a/dart_state.h
+++ b/dart_state.h
@@ -36,7 +36,8 @@
     DartApiScope api_scope_;
   };
 
-  DartState(int dirfd = -1);
+  DartState(int dirfd = -1,
+            std::function<void(Dart_Handle)> message_epilogue = nullptr);
   virtual ~DartState();
 
   static DartState* From(Dart_Isolate isolate);
@@ -51,6 +52,11 @@
   DartMessageHandler& message_handler() { return *message_handler_; }
   FileLoader& file_loader() { return *file_loader_; }
 
+  void MessageEpilogue(Dart_Handle message_result) {
+    if (message_epilogue_) {
+      message_epilogue_(message_result);
+    }
+  }
   void SetReturnCode(uint32_t return_code);
   void SetReturnCodeCallback(std::function<void(uint32_t)> callback);
   bool has_set_return_code() const { return has_set_return_code_; }
@@ -66,6 +72,7 @@
   std::unique_ptr<DartClassLibrary> class_library_;
   std::unique_ptr<DartMessageHandler> message_handler_;
   std::unique_ptr<FileLoader> file_loader_;
+  std::function<void(Dart_Handle)> message_epilogue_;
   std::function<void(uint32_t)> set_return_code_callback_;
   bool has_set_return_code_;
 
diff --git a/logging/dart_error.cc b/logging/dart_error.cc
index 45a4333..e2c62ef 100644
--- a/logging/dart_error.cc
+++ b/logging/dart_error.cc
@@ -31,4 +31,16 @@
   }
 }
 
+int GetErrorExitCode(Dart_Handle handle) {
+  if (Dart_IsCompilationError(handle)) {
+    return 254;  // dart::bin::kCompilationErrorExitCode
+  } else if (Dart_IsApiError(handle)) {
+    return 253;  // dart::bin::kApiErrorExitCode
+  } else if (Dart_IsError(handle)) {
+    return 255;  // dart::bin::kErrorExitCode
+  } else {
+    return 0;
+  }
+}
+
 }  // namespace tonic
diff --git a/logging/dart_error.h b/logging/dart_error.h
index 7e3bb30..5bd8159 100644
--- a/logging/dart_error.h
+++ b/logging/dart_error.h
@@ -24,6 +24,8 @@
 
 DartErrorHandleType GetErrorHandleType(Dart_Handle handle);
 
+int GetErrorExitCode(Dart_Handle handle);
+
 }  // namespace tonic
 
 #endif  // LIB_TONIC_DART_ERROR_H_