Bug 868715 part 4. Use on-stack Rooted<JSObject*> for 'object' arguments in WebIDL bindings. r=peterv
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 16 May 2013 12:36:55 -0400
changeset 143618 ff52b16d7b6c30b45b655706cf521bc34a5e8f4b
parent 143617 034289d541c7fbba67c1e96732d88f8be60a1a7f
child 143619 e3ef4876a29f52f145170f302d2853eec41cb094
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv
bugs868715
milestone24.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 868715 part 4. Use on-stack Rooted<JSObject*> for 'object' arguments in WebIDL bindings. r=peterv
content/canvas/src/CanvasRenderingContext2D.cpp
content/canvas/src/CanvasRenderingContext2D.h
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
dom/bindings/test/TestBindingHeader.h
dom/bindings/test/TestJSImplGen.webidl
dom/workers/EventTarget.h
dom/workers/FileReaderSync.cpp
dom/workers/FileReaderSync.h
dom/workers/XMLHttpRequest.h
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -1194,20 +1194,19 @@ ObjectToMatrix(JSContext* cx, JS::Handle
     }
     *elts[i] = Float(d);
   }
   return true;
 }
 
 void
 CanvasRenderingContext2D::SetMozCurrentTransform(JSContext* cx,
-                                                 JSObject& currentTransform_,
+                                                 JS::Handle<JSObject*> currentTransform,
                                                  ErrorResult& error)
 {
-  JS::Rooted<JSObject*> currentTransform(cx, &currentTransform_);
   EnsureTarget();
   if (!IsTargetValid()) {
     error.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   Matrix newCTM;
   if (ObjectToMatrix(cx, currentTransform, newCTM, error)) {
@@ -1219,20 +1218,19 @@ JSObject*
 CanvasRenderingContext2D::GetMozCurrentTransform(JSContext* cx,
                                                  ErrorResult& error) const
 {
   return MatrixToJSObject(cx, mTarget ? mTarget->GetTransform() : Matrix(), error);
 }
 
 void
 CanvasRenderingContext2D::SetMozCurrentTransformInverse(JSContext* cx,
-                                                        JSObject& currentTransform_,
+                                                        JS::Handle<JSObject*> currentTransform,
                                                         ErrorResult& error)
 {
-  JS::Rooted<JSObject*> currentTransform(cx, &currentTransform_);
   EnsureTarget();
   if (!IsTargetValid()) {
     error.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   Matrix newCTMInverse;
   if (ObjectToMatrix(cx, currentTransform, newCTMInverse, error)) {
--- a/content/canvas/src/CanvasRenderingContext2D.h
+++ b/content/canvas/src/CanvasRenderingContext2D.h
@@ -302,21 +302,23 @@ 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 SetMozCurrentTransform(JSContext* cx, JSObject& currentTransform,
+  void SetMozCurrentTransform(JSContext* cx,
+                              JS::Handle<JSObject*> currentTransform,
                               mozilla::ErrorResult& error);
   JSObject* GetMozCurrentTransformInverse(JSContext* cx,
                                           mozilla::ErrorResult& error) const;
-  void SetMozCurrentTransformInverse(JSContext* cx, JSObject& currentTransform, 
+  void SetMozCurrentTransformInverse(JSContext* cx,
+                                     JS::Handle<JSObject*> currentTransform,
                                      mozilla::ErrorResult& error);
   void GetFillRule(nsAString& fillRule);
   void SetFillRule(const nsAString& fillRule);
   JS::Value GetMozDash(JSContext* cx, mozilla::ErrorResult& error);
   void SetMozDash(JSContext* cx, const JS::Value& mozDash,
                   mozilla::ErrorResult& error);
 
   double MozDashOffset()
@@ -467,17 +469,17 @@ protected:
     * Lookup table used to speed up PutImageData().
     */
   static uint8_t (*sPremultiplyTable)[256];
 
   static mozilla::gfx::DrawTarget* sErrorTarget;
 
   // Some helpers.  Doesn't modify a color on failure.
   void SetStyleFromJSValue(JSContext* cx, JS::Handle<JS::Value> value,
-			   Style whichStyle);
+                           Style whichStyle);
   void SetStyleFromString(const nsAString& str, Style whichStyle);
 
   void SetStyleFromGradient(CanvasGradient *gradient, Style whichStyle)
   {
     CurrentState().SetGradientStyle(whichStyle, gradient);
   }
 
   void SetStyleFromPattern(CanvasPattern *pattern, Style whichStyle)
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1559,16 +1559,22 @@ template<class T>
 class UnionMember {
     AlignedStorage2<T> storage;
 
 public:
     T& SetValue() {
       new (storage.addr()) T();
       return *storage.addr();
     }
+    template <typename T1, typename T2>
+    T& SetValue(const T1 &t1, const T2 &t2)
+    {
+      new (storage.addr()) T(t1, t2);
+      return *storage.addr();
+    }
     const T& Value() const {
       return *storage.addr();
     }
     void Destroy() {
       storage.addr()->~T();
     }
 };
 
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2611,19 +2611,28 @@ def getJSToNativeConversionInfo(type, de
                 "}")
             if type.nullable():
                 templateBody = handleDefaultNull(templateBody, codeToSetNull)
             else:
                 assert(defaultValue is None)
 
         return templateBody
 
-    # A helper function for converting things that look like JSObject*
-    # when nullable and JSObject& when not nullable.
+    # A helper function for converting things that look like a JSObject*.
     def handleJSObjectType(type, isMember, failureCode):
+        if not isMember:
+            declType = CGGeneric("JS::Rooted<JSObject*>")
+            templateBody = "${declName} = &${valHandle}.toObject();"
+            setToNullCode = "${declName} = nullptr;"
+            template = wrapObjectTemplate(templateBody, type, setToNullCode,
+                                          failureCode)
+            return JSToNativeConversionInfo(template, declType=declType,
+                                            dealWithOptional=isOptional,
+                                            declArgs="cx")
+
         if type.nullable():
             declType = CGGeneric("LazyRootedObject")
         else:
             declType = CGGeneric("NonNullLazyRootedObject")
 
         # If cx is null then LazyRootedObject will not be
         # constructed and behave as nullptr.
         templateBody = "${declName}.construct(cx, &${val}.toObject());"
@@ -4195,27 +4204,29 @@ class CGCallGenerator(CGThing):
         resultAlreadyAddRefed = isResultAlreadyAddRefed(descriptorProvider,
                                                         extendedAttributes)
         (result, resultOutParam) = getRetvalDeclarationForType(returnType,
                                                                descriptorProvider,
                                                                resultAlreadyAddRefed)
 
         args = CGList([CGGeneric(arg) for arg in argsPre], ", ")
         for (a, name) in arguments:
-            # This is a workaround for a bug in Apple's clang.
-            if a.type.isObject() and not a.type.nullable() and not a.optional:
-                name = "(JSObject&)" + name
             arg = CGGeneric(name)
             # Now constify the things that need it
             def needsConst(a):
                 if a.type.isDictionary():
                     return True
                 if a.type.isSequence():
                     return True
-                if a.type.nullable():
+                # isObject() types are always a JS::Rooted, whether
+                # nullable or not, and it turns out a const JS::Rooted
+                # is not very helpful at all (in particular, it won't
+                # even convert to a JS::Handle).
+                # XXX bz Well, why not???
+                if a.type.nullable() and not a.type.isObject():
                     return True
                 if a.type.isString():
                     return True
                 if a.optional and not a.defaultValue:
                     # If a.defaultValue, then it's not going to use an Optional,
                     # so doesn't need to be const just due to being optional.
                     # This also covers variadic arguments.
                     return True
@@ -4279,17 +4290,19 @@ def wrapTypeIntoCurrentCompartment(type,
             value = "&" + value
         else:
             value = value + ".address()"
         return CGGeneric("if (!JS_WrapValue(cx, %s)) {\n"
                          "  return false;\n"
                          "}" % value)
 
     if type.isObject():
-        if not type.nullable():
+        if not isMember:
+            value = value + ".address()"
+        elif not type.nullable():
             value = "%s.Slot()" % value
         else:
             value = "&%s" % value
         return CGGeneric("if (!JS_WrapObject(cx, %s)) {\n"
                          "  return false;\n"
                          "}" % value)
 
     if type.isSpiderMonkeyInterface():
@@ -5587,22 +5600,17 @@ def getUnionAccessorSignatureType(type, 
         else:
             typeName = "%s&"
         return CGGeneric(typeName % type.unroll().identifier.name)
 
     if type.isAny():
         return CGGeneric("JS::Value")
 
     if type.isObject():
-        typeName = CGGeneric("JSObject")
-        if type.nullable():
-            typeName = CGWrapper(typeName, post="*")
-        else:
-            typeName = CGWrapper(typeName, post="&")
-        return typeName
+        return CGGeneric("JSObject*")
 
     if not type.isPrimitive():
         raise TypeError("Need native type for argument type '%s'" % str(type))
 
     typeName = CGGeneric(builtinNames[type.tag()])
     if type.nullable():
         typeName = CGTemplatedType("Nullable", typeName, isReference=True)
     return typeName
@@ -5639,17 +5647,17 @@ return true;"""
     structType = conversionInfo.declType.define()
     if structType.startswith("const "):
         structType = structType[6:]
     externalType = getUnionAccessorSignatureType(type, descriptorProvider).define()
 
     if type.isObject():
         setter = CGGeneric("void SetToObject(JSContext* cx, JSObject* obj)\n"
                            "{\n"
-                           "  mUnion.mValue.mObject.SetValue().construct(cx, obj);\n"
+                           "  mUnion.mValue.mObject.SetValue(cx, obj);\n"
                            "  mUnion.mType = mUnion.eObject;\n"
                            "}")
     else:
         jsConversion = string.Template(conversionInfo.template).substitute(
             {
                 "val": "value",
                 "valHandle": "value",
                 "valPtr": "pvalue",
@@ -5718,23 +5726,27 @@ class CGUnionStruct(CGThing):
         methodTemplate = """  bool Is${name}() const
   {
     return mType == e${name};
   }
   ${externalType} GetAs${name}() const
   {
     MOZ_ASSERT(Is${name}(), "Wrong type!");
     return const_cast<${structType}&>(mValue.m${name}.Value());
-  }
-  ${structType}& SetAs${name}()
+  }"""
+        methods.extend(mapTemplate(methodTemplate, templateVars))
+        # Now have to be careful: we do not want the SetAsObject() method!
+        setterTemplate = """ ${structType}& SetAs${name}()
   {
     mType = e${name};
     return mValue.m${name}.SetValue();
   }"""
-        methods.extend(mapTemplate(methodTemplate, templateVars))
+        methods.extend(mapTemplate(setterTemplate,
+                                   filter(lambda v: v["name"] != "Object",
+                                          templateVars)))
         values = mapTemplate("UnionMember<${structType} > m${name};", templateVars)
         return string.Template("""
 class ${structName} {
 public:
   ${structName}() : mType(eUninitialized)
   {
   }
   ~${structName}()
@@ -5807,22 +5819,17 @@ private:
                 "structName": str(self.type),
                 "doConversionsToJS": "\n\n".join(conversionsToJS)
                 })
 
     def getConversionToJS(self, arg):
         (templateVars, type) = arg
         assert not type.nullable() # flatMemberTypes never has nullable types
         val = "mValue.m%(name)s.Value()" % templateVars
-        if type.isObject():
-            # We'll have a NonNullLazyRootedObject while the wrapping code wants
-            # a JSObject*.  But our .ref() is a JS::Rooted<JSObject*>, which can
-            # convert to a JSObject*.
-            val = "%s.ref()" % val
-        elif type.isSpiderMonkeyInterface():
+        if type.isSpiderMonkeyInterface():
             # We have a NonNull<TypedArray> object while the wrapping code
             # wants a JSObject*.  Cheat with .get() so we don't have to
             # figure out the right reference type to cast to.
             val = "%s.get()->Obj()" % val
         wrapCode = wrapForType(
             type, self.descriptorProvider,
             {
                 "jsvalRef": "*vp",
@@ -5854,21 +5861,24 @@ class CGUnionConversionStruct(CGThing):
     return true;
   }""")
 
         templateVars = map(lambda t: getUnionTypeTemplateVars(t, self.descriptorProvider),
                            self.type.flatMemberTypes)
         structName = self.type.__str__()
 
         setters.extend(mapTemplate("${setter}", templateVars))
+        # Don't generate a SetAsObject, since we don't use it
         private = "\n".join(mapTemplate("""  ${structType}& SetAs${name}()
   {
     mUnion.mType = mUnion.e${name};
     return mUnion.mValue.m${name}.SetValue();
-  }""", templateVars))
+  }""",
+                                        filter(lambda v: v["name"] != "Object",
+                                               templateVars)))
         private += "\n\n"
         holders = filter(lambda v: v["holderType"] is not None, templateVars)
         if len(holders) > 0:
             private += "\n".join(mapTemplate("  ${holderType} m${name}Holder;", holders))
             private += "\n\n"
         private += "  " + structName + "& mUnion;"
         return string.Template("""
 class ${structName}Argument {
@@ -8231,21 +8241,17 @@ class CGNativeMember(ClassMethod):
                               "return dont_AddRef(${declName});")
             return result.define(), "nullptr", returnCode
         if type.isCallback():
             return ("already_AddRefed<%s>" % type.unroll().identifier.name,
                     "nullptr", "return ${declName}.forget();")
         if type.isAny():
             return "JS::Value", "JS::UndefinedValue()", "return ${declName};"
         if type.isObject():
-            if type.nullable():
-                returnCode = "return ${declName};"
-            else:
-                returnCode = "return ${declName}.ref();"
-            return "JSObject*", "nullptr", returnCode
+            return "JSObject*", "nullptr", "return ${declName};"
         if type.isSpiderMonkeyInterface():
             if type.nullable():
                 returnCode = "return ${declName} ? ${declName}->Obj() : nullptr;"
             else:
                 returnCode = ("return static_cast<%s&>(${declName}).Obj();" % type.name)
             return "JSObject*", "nullptr", returnCode
         if type.isSequence():
             # If we want to handle sequence-of-sequences return values, we're
@@ -8403,25 +8409,22 @@ class CGNativeMember(ClassMethod):
                 declType = "JS::Value"
             elif optional:
                 declType = "JS::Rooted<JS::Value>"
             else:
                 declType = "JS::Handle<JS::Value>"
             return declType, False, False
 
         if type.isObject():
-            if optional:
-                if type.nullable():
-                    declType = "LazyRootedObject"
-                else:
-                    declType = "NonNullLazyRootedObject"
-            elif type.nullable() or self.jsObjectsArePtr:
+            if isMember:
                 declType = "JSObject*"
+            elif optional:
+                declType = "JS::Rooted<JSObject*>"
             else:
-                declType = "JSObject&"
+                declType = "JS::Handle<JSObject*>"
             return declType, False, False
 
         if type.isDictionary():
             typeName = CGDictionary.makeDictionaryName(type.inner,
                                                        self.descriptor.workers)
             return typeName, True, True
 
         if type.isDate():
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -132,22 +132,22 @@ public:
   static
   already_AddRefed<TestInterface> Test(const GlobalObject&, const nsAString&,
                                        ErrorResult&);
   static
   already_AddRefed<TestInterface> Test2(const GlobalObject&,
                                         JSContext*,
                                         const DictForConstructor&,
                                         JS::Value,
-                                        JSObject&,
-                                        JSObject*,
+                                        JS::Handle<JSObject*>,
+                                        JS::Handle<JSObject*>,
                                         const Sequence<Dict>&,
                                         const Optional<JS::Rooted<JS::Value> >&,
-                                        const Optional<NonNullLazyRootedObject>&,
-                                        const Optional<LazyRootedObject>&,
+                                        const Optional<JS::Rooted<JSObject*> >&,
+                                        const Optional<JS::Rooted<JSObject*> >&,
                                         ErrorResult&);
 
   // Integer types
   int8_t ReadonlyByte();
   int8_t WritableByte();
   void SetWritableByte(int8_t);
   void PassByte(int8_t);
   int8_t ReceiveByte();
@@ -429,33 +429,33 @@ public:
 
   // Any types
   void PassAny(JSContext*, JS::Handle<JS::Value>);
   void PassOptionalAny(JSContext*, const Optional<JS::Rooted<JS::Value> >&);
   void PassAnyDefaultNull(JSContext*, JS::Handle<JS::Value>);
   JS::Value ReceiveAny(JSContext*);
 
   // object types
-  void PassObject(JSContext*, JSObject&);
-  void PassNullableObject(JSContext*, JSObject*);
-  void PassOptionalObject(JSContext*, const Optional<NonNullLazyRootedObject>&);
-  void PassOptionalNullableObject(JSContext*, const Optional<LazyRootedObject>&);
-  void PassOptionalNullableObjectWithDefaultValue(JSContext*, JSObject*);
+  void PassObject(JSContext*, JS::Handle<JSObject*>);
+  void PassNullableObject(JSContext*, JS::Handle<JSObject*>);
+  void PassOptionalObject(JSContext*, const Optional<JS::Rooted<JSObject*> >&);
+  void PassOptionalNullableObject(JSContext*, const Optional<JS::Rooted<JSObject*> >&);
+  void PassOptionalNullableObjectWithDefaultValue(JSContext*, JS::Handle<JSObject*>);
   JSObject* ReceiveObject(JSContext*);
   JSObject* ReceiveNullableObject(JSContext*);
 
   // Union types
   void PassUnion(JSContext*, const ObjectOrLong& arg);
-  void PassUnionWithNullable(JSContext*, const ObjectOrNullOrLong& arg)
+  void PassUnionWithNullable(JSContext* cx, const ObjectOrNullOrLong& arg)
   {
     ObjectOrLong returnValue;
     if (arg.IsNull()) {
     } else if (arg.IsObject()) {
-      JSObject& obj = (JSObject&)arg.GetAsObject();
-      JS_GetClass(&obj);
+      JS::Rooted<JSObject*> obj(cx, arg.GetAsObject());
+      JS_GetClass(obj);
       //returnValue.SetAsObject(&obj);
     } else {
       int32_t i = arg.GetAsLong();
       i += 1;
     }
   }
   void PassNullableUnion(JSContext*, const Nullable<ObjectOrLong>&);
   void PassOptionalUnion(JSContext*, const Optional<ObjectOrLong>&);
@@ -693,18 +693,18 @@ private:
   void PassOptionalExternal(Optional<TestExternalInterface*>&) MOZ_DELETE;
   void PassOptionalNonNullExternal(Optional<TestExternalInterface*>&) MOZ_DELETE;
   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<JSObject*>&) MOZ_DELETE;
-  void PassOptionalNullableCallback(JSContext*, Optional<JSObject*>&) 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;
 
   // 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;
--- a/dom/bindings/test/TestJSImplGen.webidl
+++ b/dom/bindings/test/TestJSImplGen.webidl
@@ -17,19 +17,19 @@ enum MyTestEnum {
   "b"
 };
 
 // We don't support multiple constructors (bug 869268) or named constructors
 // for JS-implemented WebIDL.
 [Constructor(DOMString str, unsigned long num, boolean? boolArg,
              TestInterface? iface, long arg1,
              DictForConstructor dict, any any1,
-             /* (BUG 856911) object obj1,*/
+             object obj1,
              object? obj2, sequence<Dict> seq, optional any any2,
-             /* (BUG 856911) optional object obj3, */
+             optional object obj3,
              optional object? obj4),
  JSImplementation="@mozilla.org/test-js-impl-interface;1"]
 interface TestJSImplInterface {
   // Integer types
   // XXXbz add tests for throwing versions of all the integer stuff
   readonly attribute byte readonlyByte;
   attribute byte writableByte;
   void passByte(byte arg);
@@ -317,22 +317,19 @@ interface TestJSImplInterface {
   void passOptionalNullableTreatAsNullCallbackWithDefaultValue(optional TestTreatAsNullCallback? arg = null);
 
   // Any types
   void passAny(any arg);
   void passOptionalAny(optional any arg);
   void passAnyDefaultNull(optional any arg = null);
   any receiveAny();
 
-  // object types.  Unfortunately, non-nullable object is inconsistently
-  // represented as either JSObject* (for callbacks) or JSObject& (for
-  // non-callbacks), so we can't handle those yet.  See bug 856911.
-  //(BUG 856911)  void passObject(object arg);
+  void passObject(object arg);
   void passNullableObject(object? arg);
-  //(BUG 856911)  void passOptionalObject(optional object arg);
+  void passOptionalObject(optional object arg);
   void passOptionalNullableObject(optional object? arg);
   void passOptionalNullableObjectWithDefaultValue(optional object? arg = null);
   object receiveObject();
   object? receiveNullableObject();
 
   // Union types
   void passUnion((object or long) arg);
   void passUnionWithNullable((object? or long) arg);
--- a/dom/workers/EventTarget.h
+++ b/dom/workers/EventTarget.h
@@ -41,19 +41,19 @@ public:
                    bool aCapture, Nullable<bool> aWantsUntrusted,
                    ErrorResult& aRv);
 
   void
   RemoveEventListener(const nsAString& aType, JSObject* aListener,
                       bool aCapture, ErrorResult& aRv);
 
   bool
-  DispatchEvent(JSObject& aEvent, ErrorResult& aRv) const
+  DispatchEvent(JS::Handle<JSObject*> aEvent, ErrorResult& aRv) const
   {
-    return mListenerManager.DispatchEvent(GetJSContext(), *this, &aEvent, aRv);
+    return mListenerManager.DispatchEvent(GetJSContext(), *this, aEvent, aRv);
   }
 
   JSObject*
   GetEventListener(const nsAString& aType, ErrorResult& aRv) const;
 
   void
   SetEventListener(const nsAString& aType, JSObject* aListener,
                    ErrorResult& aRv);
--- a/dom/workers/FileReaderSync.cpp
+++ b/dom/workers/FileReaderSync.cpp
@@ -66,20 +66,20 @@ FileReaderSync::Constructor(const Worker
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   return frs;
 }
 
 JSObject*
-FileReaderSync::ReadAsArrayBuffer(JSContext* aCx, JSObject& aBlob,
+FileReaderSync::ReadAsArrayBuffer(JSContext* aCx, JS::Handle<JSObject*> aBlob,
                                   ErrorResult& aRv)
 {
-  nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(&aBlob);
+  nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aBlob);
   if (!blob) {
     aRv.Throw(NS_ERROR_INVALID_ARG);
     return nullptr;
   }
 
   uint64_t blobSize;
   nsresult rv = blob->GetSize(&blobSize);
   if (NS_FAILED(rv)) {
@@ -112,20 +112,21 @@ FileReaderSync::ReadAsArrayBuffer(JSCont
     return nullptr;
   }
   NS_ASSERTION(numRead == bufferLength, "failed to read data");
 
   return jsArrayBuffer;
 }
 
 void
-FileReaderSync::ReadAsBinaryString(JSObject& aBlob, nsAString& aResult,
+FileReaderSync::ReadAsBinaryString(JS::Handle<JSObject*> aBlob,
+                                   nsAString& aResult,
                                    ErrorResult& aRv)
 {
-  nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(&aBlob);
+  nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aBlob);
   if (!blob) {
     aRv.Throw(NS_ERROR_INVALID_ARG);
     return;
   }
 
   nsCOMPtr<nsIInputStream> stream;
   nsresult rv = blob->GetInternalStream(getter_AddRefs(stream));
   if (NS_FAILED(rv)) {
@@ -147,22 +148,22 @@ FileReaderSync::ReadAsBinaryString(JSObj
     if (aResult.Length() - oldLength != numRead) {
       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
       return;
     }
   } while (numRead > 0);
 }
 
 void
-FileReaderSync::ReadAsText(JSObject& aBlob,
+FileReaderSync::ReadAsText(JS::Handle<JSObject*> aBlob,
                            const Optional<nsAString>& aEncoding,
                            nsAString& aResult,
                            ErrorResult& aRv)
 {
-  nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(&aBlob);
+  nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aBlob);
   if (!blob) {
     aRv.Throw(NS_ERROR_INVALID_ARG);
     return;
   }
 
   nsCOMPtr<nsIInputStream> stream;
   nsresult rv = blob->GetInternalStream(getter_AddRefs(stream));
   if (NS_FAILED(rv)) {
@@ -203,20 +204,20 @@ FileReaderSync::ReadAsText(JSObject& aBl
   rv = ConvertStream(stream, charset.get(), aResult);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 }
 
 void
-FileReaderSync::ReadAsDataURL(JSObject& aBlob, nsAString& aResult,
+FileReaderSync::ReadAsDataURL(JS::Handle<JSObject*> aBlob, nsAString& aResult,
                               ErrorResult& aRv)
 {
-  nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(&aBlob);
+  nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aBlob);
   if (!blob) {
     aRv.Throw(NS_ERROR_INVALID_ARG);
     return;
   }
 
   nsAutoString scratchResult;
   scratchResult.AssignLiteral("data:");
 
--- a/dom/workers/FileReaderSync.h
+++ b/dom/workers/FileReaderSync.h
@@ -37,23 +37,25 @@ public:
 
   static FileReaderSync*
   Constructor(const WorkerGlobalObject& aGlobal, ErrorResult& aRv);
 
   NS_DECL_ISUPPORTS_INHERITED
 
   FileReaderSync(JSContext* aCx);
 
-  JSObject* ReadAsArrayBuffer(JSContext* aCx, JSObject& aBlob,
+  JSObject* ReadAsArrayBuffer(JSContext* aCx, JS::Handle<JSObject*> aBlob,
                               ErrorResult& aRv);
-  void ReadAsBinaryString(JSObject& aBlob, nsAString& aResult,
+  void ReadAsBinaryString(JS::Handle<JSObject*> aBlob, nsAString& aResult,
                           ErrorResult& aRv);
-  void ReadAsText(JSObject& aBlob, const Optional<nsAString>& aEncoding,
+  void ReadAsText(JS::Handle<JSObject*> aBlob,
+                  const Optional<nsAString>& aEncoding,
                   nsAString& aResult, ErrorResult& aRv);
-  void ReadAsDataURL(JSObject& aBlob, nsAString& aResult, ErrorResult& aRv);
+  void ReadAsDataURL(JS::Handle<JSObject*> aBlob, nsAString& aResult,
+                     ErrorResult& aRv);
 
   // From nsICharsetDetectionObserver
   NS_IMETHOD Notify(const char *aCharset, nsDetectionConfident aConf);
 };
 
 END_WORKERS_NAMESPACE
 
 #endif // mozilla_dom_workers_filereadersync_h__
--- a/dom/workers/XMLHttpRequest.h
+++ b/dom/workers/XMLHttpRequest.h
@@ -236,17 +236,17 @@ public:
 
   JSObject*
   GetChannel() const
   {
     return NULL;
   }
 
   JS::Value
-  GetInterface(JSContext* cx, JSObject& aIID, ErrorResult& aRv)
+  GetInterface(JSContext* cx, JS::Handle<JSObject*> aIID, ErrorResult& aRv)
   {
     aRv.Throw(NS_ERROR_FAILURE);
     return JSVAL_NULL;
   }
 
   XMLHttpRequestUpload*
   GetUploadObjectNoCreate() const
   {