Bug 1383215: Part 4 - Use location string as key in modules map. r=mccr8
authorKris Maglione <maglione.k@gmail.com>
Mon, 24 Jul 2017 20:32:42 -0700
changeset 419496 03777f604c6ca9dd56de4d8314284f7303fda46b
parent 419495 5cfde6ac518b8a8704c090f4f46bbb0996665b72
child 419497 df302a197bca4990e47bce4b31dd00d051e7f079
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8
bugs1383215
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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); }
@@ -245,36 +246,33 @@ 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; }
+    const nsACString& Key() { return mLocation; }
     nsresult EnsureKey() {
-        ENSURE_DEPS(ResolvedURI);
-        mKey.emplace();
-        return mResolvedURI->GetSpec(*mKey);
+        return NS_OK;
     }
 
     MOZ_MUST_USE nsresult GetLocation(nsCString& aLocation) {
         nsresult rv = EnsureURI();
         NS_ENSURE_SUCCESS(rv, rv);
         return mURI->GetSpec(aLocation);
     }
 
   private:
     const nsACString& mLocation;
     nsCOMPtr<nsIIOService> mIOService;
     nsCOMPtr<nsIURI> mURI;
     nsCOMPtr<nsIChannel> mScriptChannel;
     nsCOMPtr<nsIURI> mResolvedURI;
-    Maybe<nsAutoCString> mKey; // This is safe because we're MOZ_STACK_CLASS
 };
 
 #undef BEGIN_ENSURE
 #undef ENSURE_DEPS
 #undef ENSURE_DEP
 
 mozJSComponentLoader::~mozJSComponentLoader()
 {
@@ -444,16 +442,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 +757,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 +936,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, new nsCString(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 +1116,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
@@ -139,29 +139,35 @@ class mozJSComponentLoader : public mozi
         size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
         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;
+        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