Bug 1285036 - Part 1: Use an enum for ProgressEvent types and use consts for the event name strings. r=baku
☠☠ backed out by 8f5af40eb365 ☠ ☠
authorThomas Wisniewski <wisniewskit@gmail.com>
Thu, 07 Jul 2016 11:07:53 -0400
changeset 304124 8e94b77f805bcad09be127117c7407c3d783b67b
parent 304123 8ae66227417f77a77459047cd0d48ac612ed7e7c
child 304125 3036026722de8fcd736ddf6b753a72eda0bc4c2f
push id79250
push userryanvm@gmail.com
push dateFri, 08 Jul 2016 01:34:14 +0000
treeherdermozilla-inbound@cc47bd26a869 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1285036
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 1285036 - Part 1: Use an enum for ProgressEvent types and use consts for the event name strings. r=baku
dom/xhr/XMLHttpRequestMainThread.cpp
dom/xhr/XMLHttpRequestMainThread.h
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -90,24 +90,34 @@ namespace dom {
 // once doubling reaches this threshold
 #define XML_HTTP_REQUEST_ARRAYBUFFER_MAX_GROWTH (32*1024*1024)
 // start at 32k to avoid lots of doubling right at the start
 #define XML_HTTP_REQUEST_ARRAYBUFFER_MIN_SIZE (32*1024)
 // the maximum Content-Length that we'll preallocate.  1GB.  Must fit
 // in an int32_t!
 #define XML_HTTP_REQUEST_MAX_CONTENT_LENGTH_PREALLOCATE (1*1024*1024*1024LL)
 
-#define LOAD_STR "load"
-#define ERROR_STR "error"
-#define ABORT_STR "abort"
-#define TIMEOUT_STR "timeout"
-#define LOADSTART_STR "loadstart"
-#define PROGRESS_STR "progress"
-#define READYSTATE_STR "readystatechange"
-#define LOADEND_STR "loadend"
+namespace {
+  const nsLiteralString ProgressEventTypeStrings[] = {
+    NS_LITERAL_STRING("loadstart"),
+    NS_LITERAL_STRING("progress"),
+    NS_LITERAL_STRING("error"),
+    NS_LITERAL_STRING("abort"),
+    NS_LITERAL_STRING("timeout"),
+    NS_LITERAL_STRING("load"),
+    NS_LITERAL_STRING("loadend")
+  };
+  static_assert(MOZ_ARRAY_LENGTH(ProgressEventTypeStrings) ==
+                  size_t(XMLHttpRequestMainThread::ProgressEventType::ENUM_MAX),
+                "Mismatched lengths for ProgressEventTypeStrings and ProgressEventType enums");
+
+  const nsString kLiteralString_readystatechange = NS_LITERAL_STRING("readystatechange");
+  const nsString kLiteralString_xmlhttprequest = NS_LITERAL_STRING("xmlhttprequest");
+  const nsString kLiteralString_DOMContentLoaded = NS_LITERAL_STRING("DOMContentLoaded");
+}
 
 // CIDs
 
 // State
 #define XML_HTTP_REQUEST_UNSENT           (1 << 0) // 0 UNSENT
 #define XML_HTTP_REQUEST_OPENED           (1 << 1) // 1 OPENED
 #define XML_HTTP_REQUEST_HEADERS_RECEIVED (1 << 2) // 2 HEADERS_RECEIVED
 #define XML_HTTP_REQUEST_LOADING          (1 << 3) // 3 LOADING
@@ -1016,17 +1026,17 @@ XMLHttpRequestMainThread::GetStatusText(
   if (httpChannel) {
     httpChannel->GetResponseStatusText(aStatusText);
   } else {
     aStatusText.AssignLiteral("OK");
   }
 }
 
 void
-XMLHttpRequestMainThread::CloseRequestWithError(const nsAString& aType,
+XMLHttpRequestMainThread::CloseRequestWithError(const ProgressEventType aType,
                                                 const uint32_t aFlag)
 {
   if (mChannel) {
     mChannel->Cancel(NS_BINDING_ABORTED);
   }
   if (mTimeoutTimer) {
     mTimeoutTimer->Cancel();
   }
@@ -1064,17 +1074,17 @@ XMLHttpRequestMainThread::CloseRequestWi
   }
 
   mState &= ~XML_HTTP_REQUEST_SYNCLOOPING;
 }
 
 void
 XMLHttpRequestMainThread::Abort(ErrorResult& arv)
 {
-  CloseRequestWithError(NS_LITERAL_STRING(ABORT_STR), XML_HTTP_REQUEST_ABORTED);
+  CloseRequestWithError(ProgressEventType::abort, XML_HTTP_REQUEST_ABORTED);
 }
 
 NS_IMETHODIMP
 XMLHttpRequestMainThread::SlowAbort()
 {
   Abort();
   return NS_OK;
 }
@@ -1293,59 +1303,57 @@ XMLHttpRequestMainThread::GetLoadGroup()
 }
 
 nsresult
 XMLHttpRequestMainThread::CreateReadystatechangeEvent(nsIDOMEvent** aDOMEvent)
 {
   RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
   event.forget(aDOMEvent);
 
-  (*aDOMEvent)->InitEvent(NS_LITERAL_STRING(READYSTATE_STR),
-                          false, false);
+  (*aDOMEvent)->InitEvent(kLiteralString_readystatechange, false, false);
 
   // We assume anyone who managed to call CreateReadystatechangeEvent is trusted
   (*aDOMEvent)->SetTrusted(true);
 
   return NS_OK;
 }
 
 void
 XMLHttpRequestMainThread::DispatchProgressEvent(DOMEventTargetHelper* aTarget,
-                                                const nsAString& aType,
+                                                const ProgressEventType aType,
                                                 bool aLengthComputable,
                                                 int64_t aLoaded, int64_t aTotal)
 {
   NS_ASSERTION(aTarget, "null target");
   NS_ASSERTION(!aType.IsEmpty(), "missing event type");
 
   if (NS_FAILED(CheckInnerWindowCorrectness()) ||
       (!AllowUploadProgress() && aTarget == mUpload)) {
     return;
   }
 
-  bool dispatchLoadend = aType.EqualsLiteral(LOAD_STR) ||
-                         aType.EqualsLiteral(ERROR_STR) ||
-                         aType.EqualsLiteral(TIMEOUT_STR) ||
-                         aType.EqualsLiteral(ABORT_STR);
-
   ProgressEventInit init;
   init.mBubbles = false;
   init.mCancelable = false;
   init.mLengthComputable = aLengthComputable;
   init.mLoaded = aLoaded;
   init.mTotal = (aTotal == -1) ? 0 : aTotal;
 
+  const nsAString& typeString = ProgressEventTypeStrings[(uint8_t)aType];
   RefPtr<ProgressEvent> event =
-    ProgressEvent::Constructor(aTarget, aType, init);
+    ProgressEvent::Constructor(aTarget, typeString, init);
   event->SetTrusted(true);
 
   aTarget->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
 
-  if (dispatchLoadend) {
-    DispatchProgressEvent(aTarget, NS_LITERAL_STRING(LOADEND_STR),
+  // 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 ||
+      aType == ProgressEventType::timeout || aType == ProgressEventType::abort) {
+    DispatchProgressEvent(aTarget, ProgressEventType::loadend,
                           aLengthComputable, aLoaded, aTotal);
   }
 }
 
 already_AddRefed<nsIHttpChannel>
 XMLHttpRequestMainThread::GetCurrentHttpChannel()
 {
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
@@ -1558,17 +1566,17 @@ XMLHttpRequestMainThread::Open(const nsA
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
   if (httpChannel) {
     rv = httpChannel->SetRequestMethod(method);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Set the initiator type
     nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(httpChannel));
     if (timedChannel) {
-      timedChannel->SetInitiatorType(NS_LITERAL_STRING("xmlhttprequest"));
+      timedChannel->SetInitiatorType(kLiteralString_xmlhttprequest);
     }
   }
 
   ChangeState(XML_HTTP_REQUEST_OPENED);
 
   return NS_OK;
 }
 
@@ -1792,17 +1800,17 @@ XMLHttpRequestMainThread::OnStartRequest
     }
     if (mUploadTransferred < mUploadTotal) {
       mUploadTransferred = mUploadTotal;
       mProgressSinceLastProgressEvent = true;
       mUploadLengthComputable = true;
       MaybeDispatchProgressEvents(true);
     }
     mUploadComplete = true;
-    DispatchProgressEvent(mUpload, NS_LITERAL_STRING(LOAD_STR),
+    DispatchProgressEvent(mUpload, ProgressEventType::load,
                           true, mUploadTotal, mUploadTotal);
   }
 
   mContext = ctxt;
   mState |= XML_HTTP_REQUEST_PARSEBODY;
   ChangeState(XML_HTTP_REQUEST_HEADERS_RECEIVED);
 
   ResetResponse();
@@ -2110,17 +2118,17 @@ XMLHttpRequestMainThread::OnStopRequest(
   }
   if (mIsHtml) {
     NS_ASSERTION(!(mState & XML_HTTP_REQUEST_SYNCLOOPING),
       "We weren't supposed to support HTML parsing with XHR!");
     nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(mResponseXML);
     EventListenerManager* manager =
       eventTarget->GetOrCreateListenerManager();
     manager->AddEventListenerByType(new nsXHRParseEndListener(this),
-                                    NS_LITERAL_STRING("DOMContentLoaded"),
+                                    kLiteralString_DOMContentLoaded,
                                     TrustedEventsAtSystemGroupBubble());
     return NS_OK;
   }
   // We might have been sent non-XML data. If that was the case,
   // we should null out the document member. The idea in this
   // check here is that if there is no document element it is not
   // an XML document. We might need a fancier check...
   if (!mResponseXML->GetRootElement()) {
@@ -2139,25 +2147,23 @@ XMLHttpRequestMainThread::ChangeStateToD
     MaybeDispatchProgressEvents(true);
   }
 
   ChangeState(XML_HTTP_REQUEST_DONE, true);
   if (mTimeoutTimer) {
     mTimeoutTimer->Cancel();
   }
 
-  NS_NAMED_LITERAL_STRING(errorStr, ERROR_STR);
-  NS_NAMED_LITERAL_STRING(loadStr, LOAD_STR);
   DispatchProgressEvent(this,
-                        mErrorLoad ? errorStr : loadStr,
+                        mErrorLoad ? ProgressEventType::error : ProgressEventType::load,
                         !mErrorLoad,
                         mLoadTransferred,
                         mErrorLoad ? 0 : mLoadTransferred);
   if (mErrorLoad && mUpload && !mUploadComplete) {
-    DispatchProgressEvent(mUpload, errorStr, true,
+    DispatchProgressEvent(mUpload, ProgressEventType::error, true,
                           mUploadTransferred, mUploadTotal);
   }
 
   if (mErrorLoad) {
     // By nulling out channel here we make it so that Send() can test
     // for that and throw. Also calling the various status
     // methods/members will not throw.
     // This matches what IE does.
@@ -2828,20 +2834,20 @@ XMLHttpRequestMainThread::Send(nsIVarian
     // Now that we've successfully opened the channel, we can change state.  Note
     // that this needs to come after the AsyncOpen() and rv check, because this
     // can run script that would try to restart this request, and that could end
     // up doing our AsyncOpen on a null channel if the reentered AsyncOpen fails.
     ChangeState(XML_HTTP_REQUEST_SENT);
     if (mUpload && mUpload->HasListenersFor(nsGkAtoms::onprogress)) {
       StartProgressEventTimer();
     }
-    DispatchProgressEvent(this, NS_LITERAL_STRING(LOADSTART_STR), false,
+    DispatchProgressEvent(this, ProgressEventType::loadstart, false,
                           0, 0);
     if (mUpload && !mUploadComplete) {
-      DispatchProgressEvent(mUpload, NS_LITERAL_STRING(LOADSTART_STR), true,
+      DispatchProgressEvent(mUpload, ProgressEventType::loadstart, true,
                             0, mUploadTotal);
     }
   }
 
   if (!mChannel) {
     return NS_ERROR_FAILURE;
   }
 
@@ -3258,26 +3264,26 @@ XMLHttpRequestMainThread::MaybeDispatchP
   if (!aFinalProgress) {
     StartProgressEventTimer();
   }
 
   // We're uploading if our state is XML_HTTP_REQUEST_OPENED or
   // XML_HTTP_REQUEST_SENT
   if ((XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT) & mState) {
     if (mUpload && !mUploadComplete) {
-      DispatchProgressEvent(mUpload, NS_LITERAL_STRING(PROGRESS_STR),
+      DispatchProgressEvent(mUpload, ProgressEventType::progress,
                             mUploadLengthComputable, mUploadTransferred,
                             mUploadTotal);
     }
   } else {
     if (aFinalProgress) {
       mLoadTotal = mLoadTransferred;
     }
     mInLoadProgressEvent = true;
-    DispatchProgressEvent(this, NS_LITERAL_STRING(PROGRESS_STR),
+    DispatchProgressEvent(this, ProgressEventType::progress,
                           mLoadLengthComputable, mLoadTransferred,
                           mLoadTotal);
     mInLoadProgressEvent = false;
     if (mResponseType == XMLHttpRequestResponseType::Moz_chunked_text ||
         mResponseType == XMLHttpRequestResponseType::Moz_chunked_arraybuffer) {
       mResponseBody.Truncate();
       mResponseText.Truncate();
       mResultArrayBuffer = nullptr;
@@ -3476,18 +3482,17 @@ void
 XMLHttpRequestMainThread::HandleTimeoutCallback()
 {
   if (mState & XML_HTTP_REQUEST_DONE) {
     NS_NOTREACHED("XMLHttpRequestMainThread::HandleTimeoutCallback with completed request");
     // do nothing!
     return;
   }
 
-  CloseRequestWithError(NS_LITERAL_STRING(TIMEOUT_STR),
-                        XML_HTTP_REQUEST_TIMED_OUT);
+  CloseRequestWithError(ProgressEventType::timeout, XML_HTTP_REQUEST_TIMED_OUT);
 }
 
 NS_IMETHODIMP
 XMLHttpRequestMainThread::Notify(nsITimer* aTimer)
 {
   if (mProgressNotifier == aTimer) {
     HandleProgressTimerCallback();
     return NS_OK;
--- a/dom/xhr/XMLHttpRequestMainThread.h
+++ b/dom/xhr/XMLHttpRequestMainThread.h
@@ -122,16 +122,27 @@ class XMLHttpRequestMainThread final : p
                                        public nsSupportsWeakReference,
                                        public nsITimerCallback,
                                        public nsISizeOfEventTarget
 {
   friend class nsXHRParseEndListener;
   friend class nsXMLHttpRequestXPCOMifier;
 
 public:
+  enum class ProgressEventType : uint8_t {
+    loadstart,
+    progress,
+    error,
+    abort,
+    timeout,
+    load,
+    loadend,
+    ENUM_MAX
+  };
+
   XMLHttpRequestMainThread();
 
   void Construct(nsIPrincipal* aPrincipal,
                  nsIGlobalObject* aGlobalObject,
                  nsIURI* aBaseURI = nullptr,
                  nsILoadGroup* aLoadGroup = nullptr)
   {
     MOZ_ASSERT(aPrincipal);
@@ -507,17 +518,17 @@ public:
   GetInterface(JSContext* aCx, nsIJSID* aIID,
                JS::MutableHandle<JS::Value> aRetval,
                ErrorResult& aRv) override;
 
   // This creates a trusted readystatechange event, which is not cancelable and
   // doesn't bubble.
   nsresult CreateReadystatechangeEvent(nsIDOMEvent** aDOMEvent);
   void DispatchProgressEvent(DOMEventTargetHelper* aTarget,
-                             const nsAString& aType,
+                             const ProgressEventType aType,
                              bool aLengthComputable,
                              int64_t aLoaded, int64_t aTotal);
 
   // Dispatch the "progress" event on the XHR or XHR.upload object if we've
   // received data since the last "progress" event. Also dispatches
   // "uploadprogress" as needed.
   void MaybeDispatchProgressEvents(bool aFinalProgress);
 
@@ -712,17 +723,17 @@ protected:
   /**
    * Close the XMLHttpRequest's channels and dispatch appropriate progress
    * events.
    *
    * @param aType The progress event type.
    * @param aFlag A XML_HTTP_REQUEST_* state flag defined in
    *              XMLHttpRequestMainthread.cpp.
    */
-  void CloseRequestWithError(const nsAString& aType, const uint32_t aFlag);
+  void CloseRequestWithError(const ProgressEventType aType, const uint32_t aFlag);
 
   bool mFirstStartRequestSeen;
   bool mInLoadProgressEvent;
 
   nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
   nsCOMPtr<nsIChannel> mNewRedirectChannel;
 
   JS::Heap<JS::Value> mResultJSON;