Bug 1249739 - Improve performance in XHR in workers - part 1 - XHR.responseText must be cached, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Mon, 12 Sep 2016 09:05:42 +0200
changeset 313513 0e3040aed6e9ccc8bb2533161e06690f9902aa8f
parent 313512 eed2a76f1a596aa4847996136dfd7517484a8f0b
child 313514 554d3b443640a216b7c8f8d97d0905db3c115511
push id30690
push userkwierso@gmail.com
push dateTue, 13 Sep 2016 00:08:29 +0000
treeherdermozilla-central@2e35fd4a4932 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1249739
milestone51.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 1249739 - Improve performance in XHR in workers - part 1 - XHR.responseText must be cached, r=smaug
dom/webidl/XMLHttpRequest.webidl
dom/xhr/XMLHttpRequestMainThread.cpp
dom/xhr/XMLHttpRequestMainThread.h
dom/xhr/XMLHttpRequestWorker.cpp
--- a/dom/webidl/XMLHttpRequest.webidl
+++ b/dom/webidl/XMLHttpRequest.webidl
@@ -125,17 +125,17 @@ interface XMLHttpRequest : XMLHttpReques
 
   [Throws]
   void overrideMimeType(DOMString mime);
 
   [SetterThrows]
   attribute XMLHttpRequestResponseType responseType;
   [Throws]
   readonly attribute any response;
-  [Throws]
+  [Cached, Pure, Throws]
   readonly attribute DOMString? responseText;
 
   [Throws, Exposed=Window]
   readonly attribute Document? responseXML;
 
   // Mozilla-specific stuff
 
   [ChromeOnly, SetterThrows]
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -283,17 +283,17 @@ XMLHttpRequestMainThread::InitParameters
   SetParameters(aAnon, aSystem);
 }
 
 void
 XMLHttpRequestMainThread::ResetResponse()
 {
   mResponseXML = nullptr;
   mResponseBody.Truncate();
-  mResponseText.Truncate();
+  TruncateResponseText();
   mResponseBlob = nullptr;
   mDOMBlob = nullptr;
   mBlobSet = nullptr;
   mResultArrayBuffer = nullptr;
   mArrayBufferBuilder.reset();
   mResultJSON.setUndefined();
   mDataAvailable = 0;
   mLoadTransferred = 0;
@@ -559,16 +559,17 @@ XMLHttpRequestMainThread::AppendToRespon
   MOZ_ASSERT(NS_SUCCEEDED(rv));
 
   totalChars += destlen;
   if (!totalChars.isValid()) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   mResponseText.SetLength(totalChars.value());
+  XMLHttpRequestBinding::ClearCachedResponseTextValue(this);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 XMLHttpRequestMainThread::GetResponseText(nsAString& aResponseText)
 {
   ErrorResult rv;
   nsString responseText;
@@ -818,17 +819,17 @@ XMLHttpRequestMainThread::GetResponse(JS
   {
     if (mState != State::done) {
       aResponse.setNull();
       return;
     }
 
     if (mResultJSON.isUndefined()) {
       aRv = CreateResponseParsedJSON(aCx);
-      mResponseText.Truncate();
+      TruncateResponseText();
       if (aRv.Failed()) {
         // Per spec, errors aren't propagated. null is returned instead.
         aRv = NS_OK;
         // It would be nice to log the error to the console. That's hard to
         // do without calling window.onerror as a side effect, though.
         JS_ClearPendingException(aCx);
         mResultJSON.setNull();
       }
@@ -1327,17 +1328,17 @@ XMLHttpRequestMainThread::DispatchProgre
 
   if (aType == ProgressEventType::progress) {
     mInLoadProgressEvent = false;
 
     // clear chunked responses after every progress event
     if (mResponseType == XMLHttpRequestResponseType::Moz_chunked_text ||
         mResponseType == XMLHttpRequestResponseType::Moz_chunked_arraybuffer) {
       mResponseBody.Truncate();
-      mResponseText.Truncate();
+      TruncateResponseText();
       mResultArrayBuffer = nullptr;
       mArrayBufferBuilder.reset();
     }
   }
 
   // If we're sending a load, error, timeout or abort event, then
   // also dispatch the subsequent loadend event.
   if (aType == ProgressEventType::load || aType == ProgressEventType::error ||
@@ -2140,17 +2141,17 @@ XMLHttpRequestMainThread::OnBodyParseEnd
   ChangeStateToDone();
 }
 
 void
 XMLHttpRequestMainThread::MatchCharsetAndDecoderToResponseDocument()
 {
   if (mResponseXML && mResponseCharset != mResponseXML->GetDocumentCharacterSet()) {
     mResponseCharset = mResponseXML->GetDocumentCharacterSet();
-    mResponseText.Truncate();
+    TruncateResponseText();
     mResponseBodyDecodedPos = 0;
     mDecoder = EncodingUtils::DecoderForEncoding(mResponseCharset);
   }
 }
 
 void
 XMLHttpRequestMainThread::ChangeStateToDone()
 {
@@ -3532,16 +3533,23 @@ XMLHttpRequestMainThread::ShouldBlockAut
 
   if (!username.IsEmpty() || !password.IsEmpty()) {
     return true;
   }
 
   return false;
 }
 
+void
+XMLHttpRequestMainThread::TruncateResponseText()
+{
+  mResponseText.Truncate();
+  XMLHttpRequestBinding::ClearCachedResponseTextValue(this);
+}
+
 NS_IMPL_ISUPPORTS(XMLHttpRequestMainThread::nsHeaderVisitor, nsIHttpHeaderVisitor)
 
 NS_IMETHODIMP XMLHttpRequestMainThread::
 nsHeaderVisitor::VisitHeader(const nsACString &header, const nsACString &value)
 {
   if (mXHR.IsSafeHeader(header, mHttpChannel)) {
     mHeaders.Append(header);
     mHeaders.AppendLiteral(": ");
--- a/dom/xhr/XMLHttpRequestMainThread.h
+++ b/dom/xhr/XMLHttpRequestMainThread.h
@@ -568,16 +568,18 @@ protected:
   // determines if the onreadystatechange listener should be called.
   nsresult ChangeState(State aState, bool aBroadcast = true);
   already_AddRefed<nsILoadGroup> GetLoadGroup() const;
   nsIURI *GetBaseURI();
 
   already_AddRefed<nsIHttpChannel> GetCurrentHttpChannel();
   already_AddRefed<nsIJARChannel> GetCurrentJARChannel();
 
+  void TruncateResponseText();
+
   bool IsSystemXHR() const;
   bool InUploadPhase() const;
 
   void OnBodyParseEnd();
   void ChangeStateToDone();
 
   void StartProgressEventTimer();
   void StopProgressEventTimer();
--- a/dom/xhr/XMLHttpRequestWorker.cpp
+++ b/dom/xhr/XMLHttpRequestWorker.cpp
@@ -1256,16 +1256,17 @@ EventRunnable::WorkerRun(JSContext* aCx,
       mProxy->mLastLoaded = mLoaded;
       mProxy->mLastTotal = mTotal;
     }
   }
 
   JS::Rooted<UniquePtr<XMLHttpRequestWorker::StateData>> state(aCx, new XMLHttpRequestWorker::StateData());
 
   state->mResponseTextResult = mResponseTextResult;
+
   state->mResponseText = mResponseText;
 
   if (NS_SUCCEEDED(mResponseTextResult)) {
     MOZ_ASSERT(mResponse.isUndefined() || mResponse.isNull());
     state->mResponseResult = mResponseTextResult;
     state->mResponse = mResponse;
   }
   else {
@@ -2427,12 +2428,14 @@ XMLHttpRequestWorker::UpdateState(const 
     JS::Rooted<JS::Value> response(mWorkerPrivate->GetJSContext(),
                                    mStateData.mResponse);
     mStateData = aStateData;
     mStateData.mResponse = response;
   }
   else {
     mStateData = aStateData;
   }
+
+  XMLHttpRequestBinding::ClearCachedResponseTextValue(this);
 }
 
 } // dom namespace
 } // mozilla namespace