Bug 1287547 Don't leak HTMLScriptElement wrapper when page is closed during off-thread script parsing. r=bz
authorBen Kelly <ben@wanderview.com>
Mon, 25 Jul 2016 15:16:58 -0700
changeset 346633 7a40fff817782a0b5ce86e78c7fac26a6d0f732a
parent 346632 0a83bbcbf688560f0c42d3fce165649ba94e7aa7
child 346634 1828ce0a42d81af6f65d7feeaf15e285f75ddb44
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1287547
milestone50.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 1287547 Don't leak HTMLScriptElement wrapper when page is closed during off-thread script parsing. r=bz
dom/base/nsScriptLoader.cpp
dom/base/nsScriptLoader.h
--- a/dom/base/nsScriptLoader.cpp
+++ b/dom/base/nsScriptLoader.cpp
@@ -82,25 +82,53 @@ NS_INTERFACE_MAP_END
 NS_IMPL_CYCLE_COLLECTION_0(nsScriptLoadRequest)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsScriptLoadRequest)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsScriptLoadRequest)
 
 nsScriptLoadRequest::~nsScriptLoadRequest()
 {
   js_free(mScriptTextBuf);
+
+  // We should always clean up any off-thread script parsing resources.
+  MOZ_ASSERT(!mOffThreadToken);
+
+  // But play it safe in release builds and try to clean them up here
+  // as a fail safe.
+  MaybeCancelOffThreadScript();
 }
 
 void
 nsScriptLoadRequest::SetReady()
 {
   MOZ_ASSERT(mProgress != Progress::Ready);
   mProgress = Progress::Ready;
 }
 
+void
+nsScriptLoadRequest::Cancel()
+{
+  MaybeCancelOffThreadScript();
+  mIsCanceled = true;
+}
+
+void
+nsScriptLoadRequest::MaybeCancelOffThreadScript()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!mOffThreadToken) {
+    return;
+  }
+
+  JSContext* cx = JS_GetContext(xpc::GetJSRuntime());
+  JS::CancelOffThreadScript(cx, mOffThreadToken);
+  mOffThreadToken = nullptr;
+}
+
 //////////////////////////////////////////////////////////////
 // nsModuleLoadRequest
 //////////////////////////////////////////////////////////////
 
 // A load request for a module, created for every top level module script and
 // every module import.  Load request can share an nsModuleScript if there are
 // multiple imports of the same module.
 
@@ -1824,19 +1852,17 @@ nsScriptLoader::ProcessRequest(nsScriptL
   }
 
   if (aRequest->mOffThreadToken) {
     // The request was parsed off-main-thread, but the result of the off
     // thread parse was not actually needed to process the request
     // (disappearing window, some other error, ...). Finish the
     // request to avoid leaks in the JS engine.
     MOZ_ASSERT(!aRequest->IsModuleRequest());
-    JSContext* cx = JS_GetContext(xpc::GetJSRuntime());
-    JS::CancelOffThreadScript(cx, aRequest->mOffThreadToken);
-    aRequest->mOffThreadToken = nullptr;
+    aRequest->MaybeCancelOffThreadScript();
   }
 
   // Free any source data.
   free(aRequest->mScriptTextBuf);
   aRequest->mScriptTextBuf = nullptr;
   aRequest->mScriptTextLength = 0;
 
   return rv;
--- a/dom/base/nsScriptLoader.h
+++ b/dom/base/nsScriptLoader.h
@@ -113,20 +113,17 @@ public:
     mElement->ScriptEvaluated(aResult, mElement, mIsInline);
   }
 
   bool IsPreload()
   {
     return mElement == nullptr;
   }
 
-  virtual void Cancel()
-  {
-    mIsCanceled = true;
-  }
+  virtual void Cancel();
 
   bool IsCanceled() const
   {
     return mIsCanceled;
   }
 
   virtual void SetReady();
 
@@ -147,16 +144,18 @@ public:
   bool IsLoading() const {
     return mProgress == Progress::Loading;
   }
   bool InCompilingStage() const {
     return mProgress == Progress::Compiling ||
            (IsReadyToRun() && mWasCompiledOMT);
   }
 
+  void MaybeCancelOffThreadScript();
+
   using super::getNext;
   using super::isInList;
 
   const nsScriptKind mKind;
   nsCOMPtr<nsIScriptElement> mElement;
   Progress mProgress;     // Are we still waiting for a load to complete?
   bool mIsInline;         // Is the script inline or loaded?
   bool mHasSourceMapURL;  // Does the HTTP header have a source map url?