Index: runtime/vm/isolate_reload.cc |
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc |
index b8f1713dd822cdda97591eb52499b2a95662ec36..c375df3b8048c91b524acab028509d6a0b95a8ef 100644 |
--- a/runtime/vm/isolate_reload.cc |
+++ b/runtime/vm/isolate_reload.cc |
@@ -420,7 +420,11 @@ bool IsolateReloadContext::IsSameClass(const Class& a, const Class& b) { |
const Library& a_lib = Library::Handle(a.library()); |
const Library& b_lib = Library::Handle(b.library()); |
- return IsSameLibrary(a_lib, b_lib); |
+ |
+ if (a_lib.IsNull() || b_lib.IsNull()) { |
+ return a_lib.raw() == b_lib.raw(); |
+ } |
+ return (a_lib.private_key() == b_lib.private_key()); |
} |
@@ -450,7 +454,7 @@ IsolateReloadContext::IsolateReloadContext(Isolate* isolate, JSONStream* js) |
reasons_to_cancel_reload_(zone_, 0), |
cid_mapper_(), |
modified_libs_(NULL), |
- script_uri_(String::null()), |
+ script_url_(String::null()), |
error_(Error::null()), |
old_classes_set_storage_(Array::null()), |
class_map_storage_(Array::null()), |
@@ -459,7 +463,9 @@ IsolateReloadContext::IsolateReloadContext(Isolate* isolate, JSONStream* js) |
become_map_storage_(Array::null()), |
become_enum_mappings_(GrowableObjectArray::null()), |
saved_root_library_(Library::null()), |
- saved_libraries_(GrowableObjectArray::null()) { |
+ saved_libraries_(GrowableObjectArray::null()), |
+ root_url_prefix_(String::null()), |
+ old_root_url_prefix_(String::null()) { |
// NOTE: DO NOT ALLOCATE ANY RAW OBJECTS HERE. The IsolateReloadContext is not |
// associated with the isolate yet and if a GC is triggered here the raw |
// objects will not be properly accounted for. |
@@ -502,20 +508,58 @@ class Aborted : public ReasonForCancelling { |
}; |
+static intptr_t CommonSuffixLength(const char* a, const char* b) { |
+ const intptr_t a_length = strlen(a); |
+ const intptr_t b_length = strlen(b); |
+ intptr_t a_cursor = a_length; |
+ intptr_t b_cursor = b_length; |
+ |
+ while ((a_cursor >= 0) && (b_cursor >= 0)) { |
+ if (a[a_cursor] != b[b_cursor]) { |
+ break; |
+ } |
+ a_cursor--; |
+ b_cursor--; |
+ } |
+ |
+ ASSERT((a_length - a_cursor) == (b_length - b_cursor)); |
+ return (a_length - a_cursor); |
+} |
+ |
+ |
// NOTE: This function returns *after* FinalizeLoading is called. |
-void IsolateReloadContext::Reload(bool force_reload) { |
+void IsolateReloadContext::Reload(bool force_reload, |
+ const char* root_script_url, |
+ const char* packages_url_) { |
TIMELINE_SCOPE(Reload); |
Thread* thread = Thread::Current(); |
ASSERT(isolate() == thread->isolate()); |
// Grab root library before calling CheckpointBeforeReload. |
- const Library& root_lib = Library::Handle(object_store()->root_library()); |
- ASSERT(!root_lib.IsNull()); |
- const String& root_lib_url = String::Handle(root_lib.url()); |
+ const Library& old_root_lib = Library::Handle(object_store()->root_library()); |
+ ASSERT(!old_root_lib.IsNull()); |
+ const String& old_root_lib_url = String::Handle(old_root_lib.url()); |
+ // Root library url. |
+ const String& root_lib_url = |
+ (root_script_url == NULL) ? old_root_lib_url |
+ : String::Handle(String::New(root_script_url)); |
+ |
+ // Check to see if the base url of the loaded libraries has moved. |
+ if (!old_root_lib_url.Equals(root_lib_url)) { |
+ const char* old_root_library_url_c = old_root_lib_url.ToCString(); |
+ const char* root_library_url_c = root_lib_url.ToCString(); |
+ const intptr_t common_suffix_length = |
+ CommonSuffixLength(root_library_url_c, old_root_library_url_c); |
+ root_url_prefix_ = String::SubString( |
+ root_lib_url, 0, root_lib_url.Length() - common_suffix_length + 1); |
+ old_root_url_prefix_ = |
+ String::SubString(old_root_lib_url, 0, |
+ old_root_lib_url.Length() - common_suffix_length + 1); |
+ } |
// Check to see which libraries have been modified. |
modified_libs_ = FindModifiedLibraries(force_reload); |
- if (!modified_libs_->Contains(root_lib.index())) { |
+ if (!modified_libs_->Contains(old_root_lib.index())) { |
ASSERT(modified_libs_->IsEmpty()); |
reload_skipped_ = true; |
ReportOnJSON(js_); |
@@ -570,17 +614,25 @@ void IsolateReloadContext::Reload(bool force_reload) { |
// for example, top level parse errors. We want to capture these errors while |
// propagating the UnwindError or an UnhandledException error. |
Object& result = Object::Handle(thread->zone()); |
+ |
+ String& packages_url = String::Handle(); |
+ if (packages_url_ != NULL) { |
+ packages_url = String::New(packages_url_); |
+ } |
+ |
+ TIR_Print("---- ENTERING TAG HANDLER\n"); |
{ |
TransitionVMToNative transition(thread); |
Api::Scope api_scope(thread); |
Dart_Handle retval = (I->library_tag_handler())( |
- Dart_kScriptTag, Api::NewHandle(thread, Library::null()), |
+ Dart_kScriptTag, Api::NewHandle(thread, packages_url.raw()), |
Api::NewHandle(thread, root_lib_url.raw())); |
result = Api::UnwrapHandle(retval); |
} |
// |
// WEIRD CONTROL FLOW ENDS. |
+ TIR_Print("---- EXITED TAG HANDLER\n"); |
BackgroundCompiler::Enable(); |
@@ -613,6 +665,7 @@ void IsolateReloadContext::RegisterClass(const Class& new_cls) { |
AddClassMapping(new_cls, new_cls); |
return; |
} |
+ VTIR_Print("Registering class: %s\n", new_cls.ToCString()); |
new_cls.set_id(old_cls.id()); |
isolate()->class_table()->SetAt(old_cls.id(), new_cls.raw()); |
if (!old_cls.is_enum_class()) { |
@@ -1658,6 +1711,11 @@ RawString* IsolateReloadContext::FindLibraryPrivateKey( |
if (old.IsNull()) { |
return String::null(); |
} |
+#if defined(DEBUG) |
+ VTIR_Print("`%s` is getting `%s`'s private key.\n", |
+ String::Handle(replacement_or_new.url()).ToCString(), |
+ String::Handle(old.url()).ToCString()); |
+#endif |
return old.private_key(); |
} |
@@ -1669,10 +1727,54 @@ RawLibrary* IsolateReloadContext::OldLibraryOrNull( |
Library& lib = Library::Handle(); |
lib ^= old_libraries_set.GetOrNull(replacement_or_new); |
old_libraries_set.Release(); |
+ if (lib.IsNull() && (root_url_prefix_ != String::null()) && |
+ (old_root_url_prefix_ != String::null())) { |
+ return OldLibraryOrNullBaseMoved(replacement_or_new); |
+ } |
return lib.raw(); |
} |
+// Attempt to find the pair to |replacement_or_new| with the knowledge that |
+// the base url prefix has moved. |
+RawLibrary* IsolateReloadContext::OldLibraryOrNullBaseMoved( |
+ const Library& replacement_or_new) { |
+ const String& url_prefix = String::Handle(root_url_prefix_); |
+ const String& old_url_prefix = String::Handle(old_root_url_prefix_); |
+ const intptr_t prefix_length = url_prefix.Length(); |
+ const intptr_t old_prefix_length = old_url_prefix.Length(); |
+ const String& new_url = String::Handle(replacement_or_new.url()); |
+ const String& suffix = |
+ String::Handle(String::SubString(new_url, prefix_length)); |
+ if (!new_url.StartsWith(url_prefix)) { |
+ return Library::null(); |
+ } |
+ Library& old = Library::Handle(); |
+ String& old_url = String::Handle(); |
+ String& old_suffix = String::Handle(); |
+ GrowableObjectArray& saved_libs = |
+ GrowableObjectArray::Handle(saved_libraries()); |
+ ASSERT(!saved_libs.IsNull()); |
+ for (intptr_t i = 0; i < saved_libs.Length(); i++) { |
+ old = Library::RawCast(saved_libs.At(i)); |
+ old_url = old.url(); |
+ if (!old_url.StartsWith(old_url_prefix)) { |
+ continue; |
+ } |
+ old_suffix ^= String::SubString(old_url, old_prefix_length); |
+ if (old_suffix.IsNull()) { |
+ continue; |
+ } |
+ if (old_suffix.Equals(suffix)) { |
+ TIR_Print("`%s` is moving to `%s`\n", old_url.ToCString(), |
+ new_url.ToCString()); |
+ return old.raw(); |
+ } |
+ } |
+ return Library::null(); |
+} |
+ |
+ |
void IsolateReloadContext::BuildLibraryMapping() { |
const GrowableObjectArray& libs = |
GrowableObjectArray::Handle(object_store()->libraries()); |