Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(456)

Unified Diff: runtime/vm/object.cc

Issue 1902563002: Add per-library cache of exported names (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Cleanup Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/object.h ('k') | runtime/vm/raw_object.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/object.cc
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index c7ca37337d6584a8869dd008768a7466a80ef938..ac631140c515473a3c9693feefe7dd5fbf492e4e 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -57,6 +57,7 @@ DEFINE_FLAG(bool, show_internal_names, false,
"Show names of internal classes (e.g. \"OneByteString\") in error messages "
"instead of showing the corresponding interface names (e.g. \"String\")");
DEFINE_FLAG(bool, use_lib_cache, true, "Use library name cache");
+DEFINE_FLAG(bool, use_exp_cache, true, "Use library exported name cache");
srdjan 2016/04/18 22:40:49 use_exported_name_cache sounds more readable than
Ivan Posva 2016/04/18 23:07:21 In the future please add new flags to the flag_lis
hausner 2016/04/18 23:51:58 Yes, I consider the flag temporary.
hausner 2016/04/18 23:51:58 More readable maybe, but I'm not sure it is more u
srdjan 2016/04/26 21:09:42 The flag is temporary, your choice.
DEFINE_FLAG(bool, ignore_patch_signature_mismatch, false,
"Ignore patch file member signature mismatch.");
@@ -9623,8 +9624,7 @@ bool Library::LookupResolvedNamesCache(const String& name,
// the name does not resolve to anything in this library scope.
void Library::AddToResolvedNamesCache(const String& name,
const Object& obj) const {
- ASSERT(!Compiler::IsBackgroundCompilation());
- if (!FLAG_use_lib_cache) {
+ if (!FLAG_use_lib_cache || Compiler::IsBackgroundCompilation()) {
srdjan 2016/04/18 22:40:48 Why are we starting to call AddToResolvedNamesCach
hausner 2016/04/18 23:51:58 No change here, but I think it is possible that th
return;
}
ResolvedNamesMap cache(resolved_names());
@@ -9633,12 +9633,53 @@ void Library::AddToResolvedNamesCache(const String& name,
}
+bool Library::LookupExportedNamesCache(const String& name,
+ Object* obj) const {
+ ASSERT(FLAG_use_exp_cache);
+ if (exported_names() == Array::null()) {
+ return false;
+ }
+ ResolvedNamesMap cache(exported_names());
+ bool present = false;
+ *obj = cache.GetOrNull(name, &present);
+ // Mutator compiler thread may add entries and therefore
+ // change 'resolved_names()' while running a background compilation;
srdjan 2016/04/18 22:40:49 s/resolved_names/exported_names/
hausner 2016/04/18 23:51:58 Done.
+ // do not ASSERT that 'exported_names()' has not changed.
+ cache.Release();
srdjan 2016/04/18 22:40:49 You may want to the same as in LookupResolvedNames
hausner 2016/04/18 23:51:58 Done.
+ return present;
+}
+
+void Library::AddToExportedNamesCache(const String& name,
+ const Object& obj) const {
+ ASSERT(!Compiler::IsBackgroundCompilation());
+ if (!FLAG_use_exp_cache || Compiler::IsBackgroundCompilation()) {
srdjan 2016/04/18 22:40:48 Why tests for background compilation when assertin
hausner 2016/04/18 23:51:58 Ok, assertion removed.
+ return;
+ }
+ if (exported_names() == Array::null()) {
+ AllocateExportedNamesCache();
+ }
+ ResolvedNamesMap cache(exported_names());
+ cache.UpdateOrInsert(name, obj);
+ StorePointer(&raw_ptr()->exported_names_, cache.Release().raw());
+}
+
+
void Library::InvalidateResolvedName(const String& name) const {
srdjan 2016/04/18 22:40:49 You may want to: Thread* thread = Thread::Current
srdjan 2016/04/18 22:40:49 ASSERT(FLAG_use_exp_cache)
hausner 2016/04/18 23:51:58 the flags for resolved name cache and exported nam
hausner 2016/04/18 23:51:58 Done.
Object& entry = Object::Handle();
if (LookupResolvedNamesCache(name, &entry)) {
// TODO(koda): Support deleted sentinel in snapshots and remove only 'name'.
InvalidateResolvedNamesCache();
}
+ GrowableObjectArray& libs = GrowableObjectArray::Handle(
Ivan Posva 2016/04/18 23:07:21 Please add a comment how we can get into a state w
hausner 2016/04/18 23:51:58 Done.
+ Isolate::Current()->object_store()->libraries());
+ Library& lib = Library::Handle();
+ intptr_t num_libs = libs.Length();
+ for (intptr_t i = 0; i < num_libs; i++) {
+ lib ^= libs.At(i);
+ if (LookupExportedNamesCache(name, &entry)) {
+ InitExportedNamesCache();
+ }
+ }
}
@@ -9648,6 +9689,19 @@ void Library::InvalidateResolvedNamesCache() const {
}
+// Invalidate all exported names caches in the isolate.
+void Library::InvalidateExportedNamesCaches() {
+ GrowableObjectArray& libs = GrowableObjectArray::Handle(
+ Isolate::Current()->object_store()->libraries());
+ Library& lib = Library::Handle();
+ intptr_t num_libs = libs.Length();
+ for (intptr_t i = 0; i < num_libs; i++) {
+ lib ^= libs.At(i);
+ lib.InitExportedNamesCache();
+ }
+}
+
+
void Library::GrowDictionary(const Array& dict, intptr_t dict_size) const {
// TODO(iposva): Avoid exponential growth.
intptr_t new_dict_size = dict_size * 2;
@@ -9723,42 +9777,45 @@ void Library::AddObject(const Object& obj, const String& name) const {
// Lookup a name in the library's re-export namespace.
// This lookup can occur from two different threads: background compiler and
// mutator thread.
-RawObject* Library::LookupReExport(const String& name) const {
- if (HasExports()) {
- const bool is_background_compiler = Compiler::IsBackgroundCompilation();
- Array& exports = Array::Handle();
- if (is_background_compiler) {
- exports = this->exports2();
- // Break potential export cycle while looking up name.
- StorePointer(&raw_ptr()->exports2_, Object::empty_array().raw());
- } else {
- exports = this->exports();
- // Break potential export cycle while looking up name.
- StorePointer(&raw_ptr()->exports_, Object::empty_array().raw());
- }
- Namespace& ns = Namespace::Handle();
- Object& obj = Object::Handle();
- for (int i = 0; i < exports.Length(); i++) {
- ns ^= exports.At(i);
- obj = ns.Lookup(name);
- if (!obj.IsNull()) {
- // The Lookup call above may return a setter x= when we are looking
- // for the name x. Make sure we only return when a matching name
- // is found.
- String& obj_name = String::Handle(obj.DictionaryName());
- if (Field::IsSetterName(obj_name) == Field::IsSetterName(name)) {
- break;
- }
+RawObject* Library::LookupReExport(const String& name,
+ ZoneGrowableArray<intptr_t>* trail) const {
+ if (!HasExports()) {
+ return Object::null();
+ }
+
+ if (trail == NULL) {
+ trail = new ZoneGrowableArray<intptr_t>();
+ }
+ Object& obj = Object::Handle();
+ if (FLAG_use_exp_cache && LookupExportedNamesCache(name, &obj)) {
+ return obj.raw();
+ }
+
+ const intptr_t lib_id = this->index();
+ ASSERT(lib_id >= 0); // We use -1 to indicate that a cycle was found.
+ trail->Add(lib_id);
+ const Array& exports = Array::Handle(this->exports());
+ Namespace& ns = Namespace::Handle();
+ for (int i = 0; i < exports.Length(); i++) {
+ ns ^= exports.At(i);
+ obj = ns.Lookup(name, trail);
+ if (!obj.IsNull()) {
+ // The Lookup call above may return a setter x= when we are looking
+ // for the name x. Make sure we only return when a matching name
+ // is found.
+ String& obj_name = String::Handle(obj.DictionaryName());
+ if (Field::IsSetterName(obj_name) == Field::IsSetterName(name)) {
+ break;
}
}
- if (is_background_compiler) {
- StorePointer(&raw_ptr()->exports2_, exports.raw());
- } else {
- StorePointer(&raw_ptr()->exports_, exports.raw());
- }
- return obj.raw();
}
- return Object::null();
+ bool in_cycle = (trail->RemoveLast() < 0);
+ if (FLAG_use_exp_cache &&
+ !in_cycle &&
+ !Compiler::IsBackgroundCompilation()) {
+ AddToExportedNamesCache(name, obj);
+ }
+ return obj.raw();
}
@@ -9844,6 +9901,7 @@ bool Library::RemoveObject(const Object& obj, const String& name) const {
dict.SetAt(dict_size, Smi::Handle(zone, Smi::New(used_elements)));
InvalidateResolvedNamesCache();
+ InvalidateExportedNamesCaches();
return true;
}
@@ -10210,7 +10268,6 @@ bool Library::ImportsCorelib() const {
void Library::DropDependencies() const {
StorePointer(&raw_ptr()->imports_, Array::null());
StorePointer(&raw_ptr()->exports_, Array::null());
- StorePointer(&raw_ptr()->exports2_, Array::null());
}
@@ -10243,7 +10300,6 @@ void Library::AddExport(const Namespace& ns) const {
intptr_t num_exports = exports.Length();
exports = Array::Grow(exports, num_exports + 1);
StorePointer(&raw_ptr()->exports_, exports.raw());
- StorePointer(&raw_ptr()->exports2_, exports.raw());
exports.SetAt(num_exports, ns);
}
@@ -10271,6 +10327,20 @@ void Library::InitResolvedNamesCache(intptr_t size,
}
+void Library::AllocateExportedNamesCache() const {
+ StorePointer(&raw_ptr()->exported_names_,
+ HashTables::New<ResolvedNamesMap>(16));
+}
+
+
+void Library::InitExportedNamesCache() const {
+ if (exported_names() != Array::null()) {
+ StorePointer(&raw_ptr()->exported_names_,
+ HashTables::New<ResolvedNamesMap>(16));
+ }
+}
+
+
void Library::InitClassDictionary() const {
// TODO(iposva): Find reasonable initial size.
const int kInitialElementCount = 16;
@@ -10305,6 +10375,8 @@ RawLibrary* Library::NewLibraryHelper(const String& url,
result.StorePointer(&result.raw_ptr()->url_, url.raw());
result.StorePointer(&result.raw_ptr()->resolved_names_,
Object::empty_array().raw());
+ result.StorePointer(&result.raw_ptr()->exported_names_,
+ Array::null());
result.StorePointer(&result.raw_ptr()->dictionary_,
Object::empty_array().raw());
result.StorePointer(&result.raw_ptr()->metadata_,
@@ -10315,8 +10387,6 @@ RawLibrary* Library::NewLibraryHelper(const String& url,
Heap::kOld));
result.StorePointer(&result.raw_ptr()->imports_, Object::empty_array().raw());
result.StorePointer(&result.raw_ptr()->exports_, Object::empty_array().raw());
- result.StorePointer(&result.raw_ptr()->exports2_,
- Object::empty_array().raw());
result.StorePointer(&result.raw_ptr()->loaded_scripts_, Array::null());
result.StorePointer(&result.raw_ptr()->load_error_, Instance::null());
result.set_native_entry_resolver(NULL);
@@ -11038,11 +11108,24 @@ bool Namespace::HidesName(const String& name) const {
// Look up object with given name in library and filter out hidden
// names. Also look up getters and setters.
-RawObject* Namespace::Lookup(const String& name) const {
+RawObject* Namespace::Lookup(const String& name,
+ ZoneGrowableArray<intptr_t>* trail) const {
Zone* zone = Thread::Current()->zone();
const Library& lib = Library::Handle(zone, library());
- intptr_t ignore = 0;
+ if (trail != NULL) {
+ // Look for cycle in reexport graph.
+ for (int i = 0; i < trail->length(); i++) {
+ if (trail->At(i) == lib.index()) {
+ for (int j = i+1; j < trail->length(); j++) {
+ (*trail)[j] = -1;
+ }
+ return Object::null();
+ }
+ }
+ }
+
+ intptr_t ignore = 0;
// Lookup the name in the library's symbols.
Object& obj = Object::Handle(zone, lib.LookupEntry(name, &ignore));
if (!Field::IsGetterName(name) &&
@@ -11064,14 +11147,14 @@ RawObject* Namespace::Lookup(const String& name) const {
// Library prefixes are not exported.
if (obj.IsNull() || obj.IsLibraryPrefix()) {
// Lookup in the re-exported symbols.
- obj = lib.LookupReExport(name);
+ obj = lib.LookupReExport(name, trail);
if (obj.IsNull() && !Field::IsSetterName(name)) {
// LookupReExport() only returns objects that match the given name.
// If there is no field/func/getter, try finding a setter.
const String& setter_name =
String::Handle(zone, Field::LookupSetterSymbol(name));
if (!setter_name.IsNull()) {
- obj = lib.LookupReExport(setter_name);
+ obj = lib.LookupReExport(setter_name, trail);
}
}
}
« no previous file with comments | « runtime/vm/object.h ('k') | runtime/vm/raw_object.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698