Index: runtime/vm/object.cc |
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc |
index cfd9c7ed28d32c54073a0fe4b498cbf0d6d258b8..edc2868613daf5abe569f34768dba942171466ba 100644 |
--- a/runtime/vm/object.cc |
+++ b/runtime/vm/object.cc |
@@ -1243,11 +1243,12 @@ NOT_IN_PRODUCT( |
// Pre-register the isolate library so the native class implementations |
// can be hooked up before compiling it. |
Library& isolate_lib = |
- Library::Handle(zone, Library::LookupLibrary(Symbols::DartIsolate())); |
+ Library::Handle(zone, Library::LookupLibrary(thread, |
+ Symbols::DartIsolate())); |
if (isolate_lib.IsNull()) { |
isolate_lib = Library::NewLibraryHelper(Symbols::DartIsolate(), true); |
isolate_lib.SetLoadRequested(); |
- isolate_lib.Register(); |
+ isolate_lib.Register(thread); |
object_store->set_bootstrap_library(ObjectStore::kIsolate, isolate_lib); |
} |
ASSERT(!isolate_lib.IsNull()); |
@@ -1365,11 +1366,11 @@ NOT_IN_PRODUCT( |
// Pre-register the mirrors library so we can place the vm class |
// MirrorReference there rather than the core library. |
NOT_IN_PRODUCT( |
- lib = Library::LookupLibrary(Symbols::DartMirrors()); |
+ lib = Library::LookupLibrary(thread, Symbols::DartMirrors()); |
if (lib.IsNull()) { |
lib = Library::NewLibraryHelper(Symbols::DartMirrors(), true); |
lib.SetLoadRequested(); |
- lib.Register(); |
+ lib.Register(thread); |
object_store->set_bootstrap_library(ObjectStore::kMirrors, lib); |
} |
ASSERT(!lib.IsNull()); |
@@ -1381,11 +1382,11 @@ NOT_IN_PRODUCT( |
// Pre-register the collection library so we can place the vm class |
// LinkedHashMap there rather than the core library. |
- lib = Library::LookupLibrary(Symbols::DartCollection()); |
+ lib = Library::LookupLibrary(thread, Symbols::DartCollection()); |
if (lib.IsNull()) { |
lib = Library::NewLibraryHelper(Symbols::DartCollection(), true); |
lib.SetLoadRequested(); |
- lib.Register(); |
+ lib.Register(thread); |
object_store->set_bootstrap_library(ObjectStore::kCollection, lib); |
} |
ASSERT(!lib.IsNull()); |
@@ -1400,17 +1401,17 @@ NOT_IN_PRODUCT( |
// Pre-register the developer library so we can place the vm class |
// UserTag there rather than the core library. |
- lib = Library::LookupLibrary(Symbols::DartDeveloper()); |
+ lib = Library::LookupLibrary(thread, Symbols::DartDeveloper()); |
if (lib.IsNull()) { |
lib = Library::NewLibraryHelper(Symbols::DartDeveloper(), true); |
lib.SetLoadRequested(); |
- lib.Register(); |
+ lib.Register(thread); |
object_store->set_bootstrap_library(ObjectStore::kDeveloper, lib); |
} |
ASSERT(!lib.IsNull()); |
ASSERT(lib.raw() == Library::DeveloperLibrary()); |
- lib = Library::LookupLibrary(Symbols::DartDeveloper()); |
+ lib = Library::LookupLibrary(thread, Symbols::DartDeveloper()); |
ASSERT(!lib.IsNull()); |
cls = Class::New<UserTag>(); |
RegisterPrivateClass(cls, Symbols::_UserTag(), lib); |
@@ -1423,11 +1424,11 @@ NOT_IN_PRODUCT( |
// Pre-register the typed_data library so the native class implementations |
// can be hooked up before compiling it. |
- lib = Library::LookupLibrary(Symbols::DartTypedData()); |
+ lib = Library::LookupLibrary(thread, Symbols::DartTypedData()); |
if (lib.IsNull()) { |
lib = Library::NewLibraryHelper(Symbols::DartTypedData(), true); |
lib.SetLoadRequested(); |
- lib.Register(); |
+ lib.Register(thread); |
object_store->set_bootstrap_library(ObjectStore::kTypedData, lib); |
} |
ASSERT(!lib.IsNull()); |
@@ -1582,7 +1583,7 @@ NOT_IN_PRODUCT( |
MethodRecognizer::InitializeState(); |
// Adds static const fields (class ids) to the class 'ClassID'); |
- lib = Library::LookupLibrary(Symbols::DartInternal()); |
+ lib = Library::LookupLibrary(thread, Symbols::DartInternal()); |
ASSERT(!lib.IsNull()); |
cls = lib.LookupClassAllowPrivate(Symbols::ClassID()); |
ASSERT(!cls.IsNull()); |
@@ -10524,19 +10525,21 @@ RawLibrary* Library::New(const String& url) { |
void Library::InitCoreLibrary(Isolate* isolate) { |
+ Thread* thread = Thread::Current(); |
+ Zone* zone = thread->zone(); |
const String& core_lib_url = Symbols::DartCore(); |
const Library& core_lib = |
- Library::Handle(Library::NewLibraryHelper(core_lib_url, false)); |
+ Library::Handle(zone, Library::NewLibraryHelper(core_lib_url, false)); |
core_lib.SetLoadRequested(); |
- core_lib.Register(); |
+ core_lib.Register(thread); |
isolate->object_store()->set_bootstrap_library(ObjectStore::kCore, core_lib); |
isolate->object_store()->set_root_library(Library::Handle()); |
// Hook up predefined classes without setting their library pointers. These |
// classes are coming from the VM isolate, and are shared between multiple |
// isolates so setting their library pointers would be wrong. |
- const Class& cls = Class::Handle(Object::dynamic_class()); |
- core_lib.AddObject(cls, String::Handle(cls.Name())); |
+ const Class& cls = Class::Handle(zone, Object::dynamic_class()); |
+ core_lib.AddObject(cls, String::Handle(zone, cls.Name())); |
} |
@@ -10562,7 +10565,7 @@ void Library::InitNativeWrappersLibrary(Isolate* isolate) { |
const String& native_flds_lib_name = Symbols::DartNativeWrappersLibName(); |
native_flds_lib.SetName(native_flds_lib_name); |
native_flds_lib.SetLoadRequested(); |
- native_flds_lib.Register(); |
+ native_flds_lib.Register(thread); |
native_flds_lib.SetLoadInProgress(); |
isolate->object_store()->set_native_wrappers_library(native_flds_lib); |
static const char* const kNativeWrappersClass = "NativeFieldWrapperClass"; |
@@ -10583,31 +10586,51 @@ void Library::InitNativeWrappersLibrary(Isolate* isolate) { |
} |
+// LibraryLookupSet maps URIs to libraries. |
+class LibraryLookupTraits { |
+ public: |
+ static const char* Name() { return "LibraryLookupTraits"; } |
+ static bool ReportStats() { return false; } |
+ |
+ static bool IsMatch(const Object& a, const Object& b) { |
+ const String& a_str = String::Cast(a); |
+ const String& b_str = String::Cast(b); |
+ |
+ ASSERT(a_str.HasHash() && b_str.HasHash()); |
+ return a_str.Equals(b_str); |
+ } |
+ |
+ static uword Hash(const Object& key) { |
+ return String::Cast(key).Hash(); |
+ } |
+ |
+ static RawObject* NewKey(const String& str) { |
+ return str.raw(); |
+ } |
+}; |
+typedef UnorderedHashMap<LibraryLookupTraits> LibraryLookupMap; |
+ |
+ |
// Returns library with given url in current isolate, or NULL. |
-RawLibrary* Library::LookupLibrary(const String &url) { |
- Thread* thread = Thread::Current(); |
+RawLibrary* Library::LookupLibrary(Thread* thread, const String &url) { |
Zone* zone = thread->zone(); |
Isolate* isolate = thread->isolate(); |
- Library& lib = Library::Handle(zone, Library::null()); |
- String& lib_url = String::Handle(zone, String::null()); |
- GrowableObjectArray& libs = GrowableObjectArray::Handle( |
- zone, isolate->object_store()->libraries()); |
+ ObjectStore* object_store = isolate->object_store(); |
// Make sure the URL string has an associated hash code |
// to speed up the repeated equality checks. |
url.Hash(); |
- intptr_t len = libs.Length(); |
- for (intptr_t i = 0; i < len; i++) { |
- lib ^= libs.At(i); |
- lib_url ^= lib.url(); |
- |
- ASSERT(url.HasHash() && lib_url.HasHash()); |
- if (lib_url.Equals(url)) { |
- return lib.raw(); |
- } |
+ // Use the libraries map to lookup the library by URL. |
+ Library& lib = Library::Handle(zone); |
+ if (object_store->libraries_map() == Array::null()) { |
+ return Library::null(); |
+ } else { |
+ LibraryLookupMap map(object_store->libraries_map()); |
+ lib ^= map.GetOrNull(url); |
+ ASSERT(map.Release().raw() == object_store->libraries_map()); |
} |
- return Library::null(); |
+ return lib.raw(); |
} |
@@ -10631,34 +10654,28 @@ bool Library::IsPrivate(const String& name) { |
} |
-bool Library::IsKeyUsed(intptr_t key) { |
- intptr_t lib_key; |
- const GrowableObjectArray& libs = GrowableObjectArray::Handle( |
- Isolate::Current()->object_store()->libraries()); |
- Library& lib = Library::Handle(); |
- String& lib_url = String::Handle(); |
- for (int i = 0; i < libs.Length(); i++) { |
- lib ^= libs.At(i); |
- lib_url ^= lib.url(); |
- lib_key = lib_url.Hash(); |
- if (lib_key == key) { |
- return true; |
- } |
- } |
- return false; |
-} |
+// Create a private key for this library. It is based on the hash of the |
+// library URI and the sequence number of the library to guarantee unique |
+// private keys without having to verify. |
+void Library::AllocatePrivateKey() const { |
+ Thread* thread = Thread::Current(); |
+ Zone* zone = thread->zone(); |
+ Isolate* isolate = thread->isolate(); |
+ // Format of the private key is: "@<sequence number><6 digits of hash> |
+ const intptr_t hash_mask = 0x7FFFF; |
+ |
+ const String& url = String::Handle(zone, this->url()); |
+ intptr_t hash_value = url.Hash() & hash_mask; |
+ |
+ const GrowableObjectArray& libs = GrowableObjectArray::Handle(zone, |
+ isolate->object_store()->libraries()); |
+ intptr_t sequence_value = libs.Length(); |
-void Library::AllocatePrivateKey() const { |
- const String& url = String::Handle(this->url()); |
- intptr_t key_value = url.Hash() & kIntptrMax; |
- while ((key_value == 0) || Library::IsKeyUsed(key_value)) { |
- key_value = (key_value + 1) & kIntptrMax; |
- } |
- ASSERT(key_value > 0); |
char private_key[32]; |
OS::SNPrint(private_key, sizeof(private_key), |
- "%c%" Pd "", kPrivateKeySeparator, key_value); |
+ "%c%" Pd "%06" Pd "", |
+ kPrivateKeySeparator, sequence_value, hash_value); |
StorePointer(&raw_ptr()->private_key_, String::New(private_key, Heap::kOld)); |
} |
@@ -10700,12 +10717,14 @@ RawString* Library::PrivateName(const String& name) const { |
RawLibrary* Library::GetLibrary(intptr_t index) { |
- Isolate* isolate = Isolate::Current(); |
+ Thread* thread = Thread::Current(); |
+ Zone* zone = thread->zone(); |
+ Isolate* isolate = thread->isolate(); |
const GrowableObjectArray& libs = |
- GrowableObjectArray::Handle(isolate->object_store()->libraries()); |
+ GrowableObjectArray::Handle(zone, isolate->object_store()->libraries()); |
ASSERT(!libs.IsNull()); |
if ((0 <= index) && (index < libs.Length())) { |
- Library& lib = Library::Handle(); |
+ Library& lib = Library::Handle(zone); |
lib ^= libs.At(index); |
return lib.raw(); |
} |
@@ -10713,15 +10732,53 @@ RawLibrary* Library::GetLibrary(intptr_t index) { |
} |
-void Library::Register() const { |
- ASSERT(Library::LookupLibrary(String::Handle(url())) == Library::null()); |
- ASSERT(String::Handle(url()).HasHash()); |
- ObjectStore* object_store = Isolate::Current()->object_store(); |
- GrowableObjectArray& libs = |
- GrowableObjectArray::Handle(object_store->libraries()); |
+void Library::Register(Thread* thread) const { |
+ Zone* zone = thread->zone(); |
+ Isolate* isolate = thread->isolate(); |
+ ObjectStore* object_store = isolate->object_store(); |
+ |
+ // A library is "registered" in two places: |
+ // - A growable array mapping from index to library. |
+ const String& lib_url = String::Handle(zone, url()); |
+ ASSERT(Library::LookupLibrary(thread, lib_url) == Library::null()); |
+ ASSERT(lib_url.HasHash()); |
+ GrowableObjectArray& libs = GrowableObjectArray::Handle(zone, |
+ object_store->libraries()); |
ASSERT(!libs.IsNull()); |
set_index(libs.Length()); |
libs.Add(*this); |
+ |
+ // - A map from URL string to library. |
+ if (object_store->libraries_map() == Array::null()) { |
+ LibraryLookupMap map(HashTables::New<LibraryLookupMap>(16, Heap::kOld)); |
+ object_store->set_libraries_map(map.Release()); |
+ } |
+ |
+ LibraryLookupMap map(object_store->libraries_map()); |
+ bool present = map.UpdateOrInsert(lib_url, *this); |
+ ASSERT(!present); |
+ object_store->set_libraries_map(map.Release()); |
+} |
+ |
+ |
+void Library::RegisterLibraries(Thread* thread, |
+ const GrowableObjectArray& libs) { |
+ Zone* zone = thread->zone(); |
+ Isolate* isolate = thread->isolate(); |
+ Library& lib = Library::Handle(zone); |
+ String& lib_url = String::Handle(zone); |
+ |
+ LibraryLookupMap map(HashTables::New<LibraryLookupMap>(16, Heap::kOld)); |
+ |
+ intptr_t len = libs.Length(); |
+ for (intptr_t i = 0; i < len; i++) { |
+ lib ^= libs.At(i); |
+ lib_url = lib.url(); |
+ map.InsertNewOrGetValue(lib_url, lib); |
+ } |
+ // Now rememeber these in the isolate's object store. |
+ isolate->object_store()->set_libraries(libs); |
+ isolate->object_store()->set_libraries_map(map.Release()); |
} |