Bug 1383215: Part 4 - Use location string as key in modules map. r?mccr8 draft
authorKris Maglione <maglione.k@gmail.com>
Fri, 21 Jul 2017 15:30:55 -0700
changeset 613440 7428c37bef38b4b5d66dc5c72f40b6c709598dcb
parent 613439 21d94c910f5cc4cc199b472f005a18fe9295e71c
child 638678 0c20326878ca43c2b1526543b636193d81827b53
push id69800
push usermaglione.k@gmail.com
push dateFri, 21 Jul 2017 23:03:45 +0000
reviewersmccr8
bugs1383215
milestone56.0a1
Bug 1383215: Part 4 - Use location string as key in modules map. r?mccr8 Using the unmolested module location string as the cache key removes a huge chunk of overhead when loading cached modules. This also ensures that multiple URLs are not used to load the same module, which would result in it being loaded more than once in the new regime MozReview-Commit-ID: BAWoOJQSTc1
js/xpconnect/loader/mozJSComponentLoader.cpp
js/xpconnect/loader/mozJSComponentLoader.h
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -191,16 +191,17 @@ ReportOnCallerUTF8(JSCLContextHelper& he
     va_end(ap);
     return NS_OK;
 }
 
 mozJSComponentLoader::mozJSComponentLoader()
     : mModules(16),
       mImports(16),
       mInProgressImports(16),
+      mLocations(16),
       mInitialized(false)
 {
     MOZ_ASSERT(!sSelf, "mozJSComponentLoader should be a singleton");
 
     sSelf = this;
 }
 
 #define ENSURE_DEP(name) { nsresult rv = Ensure##name(); NS_ENSURE_SUCCESS(rv, rv); }
@@ -247,19 +248,18 @@ class MOZ_STACK_CLASS ComponentLoaderInf
     nsIURI* ResolvedURI() { MOZ_ASSERT(mResolvedURI); return mResolvedURI; }
     nsresult EnsureResolvedURI() {
         BEGIN_ENSURE(ResolvedURI, URI);
         return ResolveURI(mURI, getter_AddRefs(mResolvedURI));
     }
 
     nsAutoCString& Key() { return *mKey; }
     nsresult EnsureKey() {
-        ENSURE_DEPS(ResolvedURI);
-        mKey.emplace();
-        return mResolvedURI->GetSpec(*mKey);
+        mKey.emplace(mLocation);
+        return NS_OK;
     }
 
     MOZ_MUST_USE nsresult GetLocation(nsCString& aLocation) {
         nsresult rv = EnsureURI();
         NS_ENSURE_SUCCESS(rv, rv);
         return mURI->GetSpec(aLocation);
     }
 
@@ -444,16 +444,17 @@ SizeOfTableExcludingThis(const nsBaseHas
 }
 
 size_t
 mozJSComponentLoader::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
 {
     size_t n = aMallocSizeOf(this);
     n += SizeOfTableExcludingThis(mModules, aMallocSizeOf);
     n += SizeOfTableExcludingThis(mImports, aMallocSizeOf);
+    n += mLocations.ShallowSizeOfExcludingThis(aMallocSizeOf);
     n += SizeOfTableExcludingThis(mInProgressImports, aMallocSizeOf);
     return n;
 }
 
 void
 mozJSComponentLoader::CreateLoaderGlobal(JSContext* aCx,
                                          nsACString& aLocation,
                                          JSAddonId* aAddonID,
@@ -758,16 +759,17 @@ mozJSComponentLoader::ObjectForLocation(
 
 void
 mozJSComponentLoader::UnloadModules()
 {
     mInitialized = false;
 
     mInProgressImports.Clear();
     mImports.Clear();
+    mLocations.Clear();
 
     for (auto iter = mModules.Iter(); !iter.Done(); iter.Next()) {
         iter.Data()->Clear();
         iter.Remove();
     }
 }
 
 nsresult
@@ -936,16 +938,25 @@ mozJSComponentLoader::ImportInto(const n
             baseFileURL = do_QueryInterface(info.ResolvedURI(), &rv);
             NS_ENSURE_SUCCESS(rv, rv);
         }
 
         nsCOMPtr<nsIFile> sourceFile;
         rv = baseFileURL->GetFile(getter_AddRefs(sourceFile));
         NS_ENSURE_SUCCESS(rv, rv);
 
+        rv = info.ResolvedURI()->GetSpec(newEntry->resolvedURL);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        nsCString* existingPath;
+        if (mLocations.Get(newEntry->resolvedURL, &existingPath) && *existingPath != info.Key()) {
+            return NS_ERROR_UNEXPECTED;
+        }
+
+        mLocations.Put(newEntry->resolvedURL, &info.Key());
         mInProgressImports.Put(info.Key(), newEntry);
 
         rv = info.EnsureURI();
         NS_ENSURE_SUCCESS(rv, rv);
         RootedValue exception(callercx);
         rv = ObjectForLocation(info, sourceFile, &newEntry->obj,
                                &newEntry->thisObjectKey,
                                &newEntry->location, true, &exception);
@@ -1107,16 +1118,17 @@ mozJSComponentLoader::Unload(const nsACS
         return NS_OK;
     }
 
     ComponentLoaderInfo info(aLocation);
     rv = info.EnsureKey();
     NS_ENSURE_SUCCESS(rv, rv);
     ModuleEntry* mod;
     if (mImports.Get(info.Key(), &mod)) {
+        mLocations.Remove(mod->resolvedURL);
         mImports.Remove(info.Key());
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 mozJSComponentLoader::Observe(nsISupports* subject, const char* topic,
--- a/js/xpconnect/loader/mozJSComponentLoader.h
+++ b/js/xpconnect/loader/mozJSComponentLoader.h
@@ -140,28 +140,34 @@ class mozJSComponentLoader : public mozi
 
         static already_AddRefed<nsIFactory> GetFactory(const mozilla::Module& module,
                                                        const mozilla::Module::CIDEntry& entry);
 
         nsCOMPtr<xpcIJSGetFactory> getfactoryobj;
         JS::PersistentRootedObject obj;
         JS::PersistentRootedScript thisObjectKey;
         char*               location;
+        nsCString           resolvedURL;
     };
 
     friend class ModuleEntry;
 
     static size_t DataEntrySizeOfExcludingThis(const nsACString& aKey, ModuleEntry* const& aData,
                                                mozilla::MallocSizeOf aMallocSizeOf, void* arg);
     static size_t ClassEntrySizeOfExcludingThis(const nsACString& aKey,
                                                 const nsAutoPtr<ModuleEntry>& aData,
                                                 mozilla::MallocSizeOf aMallocSizeOf, void* arg);
 
     // Modules are intentionally leaked, but still cleared.
     nsDataHashtable<nsCStringHashKey, ModuleEntry*> mModules;
 
     nsClassHashtable<nsCStringHashKey, ModuleEntry> mImports;
     nsDataHashtable<nsCStringHashKey, ModuleEntry*> mInProgressImports;
 
+    // A map of on-disk file locations which are loaded as modules to the
+    // pre-resolved URIs they were loaded from. Used to prevent the same file
+    // from being loaded separately, from multiple URLs.
+    nsClassHashtable<nsCStringHashKey, nsCString> mLocations;
+
     bool mInitialized;
 };
 
 #endif