Bug 1148962 - Use TakeOwnershipOfErrorReporting in CPOW code (r=bholley)
authorBill McCloskey <billm@mozilla.com>
Sun, 29 Mar 2015 09:13:36 -0700
changeset 236703 044dad7f5b5c727b95cf6aaeb8d3852f9175492a
parent 236702 07fba3393139ea9fa88b36da9fe883494d2f7a3b
child 236704 06529960107eb562fd469248d4aaed89928803ee
push id28514
push usercbook@mozilla.com
push dateTue, 31 Mar 2015 12:46:33 +0000
treeherdermozilla-central@c20f8549d631 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs1148962
milestone40.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 1148962 - Use TakeOwnershipOfErrorReporting in CPOW code (r=bholley)
js/ipc/WrapperAnswer.cpp
js/ipc/WrapperAnswer.h
--- a/js/ipc/WrapperAnswer.cpp
+++ b/js/ipc/WrapperAnswer.cpp
@@ -22,34 +22,32 @@ using namespace mozilla::jsipc;
 // happen if the target is a scripted proxy, which is probably something that we
 // don't want to support over CPOWs. When enough code is fixed up, the long-term
 // plan is to have the JS engine throw if it encounters script when it isn't
 // expecting it.
 using mozilla::dom::AutoJSAPI;
 using mozilla::dom::AutoEntryScript;
 
 bool
-WrapperAnswer::fail(JSContext* cx, ReturnStatus* rs)
+WrapperAnswer::fail(AutoJSAPI& jsapi, ReturnStatus* rs)
 {
     // By default, we set |undefined| unless we can get a more meaningful
     // exception.
     *rs = ReturnStatus(ReturnException(JSVariant(UndefinedVariant())));
 
     // Note we always return true from this function, since this propagates
     // to the IPC code, and we don't want a JS failure to cause the death
     // of the child process.
 
+    JSContext* cx = jsapi.cx();
     RootedValue exn(cx);
-    if (!JS_GetPendingException(cx, &exn))
+    if (!jsapi.HasException())
         return true;
 
-    // If we don't clear the pending exception, JS will try to wrap it as it
-    // leaves the current compartment. Since there is no previous compartment,
-    // that would crash.
-    JS_ClearPendingException(cx);
+    jsapi.StealException(&exn);
 
     if (JS_IsStopIteration(exn)) {
         *rs = ReturnStatus(ReturnStopIteration());
         return true;
     }
 
     // If this fails, we still don't want to exit. Just return an invalid
     // exception.
@@ -74,25 +72,26 @@ WrapperAnswer::ok(ReturnStatus* rs, cons
 }
 
 bool
 WrapperAnswer::RecvPreventExtensions(const ObjectId& objId, ReturnStatus* rs)
 {
     AutoJSAPI jsapi;
     if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
         return false;
+    jsapi.TakeOwnershipOfErrorReporting();
     JSContext* cx = jsapi.cx();
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     ObjectOpResult success;
     if (!JS_PreventExtensions(cx, obj, success))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     LOG("%s.preventExtensions()", ReceiverObj(objId));
     return ok(rs, success);
 }
 
 static void
 EmptyDesc(PPropertyDescriptor* desc)
 {
@@ -105,403 +104,415 @@ EmptyDesc(PPropertyDescriptor* desc)
 
 bool
 WrapperAnswer::RecvGetPropertyDescriptor(const ObjectId& objId, const JSIDVariant& idVar,
                                          ReturnStatus* rs, PPropertyDescriptor* out)
 {
     AutoJSAPI jsapi;
     if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
         return false;
+    jsapi.TakeOwnershipOfErrorReporting();
     JSContext* cx = jsapi.cx();
     EmptyDesc(out);
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     LOG("%s.getPropertyDescriptor(%s)", ReceiverObj(objId), Identifier(idVar));
 
     RootedId id(cx);
     if (!fromJSIDVariant(cx, idVar, &id))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     Rooted<JSPropertyDescriptor> desc(cx);
     if (!JS_GetPropertyDescriptorById(cx, obj, id, &desc))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     if (!fromDescriptor(cx, desc, out))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     return ok(rs);
 }
 
 bool
 WrapperAnswer::RecvGetOwnPropertyDescriptor(const ObjectId& objId, const JSIDVariant& idVar,
                                             ReturnStatus* rs, PPropertyDescriptor* out)
 {
     AutoJSAPI jsapi;
     if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
         return false;
+    jsapi.TakeOwnershipOfErrorReporting();
     JSContext* cx = jsapi.cx();
     EmptyDesc(out);
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     LOG("%s.getOwnPropertyDescriptor(%s)", ReceiverObj(objId), Identifier(idVar));
 
     RootedId id(cx);
     if (!fromJSIDVariant(cx, idVar, &id))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     Rooted<JSPropertyDescriptor> desc(cx);
     if (!JS_GetOwnPropertyDescriptorById(cx, obj, id, &desc))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     if (!fromDescriptor(cx, desc, out))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     return ok(rs);
 }
 
 bool
 WrapperAnswer::RecvDefineProperty(const ObjectId& objId, const JSIDVariant& idVar,
                                   const PPropertyDescriptor& descriptor, ReturnStatus* rs)
 {
     AutoJSAPI jsapi;
     if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
         return false;
+    jsapi.TakeOwnershipOfErrorReporting();
     JSContext* cx = jsapi.cx();
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     LOG("define %s[%s]", ReceiverObj(objId), Identifier(idVar));
 
     RootedId id(cx);
     if (!fromJSIDVariant(cx, idVar, &id))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     Rooted<JSPropertyDescriptor> desc(cx);
     if (!toDescriptor(cx, descriptor, &desc))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     ObjectOpResult success;
     if (!js::DefineOwnProperty(cx, obj, id, desc, success))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
     return ok(rs, success);
 }
 
 bool
 WrapperAnswer::RecvDelete(const ObjectId& objId, const JSIDVariant& idVar, ReturnStatus* rs)
 {
     AutoJSAPI jsapi;
     if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
         return false;
+    jsapi.TakeOwnershipOfErrorReporting();
     JSContext* cx = jsapi.cx();
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     LOG("delete %s[%s]", ReceiverObj(objId), Identifier(idVar));
 
     RootedId id(cx);
     if (!fromJSIDVariant(cx, idVar, &id))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     ObjectOpResult success;
     if (!JS_DeletePropertyById(cx, obj, id, success))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
     return ok(rs, success);
 }
 
 bool
 WrapperAnswer::RecvHas(const ObjectId& objId, const JSIDVariant& idVar, ReturnStatus* rs, bool* bp)
 {
     AutoJSAPI jsapi;
     if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
         return false;
+    jsapi.TakeOwnershipOfErrorReporting();
     JSContext* cx = jsapi.cx();
     *bp = false;
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     LOG("%s.has(%s)", ReceiverObj(objId), Identifier(idVar));
 
     RootedId id(cx);
     if (!fromJSIDVariant(cx, idVar, &id))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     bool found;
     if (!JS_HasPropertyById(cx, obj, id, &found))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
     *bp = !!found;
 
     return ok(rs);
 }
 
 bool
 WrapperAnswer::RecvHasOwn(const ObjectId& objId, const JSIDVariant& idVar, ReturnStatus* rs,
                           bool* bp)
 {
     AutoJSAPI jsapi;
     if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
         return false;
+    jsapi.TakeOwnershipOfErrorReporting();
     JSContext* cx = jsapi.cx();
     *bp = false;
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     LOG("%s.hasOwn(%s)", ReceiverObj(objId), Identifier(idVar));
 
     RootedId id(cx);
     if (!fromJSIDVariant(cx, idVar, &id))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     Rooted<JSPropertyDescriptor> desc(cx);
     if (!JS_GetPropertyDescriptorById(cx, obj, id, &desc))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
     *bp = (desc.object() == obj);
 
     return ok(rs);
 }
 
 bool
 WrapperAnswer::RecvGet(const ObjectId& objId, const ObjectVariant& receiverVar,
                        const JSIDVariant& idVar, ReturnStatus* rs, JSVariant* result)
 {
     // We may run scripted getters.
     AutoEntryScript aes(xpc::NativeGlobal(scopeForTargetObjects()));
+    aes.TakeOwnershipOfErrorReporting();
     JSContext* cx = aes.cx();
 
     // The outparam will be written to the buffer, so it must be set even if
     // the parent won't read it.
     *result = UndefinedVariant();
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
-        return fail(cx, rs);
+        return fail(aes, rs);
 
     RootedObject receiver(cx, fromObjectVariant(cx, receiverVar));
     if (!receiver)
-        return fail(cx, rs);
+        return fail(aes, rs);
 
     RootedId id(cx);
     if (!fromJSIDVariant(cx, idVar, &id))
-        return fail(cx, rs);
+        return fail(aes, rs);
 
     JS::RootedValue val(cx);
     if (!JS_ForwardGetPropertyTo(cx, obj, id, receiver, &val))
-        return fail(cx, rs);
+        return fail(aes, rs);
 
     if (!toVariant(cx, val, result))
-        return fail(cx, rs);
+        return fail(aes, rs);
 
     LOG("get %s.%s = %s", ReceiverObj(objId), Identifier(idVar), OutVariant(*result));
 
     return ok(rs);
 }
 
 bool
 WrapperAnswer::RecvSet(const ObjectId& objId, const JSIDVariant& idVar, const JSVariant& value,
                        const JSVariant& receiverVar, ReturnStatus* rs)
 {
     // We may run scripted setters.
     AutoEntryScript aes(xpc::NativeGlobal(scopeForTargetObjects()));
+    aes.TakeOwnershipOfErrorReporting();
     JSContext* cx = aes.cx();
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
-        return fail(cx, rs);
+        return fail(aes, rs);
 
     LOG("set %s[%s] = %s", ReceiverObj(objId), Identifier(idVar), InVariant(value));
 
     RootedId id(cx);
     if (!fromJSIDVariant(cx, idVar, &id))
-        return fail(cx, rs);
+        return fail(aes, rs);
 
     RootedValue val(cx);
     if (!fromVariant(cx, value, &val))
-        return fail(cx, rs);
+        return fail(aes, rs);
 
     RootedValue receiver(cx);
     if (!fromVariant(cx, receiverVar, &receiver))
-        return fail(cx, rs);
+        return fail(aes, rs);
 
     ObjectOpResult result;
     if (!JS_ForwardSetPropertyTo(cx, obj, id, val, receiver, result))
-        return fail(cx, rs);
+        return fail(aes, rs);
 
     return ok(rs, result);
 }
 
 bool
 WrapperAnswer::RecvIsExtensible(const ObjectId& objId, ReturnStatus* rs, bool* result)
 {
     AutoJSAPI jsapi;
     if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
         return false;
+    jsapi.TakeOwnershipOfErrorReporting();
     JSContext* cx = jsapi.cx();
     *result = false;
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     LOG("%s.isExtensible()", ReceiverObj(objId));
 
     bool extensible;
     if (!JS_IsExtensible(cx, obj, &extensible))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     *result = !!extensible;
     return ok(rs);
 }
 
 bool
 WrapperAnswer::RecvCallOrConstruct(const ObjectId& objId,
                                    InfallibleTArray<JSParam>&& argv,
                                    const bool& construct,
                                    ReturnStatus* rs,
                                    JSVariant* result,
                                    nsTArray<JSParam>* outparams)
 {
     AutoEntryScript aes(xpc::NativeGlobal(scopeForTargetObjects()));
+    aes.TakeOwnershipOfErrorReporting();
     JSContext* cx = aes.cx();
 
     // The outparam will be written to the buffer, so it must be set even if
     // the parent won't read it.
     *result = UndefinedVariant();
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
-        return fail(cx, rs);
+        return fail(aes, rs);
 
     MOZ_ASSERT(argv.Length() >= 2);
 
     RootedValue objv(cx);
     if (!fromVariant(cx, argv[0], &objv))
-        return fail(cx, rs);
+        return fail(aes, rs);
 
     *result = JSVariant(UndefinedVariant());
 
     AutoValueVector vals(cx);
     AutoValueVector outobjects(cx);
     for (size_t i = 0; i < argv.Length(); i++) {
         if (argv[i].type() == JSParam::Tvoid_t) {
             // This is an outparam.
             RootedObject obj(cx, xpc::NewOutObject(cx));
             if (!obj)
-                return fail(cx, rs);
+                return fail(aes, rs);
             if (!outobjects.append(ObjectValue(*obj)))
-                return fail(cx, rs);
+                return fail(aes, rs);
             if (!vals.append(ObjectValue(*obj)))
-                return fail(cx, rs);
+                return fail(aes, rs);
         } else {
             RootedValue v(cx);
             if (!fromVariant(cx, argv[i].get_JSVariant(), &v))
-                return fail(cx, rs);
+                return fail(aes, rs);
             if (!vals.append(v))
-                return fail(cx, rs);
+                return fail(aes, rs);
         }
     }
 
     RootedValue rval(cx);
     {
         AutoSaveContextOptions asco(cx);
         ContextOptionsRef(cx).setDontReportUncaught(true);
 
         HandleValueArray args = HandleValueArray::subarray(vals, 2, vals.length() - 2);
         bool success;
         if (construct)
             success = JS::Construct(cx, vals[0], args, &rval);
         else
             success = JS::Call(cx, vals[1], vals[0], args, &rval);
         if (!success)
-            return fail(cx, rs);
+            return fail(aes, rs);
     }
 
     if (!toVariant(cx, rval, result))
-        return fail(cx, rs);
+        return fail(aes, rs);
 
     // Prefill everything with a dummy jsval.
     for (size_t i = 0; i < outobjects.length(); i++)
         outparams->AppendElement(JSParam(void_t()));
 
     // Go through each argument that was an outparam, retrieve the "value"
     // field, and add it to a temporary list. We need to do this separately
     // because the outparams vector is not rooted.
     vals.clear();
     for (size_t i = 0; i < outobjects.length(); i++) {
         RootedObject obj(cx, &outobjects[i].toObject());
 
         RootedValue v(cx);
         bool found;
         if (JS_HasProperty(cx, obj, "value", &found)) {
             if (!JS_GetProperty(cx, obj, "value", &v))
-                return fail(cx, rs);
+                return fail(aes, rs);
         } else {
             v = UndefinedValue();
         }
         if (!vals.append(v))
-            return fail(cx, rs);
+            return fail(aes, rs);
     }
 
     // Copy the outparams. If any outparam is already set to a void_t, we
     // treat this as the outparam never having been set.
     for (size_t i = 0; i < vals.length(); i++) {
         JSVariant variant;
         if (!toVariant(cx, vals[i], &variant))
-            return fail(cx, rs);
+            return fail(aes, rs);
         outparams->ReplaceElementAt(i, JSParam(variant));
     }
 
     LOG("%s.call(%s) = %s", ReceiverObj(objId), argv, OutVariant(*result));
 
     return ok(rs);
 }
 
 bool
 WrapperAnswer::RecvHasInstance(const ObjectId& objId, const JSVariant& vVar, ReturnStatus* rs, bool* bp)
 {
     AutoJSAPI jsapi;
     if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
         return false;
+    jsapi.TakeOwnershipOfErrorReporting();
     JSContext* cx = jsapi.cx();
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     LOG("%s.hasInstance(%s)", ReceiverObj(objId), InVariant(vVar));
 
     RootedValue val(cx);
     if (!fromVariant(cx, vVar, &val))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     if (!JS_HasInstance(cx, obj, val, bp))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     return ok(rs);
 }
 
 bool
 WrapperAnswer::RecvObjectClassIs(const ObjectId& objId, const uint32_t& classValue,
                                  bool* result)
 {
     AutoJSAPI jsapi;
     if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
         return false;
+    jsapi.TakeOwnershipOfErrorReporting();
     JSContext* cx = jsapi.cx();
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj) {
         // This is very unfortunate, but we have no choice.
         *result = false;
         return true;
     }
@@ -513,16 +524,17 @@ WrapperAnswer::RecvObjectClassIs(const O
 }
 
 bool
 WrapperAnswer::RecvClassName(const ObjectId& objId, nsCString* name)
 {
     AutoJSAPI jsapi;
     if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
         return false;
+    jsapi.TakeOwnershipOfErrorReporting();
     JSContext* cx = jsapi.cx();
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj) {
         // This is very unfortunate, but we have no choice.
         return "<dead CPOW>";
     }
 
@@ -535,137 +547,142 @@ WrapperAnswer::RecvClassName(const Objec
 bool
 WrapperAnswer::RecvGetPrototype(const ObjectId& objId, ReturnStatus* rs, ObjectOrNullVariant* result)
 {
     *result = NullVariant();
 
     AutoJSAPI jsapi;
     if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
         return false;
+    jsapi.TakeOwnershipOfErrorReporting();
     JSContext* cx = jsapi.cx();
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     JS::RootedObject proto(cx);
     if (!JS_GetPrototype(cx, obj, &proto))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     if (!toObjectOrNullVariant(cx, proto, result))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     LOG("getPrototype(%s)", ReceiverObj(objId));
 
     return ok(rs);
 }
 
 bool
 WrapperAnswer::RecvRegExpToShared(const ObjectId& objId, ReturnStatus* rs,
                                   nsString* source, uint32_t* flags)
 {
     AutoJSAPI jsapi;
     if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
         return false;
+    jsapi.TakeOwnershipOfErrorReporting();
     JSContext* cx = jsapi.cx();
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     MOZ_RELEASE_ASSERT(JS_ObjectIsRegExp(cx, obj));
     RootedString sourceJSStr(cx, JS_GetRegExpSource(cx, obj));
     if (!sourceJSStr)
-        return fail(cx, rs);
+        return fail(jsapi, rs);
     nsAutoJSString sourceStr;
     if (!sourceStr.init(cx, sourceJSStr))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
     source->Assign(sourceStr);
 
     *flags = JS_GetRegExpFlags(cx, obj);
 
     return ok(rs);
 }
 
 bool
 WrapperAnswer::RecvGetPropertyKeys(const ObjectId& objId, const uint32_t& flags,
                                    ReturnStatus* rs, nsTArray<JSIDVariant>* ids)
 {
     AutoJSAPI jsapi;
     if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
         return false;
+    jsapi.TakeOwnershipOfErrorReporting();
     JSContext* cx = jsapi.cx();
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     LOG("%s.getPropertyKeys()", ReceiverObj(objId));
 
     AutoIdVector props(cx);
     if (!js::GetPropertyKeys(cx, obj, flags, &props))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     for (size_t i = 0; i < props.length(); i++) {
         JSIDVariant id;
         if (!toJSIDVariant(cx, props[i], &id))
-            return fail(cx, rs);
+            return fail(jsapi, rs);
 
         ids->AppendElement(id);
     }
 
     return ok(rs);
 }
 
 bool
 WrapperAnswer::RecvInstanceOf(const ObjectId& objId, const JSIID& iid, ReturnStatus* rs,
                               bool* instanceof)
 {
     AutoJSAPI jsapi;
     if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
         return false;
+    jsapi.TakeOwnershipOfErrorReporting();
     JSContext* cx = jsapi.cx();
 
     *instanceof = false;
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     LOG("%s.instanceOf()", ReceiverObj(objId));
 
     nsID nsiid;
     ConvertID(iid, &nsiid);
 
     nsresult rv = xpc::HasInstance(cx, obj, &nsiid, instanceof);
     if (rv != NS_OK)
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     return ok(rs);
 }
 
 bool
 WrapperAnswer::RecvDOMInstanceOf(const ObjectId& objId, const int& prototypeID,
                                  const int& depth, ReturnStatus* rs, bool* instanceof)
 {
     AutoJSAPI jsapi;
     if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
         return false;
+    jsapi.TakeOwnershipOfErrorReporting();
     JSContext* cx = jsapi.cx();
     *instanceof = false;
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
-        return fail(cx, rs);
+        return fail(jsapi, rs);
 
     LOG("%s.domInstanceOf()", ReceiverObj(objId));
 
     bool tmp;
     if (!mozilla::dom::InterfaceHasInstance(cx, prototypeID, depth, obj, &tmp))
-        return fail(cx, rs);
+        return fail(jsapi, rs);
     *instanceof = tmp;
 
     return ok(rs);
 }
 
 bool
 WrapperAnswer::RecvDropObject(const ObjectId& objId)
 {
--- a/js/ipc/WrapperAnswer.h
+++ b/js/ipc/WrapperAnswer.h
@@ -6,16 +6,21 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_jsipc_WrapperAnswer_h_
 #define mozilla_jsipc_WrapperAnswer_h_
 
 #include "JavaScriptShared.h"
 
 namespace mozilla {
+
+namespace dom {
+class AutoJSAPI;
+}
+
 namespace jsipc {
 
 class WrapperAnswer : public virtual JavaScriptShared
 {
   public:
     explicit WrapperAnswer(JSRuntime* rt) : JavaScriptShared(rt) {}
 
     bool RecvPreventExtensions(const ObjectId& objId, ReturnStatus* rs);
@@ -57,17 +62,17 @@ class WrapperAnswer : public virtual Jav
     bool RecvInstanceOf(const ObjectId& objId, const JSIID& iid,
                         ReturnStatus* rs, bool* instanceof);
     bool RecvDOMInstanceOf(const ObjectId& objId, const int& prototypeID, const int& depth,
                            ReturnStatus* rs, bool* instanceof);
 
     bool RecvDropObject(const ObjectId& objId);
 
   private:
-    bool fail(JSContext* cx, ReturnStatus* rs);
+    bool fail(dom::AutoJSAPI& jsapi, ReturnStatus* rs);
     bool ok(ReturnStatus* rs);
     bool ok(ReturnStatus* rs, const JS::ObjectOpResult& result);
 };
 
 } // mozilla
 } // jsipc
 
 #endif