Bug 1113369, part 4 - [[Set]] ObjectOpResult support. r=Waldo, r=bz in dom, r=dvander in js/ipc, r=bholley in js/xpconnect.
authorJason Orendorff <jorendorff@mozilla.com>
Tue, 03 Feb 2015 19:51:40 -0600
changeset 262654 0712a3d4b79c78f151cf50407fb8707f41b52b25
parent 262653 2b18c04de86c2583959e350a95ef77d621deaef3
child 262655 35f7c0795116b44f106b79dab2f1ccbea9ca688d
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo, bz, dvander, bholley
bugs1113369
milestone39.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 1113369, part 4 - [[Set]] ObjectOpResult support. r=Waldo, r=bz in dom, r=dvander in js/ipc, r=bholley in js/xpconnect.
dom/base/nsGlobalWindow.cpp
dom/bindings/DOMJSProxyHandler.cpp
dom/bindings/DOMJSProxyHandler.h
dom/plugins/base/nsJSNPRuntime.cpp
js/ipc/JavaScriptBase.h
js/ipc/JavaScriptShared.cpp
js/ipc/PJavaScript.ipdl
js/ipc/WrapperAnswer.cpp
js/ipc/WrapperAnswer.h
js/ipc/WrapperOwner.cpp
js/ipc/WrapperOwner.h
js/public/Class.h
js/public/Proxy.h
js/src/builtin/TypedObject.cpp
js/src/builtin/TypedObject.h
js/src/ctypes/CTypes.cpp
js/src/jit-test/tests/basic/expression-autopsy.js
js/src/jit/BaselineIC.cpp
js/src/jit/IonCaches.cpp
js/src/jit/JitFrames.cpp
js/src/jit/JitFrames.h
js/src/jit/VMFunctions.cpp
js/src/js.msg
js/src/jsapi-tests/testForwardSetProperty.cpp
js/src/jsapi-tests/testSetPropertyIgnoringNamedGetter.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jscntxtinlines.h
js/src/jsfriendapi.h
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsreflect.cpp
js/src/jsstr.cpp
js/src/jswrapper.h
js/src/proxy/BaseProxyHandler.cpp
js/src/proxy/CrossCompartmentWrapper.cpp
js/src/proxy/DirectProxyHandler.cpp
js/src/proxy/Proxy.cpp
js/src/proxy/Proxy.h
js/src/proxy/ScriptedDirectProxyHandler.cpp
js/src/proxy/ScriptedDirectProxyHandler.h
js/src/proxy/ScriptedIndirectProxyHandler.cpp
js/src/proxy/ScriptedIndirectProxyHandler.h
js/src/tests/js1_6/Array/regress-304828.js
js/src/vm/ArgumentsObject.cpp
js/src/vm/Debugger.cpp
js/src/vm/GlobalObject.h
js/src/vm/Interpreter-inl.h
js/src/vm/Interpreter.cpp
js/src/vm/NativeObject.cpp
js/src/vm/NativeObject.h
js/src/vm/ScopeObject.cpp
js/src/vm/SelfHosting.cpp
js/src/vm/Shape-inl.h
js/src/vm/Shape.h
js/src/vm/UnboxedObject.cpp
js/src/vm/UnboxedObject.h
js/src/vm/Xdr.h
js/xpconnect/src/Sandbox.cpp
js/xpconnect/src/XPCShellImpl.cpp
js/xpconnect/src/XPCWrappedNativeJSOps.cpp
js/xpconnect/wrappers/AddonWrapper.cpp
js/xpconnect/wrappers/AddonWrapper.h
js/xpconnect/wrappers/ChromeObjectWrapper.cpp
js/xpconnect/wrappers/ChromeObjectWrapper.h
js/xpconnect/wrappers/XrayWrapper.cpp
js/xpconnect/wrappers/XrayWrapper.h
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -641,18 +641,18 @@ public:
                    JS::Handle<jsid> id, bool *bp) const MOZ_OVERRIDE;
   virtual bool get(JSContext *cx, JS::Handle<JSObject*> proxy,
                    JS::Handle<JSObject*> receiver,
                    JS::Handle<jsid> id,
                    JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
   virtual bool set(JSContext *cx, JS::Handle<JSObject*> proxy,
                    JS::Handle<JSObject*> receiver,
                    JS::Handle<jsid> id,
-                   bool strict,
-                   JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
+                   JS::MutableHandle<JS::Value> vp,
+                   JS::ObjectOpResult &result) const MOZ_OVERRIDE;
 
   // SpiderMonkey extensions
   virtual bool getPropertyDescriptor(JSContext* cx,
                                      JS::Handle<JSObject*> proxy,
                                      JS::Handle<jsid> id,
                                      JS::MutableHandle<JSPropertyDescriptor> desc)
                                      const MOZ_OVERRIDE;
   virtual bool hasOwn(JSContext *cx, JS::Handle<JSObject*> proxy,
@@ -912,29 +912,27 @@ nsOuterWindowProxy::get(JSContext *cx, J
 
   return js::Wrapper::get(cx, proxy, receiver, id, vp);
 }
 
 bool
 nsOuterWindowProxy::set(JSContext *cx, JS::Handle<JSObject*> proxy,
                         JS::Handle<JSObject*> receiver,
                         JS::Handle<jsid> id,
-                        bool strict,
-                        JS::MutableHandle<JS::Value> vp) const
+                        JS::MutableHandle<JS::Value> vp,
+                        JS::ObjectOpResult &result) const
 {
   int32_t index = GetArrayIndexFromId(cx, id);
   if (IsArrayIndex(index)) {
     // Reject (which means throw if and only if strict) the set.
-    if (strict) {
-      // XXXbz This needs to throw, but see bug 828137.
-    }
-    return true;
-  }
-
-  return js::Wrapper::set(cx, proxy, receiver, id, strict, vp);
+    // XXX See bug 828137.
+    return result.succeed();
+  }
+
+  return js::Wrapper::set(cx, proxy, receiver, id, vp, result);
 }
 
 bool
 nsOuterWindowProxy::getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> proxy,
                                                  JS::AutoIdVector &props) const
 {
   // BaseProxyHandler::keys seems to do what we want here: call
   // ownPropertyKeys and then filter out the non-enumerable properties.
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -216,26 +216,26 @@ DOMProxyHandler::defineProperty(JSContex
     return false;
   }
   *defined = true;
   return true;
 }
 
 bool
 DOMProxyHandler::set(JSContext *cx, Handle<JSObject*> proxy, Handle<JSObject*> receiver,
-                     Handle<jsid> id, bool strict, MutableHandle<JS::Value> vp) const
+                     Handle<jsid> id, MutableHandle<JS::Value> vp, ObjectOpResult &result) const
 {
   MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
              "Should not have a XrayWrapper here");
   bool done;
   if (!setCustom(cx, proxy, id, vp, &done)) {
     return false;
   }
   if (done) {
-    return true;
+    return result.succeed();
   }
 
   // Make sure to ignore our named properties when checking for own
   // property descriptors for a set.
   JS::Rooted<JSPropertyDescriptor> desc(cx);
   if (!getOwnPropDescriptor(cx, proxy, id, /* ignoreNamedProps = */ true,
                             &desc)) {
     return false;
@@ -250,17 +250,17 @@ DOMProxyHandler::set(JSContext *cx, Hand
       return false;
     }
     if (proto && !JS_GetPropertyDescriptorById(cx, proto, id, &desc)) {
       return false;
     }
   }
 
   return js::SetPropertyIgnoringNamedGetter(cx, this, proxy, receiver, id,
-                                            &desc, descIsOwn, strict, vp);
+                                            &desc, descIsOwn, vp, result);
 }
 
 bool
 DOMProxyHandler::delete_(JSContext* cx, JS::Handle<JSObject*> proxy,
                          JS::Handle<jsid> id, bool* bp) const
 {
   JS::Rooted<JSObject*> expando(cx);
   if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) {
--- a/dom/bindings/DOMJSProxyHandler.h
+++ b/dom/bindings/DOMJSProxyHandler.h
@@ -118,17 +118,17 @@ public:
                JS::Handle<jsid> id, bool* bp) const MOZ_OVERRIDE;
   bool preventExtensions(JSContext *cx, JS::Handle<JSObject*> proxy,
                          bool *succeeded) const MOZ_OVERRIDE;
   bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible)
                     const MOZ_OVERRIDE;
   bool has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
            bool* bp) const MOZ_OVERRIDE;
   bool set(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<JSObject*> receiver,
-           JS::Handle<jsid> id, bool strict, JS::MutableHandle<JS::Value> vp)
+           JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp, JS::ObjectOpResult &result)
            const MOZ_OVERRIDE;
 
   /*
    * If assigning to proxy[id] hits a named setter with OverrideBuiltins or
    * an indexed setter, call it and set *done to true on success. Otherwise, set
    * *done to false.
    */
   virtual bool setCustom(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -159,18 +159,18 @@ NPClass nsJSObjWrapper::sJSObjWrapperNPC
 
 static bool
 NPObjWrapper_AddProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp);
 
 static bool
 NPObjWrapper_DelProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, bool *succeeded);
 
 static bool
-NPObjWrapper_SetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, bool strict,
-                         JS::MutableHandle<JS::Value> vp);
+NPObjWrapper_SetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
+                         JS::MutableHandle<JS::Value> vp, JS::ObjectOpResult &result);
 
 static bool
 NPObjWrapper_GetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp);
 
 static bool
 NPObjWrapper_Enumerate(JSContext *cx, JS::Handle<JSObject*> obj, JS::AutoIdVector &properties);
 
 static bool
@@ -1301,18 +1301,18 @@ NPObjWrapper_DelProperty(JSContext *cx, 
   }
 
   *succeeded = npobj->_class->removeProperty(npobj, identifier);
 
   return ReportExceptionIfPending(cx);
 }
 
 static bool
-NPObjWrapper_SetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, bool strict,
-                         JS::MutableHandle<JS::Value> vp)
+NPObjWrapper_SetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
+                         JS::MutableHandle<JS::Value> vp, JS::ObjectOpResult &result)
 {
   NPObject *npobj = GetNPObject(cx, obj);
 
   if (!npobj || !npobj->_class || !npobj->_class->hasProperty ||
       !npobj->_class->setProperty) {
     ThrowJSException(cx, "Bad NPObject as private data!");
 
     return false;
@@ -1357,17 +1357,17 @@ NPObjWrapper_SetProperty(JSContext *cx, 
     return false;
 
   if (!ok) {
     ThrowJSException(cx, "Error setting property on NPObject!");
 
     return false;
   }
 
-  return true;
+  return result.succeed();
 }
 
 static bool
 NPObjWrapper_GetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp)
 {
   NPObject *npobj = GetNPObject(cx, obj);
 
   if (!npobj || !npobj->_class || !npobj->_class->hasProperty ||
--- a/js/ipc/JavaScriptBase.h
+++ b/js/ipc/JavaScriptBase.h
@@ -69,19 +69,19 @@ class JavaScriptBase : public WrapperOwn
         return Answer::RecvHasOwn(ObjectId::deserialize(objId), id, rs, bp);
     }
     bool RecvGet(const uint64_t &objId, const ObjectVariant &receiverVar,
                    const JSIDVariant &id,
                    ReturnStatus *rs, JSVariant *result) {
         return Answer::RecvGet(ObjectId::deserialize(objId), receiverVar, id, rs, result);
     }
     bool RecvSet(const uint64_t &objId, const ObjectVariant &receiverVar,
-                   const JSIDVariant &id, const bool &strict,
-                   const JSVariant &value, ReturnStatus *rs, JSVariant *result) {
-        return Answer::RecvSet(ObjectId::deserialize(objId), receiverVar, id, strict, value, rs, result);
+                 const JSIDVariant &id, const JSVariant &value, ReturnStatus *rs,
+                 JSVariant *result) {
+        return Answer::RecvSet(ObjectId::deserialize(objId), receiverVar, id, value, rs, result);
     }
 
     bool RecvIsExtensible(const uint64_t &objId, ReturnStatus *rs,
                             bool *result) {
         return Answer::RecvIsExtensible(ObjectId::deserialize(objId), rs, result);
     }
     bool RecvCallOrConstruct(const uint64_t &objId, InfallibleTArray<JSParam> &&argv,
                              const bool &construct, ReturnStatus *rs, JSVariant *result,
@@ -161,19 +161,19 @@ class JavaScriptBase : public WrapperOwn
         return Base::SendHasOwn(objId.serialize(), id, rs, bp);
     }
     bool SendGet(const ObjectId &objId, const ObjectVariant &receiverVar,
                  const JSIDVariant &id,
                  ReturnStatus *rs, JSVariant *result) {
         return Base::SendGet(objId.serialize(), receiverVar, id, rs, result);
     }
     bool SendSet(const ObjectId &objId, const ObjectVariant &receiverVar,
-                 const JSIDVariant &id, const bool &strict,
-                 const JSVariant &value, ReturnStatus *rs, JSVariant *result) {
-        return Base::SendSet(objId.serialize(), receiverVar, id, strict, value, rs, result);
+                 const JSIDVariant &id, const JSVariant &value, ReturnStatus *rs,
+                 JSVariant *result) {
+        return Base::SendSet(objId.serialize(), receiverVar, id, value, rs, result);
     }
 
     bool SendIsExtensible(const ObjectId &objId, ReturnStatus *rs,
                           bool *result) {
         return Base::SendIsExtensible(objId.serialize(), rs, result);
     }
     bool SendCallOrConstruct(const ObjectId &objId, const nsTArray<JSParam> &argv,
                              const bool &construct, ReturnStatus *rs, JSVariant *result,
--- a/js/ipc/JavaScriptShared.cpp
+++ b/js/ipc/JavaScriptShared.cpp
@@ -600,17 +600,18 @@ JavaScriptShared::fromDescriptor(JSConte
 bool
 UnknownPropertyStub(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
 {
     JS_ReportError(cx, "getter could not be wrapped via CPOWs");
     return false;
 }
 
 bool
-UnknownStrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp)
+UnknownStrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp,
+                          ObjectOpResult &result)
 {
     JS_ReportError(cx, "setter could not be wrapped via CPOWs");
     return false;
 }
 
 bool
 JavaScriptShared::toDescriptor(JSContext *cx, const PPropertyDescriptor &in,
                                MutableHandle<JSPropertyDescriptor> out)
--- a/js/ipc/PJavaScript.ipdl
+++ b/js/ipc/PJavaScript.ipdl
@@ -28,17 +28,17 @@ both:
     prio(high) sync GetPropertyDescriptor(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, PPropertyDescriptor result);
     prio(high) sync GetOwnPropertyDescriptor(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, PPropertyDescriptor result);
     prio(high) sync DefineProperty(uint64_t objId, JSIDVariant id, PPropertyDescriptor descriptor) returns (ReturnStatus rs);
     prio(high) sync Delete(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool successful);
 
     prio(high) sync Has(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has);
     prio(high) sync HasOwn(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has);
     prio(high) sync Get(uint64_t objId, ObjectVariant receiver, JSIDVariant id) returns (ReturnStatus rs, JSVariant result);
-    prio(high) sync Set(uint64_t objId, ObjectVariant receiver, JSIDVariant id, bool strict, JSVariant value) returns (ReturnStatus rs, JSVariant result);
+    prio(high) sync Set(uint64_t objId, ObjectVariant receiver, JSIDVariant id, JSVariant value) returns (ReturnStatus rs, JSVariant result);
 
     prio(high) sync IsExtensible(uint64_t objId) returns (ReturnStatus rs, bool result);
     prio(high) sync CallOrConstruct(uint64_t objId, JSParam[] argv, bool construct) returns (ReturnStatus rs, JSVariant result, JSParam[] outparams);
     prio(high) sync HasInstance(uint64_t objId, JSVariant v) returns (ReturnStatus rs, bool has);
     prio(high) sync ObjectClassIs(uint64_t objId, uint32_t classValue) returns (bool result);
     prio(high) sync ClassName(uint64_t objId) returns (nsString name);
     prio(high) sync GetPrototypeOf(uint64_t objId) returns (ReturnStatus rs, ObjectOrNullVariant result);
     prio(high) sync RegExpToShared(uint64_t objId) returns (ReturnStatus rs, nsString source, uint32_t flags);
--- a/js/ipc/WrapperAnswer.cpp
+++ b/js/ipc/WrapperAnswer.cpp
@@ -308,54 +308,54 @@ WrapperAnswer::RecvGet(const ObjectId &o
 
     LOG("get %s.%s = %s", ReceiverObj(objId), Identifier(idVar), OutVariant(*result));
 
     return ok(rs);
 }
 
 bool
 WrapperAnswer::RecvSet(const ObjectId &objId, const ObjectVariant &receiverVar,
-                       const JSIDVariant &idVar, const bool &strict, const JSVariant &value,
-                       ReturnStatus *rs, JSVariant *result)
+                       const JSIDVariant &idVar, const JSVariant &value, ReturnStatus *rs,
+                       JSVariant *resultValue)
 {
     // We may run scripted setters.
     AutoEntryScript aes(xpc::NativeGlobal(scopeForTargetObjects()));
     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();
+    *resultValue = UndefinedVariant();
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
         return fail(cx, rs);
 
     RootedObject receiver(cx, fromObjectVariant(cx, receiverVar));
     if (!receiver)
         return fail(cx, rs);
 
     LOG("set %s[%s] = %s", ReceiverObj(objId), Identifier(idVar), InVariant(value));
 
     RootedId id(cx);
     if (!fromJSIDVariant(cx, idVar, &id))
         return fail(cx, rs);
 
-    MOZ_ASSERT(obj == receiver);
-
     RootedValue val(cx);
     if (!fromVariant(cx, value, &val))
         return fail(cx, rs);
 
-    if (!JS_SetPropertyById(cx, obj, id, val))
+    ObjectOpResult result;
+    RootedValue receiverVal(cx, ObjectValue(*receiver));
+    if (!JS_ForwardSetPropertyTo(cx, obj, id, val, receiverVal, result))
         return fail(cx, rs);
 
-    if (!toVariant(cx, val, result))
+    if (!toVariant(cx, val, resultValue))
         return fail(cx, rs);
 
-    return ok(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;
--- a/js/ipc/WrapperAnswer.h
+++ b/js/ipc/WrapperAnswer.h
@@ -35,18 +35,18 @@ class WrapperAnswer : public virtual Jav
     bool RecvHas(const ObjectId &objId, const JSIDVariant &id,
                  ReturnStatus *rs, bool *bp);
     bool RecvHasOwn(const ObjectId &objId, const JSIDVariant &id,
                     ReturnStatus *rs, bool *bp);
     bool RecvGet(const ObjectId &objId, const ObjectVariant &receiverVar,
                  const JSIDVariant &id,
                  ReturnStatus *rs, JSVariant *result);
     bool RecvSet(const ObjectId &objId, const ObjectVariant &receiverVar,
-                 const JSIDVariant &id, const bool &strict,
-                 const JSVariant &value, ReturnStatus *rs, JSVariant *result);
+                 const JSIDVariant &id, const JSVariant &value, ReturnStatus *rs,
+                 JSVariant *result);
 
     bool RecvIsExtensible(const ObjectId &objId, ReturnStatus *rs,
                           bool *result);
     bool RecvCallOrConstruct(const ObjectId &objId, InfallibleTArray<JSParam> &&argv,
                              const bool &construct, ReturnStatus *rs, JSVariant *result,
                              nsTArray<JSParam> *outparams);
     bool RecvHasInstance(const ObjectId &objId, const JSVariant &v, ReturnStatus *rs, bool *bp);
     bool RecvObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
--- a/js/ipc/WrapperOwner.cpp
+++ b/js/ipc/WrapperOwner.cpp
@@ -97,17 +97,18 @@ class CPOWProxyHandler : public BaseProx
     virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
     virtual bool enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp) const MOZ_OVERRIDE;
     virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE;
     virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
     virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
     virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
                      HandleId id, MutableHandleValue vp) const MOZ_OVERRIDE;
     virtual bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
-                     JS::HandleId id, bool strict, JS::MutableHandleValue vp) const MOZ_OVERRIDE;
+                     JS::HandleId id, JS::MutableHandleValue vp,
+                     JS::ObjectOpResult &result) const MOZ_OVERRIDE;
     virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
     virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
 
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                               AutoIdVector &props) const MOZ_OVERRIDE;
@@ -429,50 +430,50 @@ WrapperOwner::get(JSContext *cx, HandleO
         vp.set(ObjectValue(*toStringObj));
     }
 
     return true;
 }
 
 bool
 CPOWProxyHandler::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
-                      JS::HandleId id, bool strict, JS::MutableHandleValue vp) const
+                      JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult &result) const
 {
-    FORWARD(set, (cx, proxy, receiver, id, strict, vp));
+    FORWARD(set, (cx, proxy, receiver, id, vp, result));
 }
 
 bool
 WrapperOwner::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
-                  JS::HandleId id, bool strict, JS::MutableHandleValue vp)
+                  JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult &result)
 {
     ObjectId objId = idOf(proxy);
 
     ObjectVariant receiverVar;
     if (!toObjectVariant(cx, receiver, &receiverVar))
         return false;
 
     JSIDVariant idVar;
     if (!toJSIDVariant(cx, id, &idVar))
         return false;
 
     JSVariant val;
     if (!toVariant(cx, vp, &val))
         return false;
 
     ReturnStatus status;
-    JSVariant result;
-    if (!SendSet(objId, receiverVar, idVar, strict, val, &status, &result))
+    JSVariant resultValue;
+    if (!SendSet(objId, receiverVar, idVar, val, &status, &resultValue))
         return ipcfail(cx);
 
     LOG_STACK();
 
-    if (!ok(cx, status))
+    if (!ok(cx, status, result))
         return false;
 
-    return fromVariant(cx, result, vp);
+    return fromVariant(cx, resultValue, vp);
 }
 
 bool
 CPOWProxyHandler::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                                AutoIdVector &props) const
 {
     FORWARD(getOwnEnumerablePropertyKeys, (cx, proxy, props));
 }
--- a/js/ipc/WrapperOwner.h
+++ b/js/ipc/WrapperOwner.h
@@ -37,17 +37,17 @@ class WrapperOwner : public virtual Java
     bool ownPropertyKeys(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
     bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
     bool preventExtensions(JSContext *cx, JS::HandleObject proxy, bool *succeeded);
     bool isExtensible(JSContext *cx, JS::HandleObject proxy, bool *extensible);
     bool has(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
     bool get(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
              JS::HandleId id, JS::MutableHandleValue vp);
     bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
-             JS::HandleId id, bool strict, JS::MutableHandleValue vp);
+             JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult &result);
     bool callOrConstruct(JSContext *cx, JS::HandleObject proxy, const JS::CallArgs &args,
                          bool construct);
 
     // SpiderMonkey extensions.
     bool getPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
                                JS::MutableHandle<JSPropertyDescriptor> desc);
     bool hasOwn(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
     bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::HandleObject proxy,
@@ -123,18 +123,18 @@ class WrapperOwner : public virtual Java
     virtual bool SendHas(const ObjectId &objId, const JSIDVariant &id,
                          ReturnStatus *rs, bool *bp) = 0;
     virtual bool SendHasOwn(const ObjectId &objId, const JSIDVariant &id,
                             ReturnStatus *rs, bool *bp) = 0;
     virtual bool SendGet(const ObjectId &objId, const ObjectVariant &receiverVar,
                          const JSIDVariant &id,
                          ReturnStatus *rs, JSVariant *result) = 0;
     virtual bool SendSet(const ObjectId &objId, const ObjectVariant &receiverVar,
-                         const JSIDVariant &id, const bool &strict,
-                         const JSVariant &value, ReturnStatus *rs, JSVariant *result) = 0;
+                         const JSIDVariant &id, const JSVariant &value,
+                         ReturnStatus *rs, JSVariant *result) = 0;
 
     virtual bool SendIsExtensible(const ObjectId &objId, ReturnStatus *rs,
                                   bool *result) = 0;
     virtual bool SendCallOrConstruct(const ObjectId &objId, const nsTArray<JSParam> &argv,
                                      const bool &construct, ReturnStatus *rs, JSVariant *result,
                                      nsTArray<JSParam> *outparams) = 0;
     virtual bool SendHasInstance(const ObjectId &objId, const JSVariant &v,
                                  ReturnStatus *rs, bool *bp) = 0;
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -116,16 +116,17 @@ class ObjectOpResult
         MOZ_ASSERT(msg != OkCode);
         code_ = msg;
         return true;
     }
 
     JS_PUBLIC_API(bool) failCantRedefineProp();
     JS_PUBLIC_API(bool) failReadOnly();
     JS_PUBLIC_API(bool) failGetterOnly();
+    JS_PUBLIC_API(bool) failCantSetInterposed();
 
     uint32_t failureCode() const {
         MOZ_ASSERT(!ok());
         return code_;
     }
 
     /*
      * Report an error or warning if necessary; return true to proceed and
@@ -157,17 +158,16 @@ class ObjectOpResult
 
     /* Throw a TypeError. Call this only if !ok(). */
     bool reportError(JSContext *cx, HandleObject obj, HandleId id) {
         return reportStrictErrorOrWarning(cx, obj, id, true);
     }
 
     /* Helper function for checkStrictErrorOrWarning's slow path. */
     JS_PUBLIC_API(bool) reportStrictErrorOrWarning(JSContext *cx, HandleObject obj, HandleId id, bool strict);
-
 };
 
 }
 
 // JSClass operation signatures.
 
 // Add or get a property named by id in obj.  Note the jsid id type -- id may
 // be a string (Unicode property identifier) or an int (element index).  The
@@ -180,17 +180,17 @@ typedef JSGetterOp JSAddPropertyOp;
 
 // Set a property named by id in obj, treating the assignment as strict
 // mode code if strict is true. Note the jsid id type -- id may be a string
 // (Unicode property identifier) or an int (element index). The *vp out
 // parameter, on success, is the new property value after the
 // set.
 typedef bool
 (* JSSetterOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
-               bool strict, JS::MutableHandleValue vp);
+               JS::MutableHandleValue vp, JS::ObjectOpResult &result);
 
 // Delete a property named by id in obj.
 //
 // If an error occurred, return false as per normal JSAPI error practice.
 //
 // If no error occurred, but the deletion attempt wasn't allowed (perhaps
 // because the property was non-configurable), set *succeeded to false and
 // return true.  This will cause |delete obj[id]| to evaluate to false in
@@ -293,17 +293,17 @@ typedef bool
                      JS::ObjectOpResult &result);
 typedef bool
 (* HasPropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool *foundp);
 typedef bool
 (* GetPropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, JS::HandleId id,
                   JS::MutableHandleValue vp);
 typedef bool
 (* SetPropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, JS::HandleId id,
-                  JS::MutableHandleValue vp, bool strict);
+                  JS::MutableHandleValue vp, JS::ObjectOpResult &result);
 typedef bool
 (* GetOwnPropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
                      JS::MutableHandle<JSPropertyDescriptor> desc);
 typedef bool
 (* DeletePropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool *succeeded);
 
 typedef bool
 (* WatchOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable);
--- a/js/public/Proxy.h
+++ b/js/public/Proxy.h
@@ -286,17 +286,17 @@ class JS_FRIEND_API(BaseProxyHandler)
      *
      * The base-class implementations work by calling getPropertyDescriptor().
      * They do not follow any standard. When in doubt, override them.
      */
     virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const;
     virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
                      HandleId id, MutableHandleValue vp) const;
     virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver,
-                     HandleId id, bool strict, MutableHandleValue vp) const;
+                     HandleId id, MutableHandleValue vp, ObjectOpResult &result) const;
 
     /*
      * [[Call]] and [[Construct]] are standard internal methods but according
      * to the spec, they are not present on every object.
      *
      * SpiderMonkey never calls a proxy's call()/construct() internal method
      * unless isCallable()/isConstructor() returns true for that proxy.
      *
@@ -385,17 +385,18 @@ class JS_FRIEND_API(DirectProxyHandler) 
                                        bool *succeeded) const MOZ_OVERRIDE;
     virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE;
     virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
     virtual bool has(JSContext *cx, HandleObject proxy, HandleId id,
                      bool *bp) const MOZ_OVERRIDE;
     virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
                      HandleId id, MutableHandleValue vp) const MOZ_OVERRIDE;
     virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver,
-                     HandleId id, bool strict, MutableHandleValue vp) const MOZ_OVERRIDE;
+                     HandleId id, MutableHandleValue vp,
+                     ObjectOpResult &result) const MOZ_OVERRIDE;
     virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
     virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
 
     /* SpiderMonkey extensions. */
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id,
                         bool *bp) const MOZ_OVERRIDE;
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -1905,17 +1905,17 @@ TypedObject::obj_getArrayElement(JSConte
 
     Rooted<TypeDescr*> elementType(cx, &typeDescr->as<ArrayTypeDescr>().elementType());
     size_t offset = elementType->size() * index;
     return Reify(cx, elementType, typedObj, offset, vp);
 }
 
 bool
 TypedObject::obj_setProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
-                             MutableHandleValue vp, bool strict)
+                             MutableHandleValue vp, ObjectOpResult &result)
 {
     Rooted<TypedObject *> typedObj(cx, &obj->as<TypedObject>());
 
     switch (typedObj->typeDescr().kind()) {
       case type::Scalar:
       case type::Reference:
         break;
 
@@ -1924,56 +1924,60 @@ TypedObject::obj_setProperty(JSContext *
 
       case type::Array: {
         if (JSID_IS_ATOM(id, cx->names().length)) {
             if (obj == receiver) {
                 JS_ReportErrorNumber(cx, GetErrorMessage,
                                      nullptr, JSMSG_CANT_REDEFINE_ARRAY_LENGTH);
                 return false;
             }
-            return SetNonWritableProperty(cx, id, strict);
+            return result.failReadOnly();
         }
 
         uint32_t index;
         if (IdIsIndex(id, &index)) {
             if (obj != receiver)
-                return SetPropertyByDefining(cx, obj, receiver, id, vp, strict, false);
+                return SetPropertyByDefining(cx, obj, receiver, id, vp, false, result);
 
             if (index >= uint32_t(typedObj->length())) {
                 JS_ReportErrorNumber(cx, GetErrorMessage,
                                      nullptr, JSMSG_TYPEDOBJECT_BINARYARRAY_BAD_INDEX);
                 return false;
             }
 
             Rooted<TypeDescr*> elementType(cx);
             elementType = &typedObj->typeDescr().as<ArrayTypeDescr>().elementType();
             size_t offset = elementType->size() * index;
-            return ConvertAndCopyTo(cx, elementType, typedObj, offset, NullPtr(), vp);
+            if (!ConvertAndCopyTo(cx, elementType, typedObj, offset, NullPtr(), vp))
+                return false;
+            return result.succeed();
         }
         break;
       }
 
       case type::Struct: {
         Rooted<StructTypeDescr*> descr(cx, &typedObj->typeDescr().as<StructTypeDescr>());
 
         size_t fieldIndex;
         if (!descr->fieldIndex(id, &fieldIndex))
             break;
 
         if (obj != receiver)
-            return SetPropertyByDefining(cx, obj, receiver, id, vp, strict, false);
+            return SetPropertyByDefining(cx, obj, receiver, id, vp, false, result);
 
         size_t offset = descr->fieldOffset(fieldIndex);
         Rooted<TypeDescr*> fieldType(cx, &descr->fieldDescr(fieldIndex));
         RootedAtom fieldName(cx, &descr->fieldName(fieldIndex));
-        return ConvertAndCopyTo(cx, fieldType, typedObj, offset, fieldName, vp);
+        if (!ConvertAndCopyTo(cx, fieldType, typedObj, offset, fieldName, vp))
+            return false;
+        return result.succeed();
       }
     }
 
-    return SetPropertyOnProto(cx, obj, receiver, id, vp, strict);
+    return SetPropertyOnProto(cx, obj, receiver, id, vp, result);
 }
 
 bool
 TypedObject::obj_getOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
                                           MutableHandle<JSPropertyDescriptor> desc)
 {
     Rooted<TypedObject *> typedObj(cx, &obj->as<TypedObject>());
     if (!typedObj->isAttached()) {
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -536,17 +536,17 @@ class TypedObject : public JSObject
 
     static bool obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
                                 HandleId id, MutableHandleValue vp);
 
     static bool obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver,
                                uint32_t index, MutableHandleValue vp);
 
     static bool obj_setProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
-                                HandleId id, MutableHandleValue vp, bool strict);
+                                HandleId id, MutableHandleValue vp, ObjectOpResult &result);
 
     static bool obj_getOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
                                              MutableHandle<JSPropertyDescriptor> desc);
 
     static bool obj_deleteProperty(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded);
 
     static bool obj_enumerate(JSContext *cx, HandleObject obj, AutoIdVector &properties);
 
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -282,32 +282,33 @@ namespace ArrayType {
 
   static bool Create(JSContext* cx, unsigned argc, jsval* vp);
   static bool ConstructData(JSContext* cx, HandleObject obj, const CallArgs& args);
 
   bool ElementTypeGetter(JSContext* cx, JS::CallArgs args);
   bool LengthGetter(JSContext* cx, JS::CallArgs args);
 
   static bool Getter(JSContext* cx, HandleObject obj, HandleId idval, MutableHandleValue vp);
-  static bool Setter(JSContext* cx, HandleObject obj, HandleId idval, bool strict, MutableHandleValue vp);
+  static bool Setter(JSContext* cx, HandleObject obj, HandleId idval, MutableHandleValue vp,
+                     ObjectOpResult &result);
   static bool AddressOfElement(JSContext* cx, unsigned argc, jsval* vp);
 }
 
 namespace StructType {
   bool IsStruct(HandleValue v);
 
   static bool Create(JSContext* cx, unsigned argc, jsval* vp);
   static bool ConstructData(JSContext* cx, HandleObject obj, const CallArgs& args);
 
   bool FieldsArrayGetter(JSContext* cx, JS::CallArgs args);
 
   static bool FieldGetter(JSContext* cx, HandleObject obj, HandleId idval,
-    MutableHandleValue vp);
-  static bool FieldSetter(JSContext* cx, HandleObject obj, HandleId idval, bool strict,
-                            MutableHandleValue vp);
+                          MutableHandleValue vp);
+  static bool FieldSetter(JSContext* cx, HandleObject obj, HandleId idval,
+                          MutableHandleValue vp, ObjectOpResult &result);
   static bool AddressOfField(JSContext* cx, unsigned argc, jsval* vp);
   static bool Define(JSContext* cx, unsigned argc, jsval* vp);
 }
 
 namespace FunctionType {
   static bool Create(JSContext* cx, unsigned argc, jsval* vp);
   static bool ConstructData(JSContext* cx, HandleObject typeObj,
     HandleObject dataObj, HandleObject fnObj, HandleObject thisObj, jsval errVal);
@@ -4620,49 +4621,52 @@ ArrayType::Getter(JSContext* cx, HandleO
 
   RootedObject baseType(cx, GetBaseType(typeObj));
   size_t elementSize = CType::GetSize(baseType);
   char* data = static_cast<char*>(CData::GetData(obj)) + elementSize * index;
   return ConvertToJS(cx, baseType, obj, data, false, false, vp);
 }
 
 bool
-ArrayType::Setter(JSContext* cx, HandleObject obj, HandleId idval, bool strict, MutableHandleValue vp)
+ArrayType::Setter(JSContext* cx, HandleObject obj, HandleId idval, MutableHandleValue vp,
+                  ObjectOpResult &result)
 {
   // This should never happen, but we'll check to be safe.
   if (!CData::IsCData(obj)) {
     JS_ReportError(cx, "not a CData");
     return false;
   }
 
   // Bail early if we're not an ArrayType. (This setter is present for all
   // CData, regardless of CType.)
   JSObject* typeObj = CData::GetCType(obj);
   if (CType::GetTypeCode(typeObj) != TYPE_array)
-    return true;
+    return result.succeed();
 
   // Convert the index to a size_t and bounds-check it.
   size_t index;
   size_t length = GetLength(typeObj);
   bool ok = jsidToSize(cx, idval, true, &index);
   int32_t dummy;
   if (!ok && JSID_IS_STRING(idval) && !StringToInteger(cx, JSID_TO_STRING(idval), &dummy)) {
     // String either isn't a number, or doesn't fit in size_t.
     // Chances are it's a regular property lookup, so return.
-    return true;
+    return result.succeed();
   }
   if (!ok || index >= length) {
     JS_ReportError(cx, "invalid index");
     return false;
   }
 
   JSObject* baseType = GetBaseType(typeObj);
   size_t elementSize = CType::GetSize(baseType);
   char* data = static_cast<char*>(CData::GetData(obj)) + elementSize * index;
-  return ImplicitConvert(cx, vp, baseType, data, false, nullptr);
+  if (!ImplicitConvert(cx, vp, baseType, data, false, nullptr))
+    return false;
+  return result.succeed();
 }
 
 bool
 ArrayType::AddressOfElement(JSContext* cx, unsigned argc, jsval* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
   RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
   if (!obj)
@@ -5285,17 +5289,18 @@ StructType::FieldGetter(JSContext* cx, H
     return false;
 
   char* data = static_cast<char*>(CData::GetData(obj)) + field->mOffset;
   RootedObject fieldType(cx, field->mType);
   return ConvertToJS(cx, fieldType, obj, data, false, false, vp);
 }
 
 bool
-StructType::FieldSetter(JSContext* cx, HandleObject obj, HandleId idval, bool strict, MutableHandleValue vp)
+StructType::FieldSetter(JSContext* cx, HandleObject obj, HandleId idval, MutableHandleValue vp,
+                        ObjectOpResult &result)
 {
   if (!CData::IsCData(obj)) {
     JS_ReportError(cx, "not a CData");
     return false;
   }
 
   JSObject* typeObj = CData::GetCType(obj);
   if (CType::GetTypeCode(typeObj) != TYPE_struct) {
@@ -5303,17 +5308,19 @@ StructType::FieldSetter(JSContext* cx, H
     return false;
   }
 
   const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_FLAT_STRING(idval));
   if (!field)
     return false;
 
   char* data = static_cast<char*>(CData::GetData(obj)) + field->mOffset;
-  return ImplicitConvert(cx, vp, field->mType, data, false, nullptr);
+  if (!ImplicitConvert(cx, vp, field->mType, data, false, nullptr))
+    return false;
+  return result.succeed();
 }
 
 bool
 StructType::AddressOfField(JSContext* cx, unsigned argc, jsval* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
   RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
   if (!obj)
--- a/js/src/jit-test/tests/basic/expression-autopsy.js
+++ b/js/src/jit-test/tests/basic/expression-autopsy.js
@@ -105,17 +105,17 @@ for (let tok of ["|", "^", "&", "==", "!
 check("o[!(o)]");
 check("o[~(o)]");
 check("o[+ (o)]");
 check("o[- (o)]");
 
 
 // A few one off tests
 check_one("6", (function () { 6() }), " is not a function");
-check_one("Array.prototype.reverse.call(...)", (function () { Array.prototype.reverse.call('123'); }), " is read-only");
+check_one("0", (function () { Array.prototype.reverse.call('123'); }), " is read-only");
 check_one(`(intermediate value)[Symbol.iterator](...).next(...).value`,
           function () { var [{ x }] = [null, {}]; }, " is null");
 check_one(`(intermediate value)[Symbol.iterator](...).next(...).value`,
           function () { ieval("let (x) { var [a, b, [c0, c1]] = [x, x, x]; }") }, " is undefined");
 check_one("void 1", function() { (void 1)(); }, " is not a function");
 check_one("void o[1]", function() { var o = []; (void o[1])() }, " is not a function");
 
 // Check fallback behavior
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -8369,17 +8369,17 @@ DoSetPropFallback(JSContext *cx, Baselin
         if (!SetNameOperation(cx, script, pc, obj, rhs))
             return false;
     } else if (op == JSOP_SETALIASEDVAR || op == JSOP_INITALIASEDLEXICAL) {
         obj->as<ScopeObject>().setAliasedVar(cx, ScopeCoordinate(pc), name, rhs);
     } else {
         MOZ_ASSERT(op == JSOP_SETPROP || op == JSOP_STRICTSETPROP);
 
         RootedValue v(cx, rhs);
-        if (!SetProperty(cx, obj, obj, id, &v, op == JSOP_STRICTSETPROP))
+        if (!PutProperty(cx, obj, id, &v, op == JSOP_STRICTSETPROP))
             return false;
     }
 
     // Leave the RHS on the stack.
     res.set(rhs);
 
     // Check if debug mode toggling made the stub invalid.
     if (stub.invalid())
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -1458,16 +1458,23 @@ GetPropertyIC::tryAttachTypedArrayLength
     MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
     RepatchStubAppender attacher(*this);
     GenerateTypedArrayLength(cx, masm, attacher, AnyTypedArrayLayout(obj), object(), output());
 
     setHasTypedArrayLengthStub(obj);
     return linkAndAttachStub(cx, masm, attacher, ion, "typed array length");
 }
 
+static void
+PushObjectOpResult(MacroAssembler &masm, uint32_t value = ObjectOpResult::Uninitialized)
+{
+    static_assert(sizeof(ObjectOpResult) == sizeof(int32_t),
+                  "ObjectOpResult size must match size reserved by masm.Push() here");
+    masm.Push(Imm32(value));
+}
 
 static bool
 EmitCallProxyGet(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
                  PropertyName *name, RegisterSet liveRegs, Register object,
                  TypedOrValueRegister output, jsbytecode *pc, void *returnAddr)
 {
     MOZ_ASSERT(output.hasValue());
     MacroAssembler::AfterICSaveLive aic = masm.icSaveLive(liveRegs);
@@ -1502,16 +1509,19 @@ EmitCallProxyGet(JSContext *cx, MacroAss
     masm.movePtr(StackPointer, argIdReg);
 
     // Pushing object and receiver.  Both are the same, so Handle to one is equivalent to
     // handle to other.
     masm.Push(object);
     masm.Push(object);
     masm.movePtr(StackPointer, argProxyReg);
 
+    // Unused space, to keep the same stack layout as Proxy::set frames.
+    PushObjectOpResult(masm, 0);
+
     masm.loadJSContext(argJSContextReg);
 
     if (!masm.icBuildOOLFakeExitFrame(returnAddr, aic))
         return false;
     masm.enterFakeExitFrame(IonOOLProxyExitFrameLayout::Token());
 
     // Make the call.
     masm.setupUnalignedABICall(5, scratch);
@@ -2103,34 +2113,87 @@ IsCacheableSetPropCallPropertyOp(HandleO
     // value. The flag should be always true, apart from these rare instances.
     if (!shape->writable())
         return false;
 
     return true;
 }
 
 static bool
+ReportStrictErrorOrWarning(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool strict,
+                           JS::ObjectOpResult &result)
+{
+    return result.reportStrictErrorOrWarning(cx, obj, id, strict);
+}
+
+template <class FrameLayout>
+void
+EmitObjectOpResultCheck(MacroAssembler &masm, Label *failure, bool strict,
+                        Register scratchReg,
+                        Register argJSContextReg,
+                        Register argObjReg,
+                        Register argIdReg,
+                        Register argStrictReg,
+                        Register argResultReg)
+{
+    // if (!result) {
+    Label noStrictError;
+    masm.branch32(Assembler::Equal,
+                  Address(StackPointer,
+                          FrameLayout::offsetOfObjectOpResult()),
+                  Imm32(ObjectOpResult::OkCode),
+                  &noStrictError);
+
+    //     if (!ReportStrictErrorOrWarning(cx, obj, id, strict, &result))
+    //         goto failure;
+    masm.loadJSContext(argJSContextReg);
+    masm.computeEffectiveAddress(
+        Address(StackPointer, FrameLayout::offsetOfId()),
+        argIdReg);
+    masm.move32(Imm32(strict), argStrictReg);
+    masm.computeEffectiveAddress(
+        Address(StackPointer, FrameLayout::offsetOfObjectOpResult()),
+        argResultReg);
+    masm.setupUnalignedABICall(5, scratchReg);
+    masm.passABIArg(argJSContextReg);
+    masm.passABIArg(argObjReg);
+    masm.passABIArg(argIdReg);
+    masm.passABIArg(argStrictReg);
+    masm.passABIArg(argResultReg);
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ReportStrictErrorOrWarning));
+    masm.branchIfFalseBool(ReturnReg, failure);
+
+    // }
+    masm.bind(&noStrictError);
+}
+
+static bool
 EmitCallProxySet(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
                  HandleId propId, RegisterSet liveRegs, Register object,
                  ConstantOrRegister value, void *returnAddr, bool strict)
 {
     MacroAssembler::AfterICSaveLive aic = masm.icSaveLive(liveRegs);
 
-    // Remaining registers should be free, but we need to use |object| still
-    // so leave it alone.
+    // Remaining registers should be free, but we still need to use |object| so
+    // leave it alone.
+    //
+    // WARNING: We do not take() the register used by |value|, if any, so
+    // regSet is going to re-allocate it. Hence the emitted code must not touch
+    // any of the registers allocated from regSet until after the last use of
+    // |value|. (We can't afford to take it, either, because x86.)
     RegisterSet regSet(RegisterSet::All());
     regSet.take(AnyRegister(object));
 
     // Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
-    //            bool strict, MutableHandleValue vp)
+    //            MutableHandleValue vp, ObjectOpResult &result)
     Register argJSContextReg = regSet.takeGeneral();
     Register argProxyReg     = regSet.takeGeneral();
     Register argIdReg        = regSet.takeGeneral();
     Register argVpReg        = regSet.takeGeneral();
-    Register argStrictReg    = regSet.takeGeneral();
+    Register argResultReg    = regSet.takeGeneral();
 
     Register scratch         = regSet.takeGeneral();
 
     // Push stubCode for marking.
     attacher.pushStubCodePointer(masm);
 
     // Push args on stack first so we can take pointers to make handles.
     masm.Push(value);
@@ -2140,36 +2203,45 @@ EmitCallProxySet(JSContext *cx, MacroAss
     masm.movePtr(StackPointer, argIdReg);
 
     // Pushing object and receiver.  Both are the same, so Handle to one is equivalent to
     // handle to other.
     masm.Push(object);
     masm.Push(object);
     masm.movePtr(StackPointer, argProxyReg);
 
+    // Allocate result out-param.
+    PushObjectOpResult(masm);
+    masm.movePtr(StackPointer, argResultReg);
+
     masm.loadJSContext(argJSContextReg);
-    masm.move32(Imm32(strict? 1 : 0), argStrictReg);
 
     if (!masm.icBuildOOLFakeExitFrame(returnAddr, aic))
         return false;
     masm.enterFakeExitFrame(IonOOLProxyExitFrameLayout::Token());
 
     // Make the call.
     masm.setupUnalignedABICall(6, scratch);
     masm.passABIArg(argJSContextReg);
     masm.passABIArg(argProxyReg);
     masm.passABIArg(argProxyReg);
     masm.passABIArg(argIdReg);
-    masm.passABIArg(argStrictReg);
     masm.passABIArg(argVpReg);
+    masm.passABIArg(argResultReg);
     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, Proxy::set));
 
-    // Test for failure.
+    // Test for error.
     masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
 
+    // Test for strict failure. We emit the check even in non-strict mode in
+    // order to pick up the warning if extraWarnings is enabled.
+    EmitObjectOpResultCheck<IonOOLProxyExitFrameLayout>(masm, masm.exceptionLabel(), strict,
+                                                        scratch, argJSContextReg, argProxyReg,
+                                                        argIdReg, argVpReg, argResultReg);
+
     // masm.leaveExitFrame & pop locals
     masm.adjustStack(IonOOLProxyExitFrameLayout::Size());
 
     masm.icRestoreLive(liveRegs, aic);
     return true;
 }
 
 bool
@@ -2370,61 +2442,70 @@ GenerateCallSetter(JSContext *cx, IonScr
 
         // masm.leaveExitFrame & pop locals.
         masm.adjustStack(IonOOLNativeExitFrameLayout::Size(1));
     } else if (IsCacheableSetPropCallPropertyOp(obj, holder, shape)) {
         Register argJSContextReg = regSet.takeGeneral();
         Register argVpReg        = regSet.takeGeneral();
         Register argObjReg       = regSet.takeGeneral();
         Register argIdReg        = regSet.takeGeneral();
-        Register argStrictReg    = regSet.takeGeneral();
-
-        attacher.pushStubCodePointer(masm);
+        Register argResultReg    = regSet.takeGeneral();
 
         SetterOp target = shape->setterOp();
         MOZ_ASSERT(target);
         // JSSetterOp: bool fn(JSContext *cx, HandleObject obj,
-        //                     HandleId id, bool strict, MutableHandleValue vp);
-
-        // Push args on stack first so we can take pointers to make handles.
+        //                     HandleId id, MutableHandleValue vp, ObjectOpResult &result);
+
+        // First, allocate an ObjectOpResult on the stack. We push this before
+        // the stubCode pointer in order to match the layout of
+        // IonOOLSetterOpExitFrameLayout.
+        PushObjectOpResult(masm);
+        masm.movePtr(StackPointer, argResultReg);
+
+        attacher.pushStubCodePointer(masm);
+
+        // Push args on stack so we can take pointers to make handles.
         if (value.constant())
             masm.Push(value.value());
         else
             masm.Push(value.reg());
         masm.movePtr(StackPointer, argVpReg);
 
-        masm.move32(Imm32(strict ? 1 : 0), argStrictReg);
-
         // push canonical jsid from shape instead of propertyname.
         masm.Push(shape->propid(), argIdReg);
         masm.movePtr(StackPointer, argIdReg);
 
         masm.Push(object);
         masm.movePtr(StackPointer, argObjReg);
 
         masm.loadJSContext(argJSContextReg);
 
         if (!masm.icBuildOOLFakeExitFrame(returnAddr, aic))
             return false;
-        masm.enterFakeExitFrame(IonOOLPropertyOpExitFrameLayout::Token());
+        masm.enterFakeExitFrame(IonOOLSetterOpExitFrameLayout::Token());
 
         // Make the call.
         masm.setupUnalignedABICall(5, scratchReg);
         masm.passABIArg(argJSContextReg);
         masm.passABIArg(argObjReg);
         masm.passABIArg(argIdReg);
-        masm.passABIArg(argStrictReg);
         masm.passABIArg(argVpReg);
+        masm.passABIArg(argResultReg);
         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, target));
 
+        // Test for error.
+        masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
+
         // Test for failure.
-        masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
+        EmitObjectOpResultCheck<IonOOLSetterOpExitFrameLayout>(masm, failure, strict, scratchReg,
+                                                               argJSContextReg, argObjReg,
+                                                               argIdReg, argVpReg, argResultReg);
 
         // masm.leaveExitFrame & pop locals.
-        masm.adjustStack(IonOOLPropertyOpExitFrameLayout::Size());
+        masm.adjustStack(IonOOLSetterOpExitFrameLayout::Size());
     } else {
         MOZ_ASSERT(IsCacheableSetPropCallScripted(obj, holder, shape));
 
         JSFunction *target = &shape->setterValue().toObject().as<JSFunction>();
         uint32_t framePushedBefore = masm.framePushed();
 
         // Construct IonAccessorICFrameLayout.
         uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_IonJS);
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -1305,19 +1305,26 @@ MarkJitExitFrame(JSTracer *trc, const Ji
             frame.exitFrame()->as<IonOOLNativeExitFrameLayout>();
         gc::MarkJitCodeRoot(trc, oolnative->stubCode(), "ion-ool-native-code");
         gc::MarkValueRoot(trc, oolnative->vp(), "iol-ool-native-vp");
         size_t len = oolnative->argc() + 1;
         gc::MarkValueRootRange(trc, len, oolnative->thisp(), "ion-ool-native-thisargs");
         return;
     }
 
-    if (frame.isExitFrameLayout<IonOOLPropertyOpExitFrameLayout>()) {
+    if (frame.isExitFrameLayout<IonOOLPropertyOpExitFrameLayout>() ||
+        frame.isExitFrameLayout<IonOOLSetterOpExitFrameLayout>())
+    {
+        // A SetterOp frame is a different size, but that's the only relevant
+        // difference between the two. The fields that need marking are all in
+        // the common base class.
         IonOOLPropertyOpExitFrameLayout *oolgetter =
-            frame.exitFrame()->as<IonOOLPropertyOpExitFrameLayout>();
+            frame.isExitFrameLayout<IonOOLPropertyOpExitFrameLayout>()
+            ? frame.exitFrame()->as<IonOOLPropertyOpExitFrameLayout>()
+            : frame.exitFrame()->as<IonOOLSetterOpExitFrameLayout>();
         gc::MarkJitCodeRoot(trc, oolgetter->stubCode(), "ion-ool-property-op-code");
         gc::MarkValueRoot(trc, oolgetter->vp(), "ion-ool-property-op-vp");
         gc::MarkIdRoot(trc, oolgetter->id(), "ion-ool-property-op-id");
         gc::MarkObjectRoot(trc, oolgetter->obj(), "ion-ool-property-op-obj");
         return;
     }
 
     if (frame.isExitFrameLayout<IonOOLProxyExitFrameLayout>()) {
--- a/js/src/jit/JitFrames.h
+++ b/js/src/jit/JitFrames.h
@@ -489,17 +489,18 @@ class IonDOMExitFrameLayout;
 enum ExitFrameTokenValues
 {
     NativeExitFrameLayoutToken            = 0x0,
     IonDOMExitFrameLayoutGetterToken      = 0x1,
     IonDOMExitFrameLayoutSetterToken      = 0x2,
     IonDOMMethodExitFrameLayoutToken      = 0x3,
     IonOOLNativeExitFrameLayoutToken      = 0x4,
     IonOOLPropertyOpExitFrameLayoutToken  = 0x5,
-    IonOOLProxyExitFrameLayoutToken       = 0x6,
+    IonOOLSetterOpExitFrameLayoutToken    = 0x6,
+    IonOOLProxyExitFrameLayoutToken       = 0x7,
     ExitFrameLayoutBareToken              = 0xFF
 };
 
 // this is the frame layout when we are exiting ion code, and about to enter platform ABI code
 class ExitFrameLayout : public CommonFrameLayout
 {
     inline uint8_t *top() {
         return reinterpret_cast<uint8_t *>(this + 1);
@@ -622,17 +623,17 @@ class IonOOLNativeExitFrameLayout
     }
     inline uintptr_t argc() const {
         return argc_;
     }
 };
 
 class IonOOLPropertyOpExitFrameLayout
 {
-  protected: // only to silence a clang warning about unused private fields
+  protected:
     ExitFooterFrame footer_;
     ExitFrameLayout exit_;
 
     // Object for HandleObject
     JSObject *obj_;
 
     // id for HandleId
     jsid id_;
@@ -647,16 +648,20 @@ class IonOOLPropertyOpExitFrameLayout
 
   public:
     static JitCode *Token() { return (JitCode *)IonOOLPropertyOpExitFrameLayoutToken; }
 
     static inline size_t Size() {
         return sizeof(IonOOLPropertyOpExitFrameLayout);
     }
 
+    static size_t offsetOfId() {
+        return offsetof(IonOOLPropertyOpExitFrameLayout, id_);
+    }
+
     static size_t offsetOfResult() {
         return offsetof(IonOOLPropertyOpExitFrameLayout, vp0_);
     }
 
     inline JitCode **stubCode() {
         return &stubCode_;
     }
     inline Value *vp() {
@@ -665,26 +670,46 @@ class IonOOLPropertyOpExitFrameLayout
     inline jsid *id() {
         return &id_;
     }
     inline JSObject **obj() {
         return &obj_;
     }
 };
 
+class IonOOLSetterOpExitFrameLayout : public IonOOLPropertyOpExitFrameLayout
+{
+  protected: // only to silence a clang warning about unused private fields
+    JS::ObjectOpResult result_;
+
+  public:
+    static JitCode *Token() { return (JitCode *)IonOOLSetterOpExitFrameLayoutToken; }
+
+    static size_t offsetOfObjectOpResult() {
+        return offsetof(IonOOLSetterOpExitFrameLayout, result_);
+    }
+
+    static size_t Size() {
+        return sizeof(IonOOLSetterOpExitFrameLayout);
+    }
+};
+
 // Proxy::get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
 //            MutableHandleValue vp)
 // Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
-//            bool strict, MutableHandleValue vp)
+//            MutableHandleValue vp, ObjectOpResult &result)
 class IonOOLProxyExitFrameLayout
 {
   protected: // only to silence a clang warning about unused private fields
     ExitFooterFrame footer_;
     ExitFrameLayout exit_;
 
+    // result out-parameter (unused for Proxy::get)
+    JS::ObjectOpResult result_;
+
     // The proxy object.
     JSObject *proxy_;
 
     // Object for HandleObject
     JSObject *receiver_;
 
     // id for HandleId
     jsid id_;
@@ -703,16 +728,24 @@ class IonOOLProxyExitFrameLayout
     static inline size_t Size() {
         return sizeof(IonOOLProxyExitFrameLayout);
     }
 
     static size_t offsetOfResult() {
         return offsetof(IonOOLProxyExitFrameLayout, vp0_);
     }
 
+    static size_t offsetOfId() {
+        return offsetof(IonOOLProxyExitFrameLayout, id_);
+    }
+
+    static size_t offsetOfObjectOpResult() {
+        return offsetof(IonOOLProxyExitFrameLayout, result_);
+    }
+
     inline JitCode **stubCode() {
         return &stubCode_;
     }
     inline Value *vp() {
         return reinterpret_cast<Value*>(&vp0_);
     }
     inline jsid *id() {
         return &id_;
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -443,28 +443,34 @@ SetProperty(JSContext *cx, HandleObject 
         // Aliased var assigns ignore readonly attributes on the property, as
         // required for initializing 'const' closure variables.
         Shape *shape = obj->as<NativeObject>().lookup(cx, name);
         MOZ_ASSERT(shape && shape->hasSlot());
         obj->as<NativeObject>().setSlotWithType(cx, shape, value);
         return true;
     }
 
+    ObjectOpResult result;
     if (MOZ_LIKELY(!obj->getOps()->setProperty)) {
-        return NativeSetProperty(
-            cx, obj.as<NativeObject>(), obj.as<NativeObject>(), id,
-            (op == JSOP_SETNAME || op == JSOP_STRICTSETNAME ||
-             op == JSOP_SETGNAME || op == JSOP_STRICTSETGNAME)
-            ? Unqualified
-            : Qualified,
-            &v,
-            strict);
+        if (!NativeSetProperty(
+                cx, obj.as<NativeObject>(), obj.as<NativeObject>(), id,
+                (op == JSOP_SETNAME || op == JSOP_STRICTSETNAME ||
+                 op == JSOP_SETGNAME || op == JSOP_STRICTSETGNAME)
+                ? Unqualified
+                : Qualified,
+                &v,
+                result))
+        {
+            return false;
+        }
+    } else {
+        if (!SetProperty(cx, obj, obj, id, &v, result))
+            return false;
     }
-
-    return SetProperty(cx, obj, obj, id, &v, strict);
+    return result.checkStrictErrorOrWarning(cx, obj, id, strict);
 }
 
 bool
 InterruptCheck(JSContext *cx)
 {
     gc::MaybeVerifyBarriers(cx);
 
     {
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -464,8 +464,11 @@ MSG_DEF(JSMSG_BAD_PARSE_NODE,          0
 MSG_DEF(JSMSG_BAD_SYMBOL,              1, JSEXN_TYPEERR, "{0} is not a well-known @@-symbol")
 MSG_DEF(JSMSG_SYMBOL_TO_STRING,        0, JSEXN_TYPEERR, "can't convert symbol to string")
 MSG_DEF(JSMSG_SYMBOL_TO_NUMBER,        0, JSEXN_TYPEERR, "can't convert symbol to number")
 
 // Atomics and futexes
 MSG_DEF(JSMSG_ATOMICS_BAD_ARRAY,         0, JSEXN_TYPEERR, "invalid array type for the operation")
 MSG_DEF(JSMSG_ATOMICS_TOO_LONG,          0, JSEXN_RANGEERR, "timeout value too large")
 MSG_DEF(JSMSG_ATOMICS_WAIT_NOT_ALLOWED,  0, JSEXN_ERR, "waiting is not allowed on this thread")
+
+// XPConnect wrappers
+MSG_DEF(JSMSG_CANT_SET_INTERPOSED,      1, JSEXN_TYPEERR, "unable to set interposed data property '{0}'")
--- a/js/src/jsapi-tests/testForwardSetProperty.cpp
+++ b/js/src/jsapi-tests/testForwardSetProperty.cpp
@@ -40,21 +40,24 @@ BEGIN_TEST(testForwardSetProperty)
     EXEC("function assertEq(a, b, msg) \n"
          "{ \n"
          "  if (!Object.is(a, b)) \n"
          "    throw new Error('Assertion failure: ' + msg); \n"
          "}");
 
     // Non-strict setter
 
-    CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, v3, true, setval));
+    ObjectOpResult result;
+    CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, setval, v3, result));
+    CHECK(result);
 
     EXEC("assertEq(foundValue, obj3, 'wrong receiver passed to setter');");
 
-    CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, setval, true, setval));
+    CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, setval, setval, result));
+    CHECK(result);
 
     EXEC("assertEq(typeof foundValue === 'object', true, \n"
          "         'passing 42 as receiver to non-strict setter ' + \n"
          "         'must box');");
 
     EXEC("assertEq(foundValue instanceof Number, true, \n"
          "         'passing 42 as receiver to non-strict setter ' + \n"
          "         'must box to a Number');");
@@ -64,22 +67,23 @@ BEGIN_TEST(testForwardSetProperty)
          "         'must box to new Number(42)');");
 
     // Strict setter
 
     EVAL("obj1 = { set prop(val) { 'use strict'; foundValue = this; } }; \n"
          "obj1;",
          &v1);
 
-    CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, v3, true, setval));
+    CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, setval, v3, result));
+    CHECK(result);
 
     EXEC("assertEq(foundValue, obj3, 'wrong receiver passed to strict setter');");
 
-    CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, setval, true, setval));
-
+    CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, setval, setval, result));
+    CHECK(result);
 
     JS::RootedValue strictSetSupported(cx);
     EVAL("var strictSetSupported = false; \n"
          "Object.defineProperty(Object.prototype, \n"
          "                      'strictSetter', \n"
          "                      { \n"
          "                        set(v) { \n"
          "                          'use strict'; \n"
--- a/js/src/jsapi-tests/testSetPropertyIgnoringNamedGetter.cpp
+++ b/js/src/jsapi-tests/testSetPropertyIgnoringNamedGetter.cpp
@@ -23,23 +23,23 @@ class CustomProxyHandler : public Direct
 
     bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                   MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE
     {
         return impl(cx, proxy, id, desc, true);
     }
 
     bool set(JSContext *cx, HandleObject proxy, HandleObject receiver,
-             HandleId id, bool strict, MutableHandleValue vp) const MOZ_OVERRIDE
+             HandleId id, MutableHandleValue vp, ObjectOpResult &result) const MOZ_OVERRIDE
     {
         Rooted<JSPropertyDescriptor> desc(cx);
         if (!DirectProxyHandler::getPropertyDescriptor(cx, proxy, id, &desc))
             return false;
         return SetPropertyIgnoringNamedGetter(cx, this, proxy, receiver, id, &desc,
-                                              desc.object() == proxy, strict, vp);
+                                              desc.object() == proxy, vp, result);
     }
 
   private:
     bool impl(JSContext *cx, HandleObject proxy, HandleId id,
               MutableHandle<JSPropertyDescriptor> desc, bool ownOnly) const
     {
         if (JSID_IS_STRING(id)) {
             bool match;
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -181,16 +181,22 @@ JS::ObjectOpResult::failReadOnly()
 }
 
 JS_PUBLIC_API(bool)
 JS::ObjectOpResult::failGetterOnly()
 {
     return fail(JSMSG_GETTER_ONLY);
 }
 
+JS_PUBLIC_API(bool)
+JS::ObjectOpResult::failCantSetInterposed()
+{
+    return fail(JSMSG_CANT_SET_INTERPOSED);
+}
+
 JS_PUBLIC_API(int64_t)
 JS_Now()
 {
     return PRMJ_Now();
 }
 
 JS_PUBLIC_API(jsval)
 JS_GetNaNValue(JSContext *cx)
@@ -1653,19 +1659,20 @@ JS_DefaultValue(JSContext *cx, HandleObj
 
 JS_PUBLIC_API(bool)
 JS_PropertyStub(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
 {
     return true;
 }
 
 JS_PUBLIC_API(bool)
-JS_StrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp)
-{
-    return true;
+JS_StrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp,
+                      ObjectOpResult &result)
+{
+    return result.succeed();
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_InitClass(JSContext *cx, HandleObject obj, HandleObject parent_proto,
              const JSClass *clasp, JSNative constructor, unsigned nargs,
              const JSPropertySpec *ps, const JSFunctionSpec *fs,
              const JSPropertySpec *static_ps, const JSFunctionSpec *static_fs)
 {
@@ -2801,45 +2808,46 @@ JS_GetUCProperty(JSContext *cx, HandleOb
 JS_PUBLIC_API(bool)
 JS_SetPropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleValue v)
 {
     RootedValue value(cx, v);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
 
-    return SetProperty(cx, obj, obj, id, &value, false);
-}
-
-JS_PUBLIC_API(bool)
-JS_ForwardSetPropertyTo(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue onBehalfOf,
-                        bool strict, JS::HandleValue v)
+    ObjectOpResult ignored;
+    return SetProperty(cx, obj, obj, id, &value, ignored);
+}
+
+JS_PUBLIC_API(bool)
+JS_ForwardSetPropertyTo(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
+                        HandleValue receiver, ObjectOpResult &result)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    assertSameCompartment(cx, obj, id);
-    assertSameCompartment(cx, onBehalfOf);
+    assertSameCompartment(cx, obj, id, receiver);
 
     // XXX Bug 603201 will eliminate this ToObject.
-    RootedObject receiver(cx, ToObject(cx, onBehalfOf));
-    if (!receiver)
+    RootedObject receiverObj(cx, ToObject(cx, receiver));
+    if (!receiverObj)
         return false;
 
     RootedValue value(cx, v);
-    return SetProperty(cx, obj, receiver, id, &value, strict);
+    return SetProperty(cx, obj, receiverObj, id, &value, result);
 }
 
 static bool
 SetElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleValue vp)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, vp);
 
-    return SetElement(cx, obj, obj, index, vp, false);
+    ObjectOpResult ignored;
+    return SetElement(cx, obj, obj, index, vp, ignored);
 }
 
 JS_PUBLIC_API(bool)
 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v)
 {
     RootedValue value(cx, v);
     return SetElement(cx, obj, index, &value);
 }
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1992,18 +1992,18 @@ extern JS_PUBLIC_API(bool)
 JS_DefaultValue(JSContext *cx, JS::Handle<JSObject*> obj, JSType hint,
                 JS::MutableHandle<JS::Value> vp);
 
 extern JS_PUBLIC_API(bool)
 JS_PropertyStub(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
                 JS::MutableHandleValue vp);
 
 extern JS_PUBLIC_API(bool)
-JS_StrictPropertyStub(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool strict,
-                      JS::MutableHandleValue vp);
+JS_StrictPropertyStub(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
+                      JS::MutableHandleValue vp, JS::ObjectOpResult &result);
 
 template<typename T>
 struct JSConstScalarSpec {
     const char *name;
     T val;
 };
 
 typedef JSConstScalarSpec<double> JSConstDoubleSpec;
@@ -2836,18 +2836,18 @@ JS_ForwardGetPropertyTo(JSContext *cx, J
 
 extern JS_PUBLIC_API(bool)
 JS_SetProperty(JSContext *cx, JS::HandleObject obj, const char *name, JS::HandleValue v);
 
 extern JS_PUBLIC_API(bool)
 JS_SetPropertyById(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v);
 
 extern JS_PUBLIC_API(bool)
-JS_ForwardSetPropertyTo(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue onBehalfOf,
-                        bool strict, JS::HandleValue vp);
+JS_ForwardSetPropertyTo(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v,
+                        JS::HandleValue receiver, JS::ObjectOpResult &result);
 
 extern JS_PUBLIC_API(bool)
 JS_DeleteProperty(JSContext *cx, JS::HandleObject obj, const char *name);
 
 extern JS_PUBLIC_API(bool)
 JS_DeleteProperty2(JSContext *cx, JS::HandleObject obj, const char *name, bool *succeeded);
 
 extern JS_PUBLIC_API(bool)
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -359,17 +359,17 @@ SetArrayElement(JSContext *cx, HandleObj
         MOZ_ASSERT(result == NativeObject::ED_SPARSE);
     }
 
     RootedId id(cx);
     if (!ToId(cx, index, &id))
         return false;
 
     RootedValue tmp(cx, v);
-    return SetProperty(cx, obj, obj, id, &tmp, true);
+    return SetProperty(cx, obj, obj, id, &tmp);
 }
 
 /*
  * Attempt to delete the element |index| from |obj| as if by
  * |obj.[[Delete]](index)|.
  *
  * If an error occurs while attempting to delete the element (that is, the call
  * to [[Delete]] threw), return false.
@@ -429,17 +429,17 @@ DeletePropertyOrThrow(JSContext *cx, Han
         return false;
     return obj->reportNotConfigurable(cx, id, JSREPORT_ERROR);
 }
 
 bool
 js::SetLengthProperty(JSContext *cx, HandleObject obj, double length)
 {
     RootedValue v(cx, NumberValue(length));
-    return SetProperty(cx, obj, obj, cx->names().length, &v, true);
+    return SetProperty(cx, obj, obj, cx->names().length, &v);
 }
 
 /*
  * Since SpiderMonkey supports cross-class prototype-based delegation, we have
  * to be careful about the length getter and setter being called on an object
  * not of Array class. For the getter, we search obj's prototype chain for the
  * array that caused this getter to be invoked. In the setter case to overcome
  * the JSPROP_SHARED attribute, we must define a shadowing length property.
@@ -455,39 +455,33 @@ array_length_getter(JSContext *cx, Handl
         }
         if (!GetPrototype(cx, obj, &obj))
             return false;
     } while (obj);
     return true;
 }
 
 static bool
-array_length_setter(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp)
+array_length_setter(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp,
+                    ObjectOpResult &result)
 {
     if (!obj->is<ArrayObject>()) {
         // This array .length property was found on the prototype
         // chain. Ideally the setter should not have been called, but since
         // we're here, do an impression of SetPropertyByDefining.
         const Class *clasp = obj->getClass();
         return DefineProperty(cx, obj, cx->names().length, vp,
-                              clasp->getProperty, clasp->setProperty, JSPROP_ENUMERATE);
+                              clasp->getProperty, clasp->setProperty, JSPROP_ENUMERATE, result);
     }
 
     Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
     MOZ_ASSERT(arr->lengthIsWritable(),
                "setter shouldn't be called if property is non-writable");
 
-    ObjectOpResult success;
-    if (!ArraySetLength(cx, arr, id, JSPROP_PERMANENT, vp, success))
-        return false;
-    if (strict && !success) {
-        success.reportError(cx, arr, id);
-        return false;
-    }
-    return true;
+    return ArraySetLength(cx, arr, id, JSPROP_PERMANENT, vp, result);
 }
 
 struct ReverseIndexComparator
 {
     bool operator()(const uint32_t& a, const uint32_t& b, bool *lessOrEqualp) {
         MOZ_ASSERT(a != b, "how'd we get duplicate indexes?");
         *lessOrEqualp = b <= a;
         return true;
@@ -1272,17 +1266,17 @@ InitArrayElements(JSContext *cx, HandleO
     RootedValue value(cx);
     RootedId id(cx);
     RootedValue indexv(cx);
     double index = MAX_ARRAY_INDEX + 1;
     do {
         value = *vector++;
         indexv = DoubleValue(index);
         if (!ValueToId<CanGC>(cx, indexv, &id) ||
-            !SetProperty(cx, obj, obj, id, &value, true))
+            !SetProperty(cx, obj, obj, id, &value))
         {
             return false;
         }
         index += 1;
     } while (vector != end);
 
     return true;
 }
@@ -3069,18 +3063,17 @@ array_of(JSContext *cx, unsigned argc, V
 
     // Step 8.
     for (unsigned k = 0; k < args.length(); k++) {
         if (!DefineElement(cx, obj, k, args[k]))
             return false;
     }
 
     // Steps 9-10.
-    RootedValue v(cx, NumberValue(args.length()));
-    if (!SetProperty(cx, obj, obj, cx->names().length, &v, true))
+    if (!SetLengthProperty(cx, obj, args.length()))
         return false;
 
     // Step 11.
     args.rval().setObject(*obj);
     return true;
 }
 
 #define GENERIC JSFUN_GENERIC_NATIVE
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -306,23 +306,23 @@ CallJSGetterOp(JSContext *cx, GetterOp o
     assertSameCompartment(cx, receiver, id, vp);
     bool ok = op(cx, receiver, id, vp);
     if (ok)
         assertSameCompartment(cx, vp);
     return ok;
 }
 
 MOZ_ALWAYS_INLINE bool
-CallJSSetterOp(JSContext *cx, SetterOp op, HandleObject obj, HandleId id, bool strict,
-               MutableHandleValue vp)
+CallJSSetterOp(JSContext *cx, SetterOp op, HandleObject obj, HandleId id, MutableHandleValue vp,
+               ObjectOpResult &result)
 {
     JS_CHECK_RECURSION(cx, return false);
 
     assertSameCompartment(cx, obj, id, vp);
-    return op(cx, obj, id, strict, vp);
+    return op(cx, obj, id, vp, result);
 }
 
 static inline bool
 CallJSDeletePropertyOp(JSContext *cx, JSDeletePropertyOp op, HandleObject receiver, HandleId id,
                        bool *succeeded)
 {
     JS_CHECK_RECURSION(cx, return false);
 
@@ -330,30 +330,32 @@ CallJSDeletePropertyOp(JSContext *cx, JS
     if (op)
         return op(cx, receiver, id, succeeded);
     *succeeded = true;
     return true;
 }
 
 inline bool
 CallSetter(JSContext *cx, HandleObject obj, HandleId id, SetterOp op, unsigned attrs,
-           bool strict, MutableHandleValue vp)
+           MutableHandleValue vp, ObjectOpResult &result)
 {
     if (attrs & JSPROP_SETTER) {
         RootedValue opv(cx, CastAsObjectJsval(op));
-        return InvokeGetterOrSetter(cx, obj, opv, 1, vp.address(), vp);
+        if (!InvokeGetterOrSetter(cx, obj, opv, 1, vp.address(), vp))
+            return false;
+        return result.succeed();
     }
 
     if (attrs & JSPROP_GETTER)
-        return ReportGetterOnlyAssignment(cx, strict);
+        return result.fail(JSMSG_GETTER_ONLY);
 
     if (!op)
-        return true;
+        return result.succeed();
 
-    return CallJSSetterOp(cx, op, obj, id, strict, vp);
+    return CallJSSetterOp(cx, op, obj, id, vp, result);
 }
 
 inline uintptr_t
 GetNativeStackLimit(ExclusiveContext *cx)
 {
     StackKind kind;
     if (cx->isJSContext()) {
         kind = cx->asJSContext()->runningWithTrustedPrincipals()
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -365,17 +365,17 @@ proxy_DefineProperty(JSContext *cx, JS::
                      JS::ObjectOpResult &result);
 extern JS_FRIEND_API(bool)
 proxy_HasProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool *foundp);
 extern JS_FRIEND_API(bool)
 proxy_GetProperty(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, JS::HandleId id,
                   JS::MutableHandleValue vp);
 extern JS_FRIEND_API(bool)
 proxy_SetProperty(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, JS::HandleId id,
-                  JS::MutableHandleValue bp, bool strict);
+                  JS::MutableHandleValue bp, JS::ObjectOpResult &result);
 extern JS_FRIEND_API(bool)
 proxy_GetOwnPropertyDescriptor(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
                                JS::MutableHandle<JSPropertyDescriptor> desc);
 extern JS_FRIEND_API(bool)
 proxy_DeleteProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool *succeeded);
 
 extern JS_FRIEND_API(void)
 proxy_Trace(JSTracer *trc, JSObject *obj);
@@ -2635,17 +2635,18 @@ ForwardToNative(JSContext *cx, JSNative 
  * parameters.
  *
  * Implemented in jsproxy.cpp.
  */
 JS_FRIEND_API(bool)
 SetPropertyIgnoringNamedGetter(JSContext *cx, const BaseProxyHandler *handler,
                                JS::HandleObject proxy, JS::HandleObject receiver,
                                JS::HandleId id, JS::MutableHandle<JSPropertyDescriptor> desc,
-                               bool descIsOwn, bool strict, JS::MutableHandleValue vp);
+                               bool descIsOwn, JS::MutableHandleValue vp,
+                               JS::ObjectOpResult &result);
 
 JS_FRIEND_API(void)
 ReportErrorWithId(JSContext *cx, const char *msg, JS::HandleId id);
 
 // This function is for one specific use case, please don't use this for anything else!
 extern JS_FRIEND_API(bool)
 ExecuteInGlobalAndReturnScope(JSContext *cx, JS::HandleObject obj, JS::HandleScript script,
                               JS::MutableHandleObject scope);
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1653,34 +1653,34 @@ js::CreateThisForFunction(JSContext *cx,
         return nobj;
     }
 
     return obj;
 }
 
 /* static */ bool
 JSObject::nonNativeSetProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
-                               HandleId id, MutableHandleValue vp, bool strict)
+                               HandleId id, MutableHandleValue vp, ObjectOpResult &result)
 {
     if (MOZ_UNLIKELY(obj->watched())) {
         WatchpointMap *wpmap = cx->compartment()->watchpointMap;
         if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, vp))
             return false;
     }
-    return obj->getOps()->setProperty(cx, obj, receiver, id, vp, strict);
+    return obj->getOps()->setProperty(cx, obj, receiver, id, vp, result);
 }
 
 /* static */ bool
 JSObject::nonNativeSetElement(JSContext *cx, HandleObject obj, HandleObject receiver,
-                              uint32_t index, MutableHandleValue vp, bool strict)
+                              uint32_t index, MutableHandleValue vp, ObjectOpResult &result)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, &id))
         return false;
-    return nonNativeSetProperty(cx, obj, receiver, id, vp, strict);
+    return nonNativeSetProperty(cx, obj, receiver, id, vp, result);
 }
 
 JS_FRIEND_API(bool)
 JS_CopyPropertyFrom(JSContext *cx, HandleId id, HandleObject target,
                     HandleObject obj, PropertyCopyBehavior copyBehavior)
 {
     // |obj| and |cx| are generally not same-compartment with |target| here.
     assertSameCompartment(cx, obj, id);
@@ -3317,16 +3317,32 @@ js::DefineElement(ExclusiveContext *cx, 
     MOZ_ASSERT(setter != JS_StrictPropertyStub);
 
     RootedId id(cx);
     if (!IndexToId(cx, index, &id))
         return false;
     return DefineProperty(cx, obj, id, value, getter, setter, attrs);
 }
 
+bool
+js::SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandlePropertyName name,
+                MutableHandleValue vp)
+{
+    RootedId id(cx, NameToId(name));
+    return SetProperty(cx, obj, receiver, id, vp);
+}
+
+bool
+js::PutProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, MutableHandleValue value,
+                bool strict)
+{
+    RootedId id(cx, NameToId(name));
+    return PutProperty(cx, obj, id, value, strict);
+}
+
 
 /*** SpiderMonkey nonstandard internal methods ***************************************************/
 
 bool
 js::SetImmutablePrototype(ExclusiveContext *cx, HandleObject obj, bool *succeeded)
 {
     if (obj->hasLazyPrototype()) {
         if (!cx->shouldBeJSContext())
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -481,20 +481,20 @@ class JSObject : public js::gc::Cell
      * callable a TypeError will be thrown. On success the value returned by
      * the call is stored in *vp.
      */
     bool callMethod(JSContext *cx, js::HandleId id, unsigned argc, js::Value *argv,
                     js::MutableHandleValue vp);
 
     static bool nonNativeSetProperty(JSContext *cx, js::HandleObject obj,
                                      js::HandleObject receiver, js::HandleId id,
-                                     js::MutableHandleValue vp, bool strict);
+                                     js::MutableHandleValue vp, JS::ObjectOpResult &result);
     static bool nonNativeSetElement(JSContext *cx, js::HandleObject obj,
                                     js::HandleObject receiver, uint32_t index,
-                                    js::MutableHandleValue vp, bool strict);
+                                    js::MutableHandleValue vp, JS::ObjectOpResult &result);
 
     static bool swap(JSContext *cx, JS::HandleObject a, JS::HandleObject b);
 
   private:
     void fixDictionaryShapeAfterSwap();
 
   public:
     inline void initArrayClass();
@@ -865,29 +865,59 @@ GetElementNoGC(JSContext *cx, JSObject *
  * assignment that started out as `receiver[id] = vp`, by delegating it to obj.
  *
  * Strict errors: ES6 specifies that this method returns a boolean value
  * indicating whether assignment "succeeded". We currently take a `strict`
  * argument instead, but this has to change. See bug 1113369.
  */
 inline bool
 SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
-            MutableHandleValue vp, bool strict);
+            MutableHandleValue vp, ObjectOpResult &result);
 
 inline bool
 SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, PropertyName *name,
-            MutableHandleValue vp, bool strict)
+            MutableHandleValue vp, ObjectOpResult &result)
 {
     RootedId id(cx, NameToId(name));
-    return SetProperty(cx, obj, receiver, id, vp, strict);
+    return SetProperty(cx, obj, receiver, id, vp, result);
 }
 
 inline bool
 SetElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index,
-           MutableHandleValue vp, bool strict);
+           MutableHandleValue vp, ObjectOpResult &result);
+
+inline bool
+SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
+            MutableHandleValue vp)
+{
+    ObjectOpResult result;
+    return SetProperty(cx, obj, receiver, id, vp, result) &&
+           result.checkStrict(cx, receiver, id);
+}
+
+extern bool
+SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandlePropertyName name,
+            MutableHandleValue vp);
+
+/*
+ * ES6 draft rev 31 (15 Jan 2015) 7.3.3 Put (O, P, V, Throw), except that on
+ * success, the spec says this is supposed to return a boolean value, which we
+ * don't bother doing.
+ */
+inline bool
+PutProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue value, bool strict)
+{
+    ObjectOpResult result;
+    return SetProperty(cx, obj, obj, id, value, result) &&
+           result.checkStrictErrorOrWarning(cx, obj, id, strict);
+}
+
+extern bool
+PutProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, MutableHandleValue value,
+            bool strict);
 
 /*
  * ES6 [[Delete]]. Equivalent to the JS code `delete obj[id]`.
  */
 inline bool
 DeleteProperty(JSContext *cx, js::HandleObject obj, js::HandleId id, bool *succeeded);
 
 inline bool
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -737,17 +737,17 @@ NodeBuilder::newArray(NodeVector &elts, 
         RootedValue val(cx, elts[i]);
 
         MOZ_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
 
         /* Represent "no node" as an array hole by not adding the value. */
         if (val.isMagic(JS_SERIALIZE_NO_NODE))
             continue;
 
-        if (!SetElement(cx, array, array, i, &val, false))
+        if (!DefineElement(cx, array, i, val))
             return false;
     }
 
     dst.setObject(*array);
     return true;
 }
 
 bool
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -2163,17 +2163,17 @@ class MOZ_STACK_CLASS StringRegExpGuard
             if (nobj->lookup(cx, cx->names().lastIndex)->writable()) {
                 nobj->zeroLastIndex();
                 return true;
             }
         }
 
         // Handle everything else generically (including throwing if .lastIndex is non-writable).
         RootedValue zero(cx, Int32Value(0));
-        return SetProperty(cx, obj_, obj_, cx->names().lastIndex, &zero, true);
+        return SetProperty(cx, obj_, obj_, cx->names().lastIndex, &zero);
     }
 
     RegExpShared &regExp() { return *re_; }
 
     bool regExpIsObject() { return obj_ != nullptr; }
     HandleObject regExpObject() {
         MOZ_ASSERT(regExpIsObject());
         return obj_;
--- a/js/src/jswrapper.h
+++ b/js/src/jswrapper.h
@@ -130,18 +130,18 @@ class JS_FRIEND_API(CrossCompartmentWrap
 
     virtual bool setImmutablePrototype(JSContext *cx, HandleObject proxy,
                                        bool *succeeded) const MOZ_OVERRIDE;
     virtual bool preventExtensions(JSContext *cx, HandleObject wrapper, bool *succeeded) const MOZ_OVERRIDE;
     virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) const MOZ_OVERRIDE;
     virtual bool has(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE;
     virtual bool get(JSContext *cx, HandleObject wrapper, HandleObject receiver,
                      HandleId id, MutableHandleValue vp) const MOZ_OVERRIDE;
-    virtual bool set(JSContext *cx, HandleObject wrapper, HandleObject receiver,
-                     HandleId id, bool strict, MutableHandleValue vp) const MOZ_OVERRIDE;
+    virtual bool set(JSContext *cx, HandleObject wrapper, HandleObject receiver, HandleId id,
+                     MutableHandleValue vp, ObjectOpResult &result) const MOZ_OVERRIDE;
     virtual bool call(JSContext *cx, HandleObject wrapper, const CallArgs &args) const MOZ_OVERRIDE;
     virtual bool construct(JSContext *cx, HandleObject wrapper, const CallArgs &args) const MOZ_OVERRIDE;
 
     /* SpiderMonkey extensions. */
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool hasOwn(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE;
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper,
--- a/js/src/proxy/BaseProxyHandler.cpp
+++ b/js/src/proxy/BaseProxyHandler.cpp
@@ -68,17 +68,17 @@ BaseProxyHandler::get(JSContext *cx, Han
     else
         vp.setUndefined();
 
     return CallJSGetterOp(cx, desc.getter(), receiver, id, vp);
 }
 
 bool
 BaseProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
-                      HandleId id, bool strict, MutableHandleValue vp) const
+                      HandleId id, MutableHandleValue vp, ObjectOpResult &result) const
 {
     assertEnteredPolicy(cx, proxy, id, SET);
 
     // This method is not covered by any spec, but we follow ES6 draft rev 28
     // (2014 Oct 14) 9.1.9 fairly closely, adapting it slightly for
     // SpiderMonkey's particular foibles.
 
     // Steps 2-3.  (Step 1 is a superfluous assertion.)
@@ -89,41 +89,36 @@ BaseProxyHandler::set(JSContext *cx, Han
     // Step 4.
     if (!ownDesc.object()) {
         // The spec calls this variable "parent", but that word has weird
         // connotations in SpiderMonkey, so let's go with "proto".
         RootedObject proto(cx);
         if (!GetPrototype(cx, proxy, &proto))
             return false;
         if (proto)
-            return SetProperty(cx, proto, receiver, id, vp, strict);
+            return SetProperty(cx, proto, receiver, id, vp, result);
 
         // Change ownDesc to be a complete descriptor for a configurable,
         // writable, enumerable data property. Then fall through to step 5.
         ownDesc.clear();
         ownDesc.setAttributes(JSPROP_ENUMERATE);
     }
 
     // Step 5.
     if (ownDesc.isDataDescriptor()) {
         // Steps 5.a-b, adapted to our nonstandard implementation of ES6
         // [[Set]] return values.
-        if (!ownDesc.isWritable()) {
-            if (strict)
-                return JSObject::reportReadOnly(cx, id, JSREPORT_ERROR);
-            if (cx->compartment()->options().extraWarnings(cx))
-                return JSObject::reportReadOnly(cx, id, JSREPORT_STRICT | JSREPORT_WARNING);
-            return true;
-        }
+        if (!ownDesc.isWritable())
+            return result.fail(JSMSG_READ_ONLY);
 
         // Nonstandard SpiderMonkey special case: setter ops.
         SetterOp setter = ownDesc.setter();
         MOZ_ASSERT(setter != JS_StrictPropertyStub);
         if (setter && setter != JS_StrictPropertyStub)
-            return CallSetter(cx, receiver, id, setter, ownDesc.attributes(), strict, vp);
+            return CallSetter(cx, receiver, id, setter, ownDesc.attributes(), vp, result);
 
         // Steps 5.c-d. Adapt for SpiderMonkey by using HasOwnProperty instead
         // of the standard [[GetOwnProperty]].
         bool existingDescriptor;
         if (!HasOwnProperty(cx, receiver, id, &existingDescriptor))
             return false;
 
         // Steps 5.e-f.
@@ -132,76 +127,77 @@ BaseProxyHandler::set(JSContext *cx, Han
             ? JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_READONLY | JSPROP_IGNORE_PERMANENT
             : JSPROP_ENUMERATE;
 
         // A very old nonstandard SpiderMonkey extension: default to the Class
         // getter and setter ops.
         const Class *clasp = receiver->getClass();
         MOZ_ASSERT(clasp->getProperty != JS_PropertyStub);
         MOZ_ASSERT(clasp->setProperty != JS_StrictPropertyStub);
-        return DefineProperty(cx, receiver, id, vp,
-                              clasp->getProperty, clasp->setProperty, attrs);
+        return DefineProperty(cx, receiver, id, vp, clasp->getProperty, clasp->setProperty,
+                              attrs, result);
     }
 
     // Step 6.
     MOZ_ASSERT(ownDesc.isAccessorDescriptor());
     RootedObject setter(cx);
     if (ownDesc.hasSetterObject())
         setter = ownDesc.setterObject();
     if (!setter)
-        return ReportGetterOnlyAssignment(cx, strict);
+        return result.fail(JSMSG_GETTER_ONLY);
     RootedValue setterValue(cx, ObjectValue(*setter));
-    return InvokeGetterOrSetter(cx, receiver, setterValue, 1, vp.address(), vp);
+    if (!InvokeGetterOrSetter(cx, receiver, setterValue, 1, vp.address(), vp))
+        return false;
+    return result.succeed();
 }
 
 bool
 js::SetPropertyIgnoringNamedGetter(JSContext *cx, const BaseProxyHandler *handler,
                                    HandleObject proxy, HandleObject receiver,
                                    HandleId id, MutableHandle<PropertyDescriptor> desc,
-                                   bool descIsOwn, bool strict, MutableHandleValue vp)
+                                   bool descIsOwn, MutableHandleValue vp, ObjectOpResult &result)
 {
     /* The control-flow here differs from ::get() because of the fall-through case below. */
     MOZ_ASSERT_IF(descIsOwn, desc.object());
     if (desc.object()) {
         MOZ_ASSERT(desc.getter() != JS_PropertyStub);
         MOZ_ASSERT(desc.setter() != JS_StrictPropertyStub);
 
         // Check for read-only properties.
-        if (desc.isReadonly()) {
-            if (strict)
-                return Throw(cx, id, descIsOwn ? JSMSG_READ_ONLY : JSMSG_CANT_REDEFINE_PROP);
-            return true;
-        }
+        if (desc.isReadonly())
+            return result.fail(descIsOwn ? JSMSG_READ_ONLY : JSMSG_CANT_REDEFINE_PROP);
 
         if (desc.hasSetterObject() || desc.setter()) {
-            if (!CallSetter(cx, receiver, id, desc.setter(), desc.attributes(), strict, vp))
+            if (!CallSetter(cx, receiver, id, desc.setter(), desc.attributes(), vp, result))
                 return false;
-            if (!proxy->is<ProxyObject>() || proxy->as<ProxyObject>().handler() != handler)
+            if (!result)
                 return true;
-            if (desc.isShared())
-                return true;
+            if (!proxy->is<ProxyObject>() ||
+                proxy->as<ProxyObject>().handler() != handler ||
+                desc.isShared())
+            {
+                return result.succeed();
+            }
         }
         desc.value().set(vp.get());
 
         if (descIsOwn) {
             MOZ_ASSERT(desc.object() == proxy);
-            ObjectOpResult result;
-            if (!handler->defineProperty(cx, proxy, id, desc, result))
-                return false;
-            return result.checkStrictErrorOrWarning(cx, proxy, id, strict);
+            return handler->defineProperty(cx, proxy, id, desc, result);
         }
-        return DefineProperty(cx, receiver, id, desc.value(),
-                              desc.getter(), desc.setter(), desc.attributes());
+        return DefineProperty(cx, receiver, id, desc.value(), desc.getter(), desc.setter(),
+                              desc.attributes(), result);
     }
     desc.object().set(receiver);
     desc.value().set(vp.get());
     desc.setAttributes(JSPROP_ENUMERATE);
     desc.setGetter(nullptr);
     desc.setSetter(nullptr); // Pick up the class getter/setter.
-    return DefineProperty(cx, receiver, id, desc.value(), nullptr, nullptr, JSPROP_ENUMERATE);
+    return DefineProperty(cx, receiver, id, desc.value(), nullptr, nullptr, JSPROP_ENUMERATE,
+                          result);
 }
 
 bool
 BaseProxyHandler::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                                AutoIdVector &props) const
 {
     assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
     MOZ_ASSERT(props.length() == 0);
--- a/js/src/proxy/CrossCompartmentWrapper.cpp
+++ b/js/src/proxy/CrossCompartmentWrapper.cpp
@@ -164,23 +164,23 @@ CrossCompartmentWrapper::get(JSContext *
         if (!Wrapper::get(cx, wrapper, receiverCopy, id, vp))
             return false;
     }
     return cx->compartment()->wrap(cx, vp);
 }
 
 bool
 CrossCompartmentWrapper::set(JSContext *cx, HandleObject wrapper, HandleObject receiver,
-                             HandleId id, bool strict, MutableHandleValue vp) const
+                             HandleId id, MutableHandleValue vp, ObjectOpResult &result) const
 {
     RootedObject receiverCopy(cx, receiver);
     PIERCE(cx, wrapper,
            cx->compartment()->wrap(cx, &receiverCopy) &&
            cx->compartment()->wrap(cx, vp),
-           Wrapper::set(cx, wrapper, receiverCopy, id, strict, vp),
+           Wrapper::set(cx, wrapper, receiverCopy, id, vp, result),
            NOTHING);
 }
 
 bool
 CrossCompartmentWrapper::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper,
                                                       AutoIdVector &props) const
 {
     PIERCE(cx, wrapper,
--- a/js/src/proxy/DirectProxyHandler.cpp
+++ b/js/src/proxy/DirectProxyHandler.cpp
@@ -218,21 +218,21 @@ DirectProxyHandler::get(JSContext *cx, H
 {
     assertEnteredPolicy(cx, proxy, id, GET);
     RootedObject target(cx, proxy->as<ProxyObject>().target());
     return GetProperty(cx, target, receiver, id, vp);
 }
 
 bool
 DirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
-                        HandleId id, bool strict, MutableHandleValue vp) const
+                        HandleId id, MutableHandleValue vp, ObjectOpResult &result) const
 {
     assertEnteredPolicy(cx, proxy, id, SET);
     RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return SetProperty(cx, target, receiver, id, vp, strict);
+    return SetProperty(cx, target, receiver, id, vp, result);
 }
 
 bool
 DirectProxyHandler::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                                  AutoIdVector &props) const
 {
     assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
     RootedObject target(cx, proxy->as<ProxyObject>().target());
--- a/js/src/proxy/Proxy.cpp
+++ b/js/src/proxy/Proxy.cpp
@@ -299,30 +299,33 @@ Proxy::callProp(JSContext *cx, HandleObj
             return false;
     }
 #endif
 
     return true;
 }
 
 bool
-Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, bool strict,
-           MutableHandleValue vp)
+Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
+           MutableHandleValue vp, ObjectOpResult &result)
 {
     JS_CHECK_RECURSION(cx, return false);
     const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
     AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::SET, true);
-    if (!policy.allowed())
-        return policy.returnValue();
+    if (!policy.allowed()) {
+        if (!policy.returnValue())
+            return false;
+        return result.succeed();
+    }
 
     // Special case. See the comment on BaseProxyHandler::mHasPrototype.
     if (handler->hasPrototype())
-        return handler->BaseProxyHandler::set(cx, proxy, receiver, id, strict, vp);
+        return handler->BaseProxyHandler::set(cx, proxy, receiver, id, vp, result);
 
-    return handler->set(cx, proxy, receiver, id, strict, vp);
+    return handler->set(cx, proxy, receiver, id, vp, result);
 }
 
 bool
 Proxy::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
 {
     JS_CHECK_RECURSION(cx, return false);
     const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
     AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::ENUMERATE, true);
@@ -576,19 +579,19 @@ bool
 js::proxy_GetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
                       MutableHandleValue vp)
 {
     return Proxy::get(cx, obj, receiver, id, vp);
 }
 
 bool
 js::proxy_SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
-                      MutableHandleValue vp, bool strict)
+                      MutableHandleValue vp, ObjectOpResult &result)
 {
-    return Proxy::set(cx, obj, receiver, id, strict, vp);
+    return Proxy::set(cx, obj, receiver, id, vp, result);
 }
 
 bool
 js::proxy_GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
                                    MutableHandle<JSPropertyDescriptor> desc)
 {
     return Proxy::getOwnPropertyDescriptor(cx, obj, id, desc);
 }
--- a/js/src/proxy/Proxy.h
+++ b/js/src/proxy/Proxy.h
@@ -37,17 +37,17 @@ class Proxy
     static bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded);
     static bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop);
     static bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp);
     static bool setImmutablePrototype(JSContext *cx, HandleObject proxy, bool *succeeded);
     static bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
     static bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
                     MutableHandleValue vp);
     static bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
-                    bool strict, MutableHandleValue vp);
+                    MutableHandleValue vp, ObjectOpResult &result);
     static bool call(JSContext *cx, HandleObject proxy, const CallArgs &args);
     static bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args);
 
     /* SpiderMonkey extensions. */
     static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                       MutableHandle<JSPropertyDescriptor> desc);
     static bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
     static bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
--- a/js/src/proxy/ScriptedDirectProxyHandler.cpp
+++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp
@@ -930,17 +930,17 @@ ScriptedDirectProxyHandler::get(JSContex
     // step 13
     vp.set(trapResult);
     return true;
 }
 
 // ES6 (22 May, 2014) 9.5.9 Proxy.[[SetP]](P, V, Receiver)
 bool
 ScriptedDirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
-                                HandleId id, bool strict, MutableHandleValue vp) const
+                                HandleId id, MutableHandleValue vp, ObjectOpResult &result) const
 {
     // step 2
     RootedObject handler(cx, GetDirectProxyHandlerObject(proxy));
 
     // step 3
     if (!handler) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED);
         return false;
@@ -951,33 +951,35 @@ ScriptedDirectProxyHandler::set(JSContex
 
     // step 5-6
     RootedValue trap(cx);
     if (!GetProperty(cx, handler, handler, cx->names().set, &trap))
         return false;
 
     // step 7
     if (trap.isUndefined())
-        return DirectProxyHandler::set(cx, proxy, receiver, id, strict, vp);
+        return DirectProxyHandler::set(cx, proxy, receiver, id, vp, result);
 
     // step 8,10
     RootedValue value(cx);
     if (!IdToStringOrSymbol(cx, id, &value))
         return false;
     Value argv[] = {
         ObjectOrNullValue(target),
         value,
         vp.get(),
         ObjectValue(*receiver)
     };
     RootedValue trapResult(cx);
     if (!Invoke(cx, ObjectValue(*handler), trap, ArrayLength(argv), argv, &trapResult))
         return false;
 
-    // step 9
+    // FIXME - bug 1132522: Step 9 is not implemented yet.
+    // if (!ToBoolean(trapResult))
+    //     return result.fail(JSMSG_PROXY_SET_RETURNED_FALSE);
     bool success = ToBoolean(trapResult);
 
     if (success) {
         // step 12-13
         Rooted<PropertyDescriptor> desc(cx);
         if (!GetOwnPropertyDescriptor(cx, target, id, &desc))
             return false;
 
@@ -996,18 +998,19 @@ ScriptedDirectProxyHandler::set(JSContex
             if (IsAccessorDescriptor(desc) && desc.isPermanent() && !desc.hasSetterObject()) {
                 JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_SET_WO_SETTER);
                 return false;
             }
         }
     }
 
     // step 11, 15
+    // XXX FIXME - This use of vp is wrong. Bug 1132522 can clean it up.
     vp.setBoolean(success);
-    return true;
+    return result.succeed();
 }
 
 
 // ES6 (22 May, 2014) 9.5.13 Proxy.[[Call]]
 bool
 ScriptedDirectProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args) const
 {
     // step 1
--- a/js/src/proxy/ScriptedDirectProxyHandler.h
+++ b/js/src/proxy/ScriptedDirectProxyHandler.h
@@ -40,17 +40,17 @@ class ScriptedDirectProxyHandler : publi
 
     virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE;
     virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
 
     virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
     virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
                      MutableHandleValue vp) const MOZ_OVERRIDE;
     virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
-                     bool strict, MutableHandleValue vp) const MOZ_OVERRIDE;
+                     MutableHandleValue vp, ObjectOpResult &result) const MOZ_OVERRIDE;
     virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
     virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
 
     /* SpiderMonkey extensions. */
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE {
         return BaseProxyHandler::hasOwn(cx, proxy, id, bp);
--- a/js/src/proxy/ScriptedIndirectProxyHandler.cpp
+++ b/js/src/proxy/ScriptedIndirectProxyHandler.cpp
@@ -291,52 +291,55 @@ ScriptedIndirectProxyHandler::get(JSCont
         return false;
     if (!IsCallable(fval))
         return BaseProxyHandler::get(cx, proxy, receiver, id, vp);
     return Trap(cx, handler, fval, 2, argv.begin(), vp);
 }
 
 bool
 ScriptedIndirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
-                                  HandleId id, bool strict, MutableHandleValue vp) const
+                                  HandleId id, MutableHandleValue vp, ObjectOpResult &result) const
 {
     RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
     RootedValue idv(cx);
     if (!IdToStringOrSymbol(cx, id, &idv))
         return false;
     JS::AutoValueArray<3> argv(cx);
     argv[0].setObjectOrNull(receiver);
     argv[1].set(idv);
     argv[2].set(vp);
     RootedValue fval(cx);
     if (!GetDerivedTrap(cx, handler, cx->names().set, &fval))
         return false;
     if (!IsCallable(fval))
-        return derivedSet(cx, proxy, receiver, id, strict, vp);
-    return Trap(cx, handler, fval, 3, argv.begin(), &idv);
+        return derivedSet(cx, proxy, receiver, id, vp, result);
+    if (!Trap(cx, handler, fval, 3, argv.begin(), &idv))
+        return false;
+    return result.succeed();
 }
 
 bool
 ScriptedIndirectProxyHandler::derivedSet(JSContext *cx, HandleObject proxy, HandleObject receiver,
-                                         HandleId id, bool strict, MutableHandleValue vp) const
+                                         HandleId id, MutableHandleValue vp,
+                                         ObjectOpResult &result) const
 {
     // Find an own or inherited property. The code here is strange for maximum
     // backward compatibility with earlier code written before ES6 and before
     // SetPropertyIgnoringNamedGetter.
     Rooted<PropertyDescriptor> desc(cx);
     if (!getOwnPropertyDescriptor(cx, proxy, id, &desc))
         return false;
     bool descIsOwn = desc.object() != nullptr;
     if (!descIsOwn) {
         if (!getPropertyDescriptor(cx, proxy, id, &desc))
             return false;
     }
 
-    return SetPropertyIgnoringNamedGetter(cx, this, proxy, receiver, id, &desc, descIsOwn, strict,
-                                          vp);
+    return SetPropertyIgnoringNamedGetter(cx, this, proxy, receiver, id, &desc, descIsOwn, vp,
+                                          result);
 }
 
 bool
 ScriptedIndirectProxyHandler::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                                            AutoIdVector &props) const
 {
     RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
     RootedValue value(cx);
--- a/js/src/proxy/ScriptedIndirectProxyHandler.h
+++ b/js/src/proxy/ScriptedIndirectProxyHandler.h
@@ -31,17 +31,17 @@ class ScriptedIndirectProxyHandler : pub
     virtual bool enumerate(JSContext *cx, HandleObject proxy,
                            MutableHandleObject objp) const MOZ_OVERRIDE;
     virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE;
     virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
     virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
     virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
                      MutableHandleValue vp) const MOZ_OVERRIDE;
     virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
-                     bool strict, MutableHandleValue vp) const MOZ_OVERRIDE;
+                     MutableHandleValue vp, ObjectOpResult &result) const MOZ_OVERRIDE;
 
     /* SpiderMonkey extensions. */
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                               AutoIdVector &props) const MOZ_OVERRIDE;
     virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
@@ -49,17 +49,17 @@ class ScriptedIndirectProxyHandler : pub
     virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const MOZ_OVERRIDE;
     virtual bool isScripted() const MOZ_OVERRIDE { return true; }
 
     static const char family;
     static const ScriptedIndirectProxyHandler singleton;
 
 private:
     bool derivedSet(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
-                    bool strict, MutableHandleValue vp) const;
+                    MutableHandleValue vp, ObjectOpResult &result) const;
 };
 
 /* Derived class to handle Proxy.createFunction() */
 class CallableScriptedIndirectProxyHandler : public ScriptedIndirectProxyHandler
 {
   public:
     CallableScriptedIndirectProxyHandler() : ScriptedIndirectProxyHandler() { }
     virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
--- a/js/src/tests/js1_6/Array/regress-304828.js
+++ b/js/src/tests/js1_6/Array/regress-304828.js
@@ -24,30 +24,30 @@ try
 catch(e)
 {
   actual = e + '';
 }
 reportCompare(expect, actual, summary + ': join');
 
 // reverse
 value  = '123';
-expect = 'TypeError: Array.prototype.reverse.call(...) is read-only';
+expect = 'TypeError: 0 is read-only';
 try
 {
   actual = Array.prototype.reverse.call(value) + '';
 }
 catch(e)
 {
   actual = e + '';
 }
 reportCompare(expect, actual, summary + ': reverse');
 
 // sort
 value  = 'cba';
-expect = 'TypeError: Array.prototype.sort.call(...) is read-only';
+expect = 'TypeError: 0 is read-only';
 try
 {
   actual = Array.prototype.sort.call(value) + '';
 }
 catch(e)
 {
   actual = e + '';
 }
@@ -95,45 +95,45 @@ catch(e)
 {
   actual = e + '';
 }
 reportCompare(expect, actual, summary + ': pop');
 reportCompare('abc', value, summary + ': pop');
 
 // unshift
 value  = 'def';
-expect = 'TypeError: Array.prototype.unshift.call(...) is read-only';
+expect = 'TypeError: 0 is read-only';
 try
 {
   actual = Array.prototype.unshift.call(value, 'a', 'b', 'c');
 }
 catch(e)
 {
   actual = e + '';
 }
 reportCompare(expect, actual, summary + ': unshift');
 reportCompare('def', value, summary + ': unshift');
 
 // shift
 value  = 'abc';
-expect = 'TypeError: Array.prototype.shift.call(...) is read-only';
+expect = 'TypeError: 0 is read-only';
 try
 {
   actual = Array.prototype.shift.call(value);
 }
 catch(e)
 {
   actual = e + '';
 }
 reportCompare(expect, actual, summary + ': shift');
 reportCompare('abc', value, summary + ': shift');
 
 // splice
 value  = 'abc';
-expect = 'TypeError: Array.prototype.splice.call(...) is read-only';
+expect = 'TypeError: 1 is read-only';
 try
 {
   actual = Array.prototype.splice.call(value, 1, 1) + '';
 }
 catch(e)
 {
   actual = e + '';
 }
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -312,20 +312,21 @@ ArgGetter(JSContext *cx, HandleObject ob
         MOZ_ASSERT(JSID_IS_ATOM(id, cx->names().callee));
         if (!argsobj.callee().isMagic(JS_OVERWRITTEN_CALLEE))
             vp.set(argsobj.callee());
     }
     return true;
 }
 
 static bool
-ArgSetter(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp)
+ArgSetter(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp,
+          ObjectOpResult &result)
 {
     if (!obj->is<NormalArgumentsObject>())
-        return true;
+        return result.succeed();
     Handle<NormalArgumentsObject*> argsobj = obj.as<NormalArgumentsObject>();
 
     Rooted<PropertyDescriptor> desc(cx);
     if (!GetOwnPropertyDescriptor(cx, argsobj, id, &desc))
         return false;
     MOZ_ASSERT(desc.object());
     unsigned attrs = desc.attributes();
     MOZ_ASSERT(!(attrs & JSPROP_READONLY));
@@ -334,32 +335,32 @@ ArgSetter(JSContext *cx, HandleObject ob
     RootedScript script(cx, argsobj->containingScript());
 
     if (JSID_IS_INT(id)) {
         unsigned arg = unsigned(JSID_TO_INT(id));
         if (arg < argsobj->initialLength() && !argsobj->isElementDeleted(arg)) {
             argsobj->setElement(cx, arg, vp);
             if (arg < script->functionNonDelazifying()->nargs())
                 TypeScript::SetArgument(cx, script, arg, vp);
-            return true;
+            return result.succeed();
         }
     } else {
         MOZ_ASSERT(JSID_IS_ATOM(id, cx->names().length) || JSID_IS_ATOM(id, cx->names().callee));
     }
 
     /*
      * For simplicity we use delete/define to replace the property with a
      * simple data property. Note that we rely on args_delProperty to clear the
      * corresponding reserved slot so the GC can collect its value. Note also
      * that we must define the property instead of setting it in case the user
      * has changed the prototype to an object that has a setter for this id.
      */
     bool succeeded;
     return NativeDeleteProperty(cx, argsobj, id, &succeeded) &&
-           NativeDefineProperty(cx, argsobj, id, vp, nullptr, nullptr, attrs);
+           NativeDefineProperty(cx, argsobj, id, vp, nullptr, nullptr, attrs, result);
 }
 
 static bool
 args_resolve(JSContext *cx, HandleObject obj, HandleId id, bool *resolvedp)
 {
     Rooted<NormalArgumentsObject*> argsobj(cx, &obj->as<NormalArgumentsObject>());
 
     unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
@@ -433,48 +434,49 @@ StrictArgGetter(JSContext *cx, HandleObj
         MOZ_ASSERT(JSID_IS_ATOM(id, cx->names().length));
         if (!argsobj.hasOverriddenLength())
             vp.setInt32(argsobj.initialLength());
     }
     return true;
 }
 
 static bool
-StrictArgSetter(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp)
+StrictArgSetter(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp,
+                ObjectOpResult &result)
 {
     if (!obj->is<StrictArgumentsObject>())
-        return true;
+        return result.succeed();
     Handle<StrictArgumentsObject*> argsobj = obj.as<StrictArgumentsObject>();
 
     Rooted<PropertyDescriptor> desc(cx);
     if (!GetOwnPropertyDescriptor(cx, argsobj, id, &desc))
         return false;
     MOZ_ASSERT(desc.object());
     unsigned attrs = desc.attributes();
     MOZ_ASSERT(!(attrs & JSPROP_READONLY));
     attrs &= (JSPROP_ENUMERATE | JSPROP_PERMANENT); /* only valid attributes */
 
     if (JSID_IS_INT(id)) {
         unsigned arg = unsigned(JSID_TO_INT(id));
         if (arg < argsobj->initialLength()) {
             argsobj->setElement(cx, arg, vp);
-            return true;
+            return result.succeed();
         }
     } else {
         MOZ_ASSERT(JSID_IS_ATOM(id, cx->names().length));
     }
 
     /*
      * For simplicity we use delete/define to replace the property with a
      * simple data property. Note that we rely on args_delProperty to clear the
      * corresponding reserved slot so the GC can collect its value.
      */
     bool succeeded;
     return NativeDeleteProperty(cx, argsobj, id, &succeeded) &&
-           NativeDefineProperty(cx, argsobj, id, vp, nullptr, nullptr, attrs);
+           NativeDefineProperty(cx, argsobj, id, vp, nullptr, nullptr, attrs, result);
 }
 
 static bool
 strictargs_resolve(JSContext *cx, HandleObject obj, HandleId id, bool *resolvedp)
 {
     Rooted<StrictArgumentsObject*> argsobj(cx, &obj->as<StrictArgumentsObject>());
 
     unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -7512,17 +7512,17 @@ DebuggerEnv_setVariable(JSContext *cx, u
         if (!HasProperty(cx, env, id, &has))
             return false;
         if (!has) {
             JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_VARIABLE_NOT_FOUND);
             return false;
         }
 
         /* Just set the property. */
-        if (!SetProperty(cx, env, env, id, &v, true))
+        if (!SetProperty(cx, env, env, id, &v))
             return false;
     }
 
     args.rval().setUndefined();
     return true;
 }
 
 static const JSPropertySpec DebuggerEnv_properties[] = {
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -608,17 +608,20 @@ class GlobalObject : public NativeObject
 
     bool setIntrinsicValue(JSContext *cx, PropertyName *name, HandleValue value) {
 #ifdef DEBUG
         RootedObject self(cx, this);
         MOZ_ASSERT(cx->runtime()->isSelfHostingGlobal(self));
 #endif
         RootedObject holder(cx, intrinsicsHolder());
         RootedValue valCopy(cx, value);
-        return SetProperty(cx, holder, holder, name, &valCopy, false);
+        ObjectOpResult result;
+        bool ok = SetProperty(cx, holder, holder, name, &valCopy, result);
+        MOZ_ASSERT_IF(ok, result);
+        return ok;
     }
 
     bool getSelfHostedFunction(JSContext *cx, HandleAtom selfHostedName, HandleAtom name,
                                unsigned nargs, MutableHandleValue funVal);
 
     bool hasRegExpStatics() const;
     RegExpStatics *getRegExpStatics(ExclusiveContext *cx) const;
     RegExpStatics *getAlreadyCreatedRegExpStatics() const;
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -308,43 +308,44 @@ SetNameOperation(JSContext *cx, JSScript
                *pc == JSOP_STRICTSETGNAME);
     MOZ_ASSERT_IF(*pc == JSOP_SETGNAME, scope == cx->global());
     MOZ_ASSERT_IF(*pc == JSOP_STRICTSETGNAME, scope == cx->global());
 
     bool strict = *pc == JSOP_STRICTSETNAME || *pc == JSOP_STRICTSETGNAME;
     RootedPropertyName name(cx, script->getName(pc));
     RootedValue valCopy(cx, val);
 
-    /*
-     * In strict-mode, we need to trigger an error when trying to assign to an
-     * undeclared global variable. To do this, we call NativeSetProperty
-     * directly and pass Unqualified.
-     */
+    // In strict mode, assigning to an undeclared global variable is an
+    // error. To detect this, we call NativeSetProperty directly and pass
+    // Unqualified. It stores the error, if any, in |result|.
+    bool ok;
+    ObjectOpResult result;
+    RootedId id(cx, NameToId(name));
     if (scope->isUnqualifiedVarObj()) {
         MOZ_ASSERT(!scope->getOps()->setProperty);
-        RootedId id(cx, NameToId(name));
-        return NativeSetProperty(cx, scope.as<NativeObject>(), scope.as<NativeObject>(), id,
-                                 Unqualified, &valCopy, strict);
+        ok = NativeSetProperty(cx, scope.as<NativeObject>(), scope.as<NativeObject>(), id,
+                               Unqualified, &valCopy, result);
+    } else {
+        ok = SetProperty(cx, scope, scope, id, &valCopy, result);
     }
-
-    return SetProperty(cx, scope, scope, name, &valCopy, strict);
+    return ok && result.checkStrictErrorOrWarning(cx, scope, id, strict);
 }
 
 inline bool
 InitPropertyOperation(JSContext *cx, JSOp op, HandleObject obj, HandleId id, HandleValue rhs)
 {
     if (obj->is<PlainObject>() || obj->is<JSFunction>()) {
         unsigned propAttrs = GetInitDataPropAttrs(op);
         return NativeDefineProperty(cx, obj.as<NativeObject>(), id, rhs, nullptr, nullptr,
                                     propAttrs);
     }
 
     MOZ_ASSERT(obj->as<UnboxedPlainObject>().layout().lookup(id));
     RootedValue v(cx, rhs);
-    return SetProperty(cx, obj, obj, id, &v, false);
+    return PutProperty(cx, obj, id, &v, false);
 }
 
 inline bool
 DefVarOrConstOperation(JSContext *cx, HandleObject varobj, HandlePropertyName dn, unsigned attrs)
 {
     MOZ_ASSERT(varobj->isQualifiedVarObj());
 
     RootedShape prop(cx);
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -310,29 +310,29 @@ NameOperation(JSContext *cx, Interpreter
 
 static bool
 SetObjectProperty(JSContext *cx, JSOp op, HandleValue lval, HandleId id, MutableHandleValue rref)
 {
     MOZ_ASSERT(lval.isObject());
 
     RootedObject obj(cx, &lval.toObject());
 
-    bool strict = op == JSOP_STRICTSETPROP;
+    ObjectOpResult result;
     if (MOZ_LIKELY(!obj->getOps()->setProperty)) {
         if (!NativeSetProperty(cx, obj.as<NativeObject>(), obj.as<NativeObject>(), id,
-                               Qualified, rref, strict))
+                               Qualified, rref, result))
         {
             return false;
         }
     } else {
-        if (!SetProperty(cx, obj, obj, id, rref, strict))
+        if (!SetProperty(cx, obj, obj, id, rref, result))
             return false;
     }
 
-    return true;
+    return result.checkStrictErrorOrWarning(cx, obj, id, op == JSOP_STRICTSETPROP);
 }
 
 static bool
 SetPrimitiveProperty(JSContext *cx, JSOp op, HandleValue lval, HandleId id,
                      MutableHandleValue rref)
 {
     MOZ_ASSERT(lval.isPrimitive());
 
@@ -1385,17 +1385,17 @@ SetObjectElementOperation(JSContext *cx,
                 script->baselineScript()->noteArrayWriteHole(script->pcToOffset(pc));
         }
     }
 
     if (obj->isNative() && !JSID_IS_INT(id) && !obj->setHadElementsAccess(cx))
         return false;
 
     RootedValue tmp(cx, value);
-    return SetProperty(cx, obj, obj, id, &tmp, strict);
+    return PutProperty(cx, obj, id, &tmp, strict);
 }
 
 static MOZ_NEVER_INLINE bool
 Interpret(JSContext *cx, RunState &state)
 {
 /*
  * Define macros for an interpreter loop. Opcode dispatch may be either by a
  * switch statement or by indirect goto (aka a threaded interpreter), depending
@@ -3804,17 +3804,17 @@ js::DefFunOperation(JSContext *cx, Handl
     /*
      * Non-global properties, and global properties which we aren't simply
      * redefining, must be set.  First, this preserves their attributes.
      * Second, this will produce warnings and/or errors as necessary if the
      * specified Call object property is not writable (const).
      */
 
     /* Step 5f. */
-    return SetProperty(cx, parent, parent, name, &rval, script->strict());
+    return PutProperty(cx, parent, name, &rval, script->strict());
 }
 
 bool
 js::SetCallOperation(JSContext *cx)
 {
     JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_LEFTSIDE_OF_ASS);
     return false;
 }
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -1129,17 +1129,17 @@ UpdateShapeTypeAndValue(ExclusiveContext
         MarkTypePropertyNonData(cx, obj, id);
     if (!shape->writable())
         MarkTypePropertyNonWritable(cx, obj, id);
     return true;
 }
 
 static bool
 NativeSet(JSContext *cx, HandleNativeObject obj, HandleObject receiver,
-          HandleShape shape, bool strict, MutableHandleValue vp);
+          HandleShape shape, MutableHandleValue vp, ObjectOpResult &result);
 
 static inline bool
 DefinePropertyOrElement(ExclusiveContext *cx, HandleNativeObject obj, HandleId id,
                         GetterOp getter, SetterOp setter, unsigned attrs, HandleValue value,
                         bool callSetterAfterwards, ObjectOpResult &result)
 {
     MOZ_ASSERT(getter != JS_PropertyStub);
     MOZ_ASSERT(setter != JS_StrictPropertyStub);
@@ -1221,20 +1221,17 @@ DefinePropertyOrElement(ExclusiveContext
 
     if (!CallAddPropertyHook(cx, obj, shape, value))
         return false;
 
     if (callSetterAfterwards && setter) {
         if (!cx->shouldBeJSContext())
             return false;
         RootedValue nvalue(cx, value);
-
-        // FIXME: result should be passed to NativeSet.
-        if (!NativeSet(cx->asJSContext(), obj, obj, shape, false, &nvalue))
-            return false;
+        return NativeSet(cx->asJSContext(), obj, obj, shape, &nvalue, result);
     }
 
     return result.succeed();
 }
 
 static unsigned
 ApplyOrDefaultAttributes(unsigned attrs, const Shape *shape = nullptr)
 {
@@ -2002,17 +1999,17 @@ MaybeReportUndeclaredVarAssignment(JSCon
  * or finds a writable data property on the prototype chain, we end up here.
  * Finish the [[Set]] by defining a new property on receiver.
  *
  * This implements ES6 draft rev 28, 9.1.9 [[Set]] steps 5.c-f, but it
  * is really old code and there are a few barnacles.
  */
 bool
 js::SetPropertyByDefining(JSContext *cx, HandleObject obj, HandleObject receiver,
-                          HandleId id, HandleValue v, bool strict, bool objHasOwn)
+                          HandleId id, HandleValue v, bool objHasOwn, ObjectOpResult &result)
 {
     // Step 5.c-d: Test whether receiver has an existing own property
     // receiver[id]. The spec calls [[GetOwnProperty]]; js::HasOwnProperty is
     // the same thing except faster in the non-proxy case. Sometimes we can
     // even optimize away the HasOwnProperty call.
     bool existing;
     if (receiver == obj) {
         // The common case. The caller has necessarily done a property lookup
@@ -2033,25 +2030,18 @@ js::SetPropertyByDefining(JSContext *cx,
 
     // If the property doesn't already exist, check for an inextensible
     // receiver. (According to the specification, this is supposed to be
     // enforced by [[DefineOwnProperty]], but we haven't implemented that yet.)
     if (!existing) {
         bool extensible;
         if (!IsExtensible(cx, receiver, &extensible))
             return false;
-        if (!extensible) {
-            // Error in strict mode code, warn with extra warnings option,
-            // otherwise do nothing.
-            if (strict)
-                return receiver->reportNotExtensible(cx);
-            if (cx->compartment()->options().extraWarnings(cx))
-                return receiver->reportNotExtensible(cx, JSREPORT_STRICT | JSREPORT_WARNING);
-            return true;
-        }
+        if (!extensible)
+            return result.fail(JSMSG_OBJECT_NOT_EXTENSIBLE);
     }
 
     // Invalidate SpiderMonkey-specific caches or bail.
     const Class *clasp = receiver->getClass();
 
     // Purge the property cache of now-shadowed id in receiver's scope chain.
     if (!PurgeScopeChain(cx, receiver, id))
         return false;
@@ -2061,233 +2051,203 @@ js::SetPropertyByDefining(JSContext *cx,
         existing
         ? JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_READONLY | JSPROP_IGNORE_PERMANENT
         : JSPROP_ENUMERATE;
     JSGetterOp getter = clasp->getProperty;
     JSSetterOp setter = clasp->setProperty;
     MOZ_ASSERT(getter != JS_PropertyStub);
     MOZ_ASSERT(setter != JS_StrictPropertyStub);
     if (!receiver->is<NativeObject>())
-        return DefineProperty(cx, receiver, id, v, getter, setter, attrs);
+        return DefineProperty(cx, receiver, id, v, getter, setter, attrs, result);
 
     Rooted<NativeObject*> nativeReceiver(cx, &receiver->as<NativeObject>());
-    ObjectOpResult success;
-    if (!DefinePropertyOrElement(cx, nativeReceiver, id, getter, setter, attrs, v, true, success))
-        return false;
-    return success.checkStrictErrorOrWarning(cx, receiver, id, strict);
+    return DefinePropertyOrElement(cx, nativeReceiver, id, getter, setter, attrs, v, true, result);
 }
 
 // When setting |id| for |receiver| and |obj| has no property for id, continue
 // the search up the prototype chain.
 bool
 js::SetPropertyOnProto(JSContext *cx, HandleObject obj, HandleObject receiver,
-                       HandleId id, MutableHandleValue vp, bool strict)
+                       HandleId id, MutableHandleValue vp, ObjectOpResult &result)
 {
     MOZ_ASSERT(!obj->is<ProxyObject>());
 
     RootedObject proto(cx, obj->getProto());
     if (proto)
-        return SetProperty(cx, proto, receiver, id, vp, strict);
-    return SetPropertyByDefining(cx, obj, receiver, id, vp, strict, false);
-}
-
-bool
-js::SetNonWritableProperty(JSContext *cx, HandleId id, bool strict)
-{
-    // Setting a non-writable property is an error in strict mode code, a
-    // warning with the extra warnings option, and otherwise does nothing.
-
-    if (strict)
-        return JSObject::reportReadOnly(cx, id, JSREPORT_ERROR);
-    if (cx->compartment()->options().extraWarnings(cx))
-        return JSObject::reportReadOnly(cx, id, JSREPORT_STRICT | JSREPORT_WARNING);
-    return true;
+        return SetProperty(cx, proto, receiver, id, vp, result);
+    return SetPropertyByDefining(cx, obj, receiver, id, vp, false, result);
 }
 
 /*
  * Implement "the rest of" assignment to a property when no property receiver[id]
  * was found anywhere on the prototype chain.
  *
  * FIXME: This should be updated to follow ES6 draft rev 28, section 9.1.9,
  * steps 4.d.i and 5.
  *
  * Note that receiver is not necessarily native.
  */
 static bool
 SetNonexistentProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiver, HandleId id,
-                       QualifiedBool qualified, HandleValue v, bool strict)
+                       QualifiedBool qualified, HandleValue v, ObjectOpResult &result)
 {
     // We should never add properties to lexical blocks.
     MOZ_ASSERT(!receiver->is<BlockObject>());
 
     if (receiver->isUnqualifiedVarObj() && !qualified) {
         if (!MaybeReportUndeclaredVarAssignment(cx, JSID_TO_STRING(id)))
             return false;
     }
 
-    return SetPropertyByDefining(cx, obj, receiver, id, v, strict, false);
+    return SetPropertyByDefining(cx, obj, receiver, id, v, false, result);
 }
 
 /*
  * Set an existing own property obj[index] that's a dense element or typed
  * array element.
  */
 static bool
 SetDenseOrTypedArrayElement(JSContext *cx, HandleNativeObject obj, uint32_t index,
-                            MutableHandleValue vp, bool strict)
+                            MutableHandleValue vp, ObjectOpResult &result)
 {
     if (IsAnyTypedArray(obj)) {
         double d;
         if (!ToNumber(cx, vp, &d))
             return false;
 
         // Silently do nothing for out-of-bounds sets, for consistency with
         // current behavior.  (ES6 currently says to throw for this in
         // strict mode code, so we may eventually need to change.)
         uint32_t len = AnyTypedArrayLength(obj);
         if (index < len) {
             if (obj->is<TypedArrayObject>())
                 TypedArrayObject::setElement(obj->as<TypedArrayObject>(), index, d);
             else
                 SharedTypedArrayObject::setElement(obj->as<SharedTypedArrayObject>(), index, d);
         }
-        return true;
+        return result.succeed();
     }
 
-    if (WouldDefinePastNonwritableLength(obj, index)) {
-        if (strict) {
-            JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
-                                 JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
-            return false;
-        }
-        return true;
-    }
+    if (WouldDefinePastNonwritableLength(obj, index))
+        return result.fail(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
 
     if (!obj->maybeCopyElementsForWrite(cx))
         return false;
 
     obj->setDenseElementWithType(cx, index, vp);
-    return true;
+    return result.succeed();
 }
 
 /*
  * Finish assignment to a shapeful property of a native object obj. This
  * conforms to no standard and there is a lot of legacy baggage here.
  */
 static bool
 NativeSet(JSContext *cx, HandleNativeObject obj, HandleObject receiver,
-          HandleShape shape, bool strict, MutableHandleValue vp)
+          HandleShape shape, MutableHandleValue vp, ObjectOpResult &result)
 {
     MOZ_ASSERT(obj->isNative());
 
     if (shape->hasSlot()) {
         /* If shape has a stub setter, just store vp. */
         if (shape->hasDefaultSetter()) {
             // Global properties declared with 'var' will be initially
             // defined with an undefined value, so don't treat the initial
             // assignments to such properties as overwrites.
             bool overwriting = !obj->is<GlobalObject>() || !obj->getSlot(shape->slot()).isUndefined();
             obj->setSlotWithType(cx, shape, vp, overwriting);
-            return true;
+            return result.succeed();
         }
     }
 
     if (!shape->hasSlot()) {
         /*
          * Allow API consumers to create shared properties with stub setters.
          * Such properties effectively function as data descriptors which are
          * not writable, so attempting to set such a property should do nothing
          * or throw if we're in strict mode.
          */
         if (!shape->hasGetterValue() && shape->hasDefaultSetter())
-            return ReportGetterOnlyAssignment(cx, strict);
+            return result.fail(JSMSG_GETTER_ONLY);
     }
 
     RootedValue ovp(cx, vp);
 
     uint32_t sample = cx->runtime()->propertyRemovals;
-    if (!shape->set(cx, obj, receiver, strict, vp))
+    if (!shape->set(cx, obj, receiver, vp, result))
         return false;
 
     /*
      * Update any slot for the shape with the value produced by the setter,
      * unless the setter deleted the shape.
      */
     if (shape->hasSlot() &&
         (MOZ_LIKELY(cx->runtime()->propertyRemovals == sample) ||
          obj->contains(cx, shape)))
     {
         obj->setSlot(shape->slot(), vp);
     }
 
-    return true;
+    return true;  // result is populated by shape->set() above.
 }
 
 /*
  * Implement "the rest of" assignment to receiver[id] when an existing property
  * (shape) has been found on a native object (pobj).
  *
  * It is necessary to pass both id and shape because shape could be an implicit
  * dense or typed array element (i.e. not actually a pointer to a Shape).
  */
 static bool
 SetExistingProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiver, HandleId id,
-                    HandleNativeObject pobj, HandleShape shape, MutableHandleValue vp, bool strict)
+                    HandleNativeObject pobj, HandleShape shape, MutableHandleValue vp,
+                    ObjectOpResult &result)
 {
     if (IsImplicitDenseOrTypedArrayElement(shape)) {
         /* ES5 8.12.4 [[Put]] step 2, for a dense data property on pobj. */
         if (pobj == receiver)
-            return SetDenseOrTypedArrayElement(cx, pobj, JSID_TO_INT(id), vp, strict);
+            return SetDenseOrTypedArrayElement(cx, pobj, JSID_TO_INT(id), vp, result);
     } else {
         /* ES5 8.12.4 [[Put]] step 2. */
         if (shape->isAccessorDescriptor()) {
             if (shape->hasDefaultSetter())
-                return ReportGetterOnlyAssignment(cx, strict);
+                return result.fail(JSMSG_GETTER_ONLY);
         } else {
             MOZ_ASSERT(shape->isDataDescriptor());
-
             if (!shape->writable())
-                return SetNonWritableProperty(cx, id, strict);
+                return result.fail(JSMSG_READ_ONLY);
         }
 
         if (pobj == receiver) {
             if (pobj->is<ArrayObject>() && id == NameToId(cx->names().length)) {
                 Rooted<ArrayObject*> arr(cx, &pobj->as<ArrayObject>());
-                ObjectOpResult success;
-                if (!ArraySetLength(cx, arr, id, shape->attributes(), vp, success))
-                    return false;
-                if (strict && !success) {
-                    if (cx->shouldBeJSContext())
-                        success.reportError(cx->asJSContext(), arr, id);
-                    return false;
-                }
-                return true;
+                return ArraySetLength(cx, arr, id, shape->attributes(), vp, result);
             }
-            return NativeSet(cx, obj, receiver, shape, strict, vp);
+            return NativeSet(cx, obj, receiver, shape, vp, result);
         }
 
         // pobj[id] is not an own property of receiver. Call the setter or shadow it.
         if (!shape->shadowable() &&
             !(pobj->is<ArrayObject>() && id == NameToId(cx->names().length)))
         {
             // Weird special case: slotless property with default setter.
             if (shape->hasDefaultSetter() && !shape->hasGetterValue())
-                return true;
+                return result.succeed();
 
-            return shape->set(cx, obj, receiver, strict, vp);
+            return shape->set(cx, obj, receiver, vp, result);
         }
     }
 
     // Shadow pobj[id] by defining a new data property receiver[id].
-    return SetPropertyByDefining(cx, obj, receiver, id, vp, strict, obj == pobj);
+    return SetPropertyByDefining(cx, obj, receiver, id, vp, obj == pobj, result);
 }
 
 bool
 js::NativeSetProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiver, HandleId id,
-                      QualifiedBool qualified, MutableHandleValue vp, bool strict)
+                      QualifiedBool qualified, MutableHandleValue vp, ObjectOpResult &result)
 {
     // Fire watchpoints, if any.
     if (MOZ_UNLIKELY(obj->watched())) {
         WatchpointMap *wpmap = cx->compartment()->watchpointMap;
         if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, vp))
             return false;
     }
 
@@ -2303,64 +2263,64 @@ js::NativeSetProperty(JSContext *cx, Han
     for (;;) {
         // Steps 2-3. ('done' is a SpiderMonkey-specific thing, used below.)
         bool done;
         if (!LookupOwnPropertyInline<CanGC>(cx, pobj, id, &shape, &done))
             return false;
 
         if (shape) {
             // Steps 5-6.
-            return SetExistingProperty(cx, obj, receiver, id, pobj, shape, vp, strict);
+            return SetExistingProperty(cx, obj, receiver, id, pobj, shape, vp, result);
         }
 
         // Steps 4.a-b. The check for 'done' on this next line is tricky.
         // done can be true in exactly these unlikely-sounding cases:
         // - We're looking up an element, and pobj is a TypedArray that
         //   doesn't have that many elements.
         // - We're being called from a resolve hook to assign to the property
         //   being resolved.
         // What they all have in common is we do not want to keep walking
         // the prototype chain.
         RootedObject proto(cx, done ? nullptr : pobj->getProto());
         if (!proto) {
             // Step 4.d.i (and step 5).
-            return SetNonexistentProperty(cx, obj, receiver, id, qualified, vp, strict);
+            return SetNonexistentProperty(cx, obj, receiver, id, qualified, vp, result);
         }
 
         // Step 4.c.i. If the prototype is also native, this step is a
         // recursive tail call, and we don't need to go through all the
         // plumbing of SetProperty; the top of the loop is where we're going to
         // end up anyway. But if pobj is non-native, that optimization would be
         // incorrect.
         if (!proto->isNative()) {
             // Unqualified assignments are not specified to go through [[Set]]
             // at all, but they do go through this function. So check for
             // unqualified assignment to a nonexistent global (a strict error).
             if (!qualified) {
                 bool found;
                 if (!HasProperty(cx, proto, id, &found))
                     return false;
                 if (!found)
-                    return SetNonexistentProperty(cx, obj, receiver, id, qualified, vp, strict);
+                    return SetNonexistentProperty(cx, obj, receiver, id, qualified, vp, result);
             }
 
-            return SetProperty(cx, proto, receiver, id, vp, strict);
+            return SetProperty(cx, proto, receiver, id, vp, result);
         }
         pobj = &proto->as<NativeObject>();
     }
 }
 
 bool
 js::NativeSetElement(JSContext *cx, HandleNativeObject obj, HandleObject receiver, uint32_t index,
-                     MutableHandleValue vp, bool strict)
+                     MutableHandleValue vp, ObjectOpResult &result)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, &id))
         return false;
-    return NativeSetProperty(cx, obj, receiver, id, Qualified, vp, strict);
+    return NativeSetProperty(cx, obj, receiver, id, Qualified, vp, result);
 }
 
 /*** [[Delete]] **********************************************************************************/
 
 // ES6 draft rev31 9.1.10 [[Delete]]
 bool
 js::NativeDeleteProperty(JSContext *cx, HandleNativeObject obj, HandleId id, bool *succeeded)
 {
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -78,18 +78,17 @@ Debug_SetSlotRangeToCrashOnTouch(HeapSlo
 
 class ArrayObject;
 
 /*
  * ES6 20130308 draft 8.4.2.4 ArraySetLength.
  *
  * |id| must be "length", |attrs| are the attributes to be used for the newly-
  * changed length property, |value| is the value for the new length, and
- * |setterIsStrict| indicates whether invalid changes will cause a TypeError
- * to be thrown.
+ * |result| receives an error code if the change is invalid.
  */
 extern bool
 ArraySetLength(JSContext *cx, Handle<ArrayObject*> obj, HandleId id,
                unsigned attrs, HandleValue value, ObjectOpResult &result);
 
 /*
  * Elements header used for native objects. The elements component of such objects
  * offers an efficient representation for all or some of the indexed properties
@@ -1294,46 +1293,42 @@ NativeGetProperty(JSContext *cx, HandleN
 
 inline bool
 NativeGetElement(JSContext *cx, HandleNativeObject obj, uint32_t index, MutableHandleValue vp)
 {
     return NativeGetElement(cx, obj, obj, index, vp);
 }
 
 bool
-SetPropertyByDefining(JSContext *cx, HandleObject obj, HandleObject receiver,
-                      HandleId id, HandleValue v, bool strict, bool objHasOwn);
+SetPropertyByDefining(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
+                      HandleValue v, bool objHasOwn, ObjectOpResult &result);
 
 bool
-SetPropertyOnProto(JSContext *cx, HandleObject obj, HandleObject receiver,
-                   HandleId id, MutableHandleValue vp, bool strict);
-
-// Report any error or warning when writing to a non-writable property.
-bool
-SetNonWritableProperty(JSContext *cx, HandleId id, bool strict);
+SetPropertyOnProto(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
+                   MutableHandleValue vp, ObjectOpResult &result);
 
 /*
  * Indicates whether an assignment operation is qualified (`x.y = 0`) or
  * unqualified (`y = 0`). In strict mode, the latter is an error if no such
  * variable already exists.
  *
  * Used as an argument to NativeSetProperty.
  */
 enum QualifiedBool {
     Unqualified = 0,
     Qualified = 1
 };
 
 extern bool
 NativeSetProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiver, HandleId id,
-                  QualifiedBool qualified, MutableHandleValue vp, bool strict);
+                  QualifiedBool qualified, MutableHandleValue vp, ObjectOpResult &result);
 
 extern bool
 NativeSetElement(JSContext *cx, HandleNativeObject obj, HandleObject receiver, uint32_t index,
-                 MutableHandleValue vp, bool strict);
+                 MutableHandleValue vp, ObjectOpResult &result);
 
 extern bool
 NativeDeleteProperty(JSContext *cx, HandleNativeObject obj, HandleId id, bool *succeeded);
 
 
 /*** SpiderMonkey nonstandard internal methods ***************************************************/
 
 template <AllowGC allowGC>
@@ -1435,25 +1430,25 @@ js::GetPropertyNoGC(JSContext *cx, JSObj
 {
     if (obj->getOps()->getProperty)
         return false;
     return NativeGetPropertyNoGC(cx, &obj->as<NativeObject>(), receiver, id, vp);
 }
 
 inline bool
 js::SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
-                HandleId id, MutableHandleValue vp, bool strict)
+                HandleId id, MutableHandleValue vp, ObjectOpResult &result)
 {
     if (obj->getOps()->setProperty)
-        return JSObject::nonNativeSetProperty(cx, obj, receiver, id, vp, strict);
-    return NativeSetProperty(cx, obj.as<NativeObject>(), receiver, id, Qualified, vp, strict);
+        return JSObject::nonNativeSetProperty(cx, obj, receiver, id, vp, result);
+    return NativeSetProperty(cx, obj.as<NativeObject>(), receiver, id, Qualified, vp, result);
 }
 
 inline bool
 js::SetElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index,
-               MutableHandleValue vp, bool strict)
+               MutableHandleValue vp, ObjectOpResult &result)
 {
     if (obj->getOps()->setProperty)
-        return JSObject::nonNativeSetElement(cx, obj, receiver, index, vp, strict);
-    return NativeSetElement(cx, obj.as<NativeObject>(), receiver, index, vp, strict);
+        return JSObject::nonNativeSetElement(cx, obj, receiver, index, vp, result);
+    return NativeSetElement(cx, obj.as<NativeObject>(), receiver, index, vp, result);
 }
 
 #endif /* vm_NativeObject_h */
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -293,17 +293,17 @@ CallObject::createHollowForDebug(JSConte
     if (!callobj)
         return nullptr;
 
     RootedValue optimizedOut(cx, MagicValue(JS_OPTIMIZED_OUT));
     RootedId id(cx);
     RootedScript script(cx, callee->nonLazyScript());
     for (BindingIter bi(script); !bi.done(); bi++) {
         id = NameToId(bi->name());
-        if (!SetProperty(cx, callobj, callobj, id, &optimizedOut, true))
+        if (!SetProperty(cx, callobj, callobj, id, &optimizedOut))
             return nullptr;
     }
 
     return callobj;
 }
 
 const Class CallObject::class_ = {
     "Call",
@@ -490,23 +490,23 @@ with_GetProperty(JSContext *cx, HandleOb
                  MutableHandleValue vp)
 {
     RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
     return GetProperty(cx, actual, actual, id, vp);
 }
 
 static bool
 with_SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
-                 MutableHandleValue vp, bool strict)
+                 MutableHandleValue vp, ObjectOpResult &result)
 {
     RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
     RootedObject actualReceiver(cx, receiver);
     if (receiver == obj)
         actualReceiver = actual;
-    return SetProperty(cx, actual, actualReceiver, id, vp, strict);
+    return SetProperty(cx, actual, actualReceiver, id, vp, result);
 }
 
 static bool
 with_GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
                               MutableHandle<JSPropertyDescriptor> desc)
 {
     RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
     return GetOwnPropertyDescriptor(cx, actual, id, desc);
@@ -936,17 +936,17 @@ uninitialized_GetProperty(JSContext *cx,
                           MutableHandleValue vp)
 {
     ReportUninitializedLexicalId(cx, id);
     return false;
 }
 
 static bool
 uninitialized_SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
-                          MutableHandleValue vp, bool strict)
+                          MutableHandleValue vp, ObjectOpResult &result)
 {
     ReportUninitializedLexicalId(cx, id);
     return false;
 }
 
 static bool
 uninitialized_GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc)
@@ -1598,34 +1598,34 @@ class DebugScopeProxy : public BaseProxy
           case ACCESS_LOST:
             vp.setMagic(JS_OPTIMIZED_OUT);
             return true;
           default:
             MOZ_CRASH("bad AccessResult");
         }
     }
 
-    bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, bool strict,
-             MutableHandleValue vp) const MOZ_OVERRIDE
+    bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
+             MutableHandleValue vp, ObjectOpResult &result) const MOZ_OVERRIDE
     {
         Rooted<DebugScopeObject*> debugScope(cx, &proxy->as<DebugScopeObject>());
         Rooted<ScopeObject*> scope(cx, &proxy->as<DebugScopeObject>().scope());
 
         if (debugScope->isOptimizedOut())
             return Throw(cx, id, JSMSG_DEBUG_CANT_SET_OPT_ENV);
 
         AccessResult access;
         if (!handleUnaliasedAccess(cx, debugScope, scope, id, SET, vp, &access))
             return false;
 
         switch (access) {
           case ACCESS_UNALIASED:
-            return true;
+            return result.succeed();
           case ACCESS_GENERIC:
-            return SetProperty(cx, scope, scope, id, vp, strict);
+            return SetProperty(cx, scope, scope, id, vp, result);
           default:
             MOZ_CRASH("bad AccessResult");
         }
     }
 
     bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
                         MutableHandle<PropertyDescriptor> desc,
                         ObjectOpResult &result) const MOZ_OVERRIDE
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -333,17 +333,18 @@ js::intrinsic_UnsafePutElements(JSContex
         RootedObject arrobj(cx, &args[arri].toObject());
         uint32_t idx = args[idxi].toInt32();
 
         if (IsAnyTypedArray(arrobj.get()) || arrobj->is<TypedObject>()) {
             MOZ_ASSERT_IF(IsAnyTypedArray(arrobj.get()), idx < AnyTypedArrayLength(arrobj.get()));
             MOZ_ASSERT_IF(arrobj->is<TypedObject>(), idx < uint32_t(arrobj->as<TypedObject>().length()));
             RootedValue tmp(cx, args[elemi]);
             // XXX: Always non-strict.
-            if (!SetElement(cx, arrobj, arrobj, idx, &tmp, false))
+            ObjectOpResult ignored;
+            if (!SetElement(cx, arrobj, arrobj, idx, &tmp, ignored))
                 return false;
         } else {
             MOZ_ASSERT(idx < arrobj->as<ArrayObject>().getDenseInitializedLength());
             arrobj->as<ArrayObject>().setDenseElementWithType(cx, idx, args[elemi]);
         }
     }
 
     args.rval().setUndefined();
--- a/js/src/vm/Shape-inl.h
+++ b/js/src/vm/Shape-inl.h
@@ -36,35 +36,37 @@ StackBaseShape::StackBaseShape(Exclusive
 inline Shape *
 Shape::search(ExclusiveContext *cx, jsid id)
 {
     ShapeTable::Entry *_;
     return search(cx, this, id, &_);
 }
 
 inline bool
-Shape::set(JSContext* cx, HandleNativeObject obj, HandleObject receiver, bool strict,
-           MutableHandleValue vp)
+Shape::set(JSContext* cx, HandleNativeObject obj, HandleObject receiver, MutableHandleValue vp,
+           ObjectOpResult &result)
 {
     MOZ_ASSERT_IF(hasDefaultSetter(), hasGetterValue());
     MOZ_ASSERT(!obj->is<DynamicWithObject>());  // See bug 1128681.
 
     if (attrs & JSPROP_SETTER) {
         Value fval = setterValue();
-        return InvokeGetterOrSetter(cx, receiver, fval, 1, vp.address(), vp);
+        if (!InvokeGetterOrSetter(cx, receiver, fval, 1, vp.address(), vp))
+            return false;
+        return result.succeed();
     }
 
     if (attrs & JSPROP_GETTER)
-        return ReportGetterOnlyAssignment(cx, strict);
+        return result.fail(JSMSG_GETTER_ONLY);
 
     if (!setterOp())
-        return true;
+        return result.succeed();
 
     RootedId id(cx, propid());
-    return CallJSSetterOp(cx, setterOp(), obj, id, strict, vp);
+    return CallJSSetterOp(cx, setterOp(), obj, id, vp, result);
 }
 
 /* static */ inline Shape *
 Shape::search(ExclusiveContext *cx, Shape *start, jsid id, ShapeTable::Entry **pentry, bool adding)
 {
     if (start->inDictionary()) {
         *pentry = &start->table().search(id, adding);
         return (*pentry)->shape();
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -951,18 +951,18 @@ class Shape : public gc::TenuredCell
     {
         return base->unowned() == this->base()->unowned() &&
                maybeSlot() == aslot &&
                attrs == aattrs &&
                getter() == rawGetter &&
                setter() == rawSetter;
     }
 
-    bool set(JSContext* cx, HandleNativeObject obj, HandleObject receiver, bool strict,
-             MutableHandleValue vp);
+    bool set(JSContext* cx, HandleNativeObject obj, HandleObject receiver, MutableHandleValue vp,
+             ObjectOpResult &result);
 
     BaseShape *base() const { return base_.get(); }
 
     bool hasSlot() const {
         return (attrs & JSPROP_SHARED) == 0;
     }
     uint32_t slot() const { MOZ_ASSERT(hasSlot() && !hasMissingSlot()); return maybeSlot(); }
     uint32_t maybeSlot() const {
--- a/js/src/vm/UnboxedObject.cpp
+++ b/js/src/vm/UnboxedObject.cpp
@@ -401,34 +401,34 @@ UnboxedPlainObject::obj_getProperty(JSCo
         return true;
     }
 
     return GetProperty(cx, proto, receiver, id, vp);
 }
 
 /* static */ bool
 UnboxedPlainObject::obj_setProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
-                                    HandleId id, MutableHandleValue vp, bool strict)
+                                    HandleId id, MutableHandleValue vp, ObjectOpResult &result)
 {
     const UnboxedLayout &layout = obj->as<UnboxedPlainObject>().layout();
 
     if (const UnboxedLayout::Property *property = layout.lookup(id)) {
         if (obj == receiver) {
             if (obj->as<UnboxedPlainObject>().setValue(cx, *property, vp))
-                return true;
+                return result.succeed();
 
             if (!convertToNative(cx, obj))
                 return false;
-            return SetProperty(cx, obj, receiver, id, vp, strict);
+            return SetProperty(cx, obj, receiver, id, vp, result);
         }
 
-        return SetPropertyByDefining(cx, obj, receiver, id, vp, strict, false);
+        return SetPropertyByDefining(cx, obj, receiver, id, vp, false, result);
     }
 
-    return SetPropertyOnProto(cx, obj, receiver, id, vp, strict);
+    return SetPropertyOnProto(cx, obj, receiver, id, vp, result);
 }
 
 /* static */ bool
 UnboxedPlainObject::obj_getOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
                                                  MutableHandle<JSPropertyDescriptor> desc)
 {
     const UnboxedLayout &layout = obj->as<UnboxedPlainObject>().layout();
 
--- a/js/src/vm/UnboxedObject.h
+++ b/js/src/vm/UnboxedObject.h
@@ -169,17 +169,17 @@ class UnboxedPlainObject : public JSObje
                                    ObjectOpResult &result);
 
     static bool obj_hasProperty(JSContext *cx, HandleObject obj, HandleId id, bool *foundp);
 
     static bool obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
                                 HandleId id, MutableHandleValue vp);
 
     static bool obj_setProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
-                                HandleId id, MutableHandleValue vp, bool strict);
+                                HandleId id, MutableHandleValue vp, ObjectOpResult &result);
 
     static bool obj_getOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
                                              MutableHandle<JSPropertyDescriptor> desc);
 
     static bool obj_deleteProperty(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded);
 
     static bool obj_enumerate(JSContext *cx, HandleObject obj, AutoIdVector &properties);
     static bool obj_watch(JSContext *cx, HandleObject obj, HandleId id, HandleObject callable);
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -24,21 +24,21 @@ namespace js {
  * versions.  If deserialization fails, the data should be invalidated if
  * possible.
  *
  * When you change this, run make_opcode_doc.py and copy the new output into
  * this wiki page:
  *
  *  https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
  */
-static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 241;
+static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 242;
 static const uint32_t XDR_BYTECODE_VERSION =
     uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
 
-static_assert(JSErr_Limit == 375,
+static_assert(JSErr_Limit == 376,
               "GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or "
               "removed MSG_DEFs from js.msg, you should increment "
               "XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "
               "expected JSErr_Limit value.");
 
 class XDRBuffer {
   public:
     explicit XDRBuffer(JSContext *cx)
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -348,23 +348,24 @@ sandbox_convert(JSContext *cx, HandleObj
         return true;
     }
 
     return OrdinaryToPrimitive(cx, obj, type, vp);
 }
 
 static bool
 writeToProto_setProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
-                    bool strict, JS::MutableHandleValue vp)
+                         JS::MutableHandleValue vp, JS::ObjectOpResult &result)
 {
     RootedObject proto(cx);
     if (!JS_GetPrototype(cx, obj, &proto))
         return false;
 
-    return JS_SetPropertyById(cx, proto, id, vp);
+    RootedValue receiver(cx, ObjectValue(*proto));
+    return JS_ForwardSetPropertyTo(cx, proto, id, vp, receiver, result);
 }
 
 static bool
 writeToProto_getProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
                     JS::MutableHandleValue vp)
 {
     RootedObject proto(cx);
     if (!JS_GetPrototype(cx, obj, &proto))
@@ -729,20 +730,20 @@ xpc::SandboxProxyHandler::get(JSContext 
 {
     return BaseProxyHandler::get(cx, proxy, receiver, id, vp);
 }
 
 bool
 xpc::SandboxProxyHandler::set(JSContext *cx, JS::Handle<JSObject*> proxy,
                               JS::Handle<JSObject*> receiver,
                               JS::Handle<jsid> id,
-                              bool strict,
-                              JS::MutableHandle<Value> vp) const
+                              JS::MutableHandle<Value> vp,
+                              JS::ObjectOpResult &result) const
 {
-    return BaseProxyHandler::set(cx, proxy, receiver, id, strict, vp);
+    return BaseProxyHandler::set(cx, proxy, receiver, id, vp, result);
 }
 
 bool
 xpc::SandboxProxyHandler::getOwnEnumerablePropertyKeys(JSContext *cx,
                                                        JS::Handle<JSObject*> proxy,
                                                        AutoIdVector &props) const
 {
     return BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, proxy, props);
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -640,17 +640,18 @@ static const JSFunctionSpec glob_functio
     JS_FS("atob",            Atob,           1,0),
     JS_FS("btoa",            Btoa,           1,0),
     JS_FS("setInterruptCallback", SetInterruptCallback, 1,0),
     JS_FS("simulateActivityCallback", SimulateActivityCallback, 1,0),
     JS_FS_END
 };
 
 static bool
-env_setProperty(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp)
+env_setProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp,
+                ObjectOpResult &result)
 {
 /* XXX porting may be easy, but these don't seem to supply setenv by default */
 #if !defined SOLARIS
     JSString *valstr;
     JS::Rooted<JSString*> idstr(cx);
     int rv;
 
     RootedValue idval(cx);
@@ -690,17 +691,17 @@ env_setProperty(JSContext *cx, HandleObj
     rv = setenv(name.ptr(), value.ptr(), 1);
 #endif
     if (rv < 0) {
         JS_ReportError(cx, "can't set envariable %s to %s", name.ptr(), value.ptr());
         return false;
     }
     vp.set(STRING_TO_JSVAL(valstr));
 #endif /* !defined SOLARIS */
-    return true;
+    return result.succeed();
 }
 
 static bool
 env_enumerate(JSContext *cx, HandleObject obj)
 {
     static bool reflected;
     char **evp, *name, *value;
     RootedString valstr(cx);
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -422,19 +422,20 @@ XPC_WN_OnlyIWrite_AddPropertyStub(JSCont
     // Allow only XPConnect to add/set the property
     if (ccx.GetResolveName() == id)
         return true;
 
     return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
 }
 
 static bool
-XPC_WN_OnlyIWrite_SetPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict,
-                                  MutableHandleValue vp)
+XPC_WN_OnlyIWrite_SetPropertyStub(JSContext *cx, HandleObject obj, HandleId id,
+                                  MutableHandleValue vp, ObjectOpResult &result)
 {
+    result.succeed();
     return XPC_WN_OnlyIWrite_AddPropertyStub(cx, obj, id, vp);
 }
 
 static bool
 XPC_WN_CannotModifyPropertyStub(JSContext *cx, HandleObject obj, HandleId id,
                                 MutableHandleValue vp)
 {
     return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
@@ -443,20 +444,20 @@ XPC_WN_CannotModifyPropertyStub(JSContex
 static bool
 XPC_WN_CantDeletePropertyStub(JSContext *cx, HandleObject obj, HandleId id,
                               bool *succeeded)
 {
     return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
 }
 
 static bool
-XPC_WN_CannotModifyStrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict,
-                                      MutableHandleValue vp)
+XPC_WN_CannotModifySetPropertyStub(JSContext *cx, HandleObject obj, HandleId id,
+                                   MutableHandleValue vp, ObjectOpResult &result)
 {
-    return XPC_WN_CannotModifyPropertyStub(cx, obj, id, vp);
+    return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
 }
 
 static bool
 XPC_WN_Shared_Convert(JSContext *cx, HandleObject obj, JSType type, MutableHandleValue vp)
 {
     if (type == JSTYPE_OBJECT) {
         vp.set(OBJECT_TO_JSVAL(obj));
         return true;
@@ -702,19 +703,20 @@ XPC_WN_MaybeResolvingPropertyStub(JSCont
     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
 
     if (ccx.GetResolvingWrapper() == wrapper)
         return true;
     return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
 }
 
 static bool
-XPC_WN_MaybeResolvingStrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict,
-                                        MutableHandleValue vp)
+XPC_WN_MaybeResolvingSetPropertyStub(JSContext *cx, HandleObject obj, HandleId id,
+                                     MutableHandleValue vp, ObjectOpResult &result)
 {
+    result.succeed();
     return XPC_WN_MaybeResolvingPropertyStub(cx, obj, id, vp);
 }
 
 static bool
 XPC_WN_MaybeResolvingDeletePropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded)
 {
     XPCCallContext ccx(JS_CALLER, cx, obj);
     XPCWrappedNative* wrapper = ccx.GetWrapper();
@@ -742,16 +744,21 @@ XPC_WN_MaybeResolvingDeletePropertyStub(
     bool retval = true;                                                       \
     nsresult rv = wrapper->GetScriptableCallback()->
 
 #define POST_HELPER_STUB                                                      \
     if (NS_FAILED(rv))                                                        \
         return Throw(rv, cx);                                                 \
     return retval;
 
+#define POST_HELPER_STUB_WITH_OBJECTOPRESULT(failMethod)                      \
+    if (NS_FAILED(rv))                                                        \
+        return Throw(rv, cx);                                                 \
+    return retval ? result.succeed() : result.failMethod();
+
 static bool
 XPC_WN_Helper_AddProperty(JSContext *cx, HandleObject obj, HandleId id,
                           MutableHandleValue vp)
 {
     PRE_HELPER_STUB
     AddProperty(wrapper, cx, obj, id, vp.address(), &retval);
     POST_HELPER_STUB
 }
@@ -761,22 +768,22 @@ XPC_WN_Helper_GetProperty(JSContext *cx,
                           MutableHandleValue vp)
 {
     PRE_HELPER_STUB
     GetProperty(wrapper, cx, obj, id, vp.address(), &retval);
     POST_HELPER_STUB
 }
 
 bool
-XPC_WN_Helper_SetProperty(JSContext *cx, HandleObject obj, HandleId id, bool strict,
-                          MutableHandleValue vp)
+XPC_WN_Helper_SetProperty(JSContext *cx, HandleObject obj, HandleId id,
+                          MutableHandleValue vp, ObjectOpResult &result)
 {
     PRE_HELPER_STUB
     SetProperty(wrapper, cx, obj, id, vp.address(), &retval);
-    POST_HELPER_STUB
+    POST_HELPER_STUB_WITH_OBJECTOPRESULT(failReadOnly)
 }
 
 static bool
 XPC_WN_Helper_Call(JSContext *cx, unsigned argc, jsval *vp)
 {
     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
     // N.B. we want obj to be the callee, not JS_THIS(cx, vp)
     RootedObject obj(cx, &args.callee());
@@ -1018,19 +1025,19 @@ XPCNativeScriptableShared::PopulateJSCla
         mJSClass.base.getProperty = nullptr;
 
     JSSetterOp setProperty;
     if (mFlags.WantSetProperty())
         setProperty = XPC_WN_Helper_SetProperty;
     else if (mFlags.UseJSStubForSetProperty())
         setProperty = nullptr;
     else if (mFlags.AllowPropModsDuringResolve())
-        setProperty = XPC_WN_MaybeResolvingStrictPropertyStub;
+        setProperty = XPC_WN_MaybeResolvingSetPropertyStub;
     else
-        setProperty = XPC_WN_CannotModifyStrictPropertyStub;
+        setProperty = XPC_WN_CannotModifySetPropertyStub;
     mJSClass.base.setProperty = setProperty;
 
     MOZ_ASSERT_IF(mFlags.WantEnumerate(), !mFlags.WantNewEnumerate());
     MOZ_ASSERT_IF(mFlags.WantNewEnumerate(), !mFlags.WantEnumerate());
 
     // We will use ops->enumerate set below for NewEnumerate
     if (mFlags.WantNewEnumerate())
         mJSClass.base.enumerate = nullptr;
@@ -1350,19 +1357,20 @@ XPC_WN_OnlyIWrite_Proto_AddPropertyStub(
     // Allow XPConnect to add the property only
     if (ccx.GetResolveName() == id)
         return true;
 
     return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
 }
 
 static bool
-XPC_WN_OnlyIWrite_Proto_SetPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict,
-                                        MutableHandleValue vp)
+XPC_WN_OnlyIWrite_Proto_SetPropertyStub(JSContext *cx, HandleObject obj, HandleId id,
+                                        MutableHandleValue vp, ObjectOpResult &result)
 {
+    result.succeed();
     return XPC_WN_OnlyIWrite_Proto_AddPropertyStub(cx, obj, id, vp);
 }
 
 static bool
 XPC_WN_NoMods_Proto_Resolve(JSContext *cx, HandleObject obj, HandleId id, bool *resolvedp)
 {
     MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_NoMods_WithCall_Proto_JSClass ||
                js::GetObjectClass(obj) == &XPC_WN_NoMods_NoCall_Proto_JSClass,
--- a/js/xpconnect/wrappers/AddonWrapper.cpp
+++ b/js/xpconnect/wrappers/AddonWrapper.cpp
@@ -115,39 +115,38 @@ AddonWrapper<Base>::get(JSContext *cx, J
         vp.set(desc.value());
         return true;
     }
 }
 
 template<typename Base>
 bool
 AddonWrapper<Base>::set(JSContext *cx, JS::HandleObject wrapper, JS::HandleObject receiver,
-                        JS::HandleId id, bool strict, JS::MutableHandleValue vp) const
+                        JS::HandleId id, JS::MutableHandleValue vp,
+                        JS::ObjectOpResult &result) const
 {
     Rooted<JSPropertyDescriptor> desc(cx);
     if (!Interpose(cx, wrapper, nullptr, id, &desc))
         return false;
 
     if (!desc.object())
-        return Base::set(cx, wrapper, receiver, id, strict, vp);
+        return Base::set(cx, wrapper, receiver, id, vp, result);
 
     if (desc.setter()) {
         MOZ_ASSERT(desc.hasSetterObject());
         MOZ_ASSERT(!desc.isReadonly());
         JS::AutoValueVector args(cx);
         args.append(vp);
         RootedValue fval(cx, ObjectValue(*desc.setterObject()));
-        return JS_CallFunctionValue(cx, receiver, fval, args, vp);
-    } else {
-        if (!strict)
-            return true;
+        if (!JS_CallFunctionValue(cx, receiver, fval, args, vp))
+            return false;
+        return result.succeed();
+    }
 
-        js::ReportErrorWithId(cx, "unable to set interposed data property %s", id);
-        return false;
-    }
+    return result.failCantSetInterposed();
 }
 
 template<typename Base>
 bool
 AddonWrapper<Base>::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
                                    MutableHandle<JSPropertyDescriptor> desc,
                                    JS::ObjectOpResult &result) const
 {
--- a/js/xpconnect/wrappers/AddonWrapper.h
+++ b/js/xpconnect/wrappers/AddonWrapper.h
@@ -29,17 +29,18 @@ class AddonWrapper : public Base {
                                           JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool defineProperty(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
                                 JS::MutableHandle<JSPropertyDescriptor> desc,
                                 JS::ObjectOpResult &result) const MOZ_OVERRIDE;
     virtual bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp) const MOZ_OVERRIDE;
     virtual bool get(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<JSObject*> receiver,
                      JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
     virtual bool set(JSContext *cx, JS::HandleObject wrapper, JS::HandleObject receiver,
-                     JS::HandleId id, bool strict, JS::MutableHandleValue vp) const MOZ_OVERRIDE;
+                     JS::HandleId id, JS::MutableHandleValue vp,
+                     JS::ObjectOpResult &result) const MOZ_OVERRIDE;
 
     virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                        JS::Handle<jsid> id,
                                        JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
 
     static const AddonWrapper singleton;
 };
 
--- a/js/xpconnect/wrappers/ChromeObjectWrapper.cpp
+++ b/js/xpconnect/wrappers/ChromeObjectWrapper.cpp
@@ -27,16 +27,16 @@ ChromeObjectWrapper::defineProperty(JSCo
     if (!AccessCheck::checkPassToPrivilegedCode(cx, wrapper, desc.value()))
         return false;
     return ChromeObjectWrapperBase::defineProperty(cx, wrapper, id, desc, result);
 }
 
 bool
 ChromeObjectWrapper::set(JSContext *cx, HandleObject wrapper,
                          HandleObject receiver, HandleId id,
-                         bool strict, MutableHandleValue vp) const
+                         MutableHandleValue vp, ObjectOpResult &result) const
 {
     if (!AccessCheck::checkPassToPrivilegedCode(cx, wrapper, vp))
         return false;
-    return ChromeObjectWrapperBase::set(cx, wrapper, receiver, id, strict, vp);
+    return ChromeObjectWrapperBase::set(cx, wrapper, receiver, id, vp, result);
 }
 
 }
--- a/js/xpconnect/wrappers/ChromeObjectWrapper.h
+++ b/js/xpconnect/wrappers/ChromeObjectWrapper.h
@@ -28,16 +28,17 @@ class ChromeObjectWrapper : public Chrom
     MOZ_CONSTEXPR ChromeObjectWrapper() : ChromeObjectWrapperBase(0) {}
 
     virtual bool defineProperty(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                 JS::Handle<jsid> id,
                                 JS::MutableHandle<JSPropertyDescriptor> desc,
                                 JS::ObjectOpResult &result) const MOZ_OVERRIDE;
     virtual bool set(JSContext *cx, JS::Handle<JSObject*> wrapper,
                      JS::Handle<JSObject*> receiver, JS::Handle<jsid> id,
-                     bool strict, JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
+                     JS::MutableHandle<JS::Value> vp,
+                     JS::ObjectOpResult &result) const MOZ_OVERRIDE;
 
     static const ChromeObjectWrapper singleton;
 };
 
 } /* namespace xpc */
 
 #endif /* __ChromeObjectWrapper_h__ */
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -2054,23 +2054,23 @@ XrayWrapper<Base, Traits>::get(JSContext
     // being the wrapper, so ignore the receiver here.
     return js::BaseProxyHandler::get(cx, wrapper, Traits::HasPrototype ? receiver : wrapper, id, vp);
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::set(JSContext *cx, HandleObject wrapper,
                                HandleObject receiver, HandleId id,
-                               bool strict, MutableHandleValue vp) const
+                               MutableHandleValue vp, ObjectOpResult &result) const
 {
     MOZ_ASSERT(!Traits::HasPrototype);
     // Skip our Base if it isn't already BaseProxyHandler.
     // NB: None of the functions we call are prepared for the receiver not
     // being the wrapper, so ignore the receiver here.
-    return js::BaseProxyHandler::set(cx, wrapper, wrapper, id, strict, vp);
+    return js::BaseProxyHandler::set(cx, wrapper, wrapper, id, vp, result);
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::has(JSContext *cx, HandleObject wrapper,
                                HandleId id, bool *bp) const
 {
     // Skip our Base if it isn't already ProxyHandler.
--- a/js/xpconnect/wrappers/XrayWrapper.h
+++ b/js/xpconnect/wrappers/XrayWrapper.h
@@ -428,17 +428,18 @@ class XrayWrapper : public Base {
                                        bool *succeeded) const MOZ_OVERRIDE;
     virtual bool preventExtensions(JSContext *cx, JS::Handle<JSObject*> wrapper, bool *succeeded) const MOZ_OVERRIDE;
     virtual bool isExtensible(JSContext *cx, JS::Handle<JSObject*> wrapper, bool *extensible) const MOZ_OVERRIDE;
     virtual bool has(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
                      bool *bp) const MOZ_OVERRIDE;
     virtual bool get(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<JSObject*> receiver,
                      JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
     virtual bool set(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<JSObject*> receiver,
-                     JS::Handle<jsid> id, bool strict, JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
+                     JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp,
+                     JS::ObjectOpResult &result) const MOZ_OVERRIDE;
     virtual bool call(JSContext *cx, JS::Handle<JSObject*> wrapper,
                       const JS::CallArgs &args) const MOZ_OVERRIDE;
     virtual bool construct(JSContext *cx, JS::Handle<JSObject*> wrapper,
                            const JS::CallArgs &args) const MOZ_OVERRIDE;
 
     /* SpiderMonkey extensions. */
     virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
                                        JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
@@ -501,17 +502,18 @@ public:
 
     // We just forward the high-level methods to the BaseProxyHandler versions
     // which implement them in terms of lower-level methods.
     virtual bool has(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
                      bool *bp) const MOZ_OVERRIDE;
     virtual bool get(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<JSObject*> receiver,
                      JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
     virtual bool set(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<JSObject*> receiver,
-                     JS::Handle<jsid> id, bool strict, JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
+                     JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp,
+                     JS::ObjectOpResult &result) const MOZ_OVERRIDE;
 
     virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> proxy,
                                        JS::Handle<jsid> id,
                                        JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool hasOwn(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
                         bool *bp) const MOZ_OVERRIDE;
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> proxy,
                                               JS::AutoIdVector &props) const MOZ_OVERRIDE;