| 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);
|
|
|