Index: runtime/vm/isolate.cc |
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc |
index 2f219e6273d9be3a48e3c26f0ff91497fe676011..11f5536f6bf76b99f18a0955f57d382b2082b129 100644 |
--- a/runtime/vm/isolate.cc |
+++ b/runtime/vm/isolate.cc |
@@ -19,6 +19,7 @@ |
#include "vm/deopt_instructions.h" |
#include "vm/flags.h" |
#include "vm/heap.h" |
+#include "vm/isolate_reload.h" |
#include "vm/lockers.h" |
#include "vm/log.h" |
#include "vm/message_handler.h" |
@@ -52,6 +53,7 @@ namespace dart { |
DECLARE_FLAG(bool, print_metrics); |
DECLARE_FLAG(bool, timing); |
DECLARE_FLAG(bool, trace_service); |
+DECLARE_FLAG(bool, trace_reload); |
DECLARE_FLAG(bool, warn_on_pause_with_no_debugger); |
NOT_IN_PRODUCT( |
@@ -134,7 +136,28 @@ NoOOBMessageScope::~NoOOBMessageScope() { |
+NoReloadScope::NoReloadScope(Isolate* isolate, Thread* thread) |
+ : StackResource(thread), |
+ isolate_(isolate) { |
+ ASSERT(isolate_ != NULL); |
+ isolate_->no_reload_scope_depth_++; |
+ ASSERT(isolate_->no_reload_scope_depth_ >= 0); |
+} |
+ |
+ |
+NoReloadScope::~NoReloadScope() { |
+ isolate_->no_reload_scope_depth_--; |
+ ASSERT(isolate_->no_reload_scope_depth_ >= 0); |
+} |
+ |
+ |
void Isolate::RegisterClass(const Class& cls) { |
+ NOT_IN_PRODUCT( |
+ if (IsReloading()) { |
+ reload_context()->RegisterClass(cls); |
+ return; |
+ } |
+ ) |
class_table()->Register(cls); |
} |
@@ -624,6 +647,12 @@ static MessageHandler::MessageStatus StoreError(Thread* thread, |
MessageHandler::MessageStatus IsolateMessageHandler::ProcessUnhandledException( |
const Error& result) { |
+ NOT_IN_PRODUCT( |
+ if (I->IsReloading()) { |
+ I->ReportReloadError(result); |
+ return kOK; |
+ } |
+ ) |
// Generate the error and stacktrace strings for the error message. |
String& exc_str = String::Handle(T->zone()); |
String& stacktrace_str = String::Handle(T->zone()); |
@@ -785,6 +814,7 @@ Isolate::Isolate(const Dart_IsolateFlags& api_flags) |
deoptimized_code_array_(GrowableObjectArray::null()), |
sticky_error_(Error::null()), |
background_compiler_(NULL), |
+ background_compiler_disabled_depth_(0), |
pending_service_extension_calls_(GrowableObjectArray::null()), |
registered_service_extension_handlers_(GrowableObjectArray::null()), |
metrics_list_head_(NULL), |
@@ -799,7 +829,10 @@ Isolate::Isolate(const Dart_IsolateFlags& api_flags) |
boxed_field_list_(GrowableObjectArray::null()), |
disabling_field_list_(GrowableObjectArray::null()), |
spawn_count_monitor_(new Monitor()), |
- spawn_count_(0) { |
+ spawn_count_(0), |
+ has_attempted_reload_(false), |
+ no_reload_scope_depth_(0), |
+ reload_context_(NULL) { |
NOT_IN_PRODUCT(FlagsCopyFrom(api_flags)); |
// TODO(asiva): A Thread is not available here, need to figure out |
// how the vm_tag (kEmbedderTagId) can be set, these tags need to |
@@ -1016,6 +1049,60 @@ void Isolate::DoneLoading() { |
} |
+bool Isolate::CanReload() const { |
+#ifndef PRODUCT |
+ return (!ServiceIsolate::IsServiceIsolateDescendant(this) && |
+ is_runnable() && !IsReloading() && no_reload_scope_depth_ == 0); |
+#else |
+ return false; |
+#endif |
+} |
+ |
+ |
+#ifndef PRODUCT |
+void Isolate::ReportReloadError(const Error& error) { |
+ ASSERT(IsReloading()); |
+ reload_context_->AbortReload(error); |
+ delete reload_context_; |
+ reload_context_ = NULL; |
+} |
+ |
+ |
+void Isolate::OnStackReload() { |
+ UNREACHABLE(); |
+} |
+ |
+ |
+void Isolate::ReloadSources(bool test_mode) { |
+ ASSERT(!IsReloading()); |
+ has_attempted_reload_ = true; |
+ reload_context_ = new IsolateReloadContext(this, test_mode); |
+ reload_context_->StartReload(); |
+} |
+ |
+#endif |
+ |
+ |
+void Isolate::DoneFinalizing() { |
+ NOT_IN_PRODUCT( |
+ if (IsReloading()) { |
+ reload_context_->FinishReload(); |
+ if (reload_context_->has_error() && reload_context_->test_mode()) { |
+ // If the reload has an error and we are in test mode keep the reload |
+ // context on the isolate so that it can be used by unit tests. |
+ return; |
+ } |
+ if (!reload_context_->has_error()) { |
+ reload_context_->ReportSuccess(); |
+ } |
+ delete reload_context_; |
+ reload_context_ = NULL; |
+ } |
+ ) |
+} |
+ |
+ |
+ |
bool Isolate::MakeRunnable() { |
ASSERT(Isolate::Current() == NULL); |
@@ -1690,6 +1777,13 @@ void Isolate::VisitObjectPointers(ObjectPointerVisitor* visitor, |
debugger()->VisitObjectPointers(visitor); |
} |
+ NOT_IN_PRODUCT( |
+ // Visit objects that are being used for isolate reload. |
+ if (reload_context() != NULL) { |
+ reload_context()->VisitObjectPointers(visitor); |
+ } |
+ ) |
+ |
// Visit objects that are being used for deoptimization. |
if (deopt_context() != NULL) { |
deopt_context()->VisitObjectPointers(visitor); |
@@ -1712,6 +1806,23 @@ void Isolate::PrepareForGC() { |
} |
+RawClass* Isolate::GetClassForHeapWalkAt(intptr_t cid) { |
+ RawClass* raw_class = NULL; |
+#ifndef PRODUCT |
+ if (IsReloading()) { |
+ raw_class = reload_context()->GetClassForHeapWalkAt(cid); |
+ } else { |
+ raw_class = class_table()->At(cid); |
+ } |
+#else |
+ raw_class = class_table()->At(cid); |
+#endif // !PRODUCT |
+ ASSERT(raw_class != NULL); |
+ ASSERT(raw_class->ptr()->id_ == cid); |
+ return raw_class; |
+} |
+ |
+ |
static const char* ExceptionPauseInfoToServiceEnum(Dart_ExceptionPauseInfo pi) { |
switch (pi) { |
case kPauseOnAllExceptions: |
@@ -1755,6 +1866,7 @@ void Isolate::PrintJSON(JSONStream* stream, bool ref) { |
jsobj.AddProperty("runnable", is_runnable()); |
jsobj.AddProperty("livePorts", message_handler()->live_ports()); |
jsobj.AddProperty("pauseOnExit", message_handler()->should_pause_on_exit()); |
+ jsobj.AddProperty("_isReloading", IsReloading()); |
if (debugger() != NULL) { |
if (!is_runnable()) { |
@@ -2187,6 +2299,9 @@ void Isolate::PauseEventHandler() { |
message_notify_callback(); |
set_message_notify_callback(Isolate::WakePauseEventHandler); |
+ const bool had_isolate_reload_context = reload_context() != NULL; |
+ const int64_t start_time_micros = |
+ !had_isolate_reload_context ? 0 : reload_context()->start_time_micros(); |
bool resume = false; |
while (true) { |
// Handle all available vm service messages, up to a resume |
@@ -2200,6 +2315,17 @@ void Isolate::PauseEventHandler() { |
break; |
} |
+ if (had_isolate_reload_context && (reload_context() == NULL)) { |
+ if (FLAG_trace_reload) { |
+ const int64_t reload_time_micros = |
+ OS::GetCurrentMonotonicMicros() - start_time_micros; |
+ double reload_millis = |
+ MicrosecondsToMilliseconds(reload_time_micros); |
+ OS::Print("Reloading has finished! (%.2f ms)\n", reload_millis); |
+ } |
+ break; |
+ } |
+ |
// Wait for more service messages. |
Monitor::WaitResult res = ml.Wait(); |
ASSERT(res == Monitor::kNotified); |