Bug 1009675 - Part 3: Return WebIDL 'object' values as handles. r=peterv, a=sledru
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 11 Jun 2014 16:26:52 -0400
changeset 208032 d740cc08d96661ec5625522b5a2a663f62ecc52f
parent 208031 e993e93566fefbab6196d76a8876c282fe5f971e
child 208033 6e0f4138959eb70c06742de392562e68ce1bdea6
push id494
push userraliiev@mozilla.com
push dateMon, 25 Aug 2014 18:42:16 +0000
treeherdermozilla-release@a3cc3e46b571 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv, sledru
bugs1009675
milestone32.0a2
Bug 1009675 - Part 3: Return WebIDL 'object' values as handles. r=peterv, a=sledru
content/base/public/nsIDocument.h
content/base/src/nsDocument.cpp
content/base/src/nsDocument.h
content/canvas/src/CanvasRenderingContext2D.cpp
content/canvas/src/CanvasRenderingContext2D.h
content/canvas/src/ImageData.h
content/canvas/src/WebGLContext.h
content/canvas/src/WebGLContextExtensions.cpp
content/html/content/public/HTMLMediaElement.h
content/html/content/src/HTMLMediaElement.cpp
content/html/document/src/nsHTMLDocument.cpp
content/html/document/src/nsHTMLDocument.h
content/media/eme/MediaKeyMessageEvent.cpp
content/media/eme/MediaKeyMessageEvent.h
content/media/eme/MediaKeyNeededEvent.cpp
content/media/eme/MediaKeyNeededEvent.h
content/media/webaudio/AudioBuffer.cpp
content/media/webaudio/AudioBuffer.h
content/media/webaudio/WaveShaperNode.h
dom/base/Crypto.cpp
dom/base/Crypto.h
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/bindings/Codegen.py
dom/bindings/test/TestBindingHeader.h
dom/crypto/RsaKeyAlgorithm.h
dom/encoding/TextEncoder.cpp
dom/encoding/TextEncoder.h
dom/nfc/MozNDEFRecord.h
dom/webidl/SubtleCrypto.webidl
dom/workers/FileReaderSync.cpp
dom/workers/FileReaderSync.h
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -2082,19 +2082,20 @@ public:
   virtual void EnqueueLifecycleCallback(ElementCallbackType aType,
                                         Element* aCustomElement,
                                         mozilla::dom::LifecycleCallbackArgs* aArgs = nullptr,
                                         mozilla::dom::CustomElementDefinition* aDefinition = nullptr) = 0;
   virtual void SwizzleCustomElement(Element* aElement,
                                     const nsAString& aTypeExtension,
                                     uint32_t aNamespaceID,
                                     mozilla::ErrorResult& rv) = 0;
-  virtual JSObject*
+  virtual void
     RegisterElement(JSContext* aCx, const nsAString& aName,
                     const mozilla::dom::ElementRegistrationOptions& aOptions,
+                    JS::MutableHandle<JSObject*> aRetval,
                     mozilla::ErrorResult& rv) = 0;
 
   /**
    * In some cases, new document instances must be associated with
    * an existing web components custom element registry as specified.
    */
   virtual void UseRegistryFromDocument(nsIDocument* aDocument) = 0;
 
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -5762,24 +5762,25 @@ nsDocument::RegisterEnabled()
 // static
 Maybe<nsTArray<mozilla::dom::CustomElementData*>>
 nsDocument::sProcessingStack;
 
 // static
 bool
 nsDocument::sProcessingBaseElementQueue;
 
-JSObject*
+void
 nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
                             const ElementRegistrationOptions& aOptions,
+                            JS::MutableHandle<JSObject*> aRetval,
                             ErrorResult& rv)
 {
   if (!mRegistry) {
     rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-    return nullptr;
+    return;
   }
 
   Registry::DefinitionMap& definitions = mRegistry->mCustomDefinitions;
 
   // Unconditionally convert TYPE to lowercase.
   nsAutoString lcType;
   nsContentUtils::ASCIIToLower(aType, lcType);
 
@@ -5790,88 +5791,88 @@ nsDocument::RegisterElement(JSContext* a
     nsContentUtils::ASCIIToLower(aOptions.mExtends, lcName);
   } else {
     lcName.Assign(aOptions.mExtends);
   }
 
   nsCOMPtr<nsIAtom> typeAtom(do_GetAtom(lcType));
   if (!nsContentUtils::IsCustomElementName(typeAtom)) {
     rv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
-    return nullptr;
+    return;
   }
 
   // If there already exists a definition with the same TYPE, set ERROR to
   // DuplicateDefinition and stop.
   // Note that we need to find existing custom elements from either namespace.
   CustomElementHashKey duplicateFinder(kNameSpaceID_Unknown, typeAtom);
   if (definitions.Get(&duplicateFinder)) {
     rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-    return nullptr;
+    return;
   }
 
   nsIGlobalObject* sgo = GetScopeObject();
   if (!sgo) {
     rv.Throw(NS_ERROR_UNEXPECTED);
-    return nullptr;
+    return;
   }
   JS::Rooted<JSObject*> global(aCx, sgo->GetGlobalJSObject());
 
   JSAutoCompartment ac(aCx, global);
 
   JS::Handle<JSObject*> htmlProto(
     HTMLElementBinding::GetProtoObject(aCx, global));
   if (!htmlProto) {
     rv.Throw(NS_ERROR_OUT_OF_MEMORY);
-    return nullptr;
+    return;
   }
 
   int32_t namespaceID = kNameSpaceID_XHTML;
   JS::Rooted<JSObject*> protoObject(aCx);
   if (!aOptions.mPrototype) {
     protoObject = JS_NewObject(aCx, nullptr, htmlProto, JS::NullPtr());
     if (!protoObject) {
       rv.Throw(NS_ERROR_UNEXPECTED);
-      return nullptr;
+      return;
     }
   } else {
     // If a prototype is provided, we must check to ensure that it is from the
     // same browsing context as us.
     protoObject = aOptions.mPrototype;
     if (JS_GetGlobalForObject(aCx, protoObject) != global) {
       rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-      return nullptr;
+      return;
     }
 
     // If PROTOTYPE is already an interface prototype object for any interface
     // object or PROTOTYPE has a non-configurable property named constructor,
     // throw a NotSupportedError and stop.
     const js::Class* clasp = js::GetObjectClass(protoObject);
     if (IsDOMIfaceAndProtoClass(clasp)) {
       rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-      return nullptr;
+      return;
     }
 
     JS::Rooted<JSPropertyDescriptor> descRoot(aCx);
     JS::MutableHandle<JSPropertyDescriptor> desc(&descRoot);
     if (!JS_GetPropertyDescriptor(aCx, protoObject, "constructor", desc)) {
       rv.Throw(NS_ERROR_UNEXPECTED);
-      return nullptr;
+      return;
     }
 
     // Check if non-configurable
     if (desc.isPermanent()) {
       rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-      return nullptr;
+      return;
     }
 
     JS::Handle<JSObject*> svgProto(
       SVGElementBinding::GetProtoObject(aCx, global));
     if (!svgProto) {
       rv.Throw(NS_ERROR_OUT_OF_MEMORY);
-      return nullptr;
+      return;
     }
 
     JS::Rooted<JSObject*> protoProto(aCx, protoObject);
 
     // If PROTOTYPE's interface inherits from SVGElement, set NAMESPACE to SVG
     // Namespace.
     while (protoProto) {
       if (protoProto == htmlProto) {
@@ -5880,61 +5881,62 @@ nsDocument::RegisterElement(JSContext* a
 
       if (protoProto == svgProto) {
         namespaceID = kNameSpaceID_SVG;
         break;
       }
 
       if (!JS_GetPrototype(aCx, protoProto, &protoProto)) {
         rv.Throw(NS_ERROR_UNEXPECTED);
-        return nullptr;
+        return;
       }
     }
   }
 
   // If name was provided and not null...
   nsCOMPtr<nsIAtom> nameAtom;
   if (!lcName.IsEmpty()) {
     // Let BASE be the element interface for NAME and NAMESPACE.
     bool known = false;
     nameAtom = do_GetAtom(lcName);
     if (namespaceID == kNameSpaceID_XHTML) {
       nsIParserService* ps = nsContentUtils::GetParserService();
       if (!ps) {
         rv.Throw(NS_ERROR_UNEXPECTED);
-        return nullptr;
+        return;
       }
 
       known =
         ps->HTMLCaseSensitiveAtomTagToId(nameAtom) != eHTMLTag_userdefined;
     } else {
       known = SVGElementFactory::Exists(nameAtom);
     }
 
     // If BASE does not exist or is an interface for a custom element, set ERROR
     // to InvalidName and stop.
     // If BASE exists, then it cannot be an interface for a custom element.
     if (!known) {
       rv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
-      return nullptr;
+      return;
     }
   } else {
     // If NAMESPACE is SVG Namespace, set ERROR to InvalidName and stop.
     if (namespaceID == kNameSpaceID_SVG) {
       rv.Throw(NS_ERROR_UNEXPECTED);
-      return nullptr;
+      return;
     }
 
     nameAtom = typeAtom;
   }
 
   nsAutoPtr<LifecycleCallbacks> callbacksHolder(new LifecycleCallbacks());
   JS::RootedValue rootedv(aCx, JS::ObjectValue(*protoObject));
   if (!callbacksHolder->Init(aCx, rootedv)) {
-    return nullptr;
+    rv.Throw(NS_ERROR_FAILURE);
+    return;
   }
 
   // Associate the definition with the custom element.
   CustomElementHashKey key(namespaceID, typeAtom);
   LifecycleCallbacks* callbacks = callbacksHolder.forget();
   CustomElementDefinition* definition =
     new CustomElementDefinition(protoObject,
                                 typeAtom,
@@ -5983,18 +5985,22 @@ nsDocument::RegisterElement(JSContext* a
     }
   }
 
   // Create constructor to return. Store the name of the custom element as the
   // name of the function.
   JSFunction* constructor = JS_NewFunction(aCx, nsDocument::CustomElementConstructor, 0,
                                            JSFUN_CONSTRUCTOR, JS::NullPtr(),
                                            NS_ConvertUTF16toUTF8(lcType).get());
-  JSObject* constructorObject = JS_GetFunctionObject(constructor);
-  return constructorObject;
+  if (!constructor) {
+    rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
+
+  aRetval.set(JS_GetFunctionObject(constructor));
 }
 
 void
 nsDocument::UseRegistryFromDocument(nsIDocument* aDocument)
 {
   nsDocument* doc = static_cast<nsDocument*>(aDocument);
   MOZ_ASSERT(!mRegistry, "There should be no existing registry.");
   mRegistry = doc->mRegistry;
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -1221,19 +1221,20 @@ public:
   static bool RegisterEnabled();
 
   virtual nsresult RegisterUnresolvedElement(mozilla::dom::Element* aElement,
                                              nsIAtom* aTypeName = nullptr) MOZ_OVERRIDE;
 
   // WebIDL bits
   virtual mozilla::dom::DOMImplementation*
     GetImplementation(mozilla::ErrorResult& rv) MOZ_OVERRIDE;
-  virtual JSObject*
+  virtual void
     RegisterElement(JSContext* aCx, const nsAString& aName,
                     const mozilla::dom::ElementRegistrationOptions& aOptions,
+                    JS::MutableHandle<JSObject*> aRetval,
                     mozilla::ErrorResult& rv) MOZ_OVERRIDE;
   virtual mozilla::dom::StyleSheetList* StyleSheets() MOZ_OVERRIDE;
   virtual void SetSelectedStyleSheetSet(const nsAString& aSheetSet) MOZ_OVERRIDE;
   virtual void GetLastStyleSheetSet(nsString& aSheetSet) MOZ_OVERRIDE;
   virtual mozilla::dom::DOMStringList* StyleSheetSets() MOZ_OVERRIDE;
   virtual void EnableStyleSheetsForSet(const nsAString& aSheetSet) MOZ_OVERRIDE;
   using nsIDocument::CreateElement;
   using nsIDocument::CreateElementNS;
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -1262,31 +1262,31 @@ CanvasRenderingContext2D::SetTransform(d
     error.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   Matrix matrix(m11, m12, m21, m22, dx, dy);
   mTarget->SetTransform(matrix);
 }
 
-JSObject*
-MatrixToJSObject(JSContext* cx, const Matrix& matrix, ErrorResult& error)
+static void
+MatrixToJSObject(JSContext* cx, const Matrix& matrix,
+                 JS::MutableHandle<JSObject*> result, ErrorResult& error)
 {
   double elts[6] = { matrix._11, matrix._12,
                      matrix._21, matrix._22,
                      matrix._31, matrix._32 };
 
   // XXX Should we enter GetWrapper()'s compartment?
   JS::Rooted<JS::Value> val(cx);
   if (!ToJSValue(cx, elts, &val)) {
     error.Throw(NS_ERROR_OUT_OF_MEMORY);
-    return nullptr;
-  }
-
-  return &val.toObject();
+  } else {
+    result.set(&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) {
@@ -1329,21 +1329,23 @@ CanvasRenderingContext2D::SetMozCurrentT
   }
 
   Matrix newCTM;
   if (ObjectToMatrix(cx, currentTransform, newCTM, error)) {
     mTarget->SetTransform(newCTM);
   }
 }
 
-JSObject*
+void
 CanvasRenderingContext2D::GetMozCurrentTransform(JSContext* cx,
+                                                 JS::MutableHandle<JSObject*> result,
                                                  ErrorResult& error) const
 {
-  return MatrixToJSObject(cx, mTarget ? mTarget->GetTransform() : Matrix(), error);
+  MatrixToJSObject(cx, mTarget ? mTarget->GetTransform() : Matrix(),
+                   result, error);
 }
 
 void
 CanvasRenderingContext2D::SetMozCurrentTransformInverse(JSContext* cx,
                                                         JS::Handle<JSObject*> currentTransform,
                                                         ErrorResult& error)
 {
   EnsureTarget();
@@ -1356,32 +1358,34 @@ CanvasRenderingContext2D::SetMozCurrentT
   if (ObjectToMatrix(cx, currentTransform, newCTMInverse, error)) {
     // XXX ERRMSG we need to report an error to developers here! (bug 329026)
     if (newCTMInverse.Invert()) {
       mTarget->SetTransform(newCTMInverse);
     }
   }
 }
 
-JSObject*
+void
 CanvasRenderingContext2D::GetMozCurrentTransformInverse(JSContext* cx,
+                                                        JS::MutableHandle<JSObject*> result,
                                                         ErrorResult& error) const
 {
   if (!mTarget) {
-    return MatrixToJSObject(cx, Matrix(), error);
+    MatrixToJSObject(cx, Matrix(), result, error);
+    return;
   }
 
   Matrix ctm = mTarget->GetTransform();
 
   if (!ctm.Invert()) {
     double NaN = JS_GetNaNValue(cx).toDouble();
     ctm = Matrix(NaN, NaN, NaN, NaN, NaN, NaN);
   }
 
-  return MatrixToJSObject(cx, ctm, error);
+  MatrixToJSObject(cx, ctm, result, error);
 }
 
 //
 // colors
 //
 
 void
 CanvasRenderingContext2D::SetStyleFromUnion(const StringOrCanvasGradientOrCanvasPattern& value,
--- a/content/canvas/src/CanvasRenderingContext2D.h
+++ b/content/canvas/src/CanvasRenderingContext2D.h
@@ -383,23 +383,25 @@ public:
   }
 
   void ArcTo(double x1, double y1, double x2, double y2, double radius,
              mozilla::ErrorResult& error);
   void Rect(double x, double y, double w, double h);
   void Arc(double x, double y, double radius, double startAngle,
            double endAngle, bool anticlockwise, mozilla::ErrorResult& error);
 
-  JSObject* GetMozCurrentTransform(JSContext* cx,
-                                   mozilla::ErrorResult& error) const;
+  void GetMozCurrentTransform(JSContext* cx,
+			      JS::MutableHandle<JSObject*> result,
+			      mozilla::ErrorResult& error) const;
   void SetMozCurrentTransform(JSContext* cx,
                               JS::Handle<JSObject*> currentTransform,
                               mozilla::ErrorResult& error);
-  JSObject* GetMozCurrentTransformInverse(JSContext* cx,
-                                          mozilla::ErrorResult& error) const;
+  void GetMozCurrentTransformInverse(JSContext* cx,
+				     JS::MutableHandle<JSObject*> result,
+				     mozilla::ErrorResult& error) const;
   void SetMozCurrentTransformInverse(JSContext* cx,
                                      JS::Handle<JSObject*> currentTransform,
                                      mozilla::ErrorResult& error);
   void GetFillRule(nsAString& fillRule);
   void SetFillRule(const nsAString& fillRule);
   void GetMozDash(JSContext* cx, JS::MutableHandle<JS::Value> retval,
 		  mozilla::ErrorResult& error);
   void SetMozDash(JSContext* cx, const JS::Value& mozDash,
--- a/content/canvas/src/ImageData.h
+++ b/content/canvas/src/ImageData.h
@@ -56,19 +56,19 @@ public:
   uint32_t Width() const
   {
     return mWidth;
   }
   uint32_t Height() const
   {
     return mHeight;
   }
-  JSObject* Data(JSContext* cx) const
+  void GetData(JSContext* cx, JS::MutableHandle<JSObject*> aData) const
   {
-    return GetDataObject();
+    aData.set(GetDataObject());
   }
   JSObject* GetDataObject() const
   {
     JS::ExposeObjectToActiveJS(mData);
     return mData;
   }
 
   JSObject* WrapObject(JSContext* cx);
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -280,17 +280,19 @@ public:
     // WebIDL WebGLRenderingContext API
     dom::HTMLCanvasElement* GetCanvas() const { return mCanvasElement; }
     GLsizei DrawingBufferWidth() const { return IsContextLost() ? 0 : mWidth; }
     GLsizei DrawingBufferHeight() const { return IsContextLost() ? 0 : mHeight; }
 
     void GetContextAttributes(dom::Nullable<dom::WebGLContextAttributes>& retval);
     bool IsContextLost() const { return mContextStatus != ContextNotLost; }
     void GetSupportedExtensions(JSContext *cx, dom::Nullable< nsTArray<nsString> > &retval);
-    JSObject* GetExtension(JSContext* cx, const nsAString& aName, ErrorResult& rv);
+    void GetExtension(JSContext* cx, const nsAString& aName,
+                      JS::MutableHandle<JSObject*> aRetval,
+                      ErrorResult& rv);
     void ActiveTexture(GLenum texture);
     void AttachShader(WebGLProgram* program, WebGLShader* shader);
     void BindAttribLocation(WebGLProgram* program, GLuint location,
                             const nsAString& name);
     void BindFramebuffer(GLenum target, WebGLFramebuffer* wfb);
     void BindRenderbuffer(GLenum target, WebGLRenderbuffer* wrb);
     void BindTexture(GLenum target, WebGLTexture *tex);
     void BindVertexArray(WebGLVertexArray *vao);
--- a/content/canvas/src/WebGLContextExtensions.cpp
+++ b/content/canvas/src/WebGLContextExtensions.cpp
@@ -177,21 +177,25 @@ bool WebGLContext::IsExtensionSupported(
 }
 
 static bool
 CompareWebGLExtensionName(const nsACString& name, const char *other)
 {
     return name.Equals(other, nsCaseInsensitiveCStringComparator());
 }
 
-JSObject*
-WebGLContext::GetExtension(JSContext *cx, const nsAString& aName, ErrorResult& rv)
+void
+WebGLContext::GetExtension(JSContext *cx, const nsAString& aName,
+                           JS::MutableHandle<JSObject*> aRetval,
+                           ErrorResult& rv)
 {
-    if (IsContextLost())
-        return nullptr;
+    if (IsContextLost()) {
+        aRetval.set(nullptr);
+        return;
+    }
 
     NS_LossyConvertUTF16toASCII name(aName);
 
     WebGLExtensionID ext = WebGLExtensionID::Unknown;
 
     // step 1: figure what extension is wanted
     for (size_t i = 0; i < size_t(WebGLExtensionID::Max); i++)
     {
@@ -230,30 +234,32 @@ WebGLContext::GetExtension(JSContext *cx
             GenerateWarning("getExtension('%s'): MOZ_ prefixed WebGL extension strings are deprecated. "
                             "Support for them will be removed in the future. Use unprefixed extension strings. "
                             "To get draft extensions, set the webgl.enable-draft-extensions preference.",
                             name.get());
         }
     }
 
     if (ext == WebGLExtensionID::Unknown) {
-        return nullptr;
+        aRetval.set(nullptr);
+        return;
     }
 
     // step 2: check if the extension is supported
     if (!IsExtensionSupported(cx, ext)) {
-        return nullptr;
+        aRetval.set(nullptr);
+        return;
     }
 
     // step 3: if the extension hadn't been previously been created, create it now, thus enabling it
     if (!IsExtensionEnabled(ext)) {
         EnableExtension(ext);
     }
 
-    return WebGLObjectAsJSObject(cx, mExtensions[ext].get(), rv);
+    aRetval.set(WebGLObjectAsJSObject(cx, mExtensions[ext].get(), rv));
 }
 
 void
 WebGLContext::EnableExtension(WebGLExtensionID ext)
 {
     MOZ_ASSERT(IsExtensionEnabled(ext) == false);
 
     WebGLExtensionBase* obj = nullptr;
--- a/content/html/content/public/HTMLMediaElement.h
+++ b/content/html/content/public/HTMLMediaElement.h
@@ -524,17 +524,18 @@ public:
 
   already_AddRefed<DOMMediaStream> MozCaptureStreamUntilEnded(ErrorResult& aRv);
 
   bool MozAudioCaptured() const
   {
     return mAudioCaptured;
   }
 
-  JSObject* MozGetMetadata(JSContext* aCx, ErrorResult& aRv);
+  void MozGetMetadata(JSContext* aCx, JS::MutableHandle<JSObject*> aResult,
+                      ErrorResult& aRv);
 
   double MozFragmentEnd();
 
   AudioChannel MozAudioChannelType() const
   {
     return mAudioChannel;
   }
 
--- a/content/html/content/src/HTMLMediaElement.cpp
+++ b/content/html/content/src/HTMLMediaElement.cpp
@@ -1668,48 +1668,50 @@ HTMLMediaElement::BuildObjectFromTags(ns
     NS_WARNING("Failed to set metadata property");
     args->error = true;
     return PL_DHASH_STOP;
   }
 
   return PL_DHASH_NEXT;
 }
 
-JSObject*
-HTMLMediaElement::MozGetMetadata(JSContext* cx, ErrorResult& aRv)
+void
+HTMLMediaElement::MozGetMetadata(JSContext* cx,
+                                 JS::MutableHandle<JSObject*> aRetval,
+                                 ErrorResult& aRv)
 {
   if (mReadyState < nsIDOMHTMLMediaElement::HAVE_METADATA) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return nullptr;
+    return;
   }
 
   JS::Rooted<JSObject*> tags(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
   if (!tags) {
     aRv.Throw(NS_ERROR_FAILURE);
-    return nullptr;
+    return;
   }
   if (mTags) {
     MetadataIterCx iter = {cx, tags, false};
     mTags->EnumerateRead(BuildObjectFromTags, static_cast<void*>(&iter));
     if (iter.error) {
       NS_WARNING("couldn't create metadata object!");
       aRv.Throw(NS_ERROR_FAILURE);
-      return nullptr;
+      return;
     }
   }
 
-  return tags;
+  aRetval.set(tags);
 }
 
 NS_IMETHODIMP
 HTMLMediaElement::MozGetMetadata(JSContext* cx, JS::MutableHandle<JS::Value> aValue)
 {
   ErrorResult rv;
-
-  JSObject* obj = MozGetMetadata(cx, rv);
+  JS::Rooted<JSObject*> obj(cx);
+  MozGetMetadata(cx, &obj, rv);
   if (!rv.Failed()) {
     MOZ_ASSERT(obj);
     aValue.setObject(*obj);
   }
 
   return rv.ErrorCode();
 }
 
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -2239,36 +2239,38 @@ nsHTMLDocument::ResolveName(const nsAStr
     *aCache = e;
     return e;
   }
 
   *aCache = nullptr;
   return nullptr;
 }
 
-JSObject*
+void
 nsHTMLDocument::NamedGetter(JSContext* cx, const nsAString& aName, bool& aFound,
+                            JS::MutableHandle<JSObject*> aRetval,
                             ErrorResult& rv)
 {
   nsWrapperCache* cache;
   nsISupports* supp = ResolveName(aName, &cache);
   if (!supp) {
     aFound = false;
-    return nullptr;
+    aRetval.set(nullptr);
+    return;
   }
 
   JS::Rooted<JS::Value> val(cx);
   // XXXbz Should we call the (slightly misnamed, really) WrapNativeParent
   // here?
   if (!dom::WrapObject(cx, supp, cache, nullptr, &val)) {
     rv.Throw(NS_ERROR_OUT_OF_MEMORY);
-    return nullptr;
+    return;
   }
   aFound = true;
-  return &val.toObject();
+  aRetval.set(&val.toObject());
 }
 
 bool
 nsHTMLDocument::NameIsEnumerable(const nsAString& aName)
 {
   return true;
 }
 
--- a/content/html/document/src/nsHTMLDocument.h
+++ b/content/html/document/src/nsHTMLDocument.h
@@ -169,18 +169,19 @@ public:
 
   // WebIDL API
   virtual JSObject* WrapNode(JSContext* aCx)
     MOZ_OVERRIDE;
   void GetDomain(nsAString& aDomain, mozilla::ErrorResult& rv);
   void SetDomain(const nsAString& aDomain, mozilla::ErrorResult& rv);
   void GetCookie(nsAString& aCookie, mozilla::ErrorResult& rv);
   void SetCookie(const nsAString& aCookie, mozilla::ErrorResult& rv);
-  JSObject* NamedGetter(JSContext* cx, const nsAString& aName, bool& aFound,
-                        mozilla::ErrorResult& rv);
+  void NamedGetter(JSContext* cx, const nsAString& aName, bool& aFound,
+                   JS::MutableHandle<JSObject*> aRetval,
+                   mozilla::ErrorResult& rv);
   bool NameIsEnumerable(const nsAString& aName);
   void GetSupportedNames(unsigned, nsTArray<nsString>& aNames);
   nsGenericHTMLElement *GetBody();
   void SetBody(nsGenericHTMLElement* aBody, mozilla::ErrorResult& rv);
   mozilla::dom::HTMLSharedElement *GetHead() {
     return static_cast<mozilla::dom::HTMLSharedElement*>(GetHeadElement());
   }
   nsIHTMLCollection* Images();
--- a/content/media/eme/MediaKeyMessageEvent.cpp
+++ b/content/media/eme/MediaKeyMessageEvent.cpp
@@ -94,32 +94,34 @@ MediaKeyMessageEvent::Constructor(const 
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return nullptr;
   }
   e->mDestinationURL = aEventInitDict.mDestinationURL;
   e->SetTrusted(trusted);
   return e.forget();
 }
 
-JSObject*
-MediaKeyMessageEvent::GetMessage(JSContext* cx, ErrorResult& aRv)
+void
+MediaKeyMessageEvent::GetMessage(JSContext* cx,
+                                 JS::MutableHandle<JSObject*> aMessage,
+                                 ErrorResult& aRv)
 {
   if (!mMessage) {
     mMessage = Uint8Array::Create(cx,
                                   this,
                                   mRawMessage.Length(),
                                   mRawMessage.Elements());
     if (!mMessage) {
       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
-      return nullptr;
+      return;
     }
     mRawMessage.Clear();
   }
   JS::ExposeObjectToActiveJS(mMessage);
-  return mMessage;
+  aMessage.set(mMessage);
 }
 
 void
 MediaKeyMessageEvent::GetDestinationURL(nsString& aRetVal) const
 {
   aRetVal = mDestinationURL;
 }
 
--- a/content/media/eme/MediaKeyMessageEvent.h
+++ b/content/media/eme/MediaKeyMessageEvent.h
@@ -45,17 +45,19 @@ public:
                 const nsTArray<uint8_t>& aMessage);
 
   static already_AddRefed<MediaKeyMessageEvent>
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aType,
               const MediaKeyMessageEventInit& aEventInitDict,
               ErrorResult& aRv);
 
-  JSObject* GetMessage(JSContext* cx, ErrorResult& aRv);
+  void GetMessage(JSContext* cx,
+                  JS::MutableHandle<JSObject*> aMessage,
+                  ErrorResult& aRv);
 
   void GetDestinationURL(nsString& aRetVal) const;
 
 private:
   nsTArray<uint8_t> mRawMessage;
 };
 
 
--- a/content/media/eme/MediaKeyNeededEvent.cpp
+++ b/content/media/eme/MediaKeyNeededEvent.cpp
@@ -89,30 +89,32 @@ MediaKeyNeededEvent::Constructor(const G
 }
 
 void
 MediaKeyNeededEvent::GetInitDataType(nsString& aRetVal) const
 {
   aRetVal = mInitDataType;
 }
 
-JSObject*
-MediaKeyNeededEvent::GetInitData(JSContext* cx, ErrorResult& aRv)
+void
+MediaKeyNeededEvent::GetInitData(JSContext* cx,
+                                 JS::MutableHandle<JSObject*> aData,
+                                 ErrorResult& aRv)
 {
   if (mRawInitData.Length()) {
     mInitData = Uint8Array::Create(cx,
                                    this,
                                    mRawInitData.Length(),
                                    mRawInitData.Elements());
     if (!mInitData) {
       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
-      return nullptr;
+      return;
     }
     mRawInitData.Clear();
   }
   if (mInitData) {
     JS::ExposeObjectToActiveJS(mInitData);
   }
-  return mInitData;
+  aData.set(mInitData);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/content/media/eme/MediaKeyNeededEvent.h
+++ b/content/media/eme/MediaKeyNeededEvent.h
@@ -46,17 +46,19 @@ public:
   static already_AddRefed<MediaKeyNeededEvent>
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aType,
               const MediaKeyNeededEventInit& aEventInitDict,
               ErrorResult& aRv);
 
   void GetInitDataType(nsString& aRetVal) const;
 
-  JSObject* GetInitData(JSContext* cx, ErrorResult& aRv);
+  void GetInitData(JSContext* cx,
+                   JS::MutableHandle<JSObject*> aData,
+                   ErrorResult& aRv);
 private:
   nsTArray<uint8_t> mRawInitData;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_MediaKeyNeededEvent_h__
--- a/content/media/webaudio/AudioBuffer.cpp
+++ b/content/media/webaudio/AudioBuffer.cpp
@@ -187,31 +187,35 @@ AudioBuffer::CopyToChannel(JSContext* aJ
 void
 AudioBuffer::SetRawChannelContents(uint32_t aChannel, float* aContents)
 {
   MOZ_ASSERT(!GetWrapperPreserveColor() && !mSharedChannels,
              "The AudioBuffer object should not have been handed to JS or have C++ callers neuter its typed array");
   PodCopy(JS_GetFloat32ArrayData(mJSChannels[aChannel]), aContents, mLength);
 }
 
-JSObject*
+void
 AudioBuffer::GetChannelData(JSContext* aJSContext, uint32_t aChannel,
+                            JS::MutableHandle<JSObject*> aRetval,
                             ErrorResult& aRv)
 {
   if (aChannel >= NumberOfChannels()) {
     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
-    return nullptr;
+    return;
   }
 
   if (!RestoreJSChannelData(aJSContext)) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
-    return nullptr;
+    return;
   }
 
-  return mJSChannels[aChannel];
+  if (mJSChannels[aChannel]) {
+    JS::ExposeObjectToActiveJS(mJSChannels[aChannel]);
+  }
+  aRetval.set(mJSChannels[aChannel]);
 }
 
 static already_AddRefed<ThreadSharedFloatArrayBufferList>
 StealJSArrayDataIntoThreadSharedFloatArrayBufferList(JSContext* aJSContext,
                                                      const nsTArray<JSObject*>& aJSArrays)
 {
   nsRefPtr<ThreadSharedFloatArrayBufferList> result =
     new ThreadSharedFloatArrayBufferList(aJSArrays.Length());
--- a/content/media/webaudio/AudioBuffer.h
+++ b/content/media/webaudio/AudioBuffer.h
@@ -69,18 +69,19 @@ public:
   {
     return mJSChannels.Length();
   }
 
   /**
    * If mSharedChannels is non-null, copies its contents to
    * new Float32Arrays in mJSChannels. Returns a Float32Array.
    */
-  JSObject* GetChannelData(JSContext* aJSContext, uint32_t aChannel,
-                           ErrorResult& aRv);
+  void GetChannelData(JSContext* aJSContext, uint32_t aChannel,
+                      JS::MutableHandle<JSObject*> aRetval,
+                      ErrorResult& aRv);
 
   void CopyFromChannel(const Float32Array& aDestination, uint32_t aChannelNumber,
                        uint32_t aStartInChannel, ErrorResult& aRv);
   void CopyToChannel(JSContext* aJSContext, const Float32Array& aSource,
                      uint32_t aChannelNumber, uint32_t aStartInChannel,
                      ErrorResult& aRv);
 
   /**
--- a/content/media/webaudio/WaveShaperNode.h
+++ b/content/media/webaudio/WaveShaperNode.h
@@ -22,19 +22,22 @@ public:
   explicit WaveShaperNode(AudioContext *aContext);
   virtual ~WaveShaperNode();
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WaveShaperNode, AudioNode)
 
   virtual JSObject* WrapObject(JSContext *aCx) MOZ_OVERRIDE;
 
-  JSObject* GetCurve(JSContext* aCx) const
+  void GetCurve(JSContext* aCx, JS::MutableHandle<JSObject*> aRetval) const
   {
-    return mCurve;
+    if (mCurve) {
+      JS::ExposeObjectToActiveJS(mCurve);
+    }
+    aRetval.set(mCurve);
   }
   void SetCurve(const Nullable<Float32Array>& aData);
 
   OverSampleType Oversample() const
   {
     return mType;
   }
   void SetOversample(OverSampleType aType);
--- a/dom/base/Crypto.cpp
+++ b/dom/base/Crypto.cpp
@@ -50,18 +50,19 @@ Crypto::Init(nsIDOMWindow* aWindow)
 }
 
 /* virtual */ JSObject*
 Crypto::WrapObject(JSContext* aCx)
 {
   return CryptoBinding::Wrap(aCx, this);
 }
 
-JSObject *
+void
 Crypto::GetRandomValues(JSContext* aCx, const ArrayBufferView& aArray,
+			JS::MutableHandle<JSObject*> aRetval,
 			ErrorResult& aRv)
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Called on the wrong thread");
 
   JS::Rooted<JSObject*> view(aCx, aArray.Obj());
 
   // Throw if the wrong type of ArrayBufferView is passed in
   // (Part of the Web Crypto API spec)
@@ -71,56 +72,57 @@ Crypto::GetRandomValues(JSContext* aCx, 
     case TYPE_UINT8_CLAMPED:
     case TYPE_INT16:
     case TYPE_UINT16:
     case TYPE_INT32:
     case TYPE_UINT32:
       break;
     default:
       aRv.Throw(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
-      return nullptr;
+      return;
   }
 
   aArray.ComputeLengthAndData();
   uint32_t dataLen = aArray.Length();
   if (dataLen == 0) {
     NS_WARNING("ArrayBufferView length is 0, cannot continue");
-    return view;
+    aRetval.set(view);
+    return;
   } else if (dataLen > 65536) {
     aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
-    return nullptr;
+    return;
   }
 
   uint8_t* data = aArray.Data();
 
   if (XRE_GetProcessType() != GeckoProcessType_Default) {
     InfallibleTArray<uint8_t> randomValues;
     // Tell the parent process to generate random values via PContent
     ContentChild* cc = ContentChild::GetSingleton();
     if (!cc->SendGetRandomValues(dataLen, &randomValues) ||
         randomValues.Length() == 0) {
       aRv.Throw(NS_ERROR_FAILURE);
-      return nullptr;
+      return;
     }
     NS_ASSERTION(dataLen == randomValues.Length(),
                  "Invalid length returned from parent process!");
     memcpy(data, randomValues.Elements(), dataLen);
   } else {
     uint8_t *buf = GetRandomValues(dataLen);
 
     if (!buf) {
       aRv.Throw(NS_ERROR_FAILURE);
-      return nullptr;
+      return;
     }
 
     memcpy(data, buf, dataLen);
     NS_Free(buf);
   }
 
-  return view;
+  aRetval.set(view);
 }
 
 SubtleCrypto*
 Crypto::Subtle()
 {
   if(!mSubtle) {
     mSubtle = new SubtleCrypto(GetParentObject());
   }
--- a/dom/base/Crypto.h
+++ b/dom/base/Crypto.h
@@ -36,18 +36,19 @@ public:
   Crypto();
   virtual ~Crypto();
 
   NS_DECL_NSIDOMCRYPTO
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Crypto)
 
-  JSObject *
+  void
   GetRandomValues(JSContext* aCx, const ArrayBufferView& aArray,
+		  JS::MutableHandle<JSObject*> aRetval,
 		  ErrorResult& aRv);
 
   SubtleCrypto*
   Subtle();
 
 #ifndef MOZ_DISABLE_CRYPTOLEGACY
   virtual bool EnableSmartCardEvents();
   virtual void SetEnableSmartCardEvents(bool aEnable, ErrorResult& aRv);
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -3923,55 +3923,58 @@ nsGlobalWindow::GetRealTop(nsIDOMWindow*
       return NS_ERROR_NOT_INITIALIZED;
     }
   } else {
     outer = this;
   }
   return GetTopImpl(outer, aTop, /* aScriptable = */ false);
 }
 
-JSObject*
-nsGlobalWindow::GetContent(JSContext* aCx, ErrorResult& aError)
-{
-  FORWARD_TO_OUTER_OR_THROW(GetContent, (aCx, aError), aError, nullptr);
+void
+nsGlobalWindow::GetContent(JSContext* aCx,
+                           JS::MutableHandle<JSObject*> aRetval,
+                           ErrorResult& aError)
+{
+  FORWARD_TO_OUTER_OR_THROW(GetContent, (aCx, aRetval, aError), aError, );
 
   nsCOMPtr<nsIDOMWindow> content = GetContentInternal(aError);
   if (aError.Failed()) {
-    return nullptr;
+    return;
   }
 
   if (content) {
     JS::Rooted<JS::Value> val(aCx);
     aError = nsContentUtils::WrapNative(aCx, content, &val);
     if (aError.Failed()) {
-      return nullptr;
-    }
-
-    return &val.toObject();
+      return;
+    }
+
+    aRetval.set(&val.toObject());
+    return;
   }
 
   if (!nsContentUtils::IsCallerChrome() || !IsChromeWindow()) {
     aError.Throw(NS_ERROR_FAILURE);
-    return nullptr;
+    return;
   }
 
   // Something tries to get .content on a ChromeWindow, try to fetch the CPOW.
   nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
   if (!treeOwner) {
     aError.Throw(NS_ERROR_FAILURE);
-    return nullptr;
+    return;
   }
 
   JS::Rooted<JS::Value> val(aCx, JS::NullValue());
   aError = treeOwner->GetContentWindow(aCx, &val);
   if (aError.Failed()) {
-    return nullptr;
-  }
-
-  return val.toObjectOrNull();
+    return;
+  }
+
+  aRetval.set(val.toObjectOrNull());
 }
 
 already_AddRefed<nsIDOMWindow>
 nsGlobalWindow::GetContentInternal(ErrorResult& aError)
 {
   // First check for a named frame named "content"
   nsCOMPtr<nsIDOMWindow> domWindow =
     GetChildWindow(NS_LITERAL_STRING("content"));
@@ -4029,17 +4032,18 @@ nsGlobalWindow::GetContent(nsIDOMWindow*
 
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::GetScriptableContent(JSContext* aCx, JS::MutableHandle<JS::Value> aVal)
 {
   ErrorResult rv;
-  JS::Rooted<JSObject*> content(aCx, GetContent(aCx, rv));
+  JS::Rooted<JSObject*> content(aCx);
+  GetContent(aCx, &content, rv);
   if (!rv.Failed()) {
     aVal.setObjectOrNull(content);
   }
 
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -988,23 +988,27 @@ public:
             bool aShowDialog, mozilla::ErrorResult& aError);
   uint64_t GetMozPaintCount(mozilla::ErrorResult& aError);
   already_AddRefed<nsIDOMWindow> OpenDialog(JSContext* aCx,
                                             const nsAString& aUrl,
                                             const nsAString& aName,
                                             const nsAString& aOptions,
                                             const mozilla::dom::Sequence<JS::Value>& aExtraArgument,
                                             mozilla::ErrorResult& aError);
-  JSObject* GetContent(JSContext* aCx, mozilla::ErrorResult& aError);
-  JSObject* Get_content(JSContext* aCx, mozilla::ErrorResult& aError)
+  void GetContent(JSContext* aCx,
+                  JS::MutableHandle<JSObject*> aRetval,
+                  mozilla::ErrorResult& aError);
+  void Get_content(JSContext* aCx,
+                   JS::MutableHandle<JSObject*> aRetval,
+                   mozilla::ErrorResult& aError)
   {
     if (mDoc) {
       mDoc->WarnOnceAbout(nsIDocument::eWindow_Content);
     }
-    return GetContent(aCx, aError);
+    GetContent(aCx, aRetval, aError);
   }
 
   // ChromeWindow bits.  Do NOT call these unless your window is in
   // fact an nsGlobalChromeWindow.
   uint16_t WindowState();
   nsIBrowserDOMWindow* GetBrowserDOMWindow(mozilla::ErrorResult& aError);
   void SetBrowserDOMWindow(nsIBrowserDOMWindow* aBrowserWindow,
                            mozilla::ErrorResult& aError);
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -5638,17 +5638,19 @@ def getRetvalDeclarationForType(returnTy
     if returnType.isCallback():
         name = returnType.unroll().identifier.name
         return CGGeneric("nsRefPtr<%s>" % name), None, None, None
     if returnType.isAny():
         if isMember:
             return CGGeneric("JS::Value"), None, None, None
         return CGGeneric("JS::Rooted<JS::Value>"), "ptr", None, "cx"
     if returnType.isObject() or returnType.isSpiderMonkeyInterface():
-        return CGGeneric("JSObject*"), None, None, None
+        if isMember:
+            return CGGeneric("JSObject*"), None, None, None
+        return CGGeneric("JS::Rooted<JSObject*>"), "ptr", None, "cx"
     if returnType.isSequence():
         nullable = returnType.nullable()
         if nullable:
             returnType = returnType.inner
         # If our result is already addrefed, use the right type in the
         # sequence argument here.
         result, _, _, _ = getRetvalDeclarationForType(returnType.inner,
                                                       descriptorProvider,
@@ -11532,23 +11534,29 @@ class CGNativeMember(ClassMethod):
         if type.isAny():
             if isMember:
                 # No need for a third element in the isMember case
                 return "JS::Value", None, None
             # Outparam
             return "void", "", "aRetVal.set(${declName});\n"
 
         if type.isObject():
-            return "JSObject*", "nullptr", "return ${declName};\n"
+            if isMember:
+                # No need for a third element in the isMember case
+                return "JSObject*", None, None
+            return "void", "", "aRetVal.set(${declName});\n"
         if type.isSpiderMonkeyInterface():
+            if isMember:
+                # No need for a third element in the isMember case
+                return "JSObject*", None, None
             if type.nullable():
-                returnCode = "return ${declName}.IsNull() ? nullptr : ${declName}.Value().Obj();\n"
-            else:
-                returnCode = "return ${declName}.Obj();\n"
-            return "JSObject*", "nullptr", returnCode
+                returnCode = "${declName}.IsNull() ? nullptr : ${declName}.Value().Obj();\n"
+            else:
+                returnCode = "${declName}.Obj();\n"
+            return "void", "", "aRetVal.set(%s);\n" % returnCode
         if type.isSequence():
             # If we want to handle sequence-of-sequences return values, we're
             # going to need to fix example codegen to not produce nsTArray<void>
             # for the relevant argument...
             assert not isMember
             # Outparam.
             if type.nullable():
                 returnCode = dedent("""
@@ -11630,16 +11638,18 @@ class CGNativeMember(ClassMethod):
                 dictType = CGTemplatedType("Nullable", dictType)
             args.append(Argument("%s&" % dictType.define(), "aRetVal"))
         elif returnType.isUnion():
             args.append(Argument("%s&" %
                                  CGUnionStruct.unionTypeDecl(returnType, True),
                                  "aRetVal"))
         elif returnType.isAny():
             args.append(Argument("JS::MutableHandle<JS::Value>", "aRetVal"))
+        elif returnType.isObject() or returnType.isSpiderMonkeyInterface():
+            args.append(Argument("JS::MutableHandle<JSObject*>", "aRetVal"))
 
         # And the ErrorResult
         if 'infallible' not in self.extendedAttrs:
             # Use aRv so it won't conflict with local vars named "rv"
             args.append(Argument("ErrorResult&", "aRv"))
         # The legacycaller thisval
         if self.member.isMethod() and self.member.isLegacycaller():
             # If it has an identifier, we can't deal with it yet
@@ -13510,17 +13520,18 @@ class CGEventGetter(CGNativeMember):
         if type.isDOMString() or type.isByteString():
             return "aRetVal = " + memberName + ";\n"
         if type.isSpiderMonkeyInterface() or type.isObject():
             return fill(
                 """
                 if (${memberName}) {
                   JS::ExposeObjectToActiveJS(${memberName});
                 }
-                return ${memberName};
+                aRetVal.set(${memberName});
+                return;
                 """,
                 memberName=memberName)
         if type.isAny():
             return fill(
                 """
                 JS::ExposeValueToActiveJS(${memberName});
                 aRetVal.set(${memberName});
                 return;
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -445,17 +445,17 @@ public:
   void PassFloat32Array(const Float32Array&);
   void PassFloat64Array(const Float64Array&);
   void PassSequenceOfArrayBuffers(const Sequence<ArrayBuffer>&);
   void PassSequenceOfNullableArrayBuffers(const Sequence<Nullable<ArrayBuffer> >&);
   void PassMozMapOfArrayBuffers(const MozMap<ArrayBuffer>&);
   void PassMozMapOfNullableArrayBuffers(const MozMap<Nullable<ArrayBuffer> >&);
   void PassVariadicTypedArray(const Sequence<Float32Array>&);
   void PassVariadicNullableTypedArray(const Sequence<Nullable<Float32Array> >&);
-  JSObject* ReceiveUint8Array(JSContext*);
+  void ReceiveUint8Array(JSContext*, JS::MutableHandle<JSObject*>);
 
   // DOMString types
   void PassString(const nsAString&);
   void PassNullableString(const nsAString&);
   void PassOptionalString(const Optional<nsAString>&);
   void PassOptionalStringWithDefaultValue(const nsAString&);
   void PassOptionalNullableString(const Optional<nsAString>&);
   void PassOptionalNullableStringWithDefaultValue(const nsAString&);
@@ -534,18 +534,18 @@ public:
   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 PassNullableSequenceOfObject(JSContext*, const Nullable<Sequence<JSObject*> >&);
   void PassOptionalNullableSequenceOfNullableSequenceOfObject(JSContext*, const Optional<Nullable<Sequence<Nullable<Sequence<JSObject*> > > > >&);
   void PassOptionalNullableSequenceOfNullableSequenceOfNullableObject(JSContext*, const Optional<Nullable<Sequence<Nullable<Sequence<JSObject*> > > > >&);
   void PassMozMapOfObject(JSContext*, const MozMap<JSObject*>&);
-  JSObject* ReceiveObject(JSContext*);
-  JSObject* ReceiveNullableObject(JSContext*);
+  void ReceiveObject(JSContext*, JS::MutableHandle<JSObject*>);
+  void ReceiveNullableObject(JSContext*, JS::MutableHandle<JSObject*>);
 
   // Union types
   void PassUnion(JSContext*, const ObjectOrLong& arg);
   void PassUnionWithNullable(JSContext* cx, const ObjectOrNullOrLong& arg)
   {
     OwningObjectOrLong returnValue;
     if (arg.IsNull()) {
     } else if (arg.IsObject()) {
--- a/dom/crypto/RsaKeyAlgorithm.h
+++ b/dom/crypto/RsaKeyAlgorithm.h
@@ -2,16 +2,17 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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_RsaKeyAlgorithm_h
 #define mozilla_dom_RsaKeyAlgorithm_h
 
+#include "mozilla/ErrorResult.h"
 #include "mozilla/dom/KeyAlgorithm.h"
 #include "js/TypeDecls.h"
 
 namespace mozilla {
 namespace dom {
 
 class RsaKeyAlgorithm : public KeyAlgorithm
 {
@@ -30,20 +31,26 @@ public:
 
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
   uint32_t ModulusLength() const
   {
     return mModulusLength;
   }
 
-  JSObject* PublicExponent(JSContext* cx) const
+  void GetPublicExponent(JSContext* cx, JS::MutableHandle<JSObject*> aRetval,
+                         ErrorResult& aError) const
   {
     TypedArrayCreator<Uint8Array> creator(mPublicExponent);
-    return creator.Create(cx);
+    JSObject* retval = creator.Create(cx);
+    if (!retval) {
+      aError.Throw(NS_ERROR_OUT_OF_MEMORY);
+    } else {
+      aRetval.set(retval);
+    }
   }
 
   virtual bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const MOZ_OVERRIDE;
   static KeyAlgorithm* Create(nsIGlobalObject* aGlobal,
                               JSStructuredCloneReader* aReader);
 
 protected:
   uint32_t mModulusLength;
--- a/dom/encoding/TextEncoder.cpp
+++ b/dom/encoding/TextEncoder.cpp
@@ -29,39 +29,40 @@ TextEncoder::Init(const nsAString& aEnco
     aRv.ThrowTypeError(MSG_DOM_ENCODING_NOT_UTF);
     return;
   }
 
   // Create an encoder object for mEncoding.
   mEncoder = EncodingUtils::EncoderForEncoding(mEncoding);
 }
 
-JSObject*
+void
 TextEncoder::Encode(JSContext* aCx,
                     JS::Handle<JSObject*> aObj,
                     const nsAString& aString,
                     const bool aStream,
+		    JS::MutableHandle<JSObject*> aRetval,
                     ErrorResult& aRv)
 {
   // Run the steps of the encoding algorithm.
   int32_t srcLen = aString.Length();
   int32_t maxLen;
   const char16_t* data = PromiseFlatString(aString).get();
   nsresult rv = mEncoder->GetMaxLength(data, srcLen, &maxLen);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
-    return nullptr;
+    return;
   }
   // Need a fallible allocator because the caller may be a content
   // and the content can specify the length of the string.
   static const fallible_t fallible = fallible_t();
   nsAutoArrayPtr<char> buf(new (fallible) char[maxLen + 1]);
   if (!buf) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
-    return nullptr;
+    return;
   }
 
   int32_t dstLen = maxLen;
   rv = mEncoder->Convert(data, &srcLen, buf, &dstLen);
 
   // If the internal streaming flag is not set, then reset
   // the encoding algorithm state to the default values for encoding.
   if (!aStream) {
@@ -75,24 +76,24 @@ TextEncoder::Encode(JSContext* aCx,
   JSObject* outView = nullptr;
   if (NS_SUCCEEDED(rv)) {
     buf[dstLen] = '\0';
     JSAutoCompartment ac(aCx, aObj);
     outView = Uint8Array::Create(aCx, dstLen,
                                  reinterpret_cast<uint8_t*>(buf.get()));
     if (!outView) {
       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
-      return nullptr;
+      return;
     }
   }
 
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
   }
-  return outView;
+  aRetval.set(outView);
 }
 
 void
 TextEncoder::GetEncoding(nsAString& aEncoding)
 {
   CopyASCIItoUTF16(mEncoding, aEncoding);
   nsContentUtils::ASCIIToLower(aEncoding);
 }
--- a/dom/encoding/TextEncoder.h
+++ b/dom/encoding/TextEncoder.h
@@ -41,22 +41,23 @@ public:
   ~TextEncoder()
   {}
 
   JSObject* WrapObject(JSContext* aCx, bool* aTookOwnership)
   {
     return TextEncoderBinding::Wrap(aCx, this, aTookOwnership);
   }
 
-  JSObject* Encode(JSContext* aCx,
-                   JS::Handle<JSObject*> aObj,
-                   const nsAString& aString,
-                   const TextEncodeOptions& aOptions,
-                   ErrorResult& aRv) {
-    return TextEncoder::Encode(aCx, aObj, aString, aOptions.mStream, aRv);
+  void Encode(JSContext* aCx,
+	      JS::Handle<JSObject*> aObj,
+	      const nsAString& aString,
+	      const TextEncodeOptions& aOptions,
+	      JS::MutableHandle<JSObject*> aRetval,
+	      ErrorResult& aRv) {
+    TextEncoder::Encode(aCx, aObj, aString, aOptions.mStream, aRetval, aRv);
   }
 
 protected:
 
   /**
    * Validates provided encoding and throws an exception if invalid encoding.
    * If no encoding is provided then mEncoding is default initialised to "utf-8".
    *
@@ -80,23 +81,25 @@ public:
    *
    * @param aCx        Javascript context.
    * @param aObj       the wrapper of the TextEncoder
    * @param aString    utf-16 code units to be encoded.
    * @param aOptions   Streaming option. Initialised by default to false.
    *                   If the streaming option is false, then the encoding
    *                   algorithm state will get reset. If set to true then
    *                   the previous encoding is reused/continued.
-   * @return JSObject* The Uint8Array wrapped in a JS object.
+   * @return JSObject* The Uint8Array wrapped in a JS object.  Returned via
+   *                   the aRetval out param.
    */
-  JSObject* Encode(JSContext* aCx,
-                   JS::Handle<JSObject*> aObj,
-                   const nsAString& aString,
-                   const bool aStream,
-                   ErrorResult& aRv);
+  void Encode(JSContext* aCx,
+	      JS::Handle<JSObject*> aObj,
+	      const nsAString& aString,
+	      const bool aStream,
+	      JS::MutableHandle<JSObject*> aRetval,
+	      ErrorResult& aRv);
 
 private:
   nsCString mEncoding;
   nsCOMPtr<nsIUnicodeEncoder> mEncoder;
 };
 
 } // dom
 } // mozilla
--- a/dom/nfc/MozNDEFRecord.h
+++ b/dom/nfc/MozNDEFRecord.h
@@ -55,56 +55,38 @@ public:
               const Optional<Uint8Array>& aId,
               const Optional<Uint8Array>& aPayload, ErrorResult& aRv);
 
   uint8_t Tnf() const
   {
     return mTnf;
   }
 
-  JSObject* GetType(JSContext* cx) const
+  void GetType(JSContext* cx, JS::MutableHandle<JSObject*> retval) const
   {
     if (mType) {
-      return GetTypeObject();
-    } else {
-      return nullptr;
+      JS::ExposeObjectToActiveJS(mType);
     }
-  }
-  JSObject* GetTypeObject() const
-  {
-    JS::ExposeObjectToActiveJS(mType);
-    return mType;
+    retval.set(mType);
   }
 
-  JSObject* GetId(JSContext* cx) const
+  void GetId(JSContext* cx, JS::MutableHandle<JSObject*> retval) const
   {
     if (mId) {
-      return GetIdObject();
-    } else {
-      return nullptr;
+      JS::ExposeObjectToActiveJS(mId);
     }
-  }
-  JSObject* GetIdObject() const
-  {
-    JS::ExposeObjectToActiveJS(mId);
-    return mId;
+    retval.set(mId);
   }
 
-  JSObject* GetPayload(JSContext* cx) const
+  void GetPayload(JSContext* cx, JS::MutableHandle<JSObject*> retval) const
   {
     if (mPayload) {
-      return GetPayloadObject();
-    } else {
-      return nullptr;
+      JS::ExposeObjectToActiveJS(mPayload);
     }
-  }
-  JSObject* GetPayloadObject() const
-  {
-    JS::ExposeObjectToActiveJS(mPayload);
-    return mPayload;
+    retval.set(mPayload);
   }
 
 private:
   MozNDEFRecord() MOZ_DELETE;
   nsRefPtr<nsPIDOMWindow> mWindow;
   void HoldData();
   void DropData();
 
--- a/dom/webidl/SubtleCrypto.webidl
+++ b/dom/webidl/SubtleCrypto.webidl
@@ -27,16 +27,17 @@ interface AesKeyAlgorithm : KeyAlgorithm
 interface HmacKeyAlgorithm : KeyAlgorithm {
   readonly attribute KeyAlgorithm hash;
   readonly attribute unsigned long length;
 };
 
 [NoInterfaceObject]
 interface RsaKeyAlgorithm : KeyAlgorithm {
   readonly attribute unsigned long modulusLength;
+  [Throws]
   readonly attribute BigInteger publicExponent;
 };
 
 [NoInterfaceObject]
 interface RsaHashedKeyAlgorithm : RsaKeyAlgorithm {
   readonly attribute KeyAlgorithm hash;
 };
 
--- a/dom/workers/FileReaderSync.cpp
+++ b/dom/workers/FileReaderSync.cpp
@@ -42,66 +42,67 @@ FileReaderSync::Constructor(const Global
 }
 
 JSObject*
 FileReaderSync::WrapObject(JSContext* aCx)
 {
   return FileReaderSyncBinding_workers::Wrap(aCx, this);
 }
 
-JSObject*
+void
 FileReaderSync::ReadAsArrayBuffer(JSContext* aCx,
                                   JS::Handle<JSObject*> aScopeObj,
                                   JS::Handle<JSObject*> aBlob,
+                                  JS::MutableHandle<JSObject*> aRetval,
                                   ErrorResult& aRv)
 {
   nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aBlob);
   if (!blob) {
     aRv.Throw(NS_ERROR_INVALID_ARG);
-    return nullptr;
+    return;
   }
 
   uint64_t blobSize;
   nsresult rv = blob->GetSize(&blobSize);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
-    return nullptr;
+    return;
   }
 
   JS::Rooted<JSObject*> jsArrayBuffer(aCx, JS_NewArrayBuffer(aCx, blobSize));
   if (!jsArrayBuffer) {
     // XXXkhuey we need a way to indicate to the bindings that the call failed
     // but there's already a pending exception that we should not clobber.
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
-    return nullptr;
+    return;
   }
 
   uint32_t bufferLength = JS_GetArrayBufferByteLength(jsArrayBuffer);
   uint8_t* arrayBuffer = JS_GetStableArrayBufferData(aCx, jsArrayBuffer);
   if (!arrayBuffer) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
-    return nullptr;
+    return;
   }
 
   nsCOMPtr<nsIInputStream> stream;
   rv = blob->GetInternalStream(getter_AddRefs(stream));
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
-    return nullptr;
+    return;
   }
 
   uint32_t numRead;
   rv = stream->Read((char*)arrayBuffer, bufferLength, &numRead);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
-    return nullptr;
+    return;
   }
   NS_ASSERTION(numRead == bufferLength, "failed to read data");
 
-  return jsArrayBuffer;
+  aRetval.set(jsArrayBuffer);
 }
 
 void
 FileReaderSync::ReadAsBinaryString(JS::Handle<JSObject*> aBlob,
                                    nsAString& aResult,
                                    ErrorResult& aRv)
 {
   nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aBlob);
--- a/dom/workers/FileReaderSync.h
+++ b/dom/workers/FileReaderSync.h
@@ -37,19 +37,20 @@ private:
                          nsAString &aResult);
 
 public:
   static already_AddRefed<FileReaderSync>
   Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
 
   JSObject* WrapObject(JSContext* aCx);
 
-  JSObject* ReadAsArrayBuffer(JSContext* aCx, JS::Handle<JSObject*> aScopeObj,
-                              JS::Handle<JSObject*> aBlob,
-                              ErrorResult& aRv);
+  void ReadAsArrayBuffer(JSContext* aCx, JS::Handle<JSObject*> aScopeObj,
+                         JS::Handle<JSObject*> aBlob,
+                         JS::MutableHandle<JSObject*> aRetval,
+                         ErrorResult& aRv);
   void ReadAsBinaryString(JS::Handle<JSObject*> aBlob, nsAString& aResult,
                           ErrorResult& aRv);
   void ReadAsText(JS::Handle<JSObject*> aBlob,
                   const Optional<nsAString>& aEncoding,
                   nsAString& aResult, ErrorResult& aRv);
   void ReadAsDataURL(JS::Handle<JSObject*> aBlob, nsAString& aResult,
                      ErrorResult& aRv);
 };