Bug 994453 part 1. Factor out the to-JS conversions from Promise.h into mozilla::dom::ToJSValue methods. r=bholley
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 10 Apr 2014 14:57:07 -0400
changeset 196522 4420ba8e8b3218a5f5893bd6700a8a0a4956f519
parent 196521 16540ab2d2cb76855313d63046bf523ad24343ee
child 196523 45d3f9cfb0df50c6669d1318ff0965286c9acd0d
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs994453
milestone31.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 994453 part 1. Factor out the to-JS conversions from Promise.h into mozilla::dom::ToJSValue methods. r=bholley Apart from moving the methods, I made the following changes: 1) Renamed them to ToJSValue. 2) Inlined the boolean overload. 3) Added overloads that take integer types. 4) Changed the order of the aCx and aArgument arguments so aCx comes first. 5) Renamed "abv" to "obj" in the typed array overload.
dom/bindings/ToJSValue.cpp
dom/bindings/ToJSValue.h
dom/bindings/moz.build
dom/promise/Promise.cpp
dom/promise/Promise.h
new file mode 100644
--- /dev/null
+++ b/dom/bindings/ToJSValue.cpp
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
+/* vim: set ts=2 sw=2 et tw=79: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/ToJSValue.h"
+#include "nsAString.h"
+#include "nsContentUtils.h"
+#include "nsStringBuffer.h"
+#include "xpcpublic.h"
+
+namespace mozilla {
+namespace dom {
+
+bool
+ToJSValue(JSContext* aCx, const nsAString& aArgument,
+          JS::MutableHandle<JS::Value> aValue)
+{
+  // Make sure we're called in a compartment
+  MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
+
+// XXXkhuey I'd love to use xpc::NonVoidStringToJsval here, but it requires
+  // a non-const nsAString for silly reasons.
+  nsStringBuffer* sharedBuffer;
+  if (!XPCStringConvert::ReadableToJSVal(aCx, aArgument, &sharedBuffer,
+                                         aValue)) {
+    return false;
+  }
+
+  if (sharedBuffer) {
+    NS_ADDREF(sharedBuffer);
+  }
+
+  return true;
+}
+
+
+namespace tojsvalue_detail {
+
+bool
+ISupportsToJSValue(JSContext* aCx,
+                   nsISupports* aArgument,
+                   JS::MutableHandle<JS::Value> aValue)
+{
+  nsresult rv = nsContentUtils::WrapNative(aCx, aArgument, aValue);
+  return NS_SUCCEEDED(rv);
+}
+
+} // namespace tojsvalue_detail
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/bindings/ToJSValue.h
@@ -0,0 +1,192 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
+/* vim: set ts=2 sw=2 et tw=79: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_ToJSValue_h
+#define mozilla_dom_ToJSValue_h
+
+#include "mozilla/TypeTraits.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/TypedArray.h"
+#include "jsapi.h"
+#include "nsISupports.h"
+#include "nsTArray.h"
+#include "nsWrapperCache.h"
+
+namespace mozilla {
+namespace dom {
+
+// If ToJSValue returns false, it must set an exception on the
+// JSContext.
+
+// Accept strings.
+bool
+ToJSValue(JSContext* aCx,
+          const nsAString& aArgument,
+          JS::MutableHandle<JS::Value> aValue);
+
+// Accept booleans.
+inline bool
+ToJSValue(JSContext* aCx,
+          bool aArgument,
+          JS::MutableHandle<JS::Value> aValue)
+{
+  // Make sure we're called in a compartment
+  MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
+
+  aValue.setBoolean(aArgument);
+  return true;
+}
+
+// Accept integer types
+inline bool
+ToJSValue(JSContext* aCx,
+          int32_t aArgument,
+          JS::MutableHandle<JS::Value> aValue)
+{
+  // Make sure we're called in a compartment
+  MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
+
+  aValue.setInt32(aArgument);
+  return true;
+}
+
+inline bool
+ToJSValue(JSContext* aCx,
+          uint32_t aArgument,
+          JS::MutableHandle<JS::Value> aValue)
+{
+  // Make sure we're called in a compartment
+  MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
+
+  aValue.setNumber(aArgument);
+  return true;
+}
+
+inline bool
+ToJSValue(JSContext* aCx,
+          int64_t aArgument,
+          JS::MutableHandle<JS::Value> aValue)
+{
+  // Make sure we're called in a compartment
+  MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
+
+  aValue.setNumber(double(aArgument));
+  return true;
+}
+
+inline bool
+ToJSValue(JSContext* aCx,
+          uint64_t aArgument,
+          JS::MutableHandle<JS::Value> aValue)
+{
+  // Make sure we're called in a compartment
+  MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
+
+  aValue.setNumber(double(aArgument));
+  return true;
+}
+
+// Accept objects that inherit from nsWrapperCache and nsISupports (e.g. most
+// DOM objects).
+template <class T>
+typename EnableIf<IsBaseOf<nsWrapperCache, T>::value &&
+                  IsBaseOf<nsISupports, T>::value, bool>::Type
+ToJSValue(JSContext* aCx,
+          T& aArgument,
+          JS::MutableHandle<JS::Value> aValue)
+{
+  // Make sure we're called in a compartment
+  MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
+  // Make sure non-webidl objects don't sneak in here
+  MOZ_ASSERT(aArgument.IsDOMBinding());
+
+  return WrapNewBindingObject(aCx, aArgument, aValue);
+}
+
+// Accept typed arrays built from appropriate nsTArray values
+template<typename T>
+typename EnableIf<IsBaseOf<AllTypedArraysBase, T>::value, bool>::Type
+ToJSValue(JSContext* aCx,
+          const TypedArrayCreator<T>& aArgument,
+          JS::MutableHandle<JS::Value> aValue)
+{
+  // Make sure we're called in a compartment
+  MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
+
+  JSObject* obj = aArgument.Create(aCx);
+  if (!obj) {
+    return false;
+  }
+  aValue.setObject(*obj);
+  return true;
+}
+
+// We don't want to include nsContentUtils here, so use a helper
+// function for the nsISupports case.
+namespace tojsvalue_detail {
+bool
+ISupportsToJSValue(JSContext* aCx,
+                   nsISupports* aArgument,
+                   JS::MutableHandle<JS::Value> aValue);
+} // namespace tojsvalue_detail
+
+// Accept objects that inherit from nsISupports but not nsWrapperCache (e.g.
+// nsIDOMFile).
+template <class T>
+typename EnableIf<!IsBaseOf<nsWrapperCache, T>::value &&
+                  IsBaseOf<nsISupports, T>::value, bool>::Type
+ToJSValue(JSContext* aCx,
+          T& aArgument,
+          JS::MutableHandle<JS::Value> aValue)
+{
+  // Make sure we're called in a compartment
+  MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
+
+  return tojsvalue_detail::ISupportsToJSValue(aCx, &aArgument, aValue);
+}
+
+// Accept nsRefPtr/nsCOMPtr
+template <template <typename> class SmartPtr, typename T>
+bool
+ToJSValue(JSContext* aCx,
+          const SmartPtr<T>& aArgument,
+          JS::MutableHandle<JS::Value> aValue)
+{
+  return ToJSValue(aCx, *aArgument.get(), aValue);
+}
+
+// Accept arrays of other things we accept
+template <typename T>
+bool
+ToJSValue(JSContext* aCx,
+          const nsTArray<T>& aArgument,
+          JS::MutableHandle<JS::Value> aValue)
+{
+  // Make sure we're called in a compartment
+  MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
+
+  JS::AutoValueVector v(aCx);
+  if (!v.resize(aArgument.Length())) {
+    return false;
+  }
+  for (uint32_t i = 0; i < aArgument.Length(); ++i) {
+    if (!ToJSValue(aCx, aArgument[i], v.handleAt(i))) {
+      return false;
+    }
+  }
+  JSObject* arrayObj = JS_NewArrayObject(aCx, v);
+  if (!arrayObj) {
+    return false;
+  }
+  aValue.setObject(*arrayObj);
+  return true;
+}
+
+} // namespace dom
+} // namespace mozilla
+
+#endif /* mozilla_dom_ToJSValue_h */
--- a/dom/bindings/moz.build
+++ b/dom/bindings/moz.build
@@ -24,16 +24,17 @@ EXPORTS.mozilla.dom += [
     'Errors.msg',
     'Exceptions.h',
     'JSSlots.h',
     'NonRefcountedDOMObject.h',
     'Nullable.h',
     'OwningNonNull.h',
     'PrimitiveConversions.h',
     'RootedDictionary.h',
+    'ToJSValue.h',
     'TypedArray.h',
     'UnionMember.h',
 ]
 
 FAIL_ON_WARNINGS = True
 
 MSVC_ENABLE_PGO = True
 
@@ -71,16 +72,17 @@ LOCAL_INCLUDES += [
 
 UNIFIED_SOURCES += [
     'BindingUtils.cpp',
     'CallbackInterface.cpp',
     'CallbackObject.cpp',
     'Date.cpp',
     'DOMJSProxyHandler.cpp',
     'Exceptions.cpp',
+    'ToJSValue.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 if CONFIG['MOZ_AUDIO_CHANNEL_MANAGER']:
     LOCAL_INCLUDES += [
         '/dom/system/gonk',
     ]
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -1124,39 +1124,10 @@ bool
 PromiseReportRejectFeature::Notify(JSContext* aCx, workers::Status aStatus)
 {
   MOZ_ASSERT(aStatus > workers::Running);
   mPromise->MaybeReportRejectedOnce();
   // After this point, `this` has been deleted by RemoveFeature!
   return true;
 }
 
-bool
-Promise::ArgumentToJSValue(const nsAString& aArgument,
-                           JSContext* aCx,
-                           JS::MutableHandle<JS::Value> aValue)
-{
-  // XXXkhuey I'd love to use xpc::NonVoidStringToJsval here, but it requires
-  // a non-const nsAString for silly reasons.
-  nsStringBuffer* sharedBuffer;
-  if (!XPCStringConvert::ReadableToJSVal(aCx, aArgument, &sharedBuffer,
-                                         aValue)) {
-    return false;
-  }
-
-  if (sharedBuffer) {
-    NS_ADDREF(sharedBuffer);
-  }
-
-  return true;
-}
-
-bool
-Promise::ArgumentToJSValue(bool aArgument,
-                           JSContext* aCx,
-                           JS::MutableHandle<JS::Value> aValue)
-{
-  aValue.setBoolean(aArgument);
-  return true;
-}
-
 } // namespace dom
 } // namespace mozilla
--- a/dom/promise/Promise.h
+++ b/dom/promise/Promise.h
@@ -8,21 +8,20 @@
 #define mozilla_dom_Promise_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/TypeTraits.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/dom/PromiseBinding.h"
-#include "mozilla/dom/TypedArray.h"
+#include "mozilla/dom/ToJSValue.h"
 #include "nsWrapperCache.h"
 #include "nsAutoPtr.h"
 #include "js/TypeDecls.h"
-#include "jsapi.h"
 
 #include "mozilla/dom/workers/bindings/WorkerFeature.h"
 
 class nsIGlobalObject;
 
 namespace mozilla {
 namespace dom {
 
@@ -75,17 +74,17 @@ public:
 
   void MaybeResolve(JSContext* aCx,
                     JS::Handle<JS::Value> aValue);
   void MaybeReject(JSContext* aCx,
                    JS::Handle<JS::Value> aValue);
 
   // Helpers for using Promise from C++.
   // Most DOM objects are handled already.  To add a new type T, such as ints,
-  // or dictionaries, add an ArgumentToJSValue overload below.
+  // or dictionaries, add a ToJSValue overload in ToJSValue.h.
   template <typename T>
   void MaybeResolve(T& aArg) {
     MaybeSomething(aArg, &Promise::MaybeResolve);
   }
 
   template <typename T>
   void MaybeReject(T& aArg) {
     MaybeSomething(aArg, &Promise::MaybeReject);
@@ -199,117 +198,29 @@ private:
 
   void RejectInternal(JSContext* aCx,
                       JS::Handle<JS::Value> aValue,
                       PromiseTaskSync aSync = AsyncTask);
 
   // Helper methods for using Promises from C++
   JSObject* GetOrCreateWrapper(JSContext* aCx);
 
-  // If ArgumentToJSValue returns false, it must set an exception on the
-  // JSContext.
-
-  // Accept strings.
-  bool
-  ArgumentToJSValue(const nsAString& aArgument,
-                    JSContext* aCx,
-                    JS::MutableHandle<JS::Value> aValue);
-
-  // Accept booleans.
-  bool
-  ArgumentToJSValue(bool aArgument,
-                    JSContext* aCx,
-                    JS::MutableHandle<JS::Value> aValue);
-
-  // Accept objects that inherit from nsWrapperCache and nsISupports (e.g. most
-  // DOM objects).
-  template <class T>
-  typename EnableIf<IsBaseOf<nsWrapperCache, T>::value &&
-                    IsBaseOf<nsISupports, T>::value, bool>::Type
-  ArgumentToJSValue(T& aArgument,
-                    JSContext* aCx,
-                    JS::MutableHandle<JS::Value> aValue)
-  {
-    return WrapNewBindingObject(aCx, aArgument, aValue);
-  }
-
-  // Accept typed arrays built from appropriate nsTArray values
-  template<typename T>
-  typename EnableIf<IsBaseOf<AllTypedArraysBase, T>::value, bool>::Type
-  ArgumentToJSValue(const TypedArrayCreator<T>& aArgument,
-                    JSContext* aCx,
-                    JS::MutableHandle<JS::Value> aValue)
-  {
-    JSObject* abv = aArgument.Create(aCx);
-    if (!abv) {
-      return false;
-    }
-    aValue.setObject(*abv);
-    return true;
-  }
-
-  // Accept objects that inherit from nsISupports but not nsWrapperCache (e.g.
-  // nsIDOMFile).
-  template <class T>
-  typename EnableIf<!IsBaseOf<nsWrapperCache, T>::value &&
-                    IsBaseOf<nsISupports, T>::value, bool>::Type
-  ArgumentToJSValue(T& aArgument,
-                    JSContext* aCx,
-                    JS::MutableHandle<JS::Value> aValue)
-  {
-    nsresult rv = nsContentUtils::WrapNative(aCx, &aArgument, aValue);
-    return NS_SUCCEEDED(rv);
-  }
-
-  template <template <typename> class SmartPtr, typename T>
-  bool
-  ArgumentToJSValue(const SmartPtr<T>& aArgument,
-                    JSContext* aCx,
-                    JS::MutableHandle<JS::Value> aValue)
-  {
-    return ArgumentToJSValue(*aArgument.get(), aCx, aValue);
-  }
-
-  // Accept arrays of other things we accept
-  template <typename T>
-  bool
-  ArgumentToJSValue(const nsTArray<T>& aArgument,
-                    JSContext* aCx,
-                    JS::MutableHandle<JS::Value> aValue)
-  {
-    JS::AutoValueVector v(aCx);
-    if (!v.resize(aArgument.Length())) {
-      return false;
-    }
-    for (uint32_t i = 0; i < aArgument.Length(); ++i) {
-      if (!ArgumentToJSValue(aArgument[i], aCx, v.handleAt(i))) {
-        return false;
-      }
-    }
-    JSObject* arrayObj = JS_NewArrayObject(aCx, v);
-    if (!arrayObj) {
-      return false;
-    }
-    aValue.setObject(*arrayObj);
-    return true;
-  }
-
   template <typename T>
   void MaybeSomething(T& aArgument, MaybeFunc aFunc) {
     ThreadsafeAutoJSContext cx;
 
     JSObject* wrapper = GetOrCreateWrapper(cx);
     if (!wrapper) {
       HandleException(cx);
       return;
     }
 
     JSAutoCompartment ac(cx, wrapper);
     JS::Rooted<JS::Value> val(cx);
-    if (!ArgumentToJSValue(aArgument, cx, &val)) {
+    if (!ToJSValue(cx, aArgument, &val)) {
       HandleException(cx);
       return;
     }
 
     (this->*aFunc)(cx, val);
   }
 
   // Static methods for the PromiseInit functions.