Index: runtime/vm/isolate_reload.cc |
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc |
index 104395a469f10438d99fb93a85520494b9ff39a5..405653f697a24b2c34889a1468b187eafd7d71ca 100644 |
--- a/runtime/vm/isolate_reload.cc |
+++ b/runtime/vm/isolate_reload.cc |
@@ -365,6 +365,7 @@ IsolateReloadContext::IsolateReloadContext(Isolate* isolate, |
isolate_(isolate), |
reload_skipped_(false), |
reload_aborted_(false), |
+ reload_finalized_(false), |
js_(js), |
saved_num_cids_(-1), |
saved_class_table_(NULL), |
@@ -474,6 +475,25 @@ void IsolateReloadContext::Reload(bool force_reload) { |
DeoptimizeDependentCode(); |
Checkpoint(); |
+ // WEIRD CONTROL FLOW BEGINS. |
+ // |
+ // The flow of execution until we return from the tag handler can be complex. |
+ // |
+ // On a successful load, the following will occur: |
+ // 1) Tag Handler is invoked and the embedder is in control. |
+ // 2) All sources and libraries are loaded. |
+ // 3) Dart_FinalizeLoading is called by the embedder. |
+ // 4) Dart_FinalizeLoading invokes IsolateReloadContext::FinalizeLoading |
+ // and we are temporarily back in control. |
+ // This is where we validate the reload and commit or reject. |
+ // 5) Dart_FinalizeLoading invokes Dart code related to deferred libraries. |
+ // 6) The tag handler returns and we move on. |
+ // |
+ // Even after a successful reload the Dart code invoked in (5) can result |
+ // in an Unwind error or a StackOverflow error. This error will be returned |
+ // by the tag handler. The tag handler can return other errors, for example, |
+ // top level parse errors. We want to capture these errors while propagating |
+ // the Unwind or StackOverflow errors. |
Object& result = Object::Handle(thread->zone()); |
{ |
TransitionVMToNative transition(thread); |
@@ -485,14 +505,20 @@ void IsolateReloadContext::Reload(bool force_reload) { |
Api::NewHandle(thread, root_lib_url.raw())); |
result = Api::UnwrapHandle(retval); |
} |
+ // |
+ // WEIRD CONTROL FLOW ENDS. |
BackgroundCompiler::Enable(); |
- if (result.IsUnwindError()) { |
- // Ignore an unwind error because the isolate is dead. |
- return; |
+ if (result.IsUnwindError() || |
+ (result.raw() == isolate()->object_store()->stack_overflow())) { |
+ // When returning from the tag handler with an Unwind error or a |
+ // StackOverflow error, propagate it and give up. |
+ Exceptions::PropagateError(Error::Cast(result)); |
+ UNREACHABLE(); |
} |
+ // Other errors (e.g. a parse error) are captured by the reload system. |
if (result.IsError()) { |
FinalizeFailedLoad(Error::Cast(result)); |
} |
@@ -531,6 +557,7 @@ void IsolateReloadContext::FinalizeLoading() { |
if (reload_skipped_) { |
return; |
} |
+ ASSERT(!reload_finalized_); |
BuildLibraryMapping(); |
TIR_Print("---- LOAD SUCCEEDED\n"); |
if (ValidateReload()) { |
@@ -545,7 +572,6 @@ void IsolateReloadContext::FinalizeLoading() { |
// not remove dead subclasses. Rebuild the direct subclass |
// information from scratch. |
RebuildDirectSubclasses(); |
- |
CommonFinalizeTail(); |
} |
@@ -556,17 +582,22 @@ void IsolateReloadContext::FinalizeFailedLoad(const Error& error) { |
TIR_Print("---- LOAD FAILED, ABORTING RELOAD\n"); |
AddReasonForCancelling(new Aborted(zone_, error)); |
ReportReasonsForCancelling(); |
- Rollback(); |
+ if (!reload_finalized_) { |
+ Rollback(); |
+ } |
CommonFinalizeTail(); |
} |
void IsolateReloadContext::CommonFinalizeTail() { |
ReportOnJSON(js_); |
+ reload_finalized_ = true; |
} |
void IsolateReloadContext::ReportOnJSON(JSONStream* stream) { |
+ // Clear the buffer. |
+ stream->buffer()->Clear(); |
JSONObject jsobj(stream); |
jsobj.AddProperty("type", "ReloadReport"); |
jsobj.AddProperty("success", !HasReasonsForCancelling()); |