Bug 868715 part 10. Create specializations of Optional for 'any' and 'object' types so that we can have those look like Optional<Handle<Value> > and Optional<Handle<JSObject*> > respectively. r=peterv,sfink, a=lsblakk
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 20 May 2013 23:54:38 -0400
changeset 138517 671534d5aa664a0b4be54f33b38c1cb77203622d
parent 138516 6f0feec7b0b7b2831e1b64342d0474fe149c260c
child 138518 470da31aeb168b4f9e3fd16fbd5829667c23f55a
push id3776
push userbzbarsky@mozilla.com
push dateTue, 21 May 2013 03:55:12 +0000
treeherdermozilla-aurora@671534d5aa66 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv, sfink, lsblakk
bugs868715
milestone23.0a2
Bug 868715 part 10. Create specializations of Optional for 'any' and 'object' types so that we can have those look like Optional<Handle<Value> > and Optional<Handle<JSObject*> > respectively. r=peterv,sfink, a=lsblakk
content/html/content/public/HTMLCanvasElement.h
dom/bindings/BindingDeclarations.h
dom/bindings/Codegen.py
dom/bindings/test/TestBindingHeader.h
js/public/RootingAPI.h
--- a/content/html/content/public/HTMLCanvasElement.h
+++ b/content/html/content/public/HTMLCanvasElement.h
@@ -87,28 +87,28 @@ public:
     return GetUnsignedIntAttr(nsGkAtoms::width, DEFAULT_CANVAS_WIDTH);
   }
   void SetWidth(uint32_t aWidth, ErrorResult& aRv)
   {
     SetUnsignedIntAttr(nsGkAtoms::width, aWidth, aRv);
   }
   already_AddRefed<nsISupports>
   GetContext(JSContext* aCx, const nsAString& aContextId,
-             const Optional<JS::Rooted<JS::Value> >& aContextOptions,
+             const Optional<JS::Handle<JS::Value> >& aContextOptions,
              ErrorResult& aRv)
   {
     JS::Value contextOptions = aContextOptions.WasPassed()
                              ? aContextOptions.Value()
                              : JS::UndefinedValue();
     nsCOMPtr<nsISupports> context;
     aRv = GetContext(aContextId, contextOptions, aCx, getter_AddRefs(context));
     return context.forget();
   }
   void ToDataURL(JSContext* aCx, const nsAString& aType,
-                 const Optional<JS::Rooted<JS::Value> >& aParams,
+                 const Optional<JS::Handle<JS::Value> >& aParams,
                  nsAString& aDataURL, ErrorResult& aRv)
   {
     JS::Value params = aParams.WasPassed()
                      ? aParams.Value()
                      : JS::UndefinedValue();
     aRv = ToDataURL(aType, params, aCx, aDataURL);
   }
   void ToBlob(nsIFileCallback* aCallback, const nsAString& aType,
--- a/dom/bindings/BindingDeclarations.h
+++ b/dom/bindings/BindingDeclarations.h
@@ -220,28 +220,34 @@ private:
   // For callees that know we exist, we can be a stringbuffer/length/null-flag
   // triple.
   nsStringBuffer* mStringBuffer;
   uint32_t mLength;
   bool mIsNull;
 };
 
 // Class for representing optional arguments.
-template<typename T>
-class Optional
+template<typename T, typename InternalType>
+class Optional_base
 {
 public:
-  Optional()
+  Optional_base()
   {}
 
-  explicit Optional(const T& aValue)
+  explicit Optional_base(const T& aValue)
   {
     mImpl.construct(aValue);
   }
 
+  template<typename T1, typename T2>
+  explicit Optional_base(const T1& aValue1, const T2& aValue2)
+  {
+    mImpl.construct(aValue1, aValue2);
+  }
+
   bool WasPassed() const
   {
     return !mImpl.empty();
   }
 
   void Construct()
   {
     mImpl.construct();
@@ -254,36 +260,63 @@ public:
   }
 
   template <class T1, class T2>
   void Construct(const T1 &t1, const T2 &t2)
   {
     mImpl.construct(t1, t2);
   }
 
-  const T& Value() const
+  const InternalType& Value() const
   {
     return mImpl.ref();
   }
 
-  T& Value()
+  InternalType& Value()
   {
     return mImpl.ref();
   }
 
   // If we ever decide to add conversion operators for optional arrays
   // like the ones Nullable has, we'll need to ensure that Maybe<> has
   // the boolean before the actual data.
 
 private:
   // Forbid copy-construction and assignment
-  Optional(const Optional& other) MOZ_DELETE;
-  const Optional &operator=(const Optional &other) MOZ_DELETE;
+  Optional_base(const Optional_base& other) MOZ_DELETE;
+  const Optional_base &operator=(const Optional_base &other) MOZ_DELETE;
+
+  Maybe<InternalType> mImpl;
+};
+
+template<typename T>
+class Optional : public Optional_base<T, T>
+{
+public:
+  Optional() :
+    Optional_base<T, T>()
+  {}
 
-  Maybe<T> mImpl;
+  explicit Optional(const T& aValue) :
+    Optional_base<T, T>(aValue)
+  {}
+};
+
+template<typename T>
+class Optional<JS::Handle<T> > :
+  public Optional_base<JS::Handle<T>, JS::Rooted<T> >
+{
+public:
+  Optional() :
+    Optional_base<JS::Handle<T>, JS::Rooted<T> >()
+  {}
+
+  Optional(JSContext* cx, const T& aValue) :
+    Optional_base<JS::Handle<T>, JS::Rooted<T> >(cx, aValue)
+  {}
 };
 
 // Specialization for strings.
 // XXXbz we can't pull in FakeDependentString here, because it depends on
 // internal strings.  So we just have to forward-declare it and reimplement its
 // ToAStringPtr.
 
 struct FakeDependentString;
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2614,17 +2614,22 @@ def getJSToNativeConversionInfo(type, de
             else:
                 assert(defaultValue is None)
 
         return templateBody
 
     # A helper function for converting things that look like a JSObject*.
     def handleJSObjectType(type, isMember, failureCode):
         if not isMember:
-            declType = CGGeneric("JS::Rooted<JSObject*>")
+            if isOptional:
+                # We have a specialization of Optional that will use a
+                # Rooted for the storage here.
+                declType = CGGeneric("JS::Handle<JSObject*>")
+            else:
+                declType = CGGeneric("JS::Rooted<JSObject*>")
         else:
             assert (isMember == "Sequence" or isMember == "Variadic" or
                     isMember == "Dictionary")
             # We'll get traced by the sequence or dictionary tracer
             declType = CGGeneric("JSObject*")
         templateBody = "${declName} = &${valHandle}.toObject();"
         setToNullCode = "${declName} = nullptr;"
         template = wrapObjectTemplate(templateBody, type, setToNullCode,
@@ -3317,17 +3322,22 @@ for (uint32_t i = 0; i < length; ++i) {
 
         declArgs = None
         if (isMember == "Variadic" or isMember == "Sequence" or
             isMember == "Dictionary"):
             # Rooting is handled by the sequence and dictionary tracers.
             declType = "JS::Value"
         else:
             assert not isMember
-            declType = "JS::Rooted<JS::Value>"
+            if isOptional:
+                # We have a specialization of Optional that will use a
+                # Rooted for the storage here.
+                declType = "JS::Handle<JS::Value>"
+            else:
+                declType = "JS::Rooted<JS::Value>"
             declArgs = "cx"
 
         templateBody = "${declName} = ${val};"
         nullHandling = "${declName} = JS::NullValue()"
 
         templateBody = handleDefaultNull(templateBody, nullHandling)
         return JSToNativeConversionInfo(templateBody,
                                         declType=CGGeneric(declType),
@@ -8469,27 +8479,23 @@ class CGNativeMember(ClassMethod):
             else:
                 name = type.unroll().inner.identifier.name
             return declType % name, False, False
 
         if type.isAny():
             # Don't do the rooting stuff for variadics for now
             if isMember:
                 declType = "JS::Value"
-            elif optional:
-                declType = "JS::Rooted<JS::Value>"
             else:
                 declType = "JS::Handle<JS::Value>"
             return declType, False, False
 
         if type.isObject():
             if isMember:
                 declType = "JSObject*"
-            elif optional:
-                declType = "JS::Rooted<JSObject*>"
             else:
                 declType = "JS::Handle<JSObject*>"
             return declType, False, False
 
         if type.isDictionary():
             typeName = CGDictionary.makeDictionaryName(type.inner,
                                                        self.descriptor.workers)
             return typeName, True, True
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -135,19 +135,19 @@ public:
   static
   already_AddRefed<TestInterface> Test2(const GlobalObject&,
                                         JSContext*,
                                         const DictForConstructor&,
                                         JS::Value,
                                         JS::Handle<JSObject*>,
                                         JS::Handle<JSObject*>,
                                         const Sequence<Dict>&,
-                                        const Optional<JS::Rooted<JS::Value> >&,
-                                        const Optional<JS::Rooted<JSObject*> >&,
-                                        const Optional<JS::Rooted<JSObject*> >&,
+                                        const Optional<JS::Handle<JS::Value> >&,
+                                        const Optional<JS::Handle<JSObject*> >&,
+                                        const Optional<JS::Handle<JSObject*> >&,
                                         ErrorResult&);
 
   // Integer types
   int8_t ReadonlyByte();
   int8_t WritableByte();
   void SetWritableByte(int8_t);
   void PassByte(int8_t);
   int8_t ReceiveByte();
@@ -429,17 +429,17 @@ public:
   void SetTreatAsNullCallback(TestTreatAsNullCallback&);
   already_AddRefed<TestTreatAsNullCallback> TreatAsNullCallback();
   void SetNullableTreatAsNullCallback(TestTreatAsNullCallback*);
   already_AddRefed<TestTreatAsNullCallback> GetNullableTreatAsNullCallback();
 
   // Any types
   void PassAny(JSContext*, JS::Handle<JS::Value>);
   void PassVariadicAny(JSContext*, const Sequence<JS::Value>&);
-  void PassOptionalAny(JSContext*, const Optional<JS::Rooted<JS::Value> >&);
+  void PassOptionalAny(JSContext*, const Optional<JS::Handle<JS::Value> >&);
   void PassAnyDefaultNull(JSContext*, JS::Handle<JS::Value>);
   void PassSequenceOfAny(JSContext*, const Sequence<JS::Value>&);
   void PassNullableSequenceOfAny(JSContext*, const Nullable<Sequence<JS::Value> >&);
   void PassOptionalSequenceOfAny(JSContext*, const Optional<Sequence<JS::Value> >&);
   void PassOptionalNullableSequenceOfAny(JSContext*, const Optional<Nullable<Sequence<JS::Value> > >&);
   void PassOptionalSequenceOfAnyWithDefaultValue(JSContext*, const Nullable<Sequence<JS::Value> >&);
   void PassSequenceOfSequenceOfAny(JSContext*, const Sequence<Sequence<JS::Value> >&);
   void PassSequenceOfNullableSequenceOfAny(JSContext*, const Sequence<Nullable<Sequence<JS::Value> > >&);
@@ -447,18 +447,18 @@ public:
   void PassOptionalNullableSequenceOfNullableSequenceOfAny(JSContext*, const Optional<Nullable<Sequence<Nullable<Sequence<JS::Value> > > > >&);
   JS::Value ReceiveAny(JSContext*);
 
   // object types
   void PassObject(JSContext*, JS::Handle<JSObject*>);
   void PassVariadicObject(JSContext*, const Sequence<JSObject*>&);
   void PassNullableObject(JSContext*, JS::Handle<JSObject*>);
   void PassVariadicNullableObject(JSContext*, const Sequence<JSObject*>&);
-  void PassOptionalObject(JSContext*, const Optional<JS::Rooted<JSObject*> >&);
-  void PassOptionalNullableObject(JSContext*, const Optional<JS::Rooted<JSObject*> >&);
+  void PassOptionalObject(JSContext*, const Optional<JS::Handle<JSObject*> >&);
+  void PassOptionalNullableObject(JSContext*, const Optional<JS::Handle<JSObject*> >&);
   void PassOptionalNullableObjectWithDefaultValue(JSContext*, JS::Handle<JSObject*>);
   void PassSequenceOfObject(JSContext*, const Sequence<JSObject*>&);
   void PassSequenceOfNullableObject(JSContext*, const Sequence<JSObject*>&);
   void PassOptionalNullableSequenceOfNullableSequenceOfObject(JSContext*, const Optional<Nullable<Sequence<Nullable<Sequence<JSObject*> > > > >&);
   void PassOptionalNullableSequenceOfNullableSequenceOfNullableObject(JSContext*, const Optional<Nullable<Sequence<Nullable<Sequence<JSObject*> > > > >&);
   JSObject* ReceiveObject(JSContext*);
   JSObject* ReceiveNullableObject(JSContext*);
 
@@ -729,17 +729,17 @@ private:
   void PassOptionalSequence(Optional<Sequence<int32_t> >&) MOZ_DELETE;
   void PassOptionalNullableSequence(Optional<Nullable<Sequence<int32_t> > >&) MOZ_DELETE;
   void PassOptionalObjectSequence(Optional<Sequence<OwningNonNull<TestInterface> > >&) MOZ_DELETE;
   void PassOptionalArrayBuffer(Optional<ArrayBuffer>&) MOZ_DELETE;
   void PassOptionalNullableArrayBuffer(Optional<ArrayBuffer*>&) MOZ_DELETE;
   void PassOptionalEnum(Optional<TestEnum>&) MOZ_DELETE;
   void PassOptionalCallback(JSContext*, Optional<OwningNonNull<TestCallback> >&) MOZ_DELETE;
   void PassOptionalNullableCallback(JSContext*, Optional<nsRefPtr<TestCallback> >&) MOZ_DELETE;
-  void PassOptionalAny(Optional<JS::Rooted<JS::Value> >&) MOZ_DELETE;
+  void PassOptionalAny(Optional<JS::Handle<JS::Value> >&) MOZ_DELETE;
 
   // And test that string stuff is always const
   void PassString(nsAString&) MOZ_DELETE;
   void PassNullableString(nsAString&) MOZ_DELETE;
   void PassOptionalString(Optional<nsAString>&) MOZ_DELETE;
   void PassOptionalStringWithDefaultValue(nsAString&) MOZ_DELETE;
   void PassOptionalNullableString(Optional<nsAString>&) MOZ_DELETE;
   void PassOptionalNullableStringWithDefaultValue(nsAString&) MOZ_DELETE;
--- a/js/public/RootingAPI.h
+++ b/js/public/RootingAPI.h
@@ -215,17 +215,17 @@ class MOZ_STACK_CLASS Handle : public js
     }
 
     /*
      * Construct a handle from an explicitly rooted location. This is the
      * normal way to create a handle, and normally happens implicitly.
      */
     template <typename S>
     inline
-    Handle(Rooted<S> &root,
+    Handle(const Rooted<S> &root,
            typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy = 0);
 
     /* Construct a read only handle from a mutable handle. */
     template <typename S>
     inline
     Handle(MutableHandle<S> &root,
            typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy = 0);
 
@@ -738,17 +738,17 @@ template <typename T> class MaybeRooted<
 };
 
 } /* namespace js */
 
 namespace JS {
 
 template <typename T> template <typename S>
 inline
-Handle<T>::Handle(Rooted<S> &root,
+Handle<T>::Handle(const Rooted<S> &root,
                   typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy)
 {
     ptr = reinterpret_cast<const T *>(root.address());
 }
 
 template <typename T> template <typename S>
 inline
 Handle<T>::Handle(MutableHandle<S> &root,