Bug 994793. Make the array bits of ToJSValue nicer. r=bholley
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 10 Apr 2014 14:57:42 -0400
changeset 178028 4182ec5042d5ebd501f4d6fe8c5d158e215db2d5
parent 178027 45d3f9cfb0df50c6669d1318ff0965286c9acd0d
child 178029 52da0fc935cec05dc09f1a9ac05a5259ae977fba
push id26569
push userryanvm@gmail.com
push dateFri, 11 Apr 2014 04:11:36 +0000
treeherdermozilla-central@783c5013dbec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs994793
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 994793. Make the array bits of ToJSValue nicer. r=bholley
content/canvas/src/CanvasRenderingContext2D.cpp
content/canvas/src/CanvasUtils.h
content/canvas/src/WebGLContextGL.cpp
content/canvas/src/WebGLContextState.cpp
dom/bindings/ToJSValue.h
dom/mobilemessage/src/SmsFilter.cpp
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -68,16 +68,17 @@
 #include "jsfriendapi.h"
 
 #include "mozilla/Alignment.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/PBrowserParent.h"
+#include "mozilla/dom/ToJSValue.h"
 #include "mozilla/dom/TypedArray.h"
 #include "mozilla/Endian.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/PathHelpers.h"
 #include "mozilla/gfx/DataSurfaceHelpers.h"
 #include "mozilla/ipc/DocumentRendererParent.h"
 #include "mozilla/ipc/PDocumentRendererParent.h"
 #include "mozilla/MathAlgorithms.h"
@@ -1268,27 +1269,28 @@ CanvasRenderingContext2D::SetTransform(d
 
   Matrix matrix(m11, m12, m21, m22, dx, dy);
   mTarget->SetTransform(matrix);
 }
 
 JSObject*
 MatrixToJSObject(JSContext* cx, const Matrix& matrix, ErrorResult& error)
 {
-  JS::AutoValueArray<6> elts(cx);
-  elts[0].setDouble(matrix._11); elts[1].setDouble(matrix._12);
-  elts[2].setDouble(matrix._21); elts[3].setDouble(matrix._22);
-  elts[4].setDouble(matrix._31); elts[5].setDouble(matrix._32);
+  double elts[6] = { matrix._11, matrix._12,
+                     matrix._21, matrix._22,
+                     matrix._31, matrix._32 };
 
   // XXX Should we enter GetWrapper()'s compartment?
-  JSObject* obj = JS_NewArrayObject(cx, elts);
-  if  (!obj) {
+  JS::Rooted<JS::Value> val(cx);
+  if (!ToJSValue(cx, elts, &val)) {
     error.Throw(NS_ERROR_OUT_OF_MEMORY);
-  }
-  return obj;
+    return nullptr;
+  }
+
+  return &val.toObject();
 }
 
 static bool
 ObjectToMatrix(JSContext* cx, JS::Handle<JSObject*> obj, Matrix& matrix,
                ErrorResult& error)
 {
   uint32_t length;
   if (!JS_GetArrayLength(cx, obj, &length) || length != 6) {
--- a/content/canvas/src/CanvasUtils.h
+++ b/content/canvas/src/CanvasUtils.h
@@ -2,16 +2,17 @@
 /* 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 _CANVASUTILS_H_
 #define _CANVASUTILS_H_
 
 #include "mozilla/CheckedInt.h"
+#include "mozilla/dom/ToJSValue.h"
 #include "jsapi.h"
 
 class nsIPrincipal;
 
 namespace mozilla {
 
 namespace gfx {
 class Matrix;
@@ -150,31 +151,21 @@ JSValToDashArray(JSContext* cx, const JS
 }
 
 template<typename T>
 JS::Value
 DashArrayToJSVal(FallibleTArray<T>& dashes,
                  JSContext* cx, mozilla::ErrorResult& rv)
 {
     if (dashes.IsEmpty()) {
-        return JSVAL_NULL;
-    }
-    JS::Rooted<JSObject*> obj(cx,
-        JS_NewArrayObject(cx, dashes.Length()));
-    if (!obj) {
-        rv.Throw(NS_ERROR_OUT_OF_MEMORY);
-        return JSVAL_NULL;
+        return JS::NullValue();
     }
-    for (uint32_t i = 0; i < dashes.Length(); ++i) {
-        double d = dashes[i];
-        JS::Value elt = DOUBLE_TO_JSVAL(d);
-        if (!JS_DefineElement(cx, obj, i, elt, nullptr, nullptr, 0)) {
-            rv.Throw(NS_ERROR_FAILURE);
-            return JSVAL_NULL;
-        }
+    JS::Rooted<JS::Value> val(cx);
+    if (!mozilla::dom::ToJSValue(cx, dashes, &val)) {
+        rv.Throw(NS_ERROR_OUT_OF_MEMORY);
     }
-    return OBJECT_TO_JSVAL(obj);
+    return val;
 }
 
 }
 }
 
 #endif /* _CANVASUTILS_H_ */
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -39,16 +39,17 @@
 
 // needed to check if current OS is lower than 10.7
 #if defined(MOZ_WIDGET_COCOA)
 #include "nsCocoaFeatures.h"
 #endif
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ImageData.h"
+#include "mozilla/dom/ToJSValue.h"
 #include "mozilla/Endian.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::gl;
 using namespace mozilla::gfx;
 
 static bool BaseTypeAndSizeFromUniformType(GLenum uType, GLenum *baseType, GLint *unitSize);
@@ -1724,25 +1725,26 @@ WebGLContext::GetUniform(JSContext* cx, 
             return JS::ObjectOrNullValue(obj);
         }
     } else if (baseType == LOCAL_GL_BOOL) {
         GLint iv[16] = { 0 };
         gl->fGetUniformiv(progname, location->Location(), iv);
         if (unitSize == 1) {
             return JS::BooleanValue(iv[0] ? true : false);
         } else {
-            JS::AutoValueArray<16> uv(cx);
+            bool uv[16];
             for (int k = 0; k < unitSize; k++)
-                uv[k].setBoolean(iv[k]);
-            JSObject* obj = JS_NewArrayObject(cx, JS::HandleValueArray::subarray(uv, 0, unitSize));
-            if (!obj) {
+                uv[k] = iv[k];
+            JS::Rooted<JS::Value> val(cx);
+            // Be careful: we don't want to convert all of |uv|!
+            if (!ToJSValue(cx, uv, unitSize, &val)) {
                 ErrorOutOfMemory("getUniform: out of memory");
                 return JS::NullValue();
             }
-            return JS::ObjectOrNullValue(obj);
+            return val;
         }
     }
 
     // Else preserving behavior, but I'm not sure this is correct per spec
     return JS::UndefinedValue();
 }
 
 already_AddRefed<WebGLUniformLocation>
--- a/content/canvas/src/WebGLContextState.cpp
+++ b/content/canvas/src/WebGLContextState.cpp
@@ -419,21 +419,18 @@ WebGLContext::GetParameter(JSContext* cx
             }
             return JS::ObjectOrNullValue(obj);
         }
 
         case LOCAL_GL_COLOR_WRITEMASK: // 4 bools
         {
             realGLboolean gl_bv[4] = { 0 };
             gl->fGetBooleanv(pname, gl_bv);
-            nsAutoTArray<bool, 4> vals;
-            vals.AppendElement(gl_bv[0]);
-            vals.AppendElement(gl_bv[1]);
-            vals.AppendElement(gl_bv[2]);
-            vals.AppendElement(gl_bv[3]);
+            bool vals[4] = { bool(gl_bv[0]), bool(gl_bv[1]),
+                             bool(gl_bv[2]), bool(gl_bv[3]) };
             JS::Rooted<JS::Value> arr(cx);
             if (!ToJSValue(cx, vals, &arr)) {
                 rv = NS_ERROR_OUT_OF_MEMORY;
             }
             return arr;
         }
 
         case LOCAL_GL_ARRAY_BUFFER_BINDING:
--- a/dom/bindings/ToJSValue.h
+++ b/dom/bindings/ToJSValue.h
@@ -85,16 +85,41 @@ ToJSValue(JSContext* aCx,
 {
   // Make sure we're called in a compartment
   MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
 
   aValue.setNumber(double(aArgument));
   return true;
 }
 
+// accept floating point types
+inline bool
+ToJSValue(JSContext* aCx,
+          float 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,
+          double aArgument,
+          JS::MutableHandle<JS::Value> aValue)
+{
+  // Make sure we're called in a compartment
+  MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
+
+  aValue.setNumber(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)
@@ -145,48 +170,87 @@ ToJSValue(JSContext* aCx,
 {
   // 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>
+template <typename T>
 bool
 ToJSValue(JSContext* aCx,
-          const SmartPtr<T>& aArgument,
+          const nsCOMPtr<T>& aArgument,
+          JS::MutableHandle<JS::Value> aValue)
+{
+  return ToJSValue(aCx, *aArgument.get(), aValue);
+}
+
+template <typename T>
+bool
+ToJSValue(JSContext* aCx,
+          const nsRefPtr<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,
+          T* aArguments,
+          size_t aLength,
           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())) {
+  if (!v.resize(aLength)) {
     return false;
   }
-  for (uint32_t i = 0; i < aArgument.Length(); ++i) {
-    if (!ToJSValue(aCx, aArgument[i], v.handleAt(i))) {
+  for (size_t i = 0; i < aLength; ++i) {
+    if (!ToJSValue(aCx, aArguments[i], v.handleAt(i))) {
       return false;
     }
   }
   JSObject* arrayObj = JS_NewArrayObject(aCx, v);
   if (!arrayObj) {
     return false;
   }
   aValue.setObject(*arrayObj);
   return true;
 }
 
+template <typename T>
+bool
+ToJSValue(JSContext* aCx,
+          const nsTArray<T>& aArgument,
+          JS::MutableHandle<JS::Value> aValue)
+{
+  return ToJSValue(aCx, aArgument.Elements(),
+                   aArgument.Length(), aValue);
+}
+
+template <typename T>
+bool
+ToJSValue(JSContext* aCx,
+          const FallibleTArray<T>& aArgument,
+          JS::MutableHandle<JS::Value> aValue)
+{
+  return ToJSValue(aCx, aArgument.Elements(),
+                   aArgument.Length(), aValue);
+}
+
+template <typename T, int N>
+bool
+ToJSValue(JSContext* aCx,
+          const T(&aArgument)[N],
+          JS::MutableHandle<JS::Value> aValue)
+{
+  return ToJSValue(aCx, aArgument, N, aValue);
+}
+
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_ToJSValue_h */
--- a/dom/mobilemessage/src/SmsFilter.cpp
+++ b/dom/mobilemessage/src/SmsFilter.cpp
@@ -3,16 +3,17 @@
  * 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 "SmsFilter.h"
 #include "jsapi.h"
 #include "jsfriendapi.h" // For js_DateGetMsecSinceEpoch.
 #include "js/Utility.h"
 #include "mozilla/dom/mobilemessage/Constants.h" // For MessageType
+#include "mozilla/dom/ToJSValue.h"
 #include "nsDOMString.h"
 #include "nsError.h"
 #include "nsIDOMClassInfo.h"
 #include "nsJSUtils.h"
 
 using namespace mozilla::dom::mobilemessage;
 
 DOMCI_DATA(MozSmsFilter, mozilla::dom::SmsFilter)
@@ -125,37 +126,20 @@ SmsFilter::GetNumbers(JSContext* aCx, JS
 {
   uint32_t length = mData.numbers().Length();
 
   if (length == 0) {
     aNumbers.setNull();
     return NS_OK;
   }
 
-  JS::AutoValueVector numbers(aCx);
-  if (!numbers.resize(length)) {
+  if (!ToJSValue(aCx, mData.numbers(), aNumbers)) {
     return NS_ERROR_FAILURE;
   }
 
-  for (uint32_t i = 0; i < length; ++i) {
-    JSString* str = JS_NewUCStringCopyN(aCx, mData.numbers()[i].get(),
-                                        mData.numbers()[i].Length());
-    if (!str) {
-      return NS_ERROR_FAILURE;
-    }
-
-    numbers[i].setString(str);
-  }
-
-  JSObject* obj = JS_NewArrayObject(aCx, numbers);
-  if (!obj) {
-    return NS_ERROR_FAILURE;
-  }
-
-  aNumbers.setObject(*obj);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SmsFilter::SetNumbers(JSContext* aCx, JS::Handle<JS::Value> aNumbers)
 {
   if (aNumbers.isNull()) {
     mData.numbers().Clear();