Backed out 9 changesets (bug 1142775, bug 1139683, bug 1143810, bug 1142761, bug 1142784, bug 1142794, bug 1144819) for widespread bustage
authorPhil Ringnalda <philringnalda@gmail.com>
Sun, 22 Mar 2015 09:34:25 -0700
changeset 265299 c3638d994edd641c54b6cfcc60d8f32576530eca
parent 265298 7613fc978d36faaf405f3490c19c85886c9e9686
child 265300 052bf572cb946d7dda8867b54400bfc1d4c5c8d0
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)
bugs1142775, 1139683, 1143810, 1142761, 1142784, 1142794, 1144819
milestone39.0a1
backs out7613fc978d36faaf405f3490c19c85886c9e9686
e5f0cb31263d820a926a55b288d7ac2951777611
dcd0af73ac848137d04fa35cc1d111ece51677fe
034f9c8e79ee7a3d54a265324e980c545195c65d
ce0ee37e3ca9a78113075a3f2cb790ad20078580
1519b8f2bbba393de20366c782f0590ddb290b42
26fd5567784152b092a241061771552eb8c0004a
7ebc76a450c31ef5b8c53482f3a9ad830bc96ee8
92adb459d519c7d0c6fd08e234dafd3f6f660a14
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
Backed out 9 changesets (bug 1142775, bug 1139683, bug 1143810, bug 1142761, bug 1142784, bug 1142794, bug 1144819) for widespread bustage CLOSED TREE Backed out changeset 7613fc978d36 (bug 1142794) Backed out changeset e5f0cb31263d (bug 1142784) Backed out changeset dcd0af73ac84 (bug 1142784) Backed out changeset 034f9c8e79ee (bug 1142784) Backed out changeset ce0ee37e3ca9 (bug 1142775) Backed out changeset 1519b8f2bbba (bug 1142761) Backed out changeset 26fd55677841 (bug 1139683) Backed out changeset 7ebc76a450c3 (bug 1144819) Backed out changeset 92adb459d519 (bug 1143810)
dom/base/WindowNamedPropertiesHandler.cpp
dom/base/WindowNamedPropertiesHandler.h
dom/base/nsGlobalWindow.cpp
dom/bindings/BindingUtils.cpp
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
dom/bindings/DOMJSProxyHandler.cpp
dom/bindings/DOMJSProxyHandler.h
js/ipc/JavaScriptBase.h
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/jit/BaselineIC.cpp
js/src/jit/VMFunctions.cpp
js/src/js.msg
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/jsstr.cpp
js/src/jswrapper.h
js/src/proxy/BaseProxyHandler.cpp
js/src/proxy/CrossCompartmentWrapper.cpp
js/src/proxy/DeadObjectProxy.cpp
js/src/proxy/DeadObjectProxy.h
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/proxy/SecurityWrapper.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/Interpreter.h
js/src/vm/NativeObject-inl.h
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/XPCWrappedNativeJSOps.cpp
js/xpconnect/tests/unit/test_xpcwn_tamperproof.js
js/xpconnect/tests/unit/xpcshell.ini
js/xpconnect/wrappers/AddonWrapper.cpp
js/xpconnect/wrappers/AddonWrapper.h
js/xpconnect/wrappers/ChromeObjectWrapper.cpp
js/xpconnect/wrappers/ChromeObjectWrapper.h
js/xpconnect/wrappers/FilteringWrapper.cpp
js/xpconnect/wrappers/FilteringWrapper.h
js/xpconnect/wrappers/XrayWrapper.cpp
js/xpconnect/wrappers/XrayWrapper.h
--- a/dom/base/WindowNamedPropertiesHandler.cpp
+++ b/dom/base/WindowNamedPropertiesHandler.cpp
@@ -154,17 +154,17 @@ WindowNamedPropertiesHandler::getOwnProp
   aDesc.setAttributes(JSPROP_ENUMERATE);
   return true;
 }
 
 bool
 WindowNamedPropertiesHandler::defineProperty(JSContext* aCx,
                                              JS::Handle<JSObject*> aProxy,
                                              JS::Handle<jsid> aId,
-                                             JS::Handle<JSPropertyDescriptor> aDesc,
+                                             JS::MutableHandle<JSPropertyDescriptor> aDesc,
                                              JS::ObjectOpResult &result) const
 {
   ErrorResult rv;
   rv.ThrowTypeError(MSG_DEFINEPROPERTY_ON_GSP);
   rv.ReportErrorWithMessage(aCx);
   return false;
 }
 
--- a/dom/base/WindowNamedPropertiesHandler.h
+++ b/dom/base/WindowNamedPropertiesHandler.h
@@ -23,17 +23,17 @@ public:
   getOwnPropDescriptor(JSContext* aCx, JS::Handle<JSObject*> aProxy,
                        JS::Handle<jsid> aId,
                        bool /* unused */,
                        JS::MutableHandle<JSPropertyDescriptor> aDesc)
                        const override;
   virtual bool
   defineProperty(JSContext* aCx, JS::Handle<JSObject*> aProxy,
                  JS::Handle<jsid> aId,
-                 JS::Handle<JSPropertyDescriptor> aDesc,
+                 JS::MutableHandle<JSPropertyDescriptor> aDesc,
                  JS::ObjectOpResult &result) const override;
   virtual bool
   ownPropNames(JSContext* aCx, JS::Handle<JSObject*> aProxy, unsigned flags,
                JS::AutoIdVector& aProps) const override;
   virtual bool
   delete_(JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
           JS::ObjectOpResult &aResult) const override;
   virtual bool
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -616,17 +616,17 @@ public:
   virtual bool getOwnPropertyDescriptor(JSContext* cx,
                                         JS::Handle<JSObject*> proxy,
                                         JS::Handle<jsid> id,
                                         JS::MutableHandle<JSPropertyDescriptor> desc)
                                         const override;
   virtual bool defineProperty(JSContext* cx,
                               JS::Handle<JSObject*> proxy,
                               JS::Handle<jsid> id,
-                              JS::Handle<JSPropertyDescriptor> desc,
+                              JS::MutableHandle<JSPropertyDescriptor> desc,
                               JS::ObjectOpResult &result) const override;
   virtual bool ownPropertyKeys(JSContext *cx,
                                JS::Handle<JSObject*> proxy,
                                JS::AutoIdVector &props) const override;
   virtual bool delete_(JSContext *cx, JS::Handle<JSObject*> proxy,
                        JS::Handle<jsid> id,
                        JS::ObjectOpResult &result) const override;
   virtual bool enumerate(JSContext *cx, JS::Handle<JSObject*> proxy,
@@ -638,18 +638,19 @@ public:
                             const override;
   virtual bool has(JSContext *cx, JS::Handle<JSObject*> proxy,
                    JS::Handle<jsid> id, bool *bp) const override;
   virtual bool get(JSContext *cx, JS::Handle<JSObject*> proxy,
                    JS::Handle<JSObject*> receiver,
                    JS::Handle<jsid> id,
                    JS::MutableHandle<JS::Value> vp) const override;
   virtual bool set(JSContext *cx, JS::Handle<JSObject*> proxy,
-                   JS::Handle<jsid> id, JS::Handle<JS::Value> v,
-                   JS::Handle<JS::Value> receiver,
+                   JS::Handle<JSObject*> receiver,
+                   JS::Handle<jsid> id,
+                   JS::MutableHandle<JS::Value> vp,
                    JS::ObjectOpResult &result) const override;
 
   // SpiderMonkey extensions
   virtual bool getPropertyDescriptor(JSContext* cx,
                                      JS::Handle<JSObject*> proxy,
                                      JS::Handle<jsid> id,
                                      JS::MutableHandle<JSPropertyDescriptor> desc)
                                      const override;
@@ -776,17 +777,17 @@ nsOuterWindowProxy::getOwnPropertyDescri
 
   return js::Wrapper::getOwnPropertyDescriptor(cx, proxy, id, desc);
 }
 
 bool
 nsOuterWindowProxy::defineProperty(JSContext* cx,
                                    JS::Handle<JSObject*> proxy,
                                    JS::Handle<jsid> id,
-                                   JS::Handle<JSPropertyDescriptor> desc,
+                                   JS::MutableHandle<JSPropertyDescriptor> desc,
                                    JS::ObjectOpResult &result) const
 {
   int32_t index = GetArrayIndexFromId(cx, id);
   if (IsArrayIndex(index)) {
     // Spec says to Reject whether this is a supported index or not,
     // since we have no indexed setter or indexed creator.  It is up
     // to the caller to decide whether to throw a TypeError.
     return result.failCantDefineWindowElement();
@@ -903,29 +904,29 @@ nsOuterWindowProxy::get(JSContext *cx, J
   }
   // Else fall through to js::Wrapper
 
   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,
-                        JS::Handle<JS::Value> v,
-                        JS::Handle<JS::Value> receiver,
+                        JS::MutableHandle<JS::Value> vp,
                         JS::ObjectOpResult &result) const
 {
   int32_t index = GetArrayIndexFromId(cx, id);
   if (IsArrayIndex(index)) {
     // Reject the set.  It's up to the caller to decide whether to throw a
     // TypeError.  If the caller is strict mode JS code, it'll throw.
     return result.failReadOnly();
   }
 
-  return js::Wrapper::set(cx, proxy, id, v, receiver, result);
+  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/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1434,17 +1434,17 @@ XrayResolveOwnProperty(JSContext* cx, JS
   }
 
   return true;
 }
 
 bool
 XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
                    JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
-                   JS::Handle<JSPropertyDescriptor> desc,
+                   JS::MutableHandle<JSPropertyDescriptor> desc,
                    JS::ObjectOpResult &result, bool *defined)
 {
   if (!js::IsProxy(obj))
     return true;
 
   const DOMProxyHandler* handler = GetDOMProxyHandler(obj);
   return handler->defineProperty(cx, wrapper, id, desc, result, defined);
 }
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -2459,17 +2459,17 @@ XrayResolveOwnProperty(JSContext* cx, JS
  * id and desc are the parameters for the property to be defined.
  * result is the out-parameter indicating success (read it only if
  *     this returns true and also sets *defined to true).
  * defined will be set to true if a property was set as a result of this call.
  */
 bool
 XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
                    JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
-                   JS::Handle<JSPropertyDescriptor> desc,
+                   JS::MutableHandle<JSPropertyDescriptor> desc,
                    JS::ObjectOpResult &result,
                    bool *defined);
 
 /**
  * Add to props the property keys of all indexed or named properties of obj and
  * operations, attributes and constants of the interfaces for obj.
  *
  * wrapper is the Xray JS object.
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -9800,17 +9800,17 @@ class CGProxySpecialOperation(CGPerSigna
     foundVar: For getters and deleters, the generated code can also set a bool
     variable, declared by the caller, if the given indexed or named property
     already existed. If the caller wants this, it should pass the name of the
     bool variable as the foundVar keyword argument to the constructor. The
     caller is responsible for declaring the variable and initializing it to
     false.
     """
     def __init__(self, descriptor, operation, checkFound=True,
-                 argumentHandleValue=None, resultVar=None, foundVar=None):
+                 argumentMutableValue=None, resultVar=None, foundVar=None):
         self.checkFound = checkFound
         self.foundVar = foundVar or "found"
 
         nativeName = MakeNativeName(descriptor.binaryNameFor(operation))
         operation = descriptor.operations[operation]
         assert len(operation.signatures()) == 1
         signature = operation.signatures()[0]
 
@@ -9825,22 +9825,22 @@ class CGProxySpecialOperation(CGPerSigna
         if operation.isSetter() or operation.isCreator():
             # arguments[0] is the index or name of the item that we're setting.
             argument = arguments[1]
             info = getJSToNativeConversionInfo(
                 argument.type, descriptor,
                 treatNullAs=argument.treatNullAs,
                 sourceDescription=("value being assigned to %s setter" %
                                    descriptor.interface.identifier.name))
-            if argumentHandleValue is None:
-                argumentHandleValue = "desc.value()"
+            if argumentMutableValue is None:
+                argumentMutableValue = "desc.value()"
             templateValues = {
                 "declName": argument.identifier.name,
                 "holderName": argument.identifier.name + "_holder",
-                "val": argumentHandleValue,
+                "val": argumentMutableValue,
                 "obj": "obj",
                 "passedToJSImpl": "false"
             }
             self.cgRoot.prepend(instantiateJSToNativeConversion(info, templateValues))
         elif operation.isGetter() or operation.isDeleter():
             if foundVar is None:
                 self.cgRoot.prepend(CGGeneric("bool found = false;\n"))
 
@@ -9875,20 +9875,20 @@ class CGProxyIndexedOperation(CGProxySpe
     If checkFound is False, will just assert that the prop is found instead of
     checking that it is before wrapping the value.
 
     resultVar: See the docstring for CGCallGenerator.
 
     foundVar: See the docstring for CGProxySpecialOperation.
     """
     def __init__(self, descriptor, name, doUnwrap=True, checkFound=True,
-                 argumentHandleValue=None, resultVar=None, foundVar=None):
+                 argumentMutableValue=None, resultVar=None, foundVar=None):
         self.doUnwrap = doUnwrap
         CGProxySpecialOperation.__init__(self, descriptor, name, checkFound,
-                                         argumentHandleValue=argumentHandleValue,
+                                         argumentMutableValue=argumentMutableValue,
                                          resultVar=resultVar,
                                          foundVar=foundVar)
 
     def define(self):
         # Our first argument is the id we're getting.
         argName = self.arguments[0].identifier.name
         if argName == "index":
             # We already have our index in a variable with that name
@@ -9936,19 +9936,19 @@ class CGProxyIndexedPresenceChecker(CGPr
         CGProxyIndexedGetter.__init__(self, descriptor, foundVar=foundVar)
         self.cgRoot.append(CGGeneric("(void)result;\n"))
 
 
 class CGProxyIndexedSetter(CGProxyIndexedOperation):
     """
     Class to generate a call to an indexed setter.
     """
-    def __init__(self, descriptor, argumentHandleValue=None):
+    def __init__(self, descriptor, argumentMutableValue=None):
         CGProxyIndexedOperation.__init__(self, descriptor, 'IndexedSetter',
-                                         argumentHandleValue=argumentHandleValue)
+                                         argumentMutableValue=argumentMutableValue)
 
 
 class CGProxyIndexedDeleter(CGProxyIndexedOperation):
     """
     Class to generate a call to an indexed deleter.
 
     resultVar: See the docstring for CGCallGenerator.
 
@@ -9966,20 +9966,20 @@ class CGProxyNamedOperation(CGProxySpeci
 
     'value' is the jsval to use for the name; None indicates that it should be
     gotten from the property id.
 
     resultVar: See the docstring for CGCallGenerator.
 
     foundVar: See the docstring for CGProxySpecialOperation.
     """
-    def __init__(self, descriptor, name, value=None, argumentHandleValue=None,
+    def __init__(self, descriptor, name, value=None, argumentMutableValue=None,
                  resultVar=None, foundVar=None):
         CGProxySpecialOperation.__init__(self, descriptor, name,
-                                         argumentHandleValue=argumentHandleValue,
+                                         argumentMutableValue=argumentMutableValue,
                                          resultVar=resultVar,
                                          foundVar=foundVar)
         self.value = value
 
     def define(self):
         # Our first argument is the id we're getting.
         argName = self.arguments[0].identifier.name
         if argName == "id":
@@ -10067,19 +10067,19 @@ class CGProxyNamedPresenceChecker(CGProx
         CGProxyNamedGetter.__init__(self, descriptor, foundVar=foundVar)
         self.cgRoot.append(CGGeneric("(void)result;\n"))
 
 
 class CGProxyNamedSetter(CGProxyNamedOperation):
     """
     Class to generate a call to a named setter.
     """
-    def __init__(self, descriptor, argumentHandleValue=None):
+    def __init__(self, descriptor, argumentMutableValue=None):
         CGProxyNamedOperation.__init__(self, descriptor, 'NamedSetter',
-                                       argumentHandleValue=argumentHandleValue)
+                                       argumentMutableValue=argumentMutableValue)
 
 
 class CGProxyNamedDeleter(CGProxyNamedOperation):
     """
     Class to generate a call to a named deleter.
 
     resultVar: See the docstring for CGCallGenerator.
 
@@ -10239,17 +10239,17 @@ class CGDOMJSProxyHandler_getOwnPropDesc
 
 class CGDOMJSProxyHandler_defineProperty(ClassMethod):
     def __init__(self, descriptor):
         # The usual convention is to name the ObjectOpResult out-parameter
         # `result`, but that name is a bit overloaded around here.
         args = [Argument('JSContext*', 'cx'),
                 Argument('JS::Handle<JSObject*>', 'proxy'),
                 Argument('JS::Handle<jsid>', 'id'),
-                Argument('JS::Handle<JSPropertyDescriptor>', 'desc'),
+                Argument('JS::MutableHandle<JSPropertyDescriptor>', 'desc'),
                 Argument('JS::ObjectOpResult&', 'opresult'),
                 Argument('bool*', 'defined')]
         ClassMethod.__init__(self, "defineProperty", "bool", args, virtual=True, override=True, const=True)
         self.descriptor = descriptor
 
     def getBody(self):
         set = ""
 
@@ -10686,17 +10686,17 @@ class CGDOMJSProxyHandler_get(ClassMetho
             named=getNamed)
 
 
 class CGDOMJSProxyHandler_setCustom(ClassMethod):
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'cx'),
                 Argument('JS::Handle<JSObject*>', 'proxy'),
                 Argument('JS::Handle<jsid>', 'id'),
-                Argument('JS::Handle<JS::Value>', 'v'),
+                Argument('JS::MutableHandle<JS::Value>', 'vp'),
                 Argument('bool*', 'done')]
         ClassMethod.__init__(self, "setCustom", "bool", args, virtual=True, override=True, const=True)
         self.descriptor = descriptor
 
     def getBody(self):
         assertion = ("MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),\n"
                      '           "Should not have a XrayWrapper here");\n')
 
@@ -10711,17 +10711,17 @@ class CGDOMJSProxyHandler_setCustom(Clas
                                  "Can't cope with [OverrideBuiltins] and an indexed getter")
             if self.descriptor.operations['NamedCreator'] is not namedSetter:
                 raise ValueError("In interface " + self.descriptor.name + ": " +
                                  "Can't cope with named setter that is not also a named creator")
             if self.descriptor.hasUnforgeableMembers:
                 raise ValueError("In interface " + self.descriptor.name + ": " +
                                  "Can't cope with [OverrideBuiltins] and unforgeable members")
 
-            callSetter = CGProxyNamedSetter(self.descriptor, argumentHandleValue="v")
+            callSetter = CGProxyNamedSetter(self.descriptor, argumentMutableValue="vp")
             return (assertion +
                     callSetter.define() +
                     "*done = true;\n"
                     "return true;\n")
 
         # As an optimization, if we are going to call an IndexedSetter, go
         # ahead and call it and have done.
         indexedSetter = self.descriptor.operations['IndexedSetter']
@@ -10736,17 +10736,17 @@ class CGDOMJSProxyHandler_setCustom(Clas
                 if (IsArrayIndex(index)) {
                   $*{callSetter}
                   *done = true;
                   return true;
                 }
 
                 """,
                 callSetter=CGProxyIndexedSetter(self.descriptor,
-                                                argumentHandleValue="v").define())
+                                                argumentMutableValue="vp").define())
         else:
             setIndexed = ""
 
         return (assertion +
                 setIndexed +
                 "*done = false;\n"
                 "return true;\n")
 
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -190,17 +190,17 @@ BaseDOMProxyHandler::getOwnPropertyDescr
                                               MutableHandle<JSPropertyDescriptor> desc) const
 {
   return getOwnPropDescriptor(cx, proxy, id, /* ignoreNamedProps = */ false,
                               desc);
 }
 
 bool
 DOMProxyHandler::defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
-                                Handle<JSPropertyDescriptor> desc,
+                                MutableHandle<JSPropertyDescriptor> desc,
                                 JS::ObjectOpResult &result, bool *defined) const
 {
   if (desc.hasGetterObject() && desc.setter() == JS_StrictPropertyStub) {
     return result.failGetterOnly();
   }
 
   if (xpc::WrapperFactory::IsXrayWrapper(proxy)) {
     return result.succeed();
@@ -214,24 +214,23 @@ DOMProxyHandler::defineProperty(JSContex
   if (!js::DefineOwnProperty(cx, expando, id, desc, result)) {
     return false;
   }
   *defined = true;
   return true;
 }
 
 bool
-DOMProxyHandler::set(JSContext *cx, Handle<JSObject*> proxy, Handle<jsid> id,
-                     Handle<JS::Value> v, Handle<JS::Value> receiver,
-                     ObjectOpResult &result) const
+DOMProxyHandler::set(JSContext *cx, Handle<JSObject*> proxy, Handle<JSObject*> receiver,
+                     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, v, &done)) {
+  if (!setCustom(cx, proxy, id, vp, &done)) {
     return false;
   }
   if (done) {
     return result.succeed();
   }
 
   // Make sure to ignore our named properties when checking for own
   // property descriptors for a set.
@@ -248,17 +247,17 @@ DOMProxyHandler::set(JSContext *cx, Hand
     if (!js::GetObjectProto(cx, proxy, &proto)) {
       return false;
     }
     if (proto && !JS_GetPropertyDescriptorById(cx, proto, id, &desc)) {
       return false;
     }
   }
 
-  return js::SetPropertyIgnoringNamedGetter(cx, proxy, id, v, receiver, desc, result);
+  return js::SetPropertyIgnoringNamedGetter(cx, proxy, id, vp, receiver, &desc, result);
 }
 
 bool
 DOMProxyHandler::delete_(JSContext* cx, JS::Handle<JSObject*> proxy,
                          JS::Handle<jsid> id, JS::ObjectOpResult &result) const
 {
   JS::Rooted<JSObject*> expando(cx);
   if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) {
@@ -346,17 +345,17 @@ IdToInt32(JSContext* cx, JS::Handle<jsid
     return -1;
   }
 
   return i;
 }
 
 bool
 DOMProxyHandler::setCustom(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
-                           JS::Handle<JS::Value> v, bool *done) const
+                           JS::MutableHandle<JS::Value> vp, bool *done) const
 {
   *done = false;
   return true;
 }
 
 //static
 JSObject *
 DOMProxyHandler::GetExpandoObject(JSObject *obj)
--- a/dom/bindings/DOMJSProxyHandler.h
+++ b/dom/bindings/DOMJSProxyHandler.h
@@ -100,44 +100,44 @@ protected:
 class DOMProxyHandler : public BaseDOMProxyHandler
 {
 public:
   MOZ_CONSTEXPR DOMProxyHandler()
     : BaseDOMProxyHandler(&family)
   {}
 
   bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
-                      JS::Handle<JSPropertyDescriptor> desc,
+                      JS::MutableHandle<JSPropertyDescriptor> desc,
                       JS::ObjectOpResult &result) const override
   {
     bool unused;
     return defineProperty(cx, proxy, id, desc, result, &unused);
   }
   virtual bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
-                              JS::Handle<JSPropertyDescriptor> desc,
+                              JS::MutableHandle<JSPropertyDescriptor> desc,
                               JS::ObjectOpResult &result, bool *defined) const;
   bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
                JS::ObjectOpResult &result) const override;
   bool preventExtensions(JSContext* cx, JS::Handle<JSObject*> proxy,
                          JS::ObjectOpResult& result) const override;
   bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible)
                     const override;
   bool has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
            bool* bp) const override;
-  bool set(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
-           JS::Handle<JS::Value> v, JS::Handle<JS::Value> receiver, JS::ObjectOpResult &result)
+  bool set(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<JSObject*> receiver,
+           JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp, JS::ObjectOpResult &result)
            const 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,
-                         JS::Handle<JS::Value> v, bool *done) const;
+                         JS::MutableHandle<JS::Value> vp, bool *done) const;
 
   static JSObject* GetExpandoObject(JSObject* obj);
 
   /* GetAndClearExpandoObject does not DROP or clear the preserving wrapper flag. */
   static JSObject* GetAndClearExpandoObject(JSObject* obj);
   static JSObject* EnsureExpandoObject(JSContext* cx,
                                        JS::Handle<JSObject*> obj);
 
--- a/js/ipc/JavaScriptBase.h
+++ b/js/ipc/JavaScriptBase.h
@@ -66,19 +66,20 @@ class JavaScriptBase : public WrapperOwn
                       ReturnStatus *rs, bool *bp) {
         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 JSIDVariant &id, const JSVariant &value,
-                 const JSVariant &receiverVar, ReturnStatus *rs) {
-        return Answer::RecvSet(ObjectId::deserialize(objId), id, value, receiverVar, rs);
+    bool RecvSet(const uint64_t &objId, const ObjectVariant &receiverVar,
+                 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,
@@ -155,19 +156,20 @@ class JavaScriptBase : public WrapperOwn
                     ReturnStatus *rs, bool *bp) {
         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 JSIDVariant &id, const JSVariant &value,
-                 const JSVariant &receiverVar, ReturnStatus *rs) {
-        return Base::SendSet(objId.serialize(), id, value, receiverVar, rs);
+    bool SendSet(const ObjectId &objId, const ObjectVariant &receiverVar,
+                 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/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);
 
     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, JSIDVariant id, JSVariant value, JSVariant receiver) returns (ReturnStatus rs);
+    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 GetPrototype(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
@@ -303,43 +303,52 @@ WrapperAnswer::RecvGet(const ObjectId &o
         return fail(cx, rs);
 
     LOG("get %s.%s = %s", ReceiverObj(objId), Identifier(idVar), OutVariant(*result));
 
     return ok(rs);
 }
 
 bool
-WrapperAnswer::RecvSet(const ObjectId &objId, const JSIDVariant &idVar, const JSVariant &value,
-                       const JSVariant &receiverVar, ReturnStatus *rs)
+WrapperAnswer::RecvSet(const ObjectId &objId, const ObjectVariant &receiverVar,
+                       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.
+    *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);
 
     RootedValue val(cx);
     if (!fromVariant(cx, value, &val))
         return fail(cx, rs);
 
-    RootedValue receiver(cx);
-    if (!fromVariant(cx, receiverVar, &receiver))
+    ObjectOpResult result;
+    RootedValue receiverVal(cx, ObjectValue(*receiver));
+    if (!JS_ForwardSetPropertyTo(cx, obj, id, val, receiverVal, result))
         return fail(cx, rs);
 
-    ObjectOpResult result;
-    if (!JS_ForwardSetPropertyTo(cx, obj, id, val, receiver, result))
+    if (!toVariant(cx, val, resultValue))
         return fail(cx, rs);
 
     return ok(rs, result);
 }
 
 bool
 WrapperAnswer::RecvIsExtensible(const ObjectId &objId, ReturnStatus *rs, bool *result)
 {
--- a/js/ipc/WrapperAnswer.h
+++ b/js/ipc/WrapperAnswer.h
@@ -32,18 +32,19 @@ 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 JSIDVariant &id, const JSVariant &value,
-                 const JSVariant &receiverVar, ReturnStatus *rs);
+    bool RecvSet(const ObjectId &objId, const ObjectVariant &receiverVar,
+                 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
@@ -92,31 +92,32 @@ class CPOWProxyHandler : public BaseProx
 
     virtual bool finalizeInBackground(Value priv) const override {
         return false;
     }
 
     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                           MutableHandle<JSPropertyDescriptor> desc) const override;
     virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                                Handle<JSPropertyDescriptor> desc,
+                                MutableHandle<JSPropertyDescriptor> desc,
                                 ObjectOpResult &result) const override;
     virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy,
                                  AutoIdVector &props) const override;
     virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id,
                          ObjectOpResult &result) const override;
     virtual bool enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp) const override;
     virtual bool preventExtensions(JSContext *cx, HandleObject proxy,
                                    ObjectOpResult &result) const override;
     virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const override;
     virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const override;
     virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
                      HandleId id, MutableHandleValue vp) const override;
-    virtual bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleValue v,
-                     JS::HandleValue receiver, JS::ObjectOpResult &result) const override;
+    virtual bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
+                     JS::HandleId id, JS::MutableHandleValue vp,
+                     JS::ObjectOpResult &result) const override;
     virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const override;
     virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const override;
 
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc) const override;
     virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const override;
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                               AutoIdVector &props) const override;
@@ -207,25 +208,25 @@ WrapperOwner::getOwnPropertyDescriptor(J
     if (!ok(cx, status))
         return false;
 
     return toDescriptor(cx, result, desc);
 }
 
 bool
 CPOWProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                                 Handle<JSPropertyDescriptor> desc,
+                                 MutableHandle<JSPropertyDescriptor> desc,
                                  ObjectOpResult &result) const
 {
     FORWARD(defineProperty, (cx, proxy, id, desc, result));
 }
 
 bool
 WrapperOwner::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                             Handle<JSPropertyDescriptor> desc,
+                             MutableHandle<JSPropertyDescriptor> desc,
                              ObjectOpResult &result)
 {
     ObjectId objId = idOf(proxy);
 
     JSIDVariant idVar;
     if (!toJSIDVariant(cx, id, &idVar))
         return false;
 
@@ -511,47 +512,51 @@ WrapperOwner::get(JSContext *cx, HandleO
 
         vp.set(ObjectValue(*toStringObj));
     }
 
     return true;
 }
 
 bool
-CPOWProxyHandler::set(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleValue v,
-                      JS::HandleValue receiver, JS::ObjectOpResult &result) const
+CPOWProxyHandler::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
+                      JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult &result) const
 {
-    FORWARD(set, (cx, proxy, id, v, receiver, result));
+    FORWARD(set, (cx, proxy, receiver, id, vp, result));
 }
 
 bool
-WrapperOwner::set(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleValue v,
-                  JS::HandleValue receiver, JS::ObjectOpResult &result)
+WrapperOwner::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
+                  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, v, &val))
-        return false;
-
-    JSVariant receiverVar;
-    if (!toVariant(cx, receiver, &receiverVar))
+    if (!toVariant(cx, vp, &val))
         return false;
 
     ReturnStatus status;
-    if (!SendSet(objId, idVar, val, receiverVar, &status))
+    JSVariant resultValue;
+    if (!SendSet(objId, receiverVar, idVar, val, &status, &resultValue))
         return ipcfail(cx);
 
     LOG_STACK();
 
-    return ok(cx, status, result);
+    if (!ok(cx, status, result))
+        return false;
+
+    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
@@ -27,28 +27,28 @@ class WrapperOwner : public virtual Java
     explicit WrapperOwner(JSRuntime *rt);
     bool init();
 
     // Standard internal methods.
     // (The traps should be in the same order like js/Proxy.h)
     bool getOwnPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
                                   JS::MutableHandle<JSPropertyDescriptor> desc);
     bool defineProperty(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
-                        JS::Handle<JSPropertyDescriptor> desc,
+                        JS::MutableHandle<JSPropertyDescriptor> desc,
                         JS::ObjectOpResult &result);
     bool ownPropertyKeys(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
     bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
                  JS::ObjectOpResult &result);
     bool preventExtensions(JSContext *cx, JS::HandleObject proxy, JS::ObjectOpResult &result);
     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::HandleId id, JS::HandleValue v,
-             JS::HandleValue receiver, JS::ObjectOpResult &result);
+    bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
+             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,19 @@ 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 JSIDVariant &id, const JSVariant &value,
-                         const JSVariant &receiverVar, ReturnStatus *rs) = 0;
+    virtual bool SendSet(const ObjectId &objId, const ObjectVariant &receiverVar,
+                         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
@@ -328,27 +328,27 @@ typedef void
 /* js::Class operation signatures. */
 
 namespace js {
 
 typedef bool
 (* LookupPropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
                      JS::MutableHandleObject objp, JS::MutableHandle<Shape*> propp);
 typedef bool
-(* DefinePropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
-                     JS::Handle<JSPropertyDescriptor> desc,
+(* DefinePropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue value,
+                     JSGetterOp getter, JSSetterOp setter, unsigned attrs,
                      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::HandleId id, JS::HandleValue v,
-                  JS::HandleValue receiver, JS::ObjectOpResult &result);
+(* SetPropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, JS::HandleId id,
+                  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,
                      JS::ObjectOpResult &result);
 
 typedef bool
--- a/js/public/Proxy.h
+++ b/js/public/Proxy.h
@@ -13,17 +13,16 @@
 
 #include "js/CallNonGenericMethod.h"
 #include "js/Class.h"
 
 namespace js {
 
 using JS::AutoIdVector;
 using JS::CallArgs;
-using JS::Handle;
 using JS::HandleId;
 using JS::HandleObject;
 using JS::HandleValue;
 using JS::IsAcceptableThis;
 using JS::MutableHandle;
 using JS::MutableHandleObject;
 using JS::MutableHandleValue;
 using JS::NativeImpl;
@@ -248,17 +247,17 @@ class JS_FRIEND_API(BaseProxyHandler)
 
     virtual bool enter(JSContext *cx, HandleObject wrapper, HandleId id, Action act,
                        bool *bp) const;
 
     /* Standard internal methods. */
     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                           MutableHandle<JSPropertyDescriptor> desc) const = 0;
     virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                                Handle<JSPropertyDescriptor> desc,
+                                MutableHandle<JSPropertyDescriptor> desc,
                                 ObjectOpResult &result) const = 0;
     virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy,
                                  AutoIdVector &props) const = 0;
     virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id,
                          ObjectOpResult &result) const = 0;
 
     /*
      * Because [[Enumerate]] is one of the standard traps it should be overridden.
@@ -290,18 +289,18 @@ class JS_FRIEND_API(BaseProxyHandler)
      * that ProxyHandler subclasses don't have to provide every single method.
      *
      * 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, HandleId id, HandleValue v,
-                     HandleValue receiver, ObjectOpResult &result) const;
+    virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver,
+                     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.
      *
@@ -369,17 +368,17 @@ class JS_FRIEND_API(DirectProxyHandler) 
                                               bool aHasSecurityPolicy = false)
       : BaseProxyHandler(aFamily, aHasPrototype, aHasSecurityPolicy)
     { }
 
     /* Standard internal methods. */
     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                           MutableHandle<JSPropertyDescriptor> desc) const override;
     virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                                Handle<JSPropertyDescriptor> desc,
+                                MutableHandle<JSPropertyDescriptor> desc,
                                 ObjectOpResult &result) const override;
     virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy,
                                  AutoIdVector &props) const override;
     virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id,
                          ObjectOpResult &result) const override;
     virtual bool enumerate(JSContext *cx, HandleObject proxy,
                            MutableHandleObject objp) const override;
     virtual bool getPrototype(JSContext *cx, HandleObject proxy,
@@ -390,18 +389,19 @@ class JS_FRIEND_API(DirectProxyHandler) 
                                        bool *succeeded) const override;
     virtual bool preventExtensions(JSContext *cx, HandleObject proxy,
                                    ObjectOpResult &result) const override;
     virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const override;
     virtual bool has(JSContext *cx, HandleObject proxy, HandleId id,
                      bool *bp) const override;
     virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
                      HandleId id, MutableHandleValue vp) const override;
-    virtual bool set(JSContext *cx, HandleObject proxy, HandleId id, HandleValue v,
-                     HandleValue receiver, ObjectOpResult &result) const override;
+    virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver,
+                     HandleId id, MutableHandleValue vp,
+                     ObjectOpResult &result) const override;
     virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const override;
     virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const override;
 
     /* SpiderMonkey extensions. */
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc) const override;
     virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id,
                         bool *bp) const override;
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -1746,18 +1746,18 @@ ReportPropertyError(JSContext *cx,
     JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
                          errorNumber, propName);
 
     JS_free(cx, propName);
     return false;
 }
 
 bool
-TypedObject::obj_defineProperty(JSContext *cx, HandleObject obj, HandleId id,
-                                Handle<JSPropertyDescriptor> desc,
+TypedObject::obj_defineProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
+                                GetterOp getter, SetterOp setter, unsigned attrs,
                                 ObjectOpResult &result)
 {
     Rooted<TypedObject *> typedObj(cx, &obj->as<TypedObject>());
     return ReportTypedObjTypeError(cx, JSMSG_OBJECT_NOT_EXTENSIBLE, typedObj);
 }
 
 bool
 TypedObject::obj_hasProperty(JSContext *cx, HandleObject obj, HandleId id, bool *foundp)
@@ -1899,80 +1899,80 @@ 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, HandleId id, HandleValue v,
-                             HandleValue receiver, ObjectOpResult &result)
+TypedObject::obj_setProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
+                             MutableHandleValue vp, ObjectOpResult &result)
 {
     Rooted<TypedObject *> typedObj(cx, &obj->as<TypedObject>());
 
     switch (typedObj->typeDescr().kind()) {
       case type::Scalar:
       case type::Reference:
         break;
 
       case type::Simd:
         break;
 
       case type::Array: {
         if (JSID_IS_ATOM(id, cx->names().length)) {
-            if (receiver.isObject() && obj == &receiver.toObject()) {
+            if (obj == receiver) {
                 JS_ReportErrorNumber(cx, GetErrorMessage,
                                      nullptr, JSMSG_CANT_REDEFINE_ARRAY_LENGTH);
                 return false;
             }
             return result.failReadOnly();
         }
 
         uint32_t index;
         if (IdIsIndex(id, &index)) {
-            if (!receiver.isObject() || obj != &receiver.toObject())
-                return SetPropertyByDefining(cx, obj, id, v, receiver, false, result);
+            if (obj != receiver)
+                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;
-            if (!ConvertAndCopyTo(cx, elementType, typedObj, offset, NullPtr(), v))
+            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 (!receiver.isObject() || obj != &receiver.toObject())
-            return SetPropertyByDefining(cx, obj, id, v, receiver, false, result);
+        if (obj != receiver)
+            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));
-        if (!ConvertAndCopyTo(cx, fieldType, typedObj, offset, fieldName, v))
+        if (!ConvertAndCopyTo(cx, fieldType, typedObj, offset, fieldName, vp))
             return false;
         return result.succeed();
       }
     }
 
-    return SetPropertyOnProto(cx, obj, id, v, receiver, result);
+    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
@@ -523,30 +523,30 @@ class TypedObject : public JSObject
 
     static bool obj_lookupProperty(JSContext *cx, HandleObject obj,
                                    HandleId id, MutableHandleObject objp,
                                    MutableHandleShape propp);
 
     static bool obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
                                   MutableHandleObject objp, MutableHandleShape propp);
 
-    static bool obj_defineProperty(JSContext *cx, HandleObject obj, HandleId id,
-                                   Handle<JSPropertyDescriptor> desc,
+    static bool obj_defineProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
+                                   GetterOp getter, SetterOp setter, unsigned attrs,
                                    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_getElement(JSContext *cx, HandleObject obj, HandleObject receiver,
                                uint32_t index, MutableHandleValue vp);
 
-    static bool obj_setProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
-                                HandleValue receiver, ObjectOpResult &result);
+    static bool obj_setProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
+                                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,
                                    ObjectOpResult &result);
 
     static bool obj_enumerate(JSContext *cx, HandleObject obj, AutoIdVector &properties);
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -8359,17 +8359,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 (!PutProperty(cx, 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/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -424,44 +424,45 @@ StringFromCharCode(JSContext *cx, int32_
 
     return NewStringCopyN<CanGC>(cx, &c, 1);
 }
 
 bool
 SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value,
             bool strict, jsbytecode *pc)
 {
+    RootedValue v(cx, value);
     RootedId id(cx, NameToId(name));
 
     JSOp op = JSOp(*pc);
 
     if (op == JSOP_SETALIASEDVAR) {
         // 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;
     }
 
-    RootedValue receiver(cx, ObjectValue(*obj));
     ObjectOpResult result;
     if (MOZ_LIKELY(!obj->getOps()->setProperty)) {
         if (!NativeSetProperty(
-                cx, obj.as<NativeObject>(), id, value, receiver,
+                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, id, value, receiver, result))
+        if (!SetProperty(cx, obj, obj, id, &v, result))
             return false;
     }
     return result.checkStrictErrorOrWarning(cx, obj, id, strict);
 }
 
 bool
 InterruptCheck(JSContext *cx)
 {
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -77,17 +77,16 @@ MSG_DEF(JSMSG_MALFORMED_UTF8_CHAR,     1
 MSG_DEF(JSMSG_WRONG_CONSTRUCTOR,       1, JSEXN_TYPEERR, "wrong constructor called for {0}")
 MSG_DEF(JSMSG_BUILTIN_CTOR_NO_NEW,     1, JSEXN_NONE, "calling a builtin {0} constructor without new is deprecated and will be forbidden in ES6")
 MSG_DEF(JSMSG_PROTO_SETTING_SLOW,      0, JSEXN_NONE, "mutating the [[Prototype]] of an object will cause your code to run very slowly; instead create the object with the correct initial [[Prototype]] value using Object.create")
 MSG_DEF(JSMSG_BAD_GENERATOR_YIELD,     1, JSEXN_TYPEERR, "yield from closing generator {0}")
 MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE,      0, JSEXN_TYPEERR, "reduce of empty array with no initial value")
 MSG_DEF(JSMSG_UNEXPECTED_TYPE,         2, JSEXN_TYPEERR, "{0} is {1}")
 MSG_DEF(JSMSG_MISSING_FUN_ARG,         2, JSEXN_TYPEERR, "missing argument {0} when calling function {1}")
 MSG_DEF(JSMSG_NOT_NONNULL_OBJECT,      1, JSEXN_TYPEERR, "{0} is not a non-null object")
-MSG_DEF(JSMSG_SET_NON_OBJECT_RECEIVER, 1, JSEXN_TYPEERR, "can't assign to properties of {0}: not an object")
 MSG_DEF(JSMSG_INVALID_DESCRIPTOR,      0, JSEXN_TYPEERR, "property descriptors must not specify a value or be writable when a getter or setter has been specified")
 MSG_DEF(JSMSG_OBJECT_NOT_EXTENSIBLE,   1, JSEXN_TYPEERR, "{0} is not extensible")
 MSG_DEF(JSMSG_CANT_REDEFINE_PROP,      1, JSEXN_TYPEERR, "can't redefine non-configurable property {0}")
 MSG_DEF(JSMSG_CANT_APPEND_TO_ARRAY,    0, JSEXN_TYPEERR, "can't add elements past the end of an array if its length property is unwritable")
 MSG_DEF(JSMSG_CANT_REDEFINE_ARRAY_LENGTH, 0, JSEXN_TYPEERR, "can't redefine array length")
 MSG_DEF(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH, 0, JSEXN_TYPEERR, "can't define array index property past the end of an array with non-writable length")
 MSG_DEF(JSMSG_BAD_GET_SET_FIELD,       1, JSEXN_TYPEERR, "property descriptor's {0} field is neither undefined nor a function")
 MSG_DEF(JSMSG_THROW_TYPE_ERROR,        0, JSEXN_TYPEERR, "'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them")
--- a/js/src/jsapi-tests/testSetPropertyIgnoringNamedGetter.cpp
+++ b/js/src/jsapi-tests/testSetPropertyIgnoringNamedGetter.cpp
@@ -22,23 +22,23 @@ class CustomProxyHandler : public Direct
     }
 
     bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                   MutableHandle<JSPropertyDescriptor> desc) const override
     {
         return impl(cx, proxy, id, desc, true);
     }
 
-    bool set(JSContext *cx, HandleObject proxy, HandleId id, HandleValue v, HandleValue receiver,
-             ObjectOpResult &result) const override
+    bool set(JSContext *cx, HandleObject proxy, HandleObject receiver,
+             HandleId id, MutableHandleValue vp, ObjectOpResult &result) const override
     {
         Rooted<JSPropertyDescriptor> desc(cx);
         if (!DirectProxyHandler::getPropertyDescriptor(cx, proxy, id, &desc))
             return false;
-        return SetPropertyIgnoringNamedGetter(cx, proxy, id, v, receiver, desc, result);
+        return SetPropertyIgnoringNamedGetter(cx, proxy, id, vp, receiver, &desc, 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
@@ -142,17 +142,17 @@ JS::ObjectOpResult::reportStrictErrorOrW
                                                bool strict)
 {
     static_assert(unsigned(OkCode) == unsigned(JSMSG_NOT_AN_ERROR),
                   "unsigned value of OkCode must not be an error code");
     MOZ_ASSERT(code_ != Uninitialized);
     MOZ_ASSERT(!ok());
 
     unsigned flags = strict ? JSREPORT_ERROR : (JSREPORT_WARNING | JSREPORT_STRICT);
-    if (code_ == JSMSG_OBJECT_NOT_EXTENSIBLE || code_ == JSMSG_SET_NON_OBJECT_RECEIVER) {
+    if (code_ == JSMSG_OBJECT_NOT_EXTENSIBLE) {
         RootedValue val(cx, ObjectValue(*obj));
         return ReportValueErrorFlags(cx, flags, code_, JSDVG_IGNORE_STACK, val,
                                      NullPtr(), nullptr, nullptr);
     }
     if (ErrorTakesIdArgument(code_)) {
         RootedValue idv(cx, IdToValue(id));
         RootedString str(cx, ValueToSource(cx, idv));
         if (!str)
@@ -2200,22 +2200,20 @@ DefinePropertyById(JSContext *cx, Handle
                           ? JS_FUNC_TO_DATA_PTR(JSObject *, setter)
                           : nullptr);
 
     // In most places throughout the engine, a property with null getter and
     // not JSPROP_GETTER/SETTER/SHARED has no getter, and the same for setters:
     // it's just a plain old data property. However the JS_Define* APIs use
     // null getter and setter to mean "default to the Class getProperty and
     // setProperty ops".
-    if (!(attrs & (JSPROP_GETTER | JSPROP_SETTER))) {
-        if (!getter)
-            getter = obj->getClass()->getProperty;
-        if (!setter)
-            setter = obj->getClass()->setProperty;
-    }
+    if (!getter)
+        getter = obj->getClass()->getProperty;
+    if (!setter)
+        setter = obj->getClass()->setProperty;
     if (getter == JS_PropertyStub)
         getter = nullptr;
     if (setter == JS_StrictPropertyStub)
         setter = nullptr;
     return DefineProperty(cx, obj, id, value, getter, setter, attrs);
 }
 
 JS_PUBLIC_API(bool)
@@ -2825,87 +2823,93 @@ JS_GetUCProperty(JSContext *cx, HandleOb
         return false;
     RootedId id(cx, AtomToId(atom));
     return JS_GetPropertyById(cx, obj, id, vp);
 }
 
 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);
 
-    RootedValue receiver(cx, ObjectValue(*obj));
     ObjectOpResult ignored;
-    return SetProperty(cx, obj, id, v, receiver, 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, receiver);
 
-    return SetProperty(cx, obj, id, v, receiver, result);
+    // XXX Bug 603201 will eliminate this ToObject.
+    RootedObject receiverObj(cx, ToObject(cx, receiver));
+    if (!receiverObj)
+        return false;
+
+    RootedValue value(cx, v);
+    return SetProperty(cx, obj, receiverObj, id, &value, result);
 }
 
 static bool
-SetElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v)
+SetElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleValue vp)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    assertSameCompartment(cx, obj, v);
-
-    RootedValue receiver(cx, ObjectValue(*obj));
+    assertSameCompartment(cx, obj, vp);
+
     ObjectOpResult ignored;
-    return SetElement(cx, obj, index, v, receiver, ignored);
+    return SetElement(cx, obj, obj, index, vp, ignored);
 }
 
 JS_PUBLIC_API(bool)
 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v)
 {
-    return SetElement(cx, obj, index, v);
+    RootedValue value(cx, v);
+    return SetElement(cx, obj, index, &value);
 }
 
 JS_PUBLIC_API(bool)
 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, HandleObject v)
 {
     RootedValue value(cx, ObjectOrNullValue(v));
-    return SetElement(cx, obj, index, value);
+    return SetElement(cx, obj, index, &value);
 }
 
 JS_PUBLIC_API(bool)
 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, HandleString v)
 {
     RootedValue value(cx, StringValue(v));
-    return SetElement(cx, obj, index, value);
+    return SetElement(cx, obj, index, &value);
 }
 
 JS_PUBLIC_API(bool)
 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, int32_t v)
 {
     RootedValue value(cx, NumberValue(v));
-    return SetElement(cx, obj, index, value);
+    return SetElement(cx, obj, index, &value);
 }
 
 JS_PUBLIC_API(bool)
 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, uint32_t v)
 {
     RootedValue value(cx, NumberValue(v));
-    return SetElement(cx, obj, index, value);
+    return SetElement(cx, obj, index, &value);
 }
 
 JS_PUBLIC_API(bool)
 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, double v)
 {
     RootedValue value(cx, NumberValue(v));
-    return SetElement(cx, obj, index, value);
+    return SetElement(cx, obj, index, &value);
 }
 
 JS_PUBLIC_API(bool)
 JS_SetProperty(JSContext *cx, HandleObject obj, const char *name, HandleValue v)
 {
     JSAtom *atom = Atomize(cx, name, strlen(name));
     if (!atom)
         return false;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2595,28 +2595,16 @@ class MutablePropertyDescriptorOperation
     void clear() {
         object().set(nullptr);
         setAttributes(0);
         setGetter(nullptr);
         setSetter(nullptr);
         value().setUndefined();
     }
 
-    void initFields(HandleObject obj, HandleValue v, unsigned attrs,
-                    JSGetterOp getterOp, JSSetterOp setterOp) {
-        MOZ_ASSERT(getterOp != JS_PropertyStub);
-        MOZ_ASSERT(setterOp != JS_StrictPropertyStub);
-
-        object().set(obj);
-        value().set(v);
-        setAttributes(attrs);
-        setGetter(getterOp);
-        setSetter(setterOp);
-    }
-
     void assign(JSPropertyDescriptor &other) {
         object().set(other.obj);
         setAttributes(other.attrs);
         setGetter(other.getter);
         setSetter(other.setter);
         value().set(other.value);
     }
 
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -359,17 +359,18 @@ SetArrayElement(JSContext *cx, HandleObj
             return false;
         MOZ_ASSERT(result == NativeObject::ED_SPARSE);
     }
 
     RootedId id(cx);
     if (!ToId(cx, index, &id))
         return false;
 
-    return SetProperty(cx, obj, id, v);
+    RootedValue tmp(cx, v);
+    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.
@@ -428,17 +429,17 @@ DeletePropertyOrThrow(JSContext *cx, Han
     }
     return true;
 }
 
 bool
 js::SetLengthProperty(JSContext *cx, HandleObject obj, double length)
 {
     RootedValue v(cx, NumberValue(length));
-    return SetProperty(cx, obj, cx->names().length, v);
+    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.
@@ -1264,20 +1265,21 @@ InitArrayElements(JSContext *cx, HandleO
     MOZ_ASSERT(start == MAX_ARRAY_INDEX + 1);
     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))
+        if (!ValueToId<CanGC>(cx, indexv, &id) ||
+            !SetProperty(cx, obj, obj, id, &value))
+        {
             return false;
-        if (!SetProperty(cx, obj, id, value))
-            return false;
+        }
         index += 1;
     } while (vector != end);
 
     return true;
 }
 
 static bool
 array_reverse(JSContext *cx, unsigned argc, Value *vp)
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -327,16 +327,36 @@ CallJSDeletePropertyOp(JSContext *cx, JS
     JS_CHECK_RECURSION(cx, return false);
 
     assertSameCompartment(cx, receiver, id);
     if (op)
         return op(cx, receiver, id, result);
     return result.succeed();
 }
 
+inline bool
+CallSetter(JSContext *cx, HandleObject obj, HandleId id, SetterOp op, unsigned attrs,
+           MutableHandleValue vp, ObjectOpResult &result)
+{
+    if (attrs & JSPROP_SETTER) {
+        RootedValue opv(cx, CastAsObjectJsval(op));
+        if (!InvokeGetterOrSetter(cx, obj, opv, 1, vp.address(), vp))
+            return false;
+        return result.succeed();
+    }
+
+    if (attrs & JSPROP_GETTER)
+        return result.fail(JSMSG_GETTER_ONLY);
+
+    if (!op)
+        return result.succeed();
+
+    return CallJSSetterOp(cx, op, obj, id, vp, result);
+}
+
 inline uintptr_t
 GetNativeStackLimit(ExclusiveContext *cx)
 {
     StackKind kind;
     if (cx->isJSContext()) {
         kind = cx->asJSContext()->runningWithTrustedPrincipals()
                  ? StackForTrustedScript : StackForUntrustedScript;
     } else {
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -354,27 +354,27 @@ namespace js {
  *
  * NB: Should not be called directly.
  */
 
 extern JS_FRIEND_API(bool)
 proxy_LookupProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleObject objp,
                     JS::MutableHandle<Shape*> propp);
 extern JS_FRIEND_API(bool)
-proxy_DefineProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
-                     JS::Handle<JSPropertyDescriptor> desc,
+proxy_DefineProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue value,
+                     JSGetterOp getter, JSSetterOp setter, unsigned attrs,
                      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::HandleId id, JS::HandleValue bp,
-                  JS::HandleValue receiver, JS::ObjectOpResult &result);
+proxy_SetProperty(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, JS::HandleId id,
+                  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,
                      JS::ObjectOpResult &result);
 
 extern JS_FRIEND_API(void)
@@ -2627,18 +2627,18 @@ ForwardToNative(JSContext *cx, JSNative 
  * set() in this way.  It carries out all the steps of BaseProxyHandler::set()
  * except the initial getOwnPropertyDescriptor() call.  The caller must supply
  * that descriptor as the 'ownDesc' parameter.
  *
  * Implemented in proxy/BaseProxyHandler.cpp.
  */
 JS_FRIEND_API(bool)
 SetPropertyIgnoringNamedGetter(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
-                               JS::HandleValue v, JS::HandleValue receiver,
-                               JS::Handle<JSPropertyDescriptor> ownDesc,
+                               JS::MutableHandleValue vp, JS::HandleObject receiver,
+                               JS::MutableHandle<JSPropertyDescriptor> ownDesc,
                                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,
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -684,17 +684,17 @@ js::StandardDefineProperty(JSContext *cx
 
     if (obj->is<UnboxedPlainObject>() && !UnboxedPlainObject::convertToNative(cx, obj))
         return false;
 
     if (obj->getOps()->lookupProperty) {
         if (obj->is<ProxyObject>()) {
             Rooted<PropertyDescriptor> pd(cx, desc);
             pd.object().set(obj);
-            return Proxy::defineProperty(cx, obj, id, pd, result);
+            return Proxy::defineProperty(cx, obj, id, &pd, result);
         }
         return result.fail(JSMSG_OBJECT_NOT_EXTENSIBLE);
     }
 
     return DefinePropertyOnObject(cx, obj.as<NativeObject>(), id, desc, result);
 }
 
 bool
@@ -1579,36 +1579,35 @@ js::CreateThisForFunction(JSContext *cx,
 
         return nobj;
     }
 
     return obj;
 }
 
 /* static */ bool
-JSObject::nonNativeSetProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
-                               HandleValue receiver, ObjectOpResult &result)
+JSObject::nonNativeSetProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
+                               HandleId id, MutableHandleValue vp, ObjectOpResult &result)
 {
-    RootedValue value(cx, v);
     if (MOZ_UNLIKELY(obj->watched())) {
         WatchpointMap *wpmap = cx->compartment()->watchpointMap;
-        if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, &value))
+        if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, vp))
             return false;
     }
-    return obj->getOps()->setProperty(cx, obj, id, value, receiver, result);
+    return obj->getOps()->setProperty(cx, obj, receiver, id, vp, result);
 }
 
 /* static */ bool
-JSObject::nonNativeSetElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v,
-                              HandleValue receiver, ObjectOpResult &result)
+JSObject::nonNativeSetElement(JSContext *cx, HandleObject obj, HandleObject receiver,
+                              uint32_t index, MutableHandleValue vp, ObjectOpResult &result)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, &id))
         return false;
-    return nonNativeSetProperty(cx, obj, id, v, receiver, result);
+    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);
@@ -3189,39 +3188,32 @@ js::GetOwnPropertyDescriptor(JSContext *
         return false;
 
     desc.value().set(value);
     desc.object().set(obj);
     return true;
 }
 
 bool
-js::DefineProperty(JSContext *cx, HandleObject obj, HandleId id, Handle<PropertyDescriptor> desc,
-                   ObjectOpResult &result)
-{
-    if (DefinePropertyOp op = obj->getOps()->defineProperty)
-        return op(cx, obj, id, desc, result);
-    return NativeDefineProperty(cx, obj.as<NativeObject>(), id, desc, result);
-}
-
-bool
 js::DefineProperty(ExclusiveContext *cx, HandleObject obj, HandleId id, HandleValue value,
                    JSGetterOp getter, JSSetterOp setter, unsigned attrs,
                    ObjectOpResult &result)
 {
+    MOZ_ASSERT(getter != JS_PropertyStub);
+    MOZ_ASSERT(setter != JS_StrictPropertyStub);
     MOZ_ASSERT(!(attrs & JSPROP_PROPOP_ACCESSORS));
 
-    Rooted<PropertyDescriptor> desc(cx);
-    desc.initFields(obj, value, attrs, getter, setter);
-    if (DefinePropertyOp op = obj->getOps()->defineProperty) {
+    DefinePropertyOp op = obj->getOps()->defineProperty;
+    if (op) {
         if (!cx->shouldBeJSContext())
             return false;
-        return op(cx->asJSContext(), obj, id, desc, result);
+        return op(cx->asJSContext(), obj, id, value, getter, setter, attrs, result);
     }
-    return NativeDefineProperty(cx, obj.as<NativeObject>(), id, desc, result);
+    return NativeDefineProperty(cx, obj.as<NativeObject>(), id, value, getter, setter, attrs,
+                                result);
 }
 
 bool
 js::DefineProperty(ExclusiveContext *cx, HandleObject obj, PropertyName *name, HandleValue value,
                    JSGetterOp getter, JSSetterOp setter, unsigned attrs,
                    ObjectOpResult &result)
 {
     RootedId id(cx, NameToId(name));
@@ -3274,16 +3266,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
@@ -473,22 +473,22 @@ class JSObject : public js::gc::Cell
      * Get the property with the given id, then call it as a function with the
      * given arguments, providing this object as |this|. If the property isn't
      * 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::HandleId id,
-                                     js::HandleValue v, js::HandleValue receiver,
-                                     JS::ObjectOpResult &result);
-    static bool nonNativeSetElement(JSContext *cx, js::HandleObject obj, uint32_t index,
-                                    js::HandleValue v, js::HandleValue receiver,
-                                    JS::ObjectOpResult &result);
+    static bool nonNativeSetProperty(JSContext *cx, js::HandleObject obj,
+                                     js::HandleObject receiver, js::HandleId id,
+                                     js::MutableHandleValue vp, JS::ObjectOpResult &result);
+    static bool nonNativeSetElement(JSContext *cx, js::HandleObject obj,
+                                    js::HandleObject receiver, uint32_t index,
+                                    js::MutableHandleValue vp, JS::ObjectOpResult &result);
 
     static bool swap(JSContext *cx, JS::HandleObject a, JS::HandleObject b);
 
   private:
     void fixDictionaryShapeAfterSwap();
 
   public:
     inline void initArrayClass();
@@ -764,20 +764,16 @@ StandardDefineProperty(JSContext *cx, Ha
  * Same as above except without the ObjectOpResult out-parameter. Throws a
  * TypeError on failure.
  */
 extern bool
 StandardDefineProperty(JSContext *cx, HandleObject obj, HandleId id,
                        Handle<PropertyDescriptor> desc);
 
 extern bool
-DefineProperty(JSContext *cx, HandleObject obj, HandleId id,
-               Handle<PropertyDescriptor> desc, ObjectOpResult &result);
-
-extern bool
 DefineProperty(ExclusiveContext *cx, HandleObject obj, HandleId id, HandleValue value,
                JSGetterOp getter, JSSetterOp setter, unsigned attrs, ObjectOpResult &result);
 
 extern bool
 DefineProperty(ExclusiveContext *cx, HandleObject obj, PropertyName *name, HandleValue value,
                JSGetterOp getter, JSSetterOp setter, unsigned attrs, ObjectOpResult &result);
 
 extern bool
@@ -848,77 +844,77 @@ GetPropertyNoGC(JSContext *cx, JSObject 
 {
     return GetPropertyNoGC(cx, obj, receiver, NameToId(name), vp);
 }
 
 inline bool
 GetElementNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index, Value *vp);
 
 /*
- * ES6 [[Set]]. Carry out the assignment `obj[id] = v`.
+ * ES6 [[Set]]. Carry out the assignment `obj[id] = vp`.
  *
  * The `receiver` argument has to do with how [[Set]] interacts with the
  * prototype chain and proxies. It's hard to explain and ES6 doesn't really
- * try. Long story short, if you just want bog-standard assignment, pass
- * `ObjectValue(*obj)` as receiver. Or better, use one of the signatures that
- * doesn't have a receiver parameter.
+ * try. Long story short, if you just want bog-standard assignment, pass the
+ * same object as both obj and receiver.
  *
- * Callers pass obj != receiver e.g. when a proxy is involved, obj is the
- * proxy's target, and the proxy is using SetProperty to finish an assignment
- * that started out as `receiver[id] = v`, by delegating it to obj.
+ * When obj != receiver, it's a reasonable guess that a proxy is involved, obj
+ * is the proxy's target, and the proxy is using SetProperty to finish an
+ * 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, HandleId id, HandleValue v,
-            HandleValue receiver, ObjectOpResult &result);
+SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
+            MutableHandleValue vp, ObjectOpResult &result);
 
 inline bool
-SetProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue v)
+SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, PropertyName *name,
+            MutableHandleValue vp, ObjectOpResult &result)
 {
-    RootedValue receiver(cx, ObjectValue(*obj));
-    ObjectOpResult result;
-    return SetProperty(cx, obj, id, v, receiver, result) &&
-           result.checkStrict(cx, obj, id);
+    RootedId id(cx, NameToId(name));
+    return SetProperty(cx, obj, receiver, id, vp, result);
 }
 
 inline bool
-SetProperty(JSContext *cx, HandleObject obj, PropertyName *name, HandleValue v,
-            HandleValue receiver, ObjectOpResult &result)
-{
-    RootedId id(cx, NameToId(name));
-    return SetProperty(cx, obj, id, v, receiver, result);
-}
+SetElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index,
+           MutableHandleValue vp, ObjectOpResult &result);
 
 inline bool
-SetProperty(JSContext *cx, HandleObject obj, PropertyName *name, HandleValue v)
+SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
+            MutableHandleValue vp)
 {
-    RootedId id(cx, NameToId(name));
-    RootedValue receiver(cx, ObjectValue(*obj));
     ObjectOpResult result;
-    return SetProperty(cx, obj, id, v, receiver, result) &&
-           result.checkStrict(cx, obj, id);
+    return SetProperty(cx, obj, receiver, id, vp, result) &&
+           result.checkStrict(cx, receiver, id);
 }
 
-inline bool
-SetElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v,
-           HandleValue receiver, ObjectOpResult &result);
+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, HandleValue v, bool strict)
+PutProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue value, bool strict)
 {
-    RootedValue receiver(cx, ObjectValue(*obj));
     ObjectOpResult result;
-    return SetProperty(cx, obj, id, v, receiver, 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, HandleObject obj, HandleId id, ObjectOpResult &result);
 
 inline bool
 DeleteElement(JSContext *cx, HandleObject obj, uint32_t index, ObjectOpResult &result);
--- 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_, cx->names().lastIndex, zero);
+        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
@@ -112,17 +112,17 @@ class JS_FRIEND_API(CrossCompartmentWrap
                                                    bool aHasSecurityPolicy = false)
       : Wrapper(CROSS_COMPARTMENT | aFlags, aHasPrototype, aHasSecurityPolicy)
     { }
 
     /* Standard internal methods. */
     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
                                           MutableHandle<JSPropertyDescriptor> desc) const override;
     virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
-                                Handle<JSPropertyDescriptor> desc,
+                                MutableHandle<JSPropertyDescriptor> desc,
                                 ObjectOpResult &result) const override;
     virtual bool ownPropertyKeys(JSContext *cx, HandleObject wrapper,
                                  AutoIdVector &props) const override;
     virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id,
                          ObjectOpResult &result) const override;
     virtual bool enumerate(JSContext *cx, HandleObject wrapper, MutableHandleObject objp) const override;
     virtual bool getPrototype(JSContext *cx, HandleObject proxy,
                               MutableHandleObject protop) const override;
@@ -132,18 +132,18 @@ class JS_FRIEND_API(CrossCompartmentWrap
     virtual bool setImmutablePrototype(JSContext *cx, HandleObject proxy,
                                        bool *succeeded) const override;
     virtual bool preventExtensions(JSContext *cx, HandleObject wrapper,
                                    ObjectOpResult &result) const override;
     virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) const override;
     virtual bool has(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const override;
     virtual bool get(JSContext *cx, HandleObject wrapper, HandleObject receiver,
                      HandleId id, MutableHandleValue vp) const override;
-    virtual bool set(JSContext *cx, HandleObject wrapper, HandleId id, HandleValue v,
-                     HandleValue receiver, ObjectOpResult &result) const override;
+    virtual bool set(JSContext *cx, HandleObject wrapper, HandleObject receiver, HandleId id,
+                     MutableHandleValue vp, ObjectOpResult &result) const override;
     virtual bool call(JSContext *cx, HandleObject wrapper, const CallArgs &args) const override;
     virtual bool construct(JSContext *cx, HandleObject wrapper, const CallArgs &args) const override;
 
     /* SpiderMonkey extensions. */
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc) const override;
     virtual bool hasOwn(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const override;
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper,
@@ -180,17 +180,17 @@ class JS_FRIEND_API(SecurityWrapper) : p
     explicit MOZ_CONSTEXPR SecurityWrapper(unsigned flags, bool hasPrototype = false)
       : Base(flags, hasPrototype, /* hasSecurityPolicy = */ true)
     { }
 
     virtual bool enter(JSContext *cx, HandleObject wrapper, HandleId id, Wrapper::Action act,
                        bool *bp) const override;
 
     virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
-                                Handle<JSPropertyDescriptor> desc,
+                                MutableHandle<JSPropertyDescriptor> desc,
                                 ObjectOpResult &result) const override;
     virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) const override;
     virtual bool preventExtensions(JSContext *cx, HandleObject wrapper,
                                    ObjectOpResult &result) const override;
     virtual bool setPrototype(JSContext *cx, HandleObject proxy, HandleObject proto,
                               ObjectOpResult &result) const override;
     virtual bool setImmutablePrototype(JSContext *cx, HandleObject proxy, bool *succeeded) const override;
 
--- a/js/src/proxy/BaseProxyHandler.cpp
+++ b/js/src/proxy/BaseProxyHandler.cpp
@@ -56,113 +56,111 @@ BaseProxyHandler::get(JSContext *cx, Han
         return true;
     }
     MOZ_ASSERT(desc.getter() != JS_PropertyStub);
     if (!desc.getter()) {
         vp.set(desc.value());
         return true;
     }
     if (desc.hasGetterObject())
-        return InvokeGetter(cx, receiver, ObjectValue(*desc.getterObject()), vp);
+        return InvokeGetterOrSetter(cx, receiver, ObjectValue(*desc.getterObject()),
+                                    0, nullptr, vp);
     if (!desc.isShared())
         vp.set(desc.value());
     else
         vp.setUndefined();
 
     return CallJSGetterOp(cx, desc.getter(), receiver, id, vp);
 }
 
 bool
-BaseProxyHandler::set(JSContext *cx, HandleObject proxy, HandleId id, HandleValue v,
-                      HandleValue receiver, ObjectOpResult &result) const
+BaseProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
+                      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.)
     Rooted<PropertyDescriptor> ownDesc(cx);
     if (!getOwnPropertyDescriptor(cx, proxy, id, &ownDesc))
         return false;
 
     // The rest is factored out into a separate function with a weird name.
     // This algorithm continues just below.
-    return SetPropertyIgnoringNamedGetter(cx, proxy, id, v, receiver, ownDesc, result);
+    return SetPropertyIgnoringNamedGetter(cx, proxy, id, vp, receiver, &ownDesc, result);
 }
 
 bool
-js::SetPropertyIgnoringNamedGetter(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
-                                   HandleValue receiver, Handle<PropertyDescriptor> ownDesc_,
+js::SetPropertyIgnoringNamedGetter(JSContext *cx, HandleObject obj, HandleId id,
+                                   MutableHandleValue vp, HandleObject receiver,
+                                   MutableHandle<PropertyDescriptor> ownDesc,
                                    ObjectOpResult &result)
 {
-    Rooted<PropertyDescriptor> ownDesc(cx, ownDesc_);
-
     // 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, obj, &proto))
             return false;
         if (proto)
-            return SetProperty(cx, proto, id, v, receiver, result);
+            return SetProperty(cx, proto, receiver, id, vp, result);
 
-        // Step 4.d.
-        ownDesc.setDataDescriptor(UndefinedHandleValue, JSPROP_ENUMERATE);
+        // 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.
+        // Steps 5.a-b, adapted to our nonstandard implementation of ES6
+        // [[Set]] return values.
         if (!ownDesc.writable())
             return result.fail(JSMSG_READ_ONLY);
-        if (!receiver.isObject())
-            return result.fail(JSMSG_SET_NON_OBJECT_RECEIVER);
-        RootedObject receiverObj(cx, &receiver.toObject());
 
         // Nonstandard SpiderMonkey special case: setter ops.
         SetterOp setter = ownDesc.setter();
         MOZ_ASSERT(setter != JS_StrictPropertyStub);
-        if (setter && setter != JS_StrictPropertyStub) {
-            RootedValue valCopy(cx, v);
-            return CallJSSetterOp(cx, setter, receiverObj, id, &valCopy, result);
-        }
+        if (setter && setter != JS_StrictPropertyStub)
+            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, receiverObj, id, &existingDescriptor))
+        if (!HasOwnProperty(cx, receiver, id, &existingDescriptor))
             return false;
 
         // Steps 5.e-f.
         unsigned attrs =
             existingDescriptor
             ? 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 = receiverObj->getClass();
+        const Class *clasp = receiver->getClass();
         MOZ_ASSERT(clasp->getProperty != JS_PropertyStub);
         MOZ_ASSERT(clasp->setProperty != JS_StrictPropertyStub);
-        return DefineProperty(cx, receiverObj, id, v, clasp->getProperty, clasp->setProperty,
+        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 result.fail(JSMSG_GETTER_ONLY);
     RootedValue setterValue(cx, ObjectValue(*setter));
-    if (!InvokeSetter(cx, receiver, setterValue, v))
+    if (!InvokeGetterOrSetter(cx, receiver, setterValue, 1, vp.address(), vp))
         return false;
     return result.succeed();
 }
 
 bool
 BaseProxyHandler::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                                AutoIdVector &props) const
 {
--- a/js/src/proxy/CrossCompartmentWrapper.cpp
+++ b/js/src/proxy/CrossCompartmentWrapper.cpp
@@ -44,23 +44,23 @@ CrossCompartmentWrapper::getOwnPropertyD
     PIERCE(cx, wrapper,
            NOTHING,
            Wrapper::getOwnPropertyDescriptor(cx, wrapper, id, desc),
            cx->compartment()->wrap(cx, desc));
 }
 
 bool
 CrossCompartmentWrapper::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
-                                        Handle<PropertyDescriptor> desc,
+                                        MutableHandle<PropertyDescriptor> desc,
                                         ObjectOpResult &result) const
 {
     Rooted<PropertyDescriptor> desc2(cx, desc);
     PIERCE(cx, wrapper,
            cx->compartment()->wrap(cx, &desc2),
-           Wrapper::defineProperty(cx, wrapper, id, desc2, result),
+           Wrapper::defineProperty(cx, wrapper, id, &desc2, result),
            NOTHING);
 }
 
 bool
 CrossCompartmentWrapper::ownPropertyKeys(JSContext *cx, HandleObject wrapper,
                                          AutoIdVector &props) const
 {
     PIERCE(cx, wrapper,
@@ -164,25 +164,24 @@ 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, HandleId id, HandleValue v,
-                             HandleValue receiver, ObjectOpResult &result) const
+CrossCompartmentWrapper::set(JSContext *cx, HandleObject wrapper, HandleObject receiver,
+                             HandleId id, MutableHandleValue vp, ObjectOpResult &result) const
 {
-    RootedValue valCopy(cx, v);
-    RootedValue receiverCopy(cx, receiver);
+    RootedObject receiverCopy(cx, receiver);
     PIERCE(cx, wrapper,
-           cx->compartment()->wrap(cx, &valCopy) &&
-           cx->compartment()->wrap(cx, &receiverCopy),
-           Wrapper::set(cx, wrapper, id, valCopy, receiverCopy, result),
+           cx->compartment()->wrap(cx, &receiverCopy) &&
+           cx->compartment()->wrap(cx, 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/DeadObjectProxy.cpp
+++ b/js/src/proxy/DeadObjectProxy.cpp
@@ -27,17 +27,17 @@ DeadObjectProxy::getOwnPropertyDescripto
                                           MutableHandle<PropertyDescriptor> desc) const
 {
     JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
     return false;
 }
 
 bool
 DeadObjectProxy::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
-                                Handle<PropertyDescriptor> desc,
+                                MutableHandle<PropertyDescriptor> desc,
                                 ObjectOpResult &result) const
 {
     JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
     return false;
 }
 
 bool
 DeadObjectProxy::ownPropertyKeys(JSContext *cx, HandleObject wrapper,
--- a/js/src/proxy/DeadObjectProxy.h
+++ b/js/src/proxy/DeadObjectProxy.h
@@ -17,17 +17,17 @@ class DeadObjectProxy : public BaseProxy
     explicit MOZ_CONSTEXPR DeadObjectProxy()
       : BaseProxyHandler(&family)
     { }
 
     /* Standard internal methods. */
     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
                                           MutableHandle<JSPropertyDescriptor> desc) const override;
     virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
-                                Handle<JSPropertyDescriptor> desc,
+                                MutableHandle<JSPropertyDescriptor> desc,
                                 ObjectOpResult &result) const override;
     virtual bool ownPropertyKeys(JSContext *cx, HandleObject wrapper,
                                  AutoIdVector &props) const override;
     virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id,
                          ObjectOpResult &result) const override;
     virtual bool enumerate(JSContext *cx, HandleObject wrapper, MutableHandleObject objp) const override;
     virtual bool getPrototype(JSContext *cx, HandleObject proxy,
                               MutableHandleObject protop) const override;
--- a/js/src/proxy/DirectProxyHandler.cpp
+++ b/js/src/proxy/DirectProxyHandler.cpp
@@ -29,17 +29,17 @@ DirectProxyHandler::getOwnPropertyDescri
 {
     assertEnteredPolicy(cx, proxy, id, GET | SET | GET_PROPERTY_DESCRIPTOR);
     RootedObject target(cx, proxy->as<ProxyObject>().target());
     return GetOwnPropertyDescriptor(cx, target, id, desc);
 }
 
 bool
 DirectProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                                   Handle<PropertyDescriptor> desc,
+                                   MutableHandle<PropertyDescriptor> desc,
                                    ObjectOpResult &result) const
 {
     assertEnteredPolicy(cx, proxy, id, SET);
     RootedObject target(cx, proxy->as<ProxyObject>().target());
     return StandardDefineProperty(cx, target, id, desc, result);
 }
 
 bool
@@ -211,22 +211,22 @@ DirectProxyHandler::get(JSContext *cx, H
                         HandleId id, MutableHandleValue vp) const
 {
     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, HandleId id, HandleValue v,
-                        HandleValue receiver, ObjectOpResult &result) const
+DirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
+                        HandleId id, MutableHandleValue vp, ObjectOpResult &result) const
 {
     assertEnteredPolicy(cx, proxy, id, SET);
     RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return SetProperty(cx, target, id, v, receiver, result);
+    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
@@ -129,17 +129,17 @@ Proxy::getOwnPropertyDescriptor(JSContex
     AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET_PROPERTY_DESCRIPTOR, true);
     if (!policy.allowed())
         return policy.returnValue();
     return handler->getOwnPropertyDescriptor(cx, proxy, id, desc);
 }
 
 bool
 Proxy::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                      Handle<PropertyDescriptor> desc, ObjectOpResult &result)
+                      MutableHandle<PropertyDescriptor> desc, 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()) {
         if (!policy.returnValue())
             return false;
         return result.succeed();
@@ -302,33 +302,33 @@ Proxy::callProp(JSContext *cx, HandleObj
             return false;
     }
 #endif
 
     return true;
 }
 
 bool
-Proxy::set(JSContext *cx, HandleObject proxy, HandleId id, HandleValue v, HandleValue receiver,
-           ObjectOpResult &result)
+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()) {
         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, id, v, receiver, result);
+        return handler->BaseProxyHandler::set(cx, proxy, receiver, id, vp, result);
 
-    return handler->set(cx, proxy, id, v, receiver, result);
+    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);
@@ -554,41 +554,47 @@ js::proxy_LookupProperty(JSContext *cx, 
     } else {
         objp.set(nullptr);
         propp.set(nullptr);
     }
     return true;
 }
 
 bool
-js::proxy_DefineProperty(JSContext *cx, HandleObject obj, HandleId id,
-                         Handle<JSPropertyDescriptor> desc,
+js::proxy_DefineProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue value,
+                         GetterOp getter, SetterOp setter, unsigned attrs,
                          ObjectOpResult &result)
 {
-    return Proxy::defineProperty(cx, obj, id, desc, result);
+    Rooted<PropertyDescriptor> desc(cx);
+    desc.object().set(obj);
+    desc.value().set(value);
+    desc.setAttributes(attrs);
+    desc.setGetter(getter);
+    desc.setSetter(setter);
+    return Proxy::defineProperty(cx, obj, id, &desc, result);
 }
 
 bool
 js::proxy_HasProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool *foundp)
 {
     return Proxy::has(cx, obj, id, foundp);
 }
 
 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, HandleId id, HandleValue v,
-                      HandleValue receiver, ObjectOpResult &result)
+js::proxy_SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
+                      MutableHandleValue vp, ObjectOpResult &result)
 {
-    return Proxy::set(cx, obj, id, v, receiver, result);
+    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
@@ -24,31 +24,31 @@ class RegExpGuard;
  */
 class Proxy
 {
   public:
     /* Standard internal methods. */
     static bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                          MutableHandle<JSPropertyDescriptor> desc);
     static bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                               Handle<JSPropertyDescriptor> desc, ObjectOpResult &result);
+                               MutableHandle<JSPropertyDescriptor> desc, ObjectOpResult &result);
     static bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props);
     static bool delete_(JSContext *cx, HandleObject proxy, HandleId id, ObjectOpResult &result);
     static bool enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp);
     static bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible);
     static bool preventExtensions(JSContext *cx, HandleObject proxy, ObjectOpResult &result);
     static bool getPrototype(JSContext *cx, HandleObject proxy, MutableHandleObject protop);
     static bool setPrototype(JSContext *cx, HandleObject proxy, HandleObject proto,
                              ObjectOpResult &result);
     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, HandleId id, HandleValue v,
-                    HandleValue receiver, ObjectOpResult &result);
+    static bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
+                    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
@@ -545,17 +545,17 @@ ScriptedDirectProxyHandler::getOwnProper
     desc.set(resultDesc);
     desc.object().set(proxy);
     return true;
 }
 
 // ES6 draft rev 31 (15 Jan 2015) 9.5.6 Proxy.[[DefineOwnProperty]](P, Desc)
 bool
 ScriptedDirectProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                                           Handle<PropertyDescriptor> desc,
+                                           MutableHandle<PropertyDescriptor> desc,
                                            ObjectOpResult &result) const
 {
     // steps 2-4
     RootedObject handler(cx, GetDirectProxyHandlerObject(proxy));
     if (!handler) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED);
         return false;
     }
@@ -917,45 +917,45 @@ ScriptedDirectProxyHandler::get(JSContex
 
     // step 13
     vp.set(trapResult);
     return true;
 }
 
 // ES6 draft rev 32 (2015 Feb 2) 9.5.9 Proxy.[[Set]](P, V, Receiver)
 bool
-ScriptedDirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleId id, HandleValue v,
-                                HandleValue receiver, ObjectOpResult &result) const
+ScriptedDirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
+                                HandleId id, MutableHandleValue vp, ObjectOpResult &result) const
 {
     // step 2-3 (Steps 1 and 4 are irrelevant assertions.)
     RootedObject handler(cx, GetDirectProxyHandlerObject(proxy));
     if (!handler) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED);
         return false;
     }
 
     // step 5-7
     RootedObject target(cx, proxy->as<ProxyObject>().target());
     RootedValue trap(cx);
     if (!GetProperty(cx, handler, handler, cx->names().set, &trap))
         return false;
 
     // step 8
     if (trap.isUndefined())
-        return SetProperty(cx, target, id, v, receiver, result);
+        return SetProperty(cx, target, receiver, id, vp, result);
 
     // step 9-10
     RootedValue value(cx);
     if (!IdToStringOrSymbol(cx, id, &value))
         return false;
     Value argv[] = {
         ObjectOrNullValue(target),
         value,
-        v.get(),
-        receiver.get()
+        vp.get(),
+        ObjectValue(*receiver)
     };
     RootedValue trapResult(cx);
     if (!Invoke(cx, ObjectValue(*handler), trap, ArrayLength(argv), argv, &trapResult))
         return false;
 
     // step 11
     if (!ToBoolean(trapResult))
         return result.fail(JSMSG_PROXY_SET_RETURNED_FALSE);
@@ -964,17 +964,17 @@ ScriptedDirectProxyHandler::set(JSContex
     Rooted<PropertyDescriptor> desc(cx);
     if (!GetOwnPropertyDescriptor(cx, target, id, &desc))
         return false;
 
     // step 14
     if (desc.object()) {
         if (desc.isDataDescriptor() && !desc.configurable() && !desc.writable()) {
             bool same;
-            if (!SameValue(cx, v, desc.value(), &same))
+            if (!SameValue(cx, vp, desc.value(), &same))
                 return false;
             if (!same) {
                 JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_SET_NW_NC);
                 return false;
             }
         }
 
         if (desc.isAccessorDescriptor() && !desc.configurable() && desc.setterObject() == nullptr) {
--- a/js/src/proxy/ScriptedDirectProxyHandler.h
+++ b/js/src/proxy/ScriptedDirectProxyHandler.h
@@ -17,17 +17,17 @@ class ScriptedDirectProxyHandler : publi
     MOZ_CONSTEXPR ScriptedDirectProxyHandler()
       : BaseProxyHandler(&family)
     { }
 
     /* Standard internal methods. */
     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                           MutableHandle<JSPropertyDescriptor> desc) const override;
     virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                                Handle<JSPropertyDescriptor> desc,
+                                MutableHandle<JSPropertyDescriptor> desc,
                                 ObjectOpResult &result) const override;
     virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy,
                                  AutoIdVector &props) const override;
     virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id,
                          ObjectOpResult &result) const override;
     virtual bool enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp) const override;
 
     /* These two are standard internal methods but aren't implemented to spec yet. */
@@ -41,18 +41,18 @@ class ScriptedDirectProxyHandler : publi
 
     virtual bool preventExtensions(JSContext *cx, HandleObject proxy,
                                    ObjectOpResult &result) const override;
     virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const override;
 
     virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const override;
     virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
                      MutableHandleValue vp) const override;
-    virtual bool set(JSContext *cx, HandleObject proxy, HandleId id, HandleValue v,
-                     HandleValue receiver, ObjectOpResult &result) const override;
+    virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
+                     MutableHandleValue vp, ObjectOpResult &result) const override;
     virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const override;
     virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const override;
 
     /* SpiderMonkey extensions. */
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc) const override;
     virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const override {
         return BaseProxyHandler::hasOwn(cx, proxy, id, bp);
--- a/js/src/proxy/ScriptedIndirectProxyHandler.cpp
+++ b/js/src/proxy/ScriptedIndirectProxyHandler.cpp
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #include "proxy/ScriptedIndirectProxyHandler.h"
 
 #include "jsapi.h"
 #include "jscntxt.h"
 
-#include "jscntxtinlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 
 static bool
 GetFundamentalTrap(JSContext *cx, HandleObject handler, HandlePropertyName name,
                    MutableHandleValue fvalp)
 {
@@ -192,17 +191,17 @@ ScriptedIndirectProxyHandler::getOwnProp
            Trap1(cx, handler, fval, id, &value) &&
            ((value.isUndefined() && IndicatePropertyNotFound(desc)) ||
             (ReturnedValueMustNotBePrimitive(cx, proxy, cx->names().getPropertyDescriptor, value) &&
              ObjectToCompletePropertyDescriptor(cx, proxy, value, desc)));
 }
 
 bool
 ScriptedIndirectProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                                             Handle<PropertyDescriptor> desc,
+                                             MutableHandle<PropertyDescriptor> desc,
                                              ObjectOpResult &result) const
 {
     RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
     RootedValue fval(cx), value(cx);
     return GetFundamentalTrap(cx, handler, cx->names().defineProperty, &fval) &&
            FromPropertyDescriptor(cx, desc, &value) &&
            Trap2(cx, handler, fval, id, value, &value) &&
            result.succeed();
@@ -299,65 +298,40 @@ ScriptedIndirectProxyHandler::get(JSCont
     if (!GetDerivedTrap(cx, handler, cx->names().get, &fval))
         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, HandleId id, HandleValue v,
-                                  HandleValue receiver, ObjectOpResult &result) const
+ScriptedIndirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
+                                  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].set(receiver);
+    argv[0].setObjectOrNull(receiver);
     argv[1].set(idv);
-    argv[2].set(v);
+    argv[2].set(vp);
     RootedValue fval(cx);
     if (!GetDerivedTrap(cx, handler, cx->names().set, &fval))
         return false;
     if (!IsCallable(fval))
-        return derivedSet(cx, proxy, id, v, receiver, result);
+        return derivedSet(cx, proxy, receiver, id, vp, result);
     if (!Trap(cx, handler, fval, 3, argv.begin(), &idv))
         return false;
     return result.succeed();
 }
 
-static bool
-CallSetter(JSContext *cx, HandleValue receiver, HandleId id, SetterOp op, unsigned attrs,
-           HandleValue v, ObjectOpResult &result)
-{
-    if (attrs & JSPROP_SETTER) {
-        RootedValue fval(cx, CastAsObjectJsval(op));
-        if (!InvokeSetter(cx, receiver, fval, v))
-            return false;
-        return result.succeed();
-    }
-
-    if (attrs & JSPROP_GETTER)
-        return result.fail(JSMSG_GETTER_ONLY);
-
-    if (!receiver.isObject())
-        return result.fail(JSMSG_SET_NON_OBJECT_RECEIVER);
-    RootedObject receiverObj(cx, &receiver.toObject());
-
-    if (!op)
-        return result.succeed();
-
-    RootedValue valCopy(cx, v);
-    return CallJSSetterOp(cx, op, receiverObj, id, &valCopy, result);
-}
-
 bool
-ScriptedIndirectProxyHandler::derivedSet(JSContext *cx, HandleObject proxy, HandleId id,
-                                         HandleValue v, HandleValue receiver,
+ScriptedIndirectProxyHandler::derivedSet(JSContext *cx, HandleObject proxy, HandleObject receiver,
+                                         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.
     //
     // As of March 2015, testing/specialpowers/content/specialpowersAPI.js
     // depends on the call to getPropertyDescriptor below, because it does
@@ -378,42 +352,43 @@ ScriptedIndirectProxyHandler::derivedSet
         MOZ_ASSERT(desc.getter() != JS_PropertyStub);
         MOZ_ASSERT(desc.setter() != JS_StrictPropertyStub);
 
         // Check for read-only properties.
         if (desc.isDataDescriptor() && !desc.writable())
             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(), v, result))
+            if (!CallSetter(cx, receiver, id, desc.setter(), desc.attributes(), vp, result))
                 return false;
             if (!result)
                 return true;
             if (!proxy->is<ProxyObject>() ||
                 proxy->as<ProxyObject>().handler() != this ||
                 desc.isShared())
             {
                 return result.succeed();
             }
         }
-        desc.value().set(v);
+        desc.value().set(vp.get());
 
         if (descIsOwn) {
             MOZ_ASSERT(desc.object() == proxy);
-            return this->defineProperty(cx, proxy, id, desc, result);
+            return this->defineProperty(cx, proxy, id, &desc, result);
         }
-    } else {
-        desc.setDataDescriptor(v, JSPROP_ENUMERATE);
+        return DefineProperty(cx, receiver, id, desc.value(), desc.getter(), desc.setter(),
+                              desc.attributes(), result);
     }
-
-    if (!receiver.isObject())
-        return result.fail(JSMSG_SET_NON_OBJECT_RECEIVER);
-    RootedObject receiverObj(cx, &receiver.toObject());
-    desc.object().set(receiverObj);
-    return DefineProperty(cx, receiverObj, id, desc, 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,
+                          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
@@ -18,50 +18,50 @@ class ScriptedIndirectProxyHandler : pub
     MOZ_CONSTEXPR ScriptedIndirectProxyHandler()
       : BaseProxyHandler(&family)
     { }
 
     /* Standard internal methods. */
     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                           MutableHandle<JSPropertyDescriptor> desc) const override;
     virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                                Handle<JSPropertyDescriptor> desc,
+                                MutableHandle<JSPropertyDescriptor> desc,
                                 ObjectOpResult &result) const override;
     virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy,
                                  AutoIdVector &props) const override;
     virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id,
                          ObjectOpResult &result) const override;
     virtual bool enumerate(JSContext *cx, HandleObject proxy,
                            MutableHandleObject objp) const override;
     virtual bool preventExtensions(JSContext *cx, HandleObject proxy,
                                    ObjectOpResult &result) const override;
     virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const override;
     virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const override;
     virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
                      MutableHandleValue vp) const override;
-    virtual bool set(JSContext *cx, HandleObject proxy, HandleId id, HandleValue v,
-                     HandleValue receiver, ObjectOpResult &result) const override;
+    virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
+                     MutableHandleValue vp, ObjectOpResult &result) const override;
 
     /* SpiderMonkey extensions. */
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc) const override;
     virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const override;
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                               AutoIdVector &props) const override;
     virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
                             CallArgs args) const override;
     virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const override;
     virtual bool isScripted() const override { return true; }
 
     static const char family;
     static const ScriptedIndirectProxyHandler singleton;
 
 private:
-    bool derivedSet(JSContext *cx, HandleObject proxy, HandleId id, HandleValue v,
-                    HandleValue receiver, ObjectOpResult &result) const;
+    bool derivedSet(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
+                    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 override;
--- a/js/src/proxy/SecurityWrapper.cpp
+++ b/js/src/proxy/SecurityWrapper.cpp
@@ -98,18 +98,18 @@ bool
 SecurityWrapper<Base>::boxedValue_unbox(JSContext *cx, HandleObject obj, MutableHandleValue vp) const
 {
     vp.setUndefined();
     return true;
 }
 
 template <class Base>
 bool
-SecurityWrapper<Base>::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
-                                      Handle<PropertyDescriptor> desc,
+SecurityWrapper<Base>::defineProperty(JSContext *cx, HandleObject wrapper,
+                                      HandleId id, MutableHandle<PropertyDescriptor> desc,
                                       ObjectOpResult &result) const
 {
     if (desc.getter() || desc.setter()) {
         RootedValue idVal(cx, IdToValue(id));
         JSString *str = ValueToSource(cx, idVal);
         if (!str)
             return false;
         AutoStableStringChars chars(cx);
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -7632,17 +7632,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, id, v))
+        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
@@ -607,17 +607,21 @@ class GlobalObject : public NativeObject
     bool addIntrinsicValue(JSContext *cx, HandleId id, HandleValue value);
 
     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());
-        return SetProperty(cx, holder, name, value);
+        RootedValue valCopy(cx, value);
+        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
@@ -303,45 +303,46 @@ SetNameOperation(JSContext *cx, JSScript
                *pc == JSOP_STRICTSETNAME ||
                *pc == JSOP_SETGNAME ||
                *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, 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));
-    RootedValue receiver(cx, ObjectValue(*scope));
     if (scope->isUnqualifiedVarObj()) {
         MOZ_ASSERT(!scope->getOps()->setProperty);
-        ok = NativeSetProperty(cx, scope.as<NativeObject>(), id, val, receiver, Unqualified,
-                               result);
+        ok = NativeSetProperty(cx, scope.as<NativeObject>(), scope.as<NativeObject>(), id,
+                               Unqualified, &valCopy, result);
     } else {
-        ok = SetProperty(cx, scope, id, val, receiver, result);
+        ok = SetProperty(cx, scope, scope, id, &valCopy, result);
     }
     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));
-    return PutProperty(cx, obj, id, rhs, false);
+    RootedValue v(cx, rhs);
+    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
@@ -308,30 +308,62 @@ GetNameOperation(JSContext *cx, Interpre
     /* Kludge to allow (typeof foo == "undefined") tests. */
     JSOp op2 = JSOp(pc[JSOP_GETNAME_LENGTH]);
     if (op2 == JSOP_TYPEOF)
         return FetchName<true>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp);
     return FetchName<false>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp);
 }
 
 static bool
-SetPropertyOperation(JSContext *cx, JSOp op, HandleValue lval, HandleId id, HandleValue rval)
+SetObjectProperty(JSContext *cx, JSOp op, HandleValue lval, HandleId id, MutableHandleValue rref)
 {
-    MOZ_ASSERT(op == JSOP_SETPROP || op == JSOP_STRICTSETPROP);
+    MOZ_ASSERT(lval.isObject());
+
+    RootedObject obj(cx, &lval.toObject());
+
+    ObjectOpResult result;
+    if (MOZ_LIKELY(!obj->getOps()->setProperty)) {
+        if (!NativeSetProperty(cx, obj.as<NativeObject>(), obj.as<NativeObject>(), id,
+                               Qualified, rref, result))
+        {
+            return false;
+        }
+    } else {
+        if (!SetProperty(cx, obj, obj, id, rref, result))
+            return false;
+    }
+
+    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());
 
     RootedObject obj(cx, ToObjectFromStack(cx, lval));
     if (!obj)
         return false;
 
-    // Note: ES6 specifies that the value lval, not obj, is passed as receiver
-    // to obj's [[Set]] internal method. See bug 603201.
     RootedValue receiver(cx, ObjectValue(*obj));
-    ObjectOpResult result;
-    return SetProperty(cx, obj, id, rval, receiver, result) &&
-           result.checkStrictErrorOrWarning(cx, obj, id, op == JSOP_STRICTSETPROP);
+    return SetObjectProperty(cx, op, receiver, id, rref);
+}
+
+static bool
+SetPropertyOperation(JSContext *cx, JSOp op, HandleValue lval, HandleId id, HandleValue rval)
+{
+    MOZ_ASSERT(op == JSOP_SETPROP || op == JSOP_STRICTSETPROP);
+
+    RootedValue rref(cx, rval);
+
+    if (lval.isPrimitive())
+        return SetPrimitiveProperty(cx, op, lval, id, &rref);
+
+    return SetObjectProperty(cx, op, lval, id, &rref);
 }
 
 bool
 js::ReportIsNotFunction(JSContext *cx, HandleValue v, int numToSkip, MaybeConstruct construct)
 {
     unsigned error = construct ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION;
     int spIndex = numToSkip >= 0 ? -(numToSkip + 1) : JSDVG_SEARCH_STACK;
 
@@ -579,34 +611,26 @@ js::InvokeConstructor(JSContext *cx, Val
     if (!InvokeConstructor(cx, args))
         return false;
 
     rval.set(args.rval());
     return true;
 }
 
 bool
-js::InvokeGetter(JSContext *cx, JSObject *obj, Value fval, MutableHandleValue rval)
+js::InvokeGetterOrSetter(JSContext *cx, JSObject *obj, Value fval, unsigned argc,
+                         Value *argv, MutableHandleValue rval)
 {
     /*
      * Invoke could result in another try to get or set the same id again, see
      * bug 355497.
      */
     JS_CHECK_RECURSION(cx, return false);
 
-    return Invoke(cx, ObjectValue(*obj), fval, 0, nullptr, rval);
-}
-
-bool
-js::InvokeSetter(JSContext *cx, const Value &thisv, Value fval, HandleValue v)
-{
-    JS_CHECK_RECURSION(cx, return false);
-
-    RootedValue ignored(cx);
-    return Invoke(cx, thisv, fval, 1, v.address(), &ignored);
+    return Invoke(cx, ObjectValue(*obj), fval, argc, argv, rval);
 }
 
 bool
 js::ExecuteKernel(JSContext *cx, HandleScript script, JSObject &scopeChainArg, const Value &thisv,
                   ExecuteType type, AbstractFramePtr evalInFrame, Value *result)
 {
     MOZ_ASSERT_IF(evalInFrame, type == EXECUTE_DEBUG);
     MOZ_ASSERT_IF(type == EXECUTE_GLOBAL, !IsSyntacticScope(&scopeChainArg));
@@ -1374,17 +1398,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 PutProperty(cx, 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
@@ -3856,18 +3880,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. */
-    RootedId id(cx, NameToId(name));
-    return PutProperty(cx, parent, id, 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/Interpreter.h
+++ b/js/src/vm/Interpreter.h
@@ -71,24 +71,22 @@ Invoke(JSContext *cx, CallArgs args, May
  * called at any time and it takes care of copying the given callee, this, and
  * arguments onto the stack.
  */
 extern bool
 Invoke(JSContext *cx, const Value &thisv, const Value &fval, unsigned argc, const Value *argv,
        MutableHandleValue rval);
 
 /*
- * These helpers take care of the infinite-recursion check necessary for
+ * This helper takes care of the infinite-recursion check necessary for
  * getter/setter calls.
  */
 extern bool
-InvokeGetter(JSContext *cx, JSObject *obj, Value fval, MutableHandleValue rval);
-
-extern bool
-InvokeSetter(JSContext *cx, const Value &thisv, Value fval, HandleValue v);
+InvokeGetterOrSetter(JSContext *cx, JSObject *obj, Value fval, unsigned argc, Value *argv,
+                     MutableHandleValue rval);
 
 /*
  * InvokeConstructor implement a function call from a constructor context
  * (e.g. 'new') handling the the creation of the new 'this' object.
  */
 extern bool
 InvokeConstructor(JSContext *cx, CallArgs args);
 
--- a/js/src/vm/NativeObject-inl.h
+++ b/js/src/vm/NativeObject-inl.h
@@ -68,28 +68,30 @@ NativeObject::setShouldConvertDoubleElem
 inline void
 NativeObject::clearShouldConvertDoubleElements()
 {
     MOZ_ASSERT(is<ArrayObject>() && !hasEmptyElements());
     getElementsHeader()->clearShouldConvertDoubleElements();
 }
 
 inline void
-NativeObject::setDenseElementWithType(ExclusiveContext *cx, uint32_t index, const Value &val)
+NativeObject::setDenseElementWithType(ExclusiveContext *cx, uint32_t index,
+                                      const Value &val)
 {
     // Avoid a slow AddTypePropertyId call if the type is the same as the type
     // of the previous element.
     TypeSet::Type thisType = TypeSet::GetValueType(val);
     if (index == 0 || TypeSet::GetValueType(elements_[index - 1]) != thisType)
         AddTypePropertyId(cx, this, JSID_VOID, thisType);
     setDenseElementMaybeConvertDouble(index, val);
 }
 
 inline void
-NativeObject::initDenseElementWithType(ExclusiveContext *cx, uint32_t index, const Value &val)
+NativeObject::initDenseElementWithType(ExclusiveContext *cx, uint32_t index,
+                                       const Value &val)
 {
     MOZ_ASSERT(!shouldConvertDoubleElements());
     AddTypePropertyId(cx, this, JSID_VOID, val);
     initDenseElement(index, val);
 }
 
 inline void
 NativeObject::setDenseElementHole(ExclusiveContext *cx, uint32_t index)
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -976,69 +976,16 @@ NativeObject::addDataProperty(ExclusiveC
                           uint32_t slot, unsigned attrs)
 {
     MOZ_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
     RootedNativeObject self(cx, this);
     RootedId id(cx, NameToId(name));
     return addProperty(cx, self, id, nullptr, nullptr, slot, attrs, 0);
 }
 
-template <AllowGC allowGC>
-bool
-js::NativeLookupOwnProperty(ExclusiveContext *cx,
-                            typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
-                            typename MaybeRooted<jsid, allowGC>::HandleType id,
-                            typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
-{
-    bool done;
-    return LookupOwnPropertyInline<allowGC>(cx, obj, id, propp, &done);
-}
-
-template bool
-js::NativeLookupOwnProperty<CanGC>(ExclusiveContext *cx, HandleNativeObject obj, HandleId id,
-                                   MutableHandleShape propp);
-
-template bool
-js::NativeLookupOwnProperty<NoGC>(ExclusiveContext *cx, NativeObject *obj, jsid id,
-                                  FakeMutableHandle<Shape*> propp);
-
-template <AllowGC allowGC>
-bool
-js::NativeLookupProperty(ExclusiveContext *cx,
-                         typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
-                         typename MaybeRooted<jsid, allowGC>::HandleType id,
-                         typename MaybeRooted<JSObject*, allowGC>::MutableHandleType objp,
-                         typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
-{
-    return LookupPropertyInline<allowGC>(cx, obj, id, objp, propp);
-}
-
-template bool
-js::NativeLookupProperty<CanGC>(ExclusiveContext *cx, HandleNativeObject obj, HandleId id,
-                                MutableHandleObject objp, MutableHandleShape propp);
-
-template bool
-js::NativeLookupProperty<NoGC>(ExclusiveContext *cx, NativeObject *obj, jsid id,
-                               FakeMutableHandle<JSObject*> objp,
-                               FakeMutableHandle<Shape*> propp);
-
-bool
-js::NativeLookupElement(JSContext *cx, HandleNativeObject obj, uint32_t index,
-                        MutableHandleObject objp, MutableHandleShape propp)
-{
-    RootedId id(cx);
-    if (!IndexToId(cx, index, &id))
-        return false;
-
-    return LookupPropertyInline<CanGC>(cx, obj, id, objp, propp);
-}
-
-
-/*** [[DefineOwnProperty]] ***********************************************************************/
-
 /*
  * Backward compatibility requires allowing addProperty hooks to mutate the
  * nominal initial value of a slotful property, while GC safety wants that
  * value to be stored before the call-out through the hook.  Optimize to do
  * both while saving cycles for classes that stub their addProperty hook.
  */
 static inline bool
 CallAddPropertyHook(ExclusiveContext *cx, HandleNativeObject obj, HandleShape shape,
@@ -1125,18 +1072,18 @@ UpdateShapeTypeAndValue(ExclusiveContext
     if (!shape->hasSlot() || !shape->hasDefaultGetter() || !shape->hasDefaultSetter())
         MarkTypePropertyNonData(cx, obj, id);
     if (!shape->writable())
         MarkTypePropertyNonWritable(cx, obj, id);
     return true;
 }
 
 static bool
-NativeSetExistingDataProperty(JSContext *cx, HandleNativeObject obj, HandleShape shape,
-                              HandleValue v, HandleValue receiver, ObjectOpResult &result);
+NativeSet(JSContext *cx, HandleNativeObject obj, HandleObject receiver,
+          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);
@@ -1215,23 +1162,20 @@ DefinePropertyOrElement(ExclusiveContext
             return result.succeed();
         }
     }
 
     if (!CallAddPropertyHook(cx, obj, shape, value))
         return false;
 
     if (callSetterAfterwards && setter) {
-        MOZ_ASSERT(!(attrs & JSPROP_GETTER));
-        MOZ_ASSERT(!(attrs & JSPROP_SETTER));
         if (!cx->shouldBeJSContext())
             return false;
-        RootedValue receiver(cx, ObjectValue(*obj));
-        return NativeSetExistingDataProperty(cx->asJSContext(), obj, shape, value, receiver,
-                                             result);
+        RootedValue nvalue(cx, value);
+        return NativeSet(cx->asJSContext(), obj, obj, shape, &nvalue, result);
     }
 
     return result.succeed();
 }
 
 static unsigned
 ApplyOrDefaultAttributes(unsigned attrs, const Shape *shape = nullptr)
 {
@@ -1336,37 +1280,36 @@ CheckAccessorRedefinition(ExclusiveConte
 
     if (!cx->isJSContext())
         return false;
 
     return Throw(cx->asJSContext(), id, JSMSG_CANT_REDEFINE_PROP);
 }
 
 bool
-js::NativeDefineProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId id,
-                         Handle<JSPropertyDescriptor> desc,
+js::NativeDefineProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId id, HandleValue value,
+                         GetterOp getter, SetterOp setter, unsigned attrs,
                          ObjectOpResult &result)
 {
-    GetterOp getter = desc.getter();
-    SetterOp setter = desc.setter();
-    unsigned attrs = desc.attributes();
     MOZ_ASSERT(getter != JS_PropertyStub);
     MOZ_ASSERT(setter != JS_StrictPropertyStub);
     MOZ_ASSERT(!(attrs & JSPROP_PROPOP_ACCESSORS));
 
+    AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
+
     RootedShape shape(cx);
-    RootedValue updateValue(cx, desc.value());
+    RootedValue updateValue(cx, value);
     bool shouldDefine = true;
 
     /*
      * If defining a getter or setter, we must check for its counterpart and
      * update the attributes and property ops.  A getter or setter is really
      * only half of a property.
      */
-    if (desc.isAccessorDescriptor()) {
+    if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
         if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &shape))
             return false;
         if (shape) {
             /*
              * If we are defining a getter whose setter was already defined, or
              * vice versa, finish the job via obj->changeProperty.
              */
             if (IsImplicitDenseOrTypedArrayElement(shape)) {
@@ -1390,17 +1333,17 @@ js::NativeDefineProperty(ExclusiveContex
                                                      (attrs & JSPROP_SETTER)
                                                      ? setter
                                                      : shape->setter());
                 if (!shape)
                     return false;
                 shouldDefine = false;
             }
         }
-    } else if (desc.hasValue()) {
+    } else if (!(attrs & JSPROP_IGNORE_VALUE)) {
         // If we did a normal lookup here, it would cause resolve hook recursion in
         // the following case. Suppose the first script we run in a lazy global is
         // |parseInt()|.
         //   - js::InitNumberClass is called to resolve parseInt.
         //   - js::InitNumberClass tries to define the Number constructor on the
         //     global.
         //   - We end up here.
         //   - This lookup for 'Number' triggers the global resolve hook.
@@ -1452,18 +1395,18 @@ js::NativeDefineProperty(ExclusiveContex
                 !CheckAccessorRedefinition(cx, obj, shape, getter, setter, id, attrs))
             {
                 return false;
             }
 
             attrs = ApplyOrDefaultAttributes(attrs, shape);
 
             if (shape->isAccessorDescriptor() && !(attrs & JSPROP_IGNORE_READONLY)) {
-                // ES6 draft 2014-10-14 9.1.6.3 step 7.c: Since [[Writable]]
-                // is present, change the existing accessor property to a data
+                // ES6 draft 2014-10-14 9.1.6.3 step 7.c: Since [[Writable]] 
+                // is present, change the existing accessor property to a data 
                 // property.
                 updateValue = UndefinedValue();
             } else {
                 // We are at most changing some attributes, and cannot convert
                 // from data descriptor to accessor, or vice versa. Take
                 // everything from the shape that we aren't changing.
                 uint32_t propMask = JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT;
                 attrs = (shape->attributes() & ~propMask) | (attrs & propMask);
@@ -1495,39 +1438,79 @@ js::NativeDefineProperty(ExclusiveContex
 
     JS_ALWAYS_TRUE(UpdateShapeTypeAndValue(cx, obj, shape, updateValue));
 
     if (!CallAddPropertyHook(cx, obj, shape, updateValue))
         return false;
     return result.succeed();
 }
 
+template <AllowGC allowGC>
 bool
-js::NativeDefineProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId id,
-                         HandleValue value, GetterOp getter, SetterOp setter, unsigned attrs,
-                         ObjectOpResult &result)
+js::NativeLookupOwnProperty(ExclusiveContext *cx,
+                            typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
+                            typename MaybeRooted<jsid, allowGC>::HandleType id,
+                            typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
 {
-    Rooted<PropertyDescriptor> desc(cx);
-    desc.initFields(obj, value, attrs, getter, setter);
-    return NativeDefineProperty(cx, obj, id, desc, result);
+    bool done;
+    return LookupOwnPropertyInline<allowGC>(cx, obj, id, propp, &done);
+}
+
+template bool
+js::NativeLookupOwnProperty<CanGC>(ExclusiveContext *cx, HandleNativeObject obj, HandleId id,
+                                   MutableHandleShape propp);
+
+template bool
+js::NativeLookupOwnProperty<NoGC>(ExclusiveContext *cx, NativeObject *obj, jsid id,
+                                  FakeMutableHandle<Shape*> propp);
+
+template <AllowGC allowGC>
+bool
+js::NativeLookupProperty(ExclusiveContext *cx,
+                         typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
+                         typename MaybeRooted<jsid, allowGC>::HandleType id,
+                         typename MaybeRooted<JSObject*, allowGC>::MutableHandleType objp,
+                         typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
+{
+    return LookupPropertyInline<allowGC>(cx, obj, id, objp, propp);
+}
+
+template bool
+js::NativeLookupProperty<CanGC>(ExclusiveContext *cx, HandleNativeObject obj, HandleId id,
+                                MutableHandleObject objp, MutableHandleShape propp);
+
+template bool
+js::NativeLookupProperty<NoGC>(ExclusiveContext *cx, NativeObject *obj, jsid id,
+                               FakeMutableHandle<JSObject*> objp,
+                               FakeMutableHandle<Shape*> propp);
+
+bool
+js::NativeLookupElement(JSContext *cx, HandleNativeObject obj, uint32_t index,
+                        MutableHandleObject objp, MutableHandleShape propp)
+{
+    RootedId id(cx);
+    if (!IndexToId(cx, index, &id))
+        return false;
+
+    return LookupPropertyInline<CanGC>(cx, obj, id, objp, propp);
 }
 
 bool
 js::NativeDefineProperty(ExclusiveContext *cx, HandleNativeObject obj, PropertyName *name,
-                         HandleValue value, GetterOp getter, SetterOp setter, unsigned attrs,
-                         ObjectOpResult &result)
+                         HandleValue value, GetterOp getter, SetterOp setter,
+                         unsigned attrs, ObjectOpResult &result)
 {
     RootedId id(cx, NameToId(name));
     return NativeDefineProperty(cx, obj, id, value, getter, setter, attrs, result);
 }
 
 bool
 js::NativeDefineElement(ExclusiveContext *cx, HandleNativeObject obj, uint32_t index,
-                        HandleValue value, GetterOp getter, SetterOp setter, unsigned attrs,
-                        ObjectOpResult &result)
+                        HandleValue value, GetterOp getter, SetterOp setter,
+                        unsigned attrs, ObjectOpResult &result)
 {
     RootedId id(cx);
     if (index <= JSID_INT_MAX) {
         id = INT_TO_JSID(index);
         return NativeDefineProperty(cx, obj, id, value, getter, setter, attrs, result);
     }
 
     AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
@@ -1562,17 +1545,16 @@ bool
 js::NativeDefineProperty(ExclusiveContext *cx, HandleNativeObject obj, PropertyName *name,
                          HandleValue value, JSGetterOp getter, JSSetterOp setter,
                          unsigned attrs)
 {
     RootedId id(cx, NameToId(name));
     return NativeDefineProperty(cx, obj, id, value, getter, setter, attrs);
 }
 
-
 /*** [[HasProperty]] *****************************************************************************/
 
 // ES6 draft rev31 9.1.7.1 OrdinaryHasProperty
 bool
 js::NativeHasProperty(JSContext *cx, HandleNativeObject obj, HandleId id, bool *foundp)
 {
     RootedNativeObject pobj(cx, obj);
     RootedShape shape(cx);
@@ -1615,27 +1597,26 @@ js::NativeHasProperty(JSContext *cx, Han
         // that optimization would be incorrect.
         if (!proto->isNative())
             return HasProperty(cx, proto, id, foundp);
 
         pobj = &proto->as<NativeObject>();
     }
 }
 
-
 /*** [[Get]] *************************************************************************************/
 
 static inline bool
 CallGetter(JSContext* cx, HandleObject receiver, HandleShape shape, MutableHandleValue vp)
 {
     MOZ_ASSERT(!shape->hasDefaultGetter());
 
     if (shape->hasGetterValue()) {
         Value fval = shape->getterValue();
-        return InvokeGetter(cx, receiver, fval, vp);
+        return InvokeGetterOrSetter(cx, receiver, fval, 0, 0, vp);
     }
 
     RootedId id(cx, shape->propid());
     return CallJSGetterOp(cx, shape->getterOp(), receiver, id, vp);
 }
 
 template <AllowGC allowGC>
 static MOZ_ALWAYS_INLINE bool
@@ -1941,17 +1922,16 @@ js::NativeGetPropertyNoGC(JSContext *cx,
 bool
 js::GetPropertyForNameLookup(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
 {
     if (obj->getOps()->getProperty)
         return GeneralizedGetProperty(cx, obj, id, obj, NameLookup, vp);
     return NativeGetPropertyInline<CanGC>(cx, obj.as<NativeObject>(), obj, id, NameLookup, vp);
 }
 
-
 /*** [[Set]] *************************************************************************************/
 
 static bool
 MaybeReportUndeclaredVarAssignment(JSContext *cx, JSString *propname)
 {
     {
         jsbytecode *pc;
         JSScript *script = cx->currentScript(&pc, JSContext::ALLOW_CROSS_COMPARTMENT);
@@ -1973,28 +1953,23 @@ MaybeReportUndeclaredVarAssignment(JSCon
                                         JSMSG_UNDECLARED_VAR, bytes.ptr());
 }
 
 /*
  * When a [[Set]] operation finds no existing property with the given id
  * 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.b-f, but it
+ * 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, HandleId id, HandleValue v,
-                          HandleValue receiverValue, bool objHasOwn, ObjectOpResult &result)
+js::SetPropertyByDefining(JSContext *cx, HandleObject obj, HandleObject receiver,
+                          HandleId id, HandleValue v, bool objHasOwn, ObjectOpResult &result)
 {
-    // Step 5.b.
-    if (!receiverValue.isObject())
-        return result.fail(JSMSG_SET_NON_OBJECT_RECEIVER);
-    RootedObject receiver(cx, &receiverValue.toObject());
-
     // 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
         // on obj and passed us the answer as objHasOwn.
@@ -2037,69 +2012,69 @@ js::SetPropertyByDefining(JSContext *cx,
         : 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, result);
 
-    // If the receiver is native, there is one more legacy wrinkle: the class
-    // JSSetterOp is called after defining the new property.
     Rooted<NativeObject*> nativeReceiver(cx, &receiver->as<NativeObject>());
     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, HandleId id, HandleValue v,
-                       HandleValue receiver, ObjectOpResult &result)
+js::SetPropertyOnProto(JSContext *cx, HandleObject obj, HandleObject receiver,
+                       HandleId id, MutableHandleValue vp, ObjectOpResult &result)
 {
     MOZ_ASSERT(!obj->is<ProxyObject>());
 
     RootedObject proto(cx, obj->getProto());
     if (proto)
-        return SetProperty(cx, proto, id, v, receiver, result);
-    return SetPropertyByDefining(cx, obj, id, v, receiver, false, result);
+        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, HandleId id, HandleValue v,
-                       HandleValue receiver, QualifiedBool qualified, ObjectOpResult &result)
+SetNonexistentProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiver, HandleId id,
+                       QualifiedBool qualified, HandleValue v, ObjectOpResult &result)
 {
     // We should never add properties to lexical blocks.
-    MOZ_ASSERT_IF(receiver.isObject(), !receiver.toObject().is<BlockObject>());
+    MOZ_ASSERT(!receiver->is<BlockObject>());
 
-    if (!qualified && receiver.isObject() && receiver.toObject().isUnqualifiedVarObj()) {
+    if (receiver->isUnqualifiedVarObj() && !qualified) {
         if (!MaybeReportUndeclaredVarAssignment(cx, JSID_TO_STRING(id)))
             return false;
     }
 
-    return SetPropertyByDefining(cx, obj, id, v, receiver, false, result);
+    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, HandleValue v,
-                            ObjectOpResult &result)
+SetDenseOrTypedArrayElement(JSContext *cx, HandleNativeObject obj, uint32_t index,
+                            MutableHandleValue vp, ObjectOpResult &result)
 {
     if (IsAnyTypedArray(obj)) {
         double d;
-        if (!ToNumber(cx, v, &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>())
@@ -2111,224 +2086,200 @@ SetDenseOrTypedArrayElement(JSContext *c
     }
 
     if (WouldDefinePastNonwritableLength(obj, index))
         return result.fail(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
 
     if (!obj->maybeCopyElementsForWrite(cx))
         return false;
 
-    obj->setDenseElementWithType(cx, index, v);
+    obj->setDenseElementWithType(cx, index, vp);
     return result.succeed();
 }
 
 /*
- * Finish assignment to a shapeful data property of a native object obj. This
+ * 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
-NativeSetExistingDataProperty(JSContext *cx, HandleNativeObject obj, HandleShape shape,
-                              HandleValue v, HandleValue receiver, ObjectOpResult &result)
+NativeSet(JSContext *cx, HandleNativeObject obj, HandleObject receiver,
+          HandleShape shape, MutableHandleValue vp, ObjectOpResult &result)
 {
     MOZ_ASSERT(obj->isNative());
-    MOZ_ASSERT(shape->isDataDescriptor());
 
-    if (shape->hasDefaultSetter()) {
-        if (shape->hasSlot()) {
-            // The common path. Standard data property.
-
+    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, v, overwriting);
+            obj->setSlotWithType(cx, shape, vp, overwriting);
             return result.succeed();
         }
-
-        // Bizarre: shared (slotless) property that's writable but has no
-        // JSSetterOp. JS code can't define such a property, but it can be done
-        // through the JSAPI. Treat it as non-writable.
-        return result.fail(JSMSG_GETTER_ONLY);
     }
 
-    MOZ_ASSERT(!obj->is<DynamicWithObject>());  // See bug 1128681.
+    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 result.fail(JSMSG_GETTER_ONLY);
+    }
+
+    RootedValue ovp(cx, vp);
 
     uint32_t sample = cx->runtime()->propertyRemovals;
-    RootedId id(cx, shape->propid());
-    RootedValue value(cx, v);
-    if (!CallJSSetterOp(cx, shape->setterOp(), obj, id, &value, result))
+    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.
+    /*
+     * 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(), value);
+        obj->setSlot(shape->slot(), vp);
     }
 
-    return true;  // result is populated by CallJSSetterOp above.
+    return true;  // result is populated by shape->set() above.
 }
 
 /*
- * Finish the assignment `receiver[id] = v` when an existing property (shape)
- * has been found on a native object (pobj). This implements ES6 draft rev 32
- * (2015 Feb 2) 9.1.9 steps 5 and 6.
+ * 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, HandleId id, HandleValue v,
-                    HandleValue receiver, HandleNativeObject pobj, HandleShape shape,
+SetExistingProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiver, HandleId id,
+                    HandleNativeObject pobj, HandleShape shape, MutableHandleValue vp,
                     ObjectOpResult &result)
 {
-    // Step 5 for dense elements.
     if (IsImplicitDenseOrTypedArrayElement(shape)) {
-        // Step 5.a is a no-op: all dense elements are writable.
-
-        // Pure optimization for the common case:
-        if (receiver.isObject() && pobj == &receiver.toObject())
-            return SetDenseOrTypedArrayElement(cx, pobj, JSID_TO_INT(id), v, result);
-
-        // Steps 5.b-f.
-        return SetPropertyByDefining(cx, obj, id, v, receiver, obj == pobj, result);
-    }
+        /* 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, result);
+    } else {
+        /* ES5 8.12.4 [[Put]] step 2. */
+        if (shape->isAccessorDescriptor()) {
+            if (shape->hasDefaultSetter())
+                return result.fail(JSMSG_GETTER_ONLY);
+        } else {
+            MOZ_ASSERT(shape->isDataDescriptor());
+            if (!shape->writable())
+                return result.fail(JSMSG_READ_ONLY);
+        }
 
-    // Step 5 for all other properties.
-    if (shape->isDataDescriptor()) {
-        // Step 5.a.
-        if (!shape->writable())
-            return result.fail(JSMSG_READ_ONLY);
-
-        // steps 5.c-f.
-        if (receiver.isObject() && pobj == &receiver.toObject()) {
-            // Pure optimization for the common case. There's no point performing
-            // the lookup in step 5.c again, as our caller just did it for us. The
-            // result is |shape|.
-
-            // Steps 5.e.i-ii.
+        if (pobj == receiver) {
             if (pobj->is<ArrayObject>() && id == NameToId(cx->names().length)) {
                 Rooted<ArrayObject*> arr(cx, &pobj->as<ArrayObject>());
-                return ArraySetLength(cx, arr, id, shape->attributes(), v, result);
+                return ArraySetLength(cx, arr, id, shape->attributes(), vp, result);
             }
-            return NativeSetExistingDataProperty(cx, obj, shape, v, receiver, result);
+            return NativeSet(cx, obj, receiver, shape, vp, result);
         }
 
-        // SpiderMonkey special case: assigning to an inherited slotless
-        // property causes the setter to be called, instead of shadowing,
-        // unless the existing property is JSPROP_SHADOWABLE (see bug 552432)
-        // or it's the array length property.
-        if (!shape->hasSlot() &&
-            !shape->hasShadowable() &&
+        // 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)))
         {
-            // Even weirder sub-special-case: inherited slotless data property
-            // with default setter. Wut.
-            if (shape->hasDefaultSetter())
+            // Weird special case: slotless property with default setter.
+            if (shape->hasDefaultSetter() && !shape->hasGetterValue())
                 return result.succeed();
 
-            RootedValue valCopy(cx, v);
-            return CallJSSetterOp(cx, shape->setterOp(), obj, id, &valCopy, result);
+            return shape->set(cx, obj, receiver, vp, result);
         }
-
-        // Shadow pobj[id] by defining a new data property receiver[id].
-        // Delegate everything to SetPropertyByDefining.
-        return SetPropertyByDefining(cx, obj, id, v, receiver, obj == pobj, result);
     }
 
-    // Steps 6-11.
-    MOZ_ASSERT(shape->isAccessorDescriptor());
-    MOZ_ASSERT_IF(!shape->hasSetterObject(), shape->hasDefaultSetter());
-    if (shape->hasDefaultSetter())
-        return result.fail(JSMSG_GETTER_ONLY);
-    Value setter = ObjectValue(*shape->setterObject());
-    if (!InvokeSetter(cx, receiver, setter, v))
-        return false;
-    return result.succeed();
+    // Shadow pobj[id] by defining a new data property receiver[id].
+    return SetPropertyByDefining(cx, obj, receiver, id, vp, obj == pobj, result);
 }
 
 bool
-js::NativeSetProperty(JSContext *cx, HandleNativeObject obj, HandleId id, HandleValue value,
-                      HandleValue receiver, QualifiedBool qualified, ObjectOpResult &result)
+js::NativeSetProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiver, HandleId id,
+                      QualifiedBool qualified, MutableHandleValue vp, ObjectOpResult &result)
 {
     // Fire watchpoints, if any.
-    RootedValue v(cx, value);
     if (MOZ_UNLIKELY(obj->watched())) {
         WatchpointMap *wpmap = cx->compartment()->watchpointMap;
-        if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, &v))
+        if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, vp))
             return false;
     }
 
     // Step numbers below reference ES6 rev 27 9.1.9, the [[Set]] internal
     // method for ordinary objects. We substitute our own names for these names
-    // used in the spec: O -> pobj, P -> id, ownDesc -> shape.
+    // used in the spec: O -> pobj, P -> id, V -> *vp, ownDesc -> shape.
     RootedShape shape(cx);
     RootedNativeObject pobj(cx, obj);
 
     // This loop isn't explicit in the spec algorithm. See the comment on step
     // 4.c.i below. (There's a very similar loop in the NativeGetProperty
     // implementation, but unfortunately not similar enough to common up.)
     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, id, v, receiver, pobj, shape, result);
+            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, id, v, receiver, qualified, result);
+            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, id, v, receiver, qualified, result);
+                    return SetNonexistentProperty(cx, obj, receiver, id, qualified, vp, result);
             }
 
-            return SetProperty(cx, proto, id, v, receiver, result);
+            return SetProperty(cx, proto, receiver, id, vp, result);
         }
         pobj = &proto->as<NativeObject>();
     }
 }
 
 bool
-js::NativeSetElement(JSContext *cx, HandleNativeObject obj, uint32_t index, HandleValue v,
-                     HandleValue receiver, ObjectOpResult &result)
+js::NativeSetElement(JSContext *cx, HandleNativeObject obj, HandleObject receiver, uint32_t index,
+                     MutableHandleValue vp, ObjectOpResult &result)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, &id))
         return false;
-    return NativeSetProperty(cx, obj, id, v, receiver, Qualified, result);
+    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,
                          ObjectOpResult &result)
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -1251,21 +1251,16 @@ IsObjectValueInCompartment(Value v, JSCo
  * ("Ordinary Object Internal Methods"). It's an ongoing project.
  *
  * Many native objects are not "ordinary" in ES6, so these functions also have
  * to serve some of the special needs of Functions (9.2, 9.3, 9.4.1), Arrays
  * (9.4.2), Strings (9.4.3), and so on.
  */
 
 extern bool
-NativeDefineProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId id,
-                     Handle<PropertyDescriptor> desc,
-                     ObjectOpResult &result);
-
-extern bool
 NativeDefineProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId id, HandleValue value,
                      JSGetterOp getter, JSSetterOp setter, unsigned attrs,
                      ObjectOpResult &result);
 
 extern bool
 NativeDefineProperty(ExclusiveContext *cx, HandleNativeObject obj, PropertyName *name,
                      HandleValue value, GetterOp getter, SetterOp setter,
                      unsigned attrs, ObjectOpResult &result);
@@ -1307,42 +1302,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, HandleId id, HandleValue v,
-                      HandleValue receiver, bool objHasOwn, ObjectOpResult &result);
+SetPropertyByDefining(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
+                      HandleValue v, bool objHasOwn, ObjectOpResult &result);
 
 bool
-SetPropertyOnProto(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
-                   HandleValue receiver, ObjectOpResult &result);
+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, HandleId id, HandleValue v,
-                  HandleValue receiver, QualifiedBool qualified, ObjectOpResult &result);
+NativeSetProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiver, HandleId id,
+                  QualifiedBool qualified, MutableHandleValue vp, ObjectOpResult &result);
 
 extern bool
-NativeSetElement(JSContext *cx, HandleNativeObject obj, uint32_t index, HandleValue v,
-                 HandleValue receiver, ObjectOpResult &result);
+NativeSetElement(JSContext *cx, HandleNativeObject obj, HandleObject receiver, uint32_t index,
+                 MutableHandleValue vp, ObjectOpResult &result);
 
 extern bool
 NativeDeleteProperty(JSContext *cx, HandleNativeObject obj, HandleId id, ObjectOpResult &result);
 
 
 /*** SpiderMonkey nonstandard internal methods ***************************************************/
 
 template <AllowGC allowGC>
@@ -1443,26 +1438,26 @@ inline bool
 js::GetPropertyNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
 {
     if (obj->getOps()->getProperty)
         return false;
     return NativeGetPropertyNoGC(cx, &obj->as<NativeObject>(), receiver, id, vp);
 }
 
 inline bool
-js::SetProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
-                HandleValue receiver, ObjectOpResult &result)
+js::SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
+                HandleId id, MutableHandleValue vp, ObjectOpResult &result)
 {
     if (obj->getOps()->setProperty)
-        return JSObject::nonNativeSetProperty(cx, obj, id, v, receiver, result);
-    return NativeSetProperty(cx, obj.as<NativeObject>(), id, v, receiver, Qualified, result);
+        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, uint32_t index, HandleValue v,
-               HandleValue receiver, ObjectOpResult &result)
+js::SetElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index,
+               MutableHandleValue vp, ObjectOpResult &result)
 {
     if (obj->getOps()->setProperty)
-        return JSObject::nonNativeSetElement(cx, obj, index, v, receiver, result);
-    return NativeSetElement(cx, obj.as<NativeObject>(), index, v, receiver, result);
+        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, id, optimizedOut))
+        if (!SetProperty(cx, callobj, callobj, id, &optimizedOut))
             return nullptr;
     }
 
     return callobj;
 }
 
 const Class CallObject::class_ = {
     "Call",
@@ -464,21 +464,22 @@ static bool
 with_LookupProperty(JSContext *cx, HandleObject obj, HandleId id,
                     MutableHandleObject objp, MutableHandleShape propp)
 {
     RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
     return LookupProperty(cx, actual, id, objp, propp);
 }
 
 static bool
-with_DefineProperty(JSContext *cx, HandleObject obj, HandleId id, Handle<PropertyDescriptor> desc,
+with_DefineProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue value,
+                    JSGetterOp getter, JSSetterOp setter, unsigned attrs,
                     ObjectOpResult &result)
 {
     RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
-    return DefineProperty(cx, actual, id, desc, result);
+    return DefineProperty(cx, actual, id, value, getter, setter, attrs, result);
 }
 
 static bool
 with_HasProperty(JSContext *cx, HandleObject obj, HandleId id, bool *foundp)
 {
     RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
     return HasProperty(cx, actual, id, foundp);
 }
@@ -487,24 +488,24 @@ static bool
 with_GetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
                  MutableHandleValue vp)
 {
     RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
     return GetProperty(cx, actual, actual, id, vp);
 }
 
 static bool
-with_SetProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
-                 HandleValue receiver, ObjectOpResult &result)
+with_SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
+                 MutableHandleValue vp, ObjectOpResult &result)
 {
     RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
-    RootedValue actualReceiver(cx, receiver);
-    if (receiver.isObject() && &receiver.toObject() == obj)
-        actualReceiver.setObject(*actual);
-    return SetProperty(cx, actual, id, v, actualReceiver, result);
+    RootedObject actualReceiver(cx, receiver);
+    if (receiver == obj)
+        actualReceiver = actual;
+    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);
@@ -925,18 +926,18 @@ static bool
 uninitialized_GetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
                           MutableHandleValue vp)
 {
     ReportUninitializedLexicalId(cx, id);
     return false;
 }
 
 static bool
-uninitialized_SetProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
-                          HandleValue receiver, ObjectOpResult &result)
+uninitialized_SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
+                          MutableHandleValue vp, ObjectOpResult &result)
 {
     ReportUninitializedLexicalId(cx, id);
     return false;
 }
 
 static bool
 uninitialized_GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc)
@@ -1588,45 +1589,41 @@ 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, HandleId id, HandleValue v, HandleValue receiver,
-             ObjectOpResult &result) const override
+    bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
+             MutableHandleValue vp, ObjectOpResult &result) const 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;
-        RootedValue valCopy(cx, v);
-        if (!handleUnaliasedAccess(cx, debugScope, scope, id, SET, &valCopy, &access))
+        if (!handleUnaliasedAccess(cx, debugScope, scope, id, SET, vp, &access))
             return false;
 
         switch (access) {
           case ACCESS_UNALIASED:
             return result.succeed();
           case ACCESS_GENERIC:
-            {
-                RootedValue scopeVal(cx, ObjectValue(*scope));
-                return SetProperty(cx, scope, id, v, scopeVal, result);
-            }
+            return SetProperty(cx, scope, scope, id, vp, result);
           default:
             MOZ_CRASH("bad AccessResult");
         }
     }
 
     bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                        Handle<PropertyDescriptor> desc,
+                        MutableHandle<PropertyDescriptor> desc,
                         ObjectOpResult &result) const override
     {
         Rooted<ScopeObject*> scope(cx, &proxy->as<DebugScopeObject>().scope());
 
         bool found;
         if (!has(cx, proxy, id, &found))
             return false;
         if (found)
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -331,20 +331,20 @@ js::intrinsic_UnsafePutElements(JSContex
         MOZ_ASSERT(args[idxi].isInt32());
 
         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.
             ObjectOpResult ignored;
-            RootedValue receiver(cx, ObjectValue(*arrobj));
-            if (!SetElement(cx, arrobj, idx, args[elemi], receiver, 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
@@ -34,16 +34,40 @@ 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, MutableHandleValue vp,
+           ObjectOpResult &result)
+{
+    MOZ_ASSERT_IF(hasDefaultSetter(), hasGetterValue());
+    MOZ_ASSERT(!obj->is<DynamicWithObject>());  // See bug 1128681.
+
+    if (attrs & JSPROP_SETTER) {
+        Value fval = setterValue();
+        if (!InvokeGetterOrSetter(cx, receiver, fval, 1, vp.address(), vp))
+            return false;
+        return result.succeed();
+    }
+
+    if (attrs & JSPROP_GETTER)
+        return result.fail(JSMSG_GETTER_ONLY);
+
+    if (!setterOp())
+        return result.succeed();
+
+    RootedId id(cx, propid());
+    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
@@ -1014,17 +1014,26 @@ class Shape : public gc::TenuredCell
 
     bool isDataDescriptor() const {
         return (attrs & (JSPROP_SETTER | JSPROP_GETTER)) == 0;
     }
     bool isAccessorDescriptor() const {
         return (attrs & (JSPROP_SETTER | JSPROP_GETTER)) != 0;
     }
 
-    bool hasShadowable() const { return attrs & JSPROP_SHADOWABLE; }
+    /*
+     * For ES5 compatibility, we allow properties with SetterOp-flavored
+     * setters to be shadowed when set. The "own" property thereby created in
+     * the directly referenced object will have the same getter and setter as
+     * the prototype property. See bug 552432.
+     */
+    bool shadowable() const {
+        MOZ_ASSERT_IF(isDataDescriptor(), writable());
+        return hasSlot() || (attrs & JSPROP_SHADOWABLE);
+    }
 
     uint32_t entryCount() {
         if (hasTable())
             return table().entryCount();
         uint32_t count = 0;
         for (Shape::Range<NoGC> r(this); !r.empty(); r.popFront())
             ++count;
         return count;
--- a/js/src/vm/UnboxedObject.cpp
+++ b/js/src/vm/UnboxedObject.cpp
@@ -674,47 +674,46 @@ UnboxedPlainObject::obj_lookupProperty(J
         propp.set(nullptr);
         return true;
     }
 
     return LookupProperty(cx, proto, id, objp, propp);
 }
 
 /* static */ bool
-UnboxedPlainObject::obj_defineProperty(JSContext *cx, HandleObject obj, HandleId id,
-                                       Handle<JSPropertyDescriptor> desc,
+UnboxedPlainObject::obj_defineProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
+                                       GetterOp getter, SetterOp setter, unsigned attrs,
                                        ObjectOpResult &result)
 {
     const UnboxedLayout &layout = obj->as<UnboxedPlainObject>().layout();
 
     if (const UnboxedLayout::Property *property = layout.lookup(id)) {
-        if (!desc.getter() && !desc.setter() && desc.attributes() == JSPROP_ENUMERATE) {
+        if (!getter && !setter && attrs == JSPROP_ENUMERATE) {
             // This define is equivalent to setting an existing property.
-            if (obj->as<UnboxedPlainObject>().setValue(cx, *property, desc.value()))
+            if (obj->as<UnboxedPlainObject>().setValue(cx, *property, v))
                 return true;
         }
 
         // Trying to incompatibly redefine an existing property requires the
         // object to be converted to a native object.
         if (!convertToNative(cx, obj))
             return false;
 
-        return DefineProperty(cx, obj, id, desc, result) &&
-               result.checkStrict(cx, obj, id);
+        return DefineProperty(cx, obj, id, v, getter, setter, attrs);
     }
 
     // Define the property on the expando object.
     Rooted<UnboxedExpandoObject *> expando(cx, ensureExpando(cx, obj.as<UnboxedPlainObject>()));
     if (!expando)
         return false;
 
     // Update property types on the unboxed object as well.
-    AddTypePropertyId(cx, obj, id, desc.value());
+    AddTypePropertyId(cx, obj, id, v);
 
-    return DefineProperty(cx, expando, id, desc, result);
+    return DefineProperty(cx, expando, id, v, getter, setter, attrs, result);
 }
 
 /* static */ bool
 UnboxedPlainObject::obj_hasProperty(JSContext *cx, HandleObject obj, HandleId id, bool *foundp)
 {
     if (obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id)) {
         *foundp = true;
         return true;
@@ -753,48 +752,46 @@ UnboxedPlainObject::obj_getProperty(JSCo
         vp.setUndefined();
         return true;
     }
 
     return GetProperty(cx, proto, receiver, id, vp);
 }
 
 /* static */ bool
-UnboxedPlainObject::obj_setProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
-                                    HandleValue receiver, ObjectOpResult &result)
+UnboxedPlainObject::obj_setProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
+                                    HandleId id, MutableHandleValue vp, ObjectOpResult &result)
 {
     const UnboxedLayout &layout = obj->as<UnboxedPlainObject>().layout();
 
     if (const UnboxedLayout::Property *property = layout.lookup(id)) {
-        if (receiver.isObject() && obj == &receiver.toObject()) {
-            if (obj->as<UnboxedPlainObject>().setValue(cx, *property, v))
+        if (obj == receiver) {
+            if (obj->as<UnboxedPlainObject>().setValue(cx, *property, vp))
                 return result.succeed();
 
             if (!convertToNative(cx, obj))
                 return false;
-            return SetProperty(cx, obj, id, v, receiver, result);
+            return SetProperty(cx, obj, receiver, id, vp, result);
         }
 
-        return SetPropertyByDefining(cx, obj, id, v, receiver, false, result);
+        return SetPropertyByDefining(cx, obj, receiver, id, vp, false, result);
     }
 
     if (UnboxedExpandoObject *expando = obj->as<UnboxedPlainObject>().maybeExpando()) {
         if (expando->containsShapeOrElement(cx, id)) {
             // Update property types on the unboxed object as well.
-            AddTypePropertyId(cx, obj, id, v);
+            AddTypePropertyId(cx, obj, id, vp);
 
             RootedObject nexpando(cx, expando);
-            RootedValue nreceiver(cx, (receiver.isObject() && obj == &receiver.toObject())
-                                      ? ObjectValue(*expando)
-                                      : receiver);
-            return SetProperty(cx, nexpando, id, v, nreceiver, result);
+            RootedObject nreceiver(cx, (obj == receiver) ? expando : receiver.get());
+            return SetProperty(cx, nexpando, nreceiver, id, vp, result);
         }
     }
 
-    return SetPropertyOnProto(cx, obj, id, v, receiver, result);
+    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
@@ -187,27 +187,27 @@ class UnboxedPlainObject : public JSObje
 
   public:
     static const Class class_;
 
     static bool obj_lookupProperty(JSContext *cx, HandleObject obj,
                                    HandleId id, MutableHandleObject objp,
                                    MutableHandleShape propp);
 
-    static bool obj_defineProperty(JSContext *cx, HandleObject obj, HandleId id,
-                                   Handle<JSPropertyDescriptor> desc,
+    static bool obj_defineProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
+                                   GetterOp getter, SetterOp setter, unsigned attrs,
                                    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, HandleId id, HandleValue v,
-                                HandleValue receiver, ObjectOpResult &result);
+    static bool obj_setProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
+                                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,
                                    ObjectOpResult &result);
 
     static bool obj_enumerate(JSContext *cx, HandleObject obj, AutoIdVector &properties);
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -28,17 +28,17 @@ namespace js {
  * this wiki page:
  *
  *  https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
  */
 static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 265;
 static const uint32_t XDR_BYTECODE_VERSION =
     uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
 
-static_assert(JSErr_Limit == 389,
+static_assert(JSErr_Limit == 388,
               "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
@@ -728,22 +728,22 @@ xpc::SandboxProxyHandler::get(JSContext 
                               JS::Handle<jsid> id,
                               JS::MutableHandle<Value> vp) const
 {
     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,
-                              JS::Handle<Value> v,
-                              JS::Handle<Value> receiver,
+                              JS::MutableHandle<Value> vp,
                               JS::ObjectOpResult &result) const
 {
-    return BaseProxyHandler::set(cx, proxy, id, v, receiver, result);
+    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/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -422,16 +422,24 @@ 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,
+                                  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);
 }
 
 static bool
 XPC_WN_CantDeletePropertyStub(JSContext *cx, HandleObject obj, HandleId id,
@@ -639,17 +647,17 @@ const XPCWrappedNativeJSClass XPC_WN_NoH
     "XPCWrappedNative_NoHelper",    // name;
     WRAPPER_FLAGS |
     JSCLASS_PRIVATE_IS_NSISUPPORTS, // flags
 
     /* Mandatory non-null function pointer members. */
     XPC_WN_OnlyIWrite_AddPropertyStub, // addProperty
     XPC_WN_CantDeletePropertyStub,     // delProperty
     nullptr,                           // getProperty
-    nullptr,                           // setProperty
+    XPC_WN_OnlyIWrite_SetPropertyStub, // setProperty
 
     XPC_WN_Shared_Enumerate,           // enumerate
     XPC_WN_NoHelper_Resolve,           // resolve
     XPC_WN_Shared_Convert,             // convert
     XPC_WN_NoHelper_Finalize,          // finalize
 
     /* Optionally non-null members start here. */
     nullptr,                         // call
@@ -1349,16 +1357,24 @@ 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,
+                                        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,
                "bad proto");
 
     XPCWrappedNativeProto* self =
         (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
@@ -1383,17 +1399,17 @@ XPC_WN_NoMods_Proto_Resolve(JSContext *c
 const js::Class XPC_WN_NoMods_WithCall_Proto_JSClass = {
     "XPC_WN_NoMods_WithCall_Proto_JSClass",    // name;
     WRAPPER_FLAGS,                             // flags;
 
     /* Mandatory non-null function pointer members. */
     XPC_WN_OnlyIWrite_Proto_AddPropertyStub,   // addProperty;
     XPC_WN_CantDeletePropertyStub,             // delProperty;
     nullptr,                                   // getProperty;
-    nullptr,                                   // setProperty;
+    XPC_WN_OnlyIWrite_Proto_SetPropertyStub,   // setProperty;
     XPC_WN_Shared_Proto_Enumerate,             // enumerate;
     XPC_WN_NoMods_Proto_Resolve,               // resolve;
     nullptr,                                   // convert;
     XPC_WN_Shared_Proto_Finalize,              // finalize;
 
     /* Optionally non-null members start here. */
     nullptr,                         // call;
     nullptr,                         // construct;
@@ -1408,17 +1424,17 @@ const js::Class XPC_WN_NoMods_WithCall_P
 const js::Class XPC_WN_NoMods_NoCall_Proto_JSClass = {
     "XPC_WN_NoMods_NoCall_Proto_JSClass",      // name;
     WRAPPER_FLAGS,                             // flags;
 
     /* Mandatory non-null function pointer members. */
     XPC_WN_OnlyIWrite_Proto_AddPropertyStub,   // addProperty;
     XPC_WN_CantDeletePropertyStub,             // delProperty;
     nullptr,                                   // getProperty;
-    nullptr,                                   // setProperty;
+    XPC_WN_OnlyIWrite_Proto_SetPropertyStub,   // setProperty;
     XPC_WN_Shared_Proto_Enumerate,             // enumerate;
     XPC_WN_NoMods_Proto_Resolve,               // resolve;
     nullptr,                                   // convert;
     XPC_WN_Shared_Proto_Finalize,              // finalize;
 
     /* Optionally non-null members start here. */
     nullptr,                         // call;
     nullptr,                         // construct;
@@ -1503,17 +1519,17 @@ static_assert(((WRAPPER_FLAGS >> JSCLASS
 
 const js::Class XPC_WN_Tearoff_JSClass = {
     "WrappedNative_TearOff",                   // name;
     WRAPPER_FLAGS |
     JSCLASS_HAS_RESERVED_SLOTS(XPC_WN_TEAROFF_RESERVED_SLOTS), // flags;
     XPC_WN_OnlyIWrite_AddPropertyStub,         // addProperty;
     XPC_WN_CantDeletePropertyStub,             // delProperty;
     nullptr,                                   // getProperty;
-    nullptr,                                   // setProperty;
+    XPC_WN_OnlyIWrite_SetPropertyStub,         // setProperty;
     XPC_WN_TearOff_Enumerate,                  // enumerate;
     XPC_WN_TearOff_Resolve,                    // resolve;
     XPC_WN_Shared_Convert,                     // convert;
     XPC_WN_TearOff_Finalize,                   // finalize;
 
     /* Optionally non-null members start here. */
     nullptr,                                   // call
     nullptr,                                   // construct
deleted file mode 100644
--- a/js/xpconnect/tests/unit/test_xpcwn_tamperproof.js
+++ /dev/null
@@ -1,175 +0,0 @@
-// Test that it's not possible to create expando properties on XPCWNs.
-// See <https://bugzilla.mozilla.org/show_bug.cgi?id=1143810#c5>.
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-
-function check_throws(f) {
-  try {
-    f();
-  } catch (exc) {
-    return;
-  }
-  throw new TypeError("Expected exception, no exception thrown");
-}
-
-/*
- * Test that XPCWrappedNative objects do not permit expando properties to be created.
- *
- * This function is called twice. The first time, realObj is an nsITimer XPCWN
- * and accessObj === realObj.
- *
- * The second time, accessObj is a scripted proxy with realObj as its target.
- * So the second time we are testing that scripted proxies don't magically
- * bypass whatever mechanism enforces the expando policy on XPCWNs.
- */
-function test_tamperproof(realObj, accessObj, {method, constant, attribute}) {
-  // Assignment can't create an expando property.
-  check_throws(function () { accessObj.expando = 14; });
-  do_check_false("expando" in realObj);
-
-  // Strict assignment throws.
-  check_throws(function () { "use strict"; accessObj.expando = 14; });
-  do_check_false("expando" in realObj);
-
-  // Assignment to an inherited method name doesn't work either.
-  check_throws(function () { accessObj.hasOwnProperty = () => "lies"; });
-  check_throws(function () { "use strict"; accessObj.hasOwnProperty = () => "lies"; });
-  do_check_false(realObj.hasOwnProperty("hasOwnProperty"));
-
-  // Assignment to a method name doesn't work either.
-  let originalMethod;
-  if (method) {
-    originalMethod = accessObj[method];
-    accessObj[method] = "nope";  // non-writable data property, no exception in non-strict code
-    check_throws(function () { "use strict"; accessObj[method] = "nope"; });
-    do_check_true(realObj[method] === originalMethod);
-  }
-
-  // A constant is the same thing.
-  let originalConstantValue;
-  if (constant) {
-    originalConstantValue = accessObj[constant];
-    accessObj[constant] = "nope";
-    do_check_eq(realObj[constant], originalConstantValue);
-    check_throws(function () { "use strict"; accessObj[constant] = "nope"; });
-    do_check_eq(realObj[constant], originalConstantValue);
-  }
-
-  // Assignment to a readonly accessor property with no setter doesn't work either.
-  let originalAttributeDesc;
-  if (attribute) {
-    originalAttributeDesc = Object.getOwnPropertyDescriptor(realObj, attribute);
-    do_check_true("set" in originalAttributeDesc);
-    do_check_true(originalAttributeDesc.set === undefined);
-
-    accessObj[attribute] = "nope";  // accessor property with no setter: no exception in non-strict code
-    check_throws(function () { "use strict"; accessObj[attribute] = "nope"; });
-
-    let desc = Object.getOwnPropertyDescriptor(realObj, attribute);
-    do_check_true("set" in desc);
-    do_check_eq(originalAttributeDesc.get, desc.get);
-    do_check_eq(undefined, desc.set);
-  }
-
-  // Reflect.set doesn't work either.
-  if (this.Reflect && this.Reflect.set)
-    throw new Error("Congratulations on implementing Reflect.set! Here are some tests to uncomment.");
-  /*
-    if (method) {
-      do_check_false(Reflect.set({}, method, "bad", accessObj));
-      do_check_eq(realObj[method], originalMethod);
-    }
-    if (attribute) {
-      do_check_false(Reflect.set({}, attribute, "bad", accessObj));
-      do_check_eq(originalAttributeDesc.get, Object.getOwnPropertyDescriptor(realObj, attribute).get);
-    }
-  */
-
-  // Object.defineProperty can't do anything either.
-  let names = ["expando"];
-  if (method) names.push(method);
-  if (constant) names.push(constant);
-  if (attribute) names.push(attribute);
-  for (let name of names) {
-    let originalDesc = Object.getOwnPropertyDescriptor(realObj, name);
-    check_throws(function () {
-      Object.defineProperty(accessObj, name, {configurable: true});
-    });
-    check_throws(function () {
-      Object.defineProperty(accessObj, name, {writable: true});
-    });
-    check_throws(function () {
-      Object.defineProperty(accessObj, name, {get: function () { return "lies"; }});
-    });
-    check_throws(function () {
-      Object.defineProperty(accessObj, name, {value: "bad"});
-    });
-    let desc = Object.getOwnPropertyDescriptor(realObj, name);
-    if (originalDesc === undefined) {
-      do_check_eq(undefined, desc);
-    } else {
-      do_check_eq(originalDesc.configurable, desc.configurable);
-      do_check_eq(originalDesc.enumerable, desc.enumerable);
-      do_check_eq(originalDesc.writable, desc.writable);
-      do_check_eq(originalDesc.value, desc.value);
-      do_check_eq(originalDesc.get, desc.get);
-      do_check_eq(originalDesc.set, desc.set);
-    }
-  }
-
-  // Existing properties can't be deleted.
-  if (method) {
-    do_check_false(delete accessObj[method]);
-    check_throws(function () { "use strict"; delete accessObj[method]; });
-    do_check_eq(realObj[method], originalMethod);
-  }
-  if (constant) {
-    do_check_false(delete accessObj[constant]);
-    check_throws(function () { "use strict"; delete accessObj[constant]; });
-    do_check_eq(realObj[constant], originalConstantValue);
-  }
-  if (attribute) {
-    do_check_false(delete accessObj[attribute]);
-    check_throws(function () { "use strict"; delete accessObj[attribute]; });
-    desc = Object.getOwnPropertyDescriptor(realObj, attribute);
-    do_check_eq(originalAttributeDesc.get, desc.get);
-  }
-}
-
-function test_twice(obj, options) {
-  test_tamperproof(obj, obj, options);
-
-  let handler = {
-    getPrototypeOf(t) {
-      return new Proxy(Object.getPrototypeOf(t), handler);
-    }
-  };
-  test_tamperproof(obj, new Proxy(obj, handler), options);
-}
-
-function run_test() {
-  let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-  test_twice(timer, {
-    method: "init",
-    constant: "TYPE_ONE_SHOT",
-    attribute: "callback"
-  });
-
-  let principal = Cc["@mozilla.org/nullprincipal;1"].createInstance(Ci.nsIPrincipal);
-  test_twice(principal, {});
-
-  test_twice(Object.getPrototypeOf(principal), {
-    method: "subsumes",
-    constant: "APP_STATUS_INSTALLED",
-    attribute: "origin"
-  });
-
-  // Test a tearoff object.
-  Components.manager.autoRegister(do_get_file('../components/js/xpctest.manifest'));
-  let b = Cc["@mozilla.org/js/xpc/test/js/TestInterfaceAll;1"].createInstance(Ci.nsIXPCTestInterfaceB);
-  let tearoff = b.nsIXPCTestInterfaceA;
-  test_twice(tearoff, {
-    method: "QueryInterface"
-  });
-}
--- a/js/xpconnect/tests/unit/xpcshell.ini
+++ b/js/xpconnect/tests/unit/xpcshell.ini
@@ -104,11 +104,10 @@ head = head_watchdog.js
 head = head_watchdog.js
 [test_watchdog_toggle.js]
 head = head_watchdog.js
 [test_watchdog_default.js]
 head = head_watchdog.js
 [test_watchdog_hibernate.js]
 head = head_watchdog.js
 [test_writeToGlobalPrototype.js]
-[test_xpcwn_tamperproof.js]
 [test_xrayed_iterator.js]
 [test_xray_SavedFrame.js]
\ No newline at end of file
--- a/js/xpconnect/wrappers/AddonWrapper.cpp
+++ b/js/xpconnect/wrappers/AddonWrapper.cpp
@@ -114,46 +114,46 @@ AddonWrapper<Base>::get(JSContext *cx, J
     } else {
         vp.set(desc.value());
         return true;
     }
 }
 
 template<typename Base>
 bool
-AddonWrapper<Base>::set(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id, JS::HandleValue v,
-                        JS::HandleValue receiver, JS::ObjectOpResult &result) const
+AddonWrapper<Base>::set(JSContext *cx, JS::HandleObject wrapper, JS::HandleObject receiver,
+                        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, id, v, receiver, result);
+        return Base::set(cx, wrapper, receiver, id, vp, result);
 
     if (desc.setter()) {
         MOZ_ASSERT(desc.hasSetterObject());
         JS::AutoValueVector args(cx);
-        if (!args.append(v))
+        if (!args.append(vp))
             return false;
         RootedValue fval(cx, ObjectValue(*desc.setterObject()));
-        RootedValue ignored(cx);
-        if (!JS::Call(cx, receiver, fval, args, &ignored))
+        if (!JS_CallFunctionValue(cx, receiver, fval, args, vp))
             return false;
         return result.succeed();
     }
 
     return result.failCantSetInterposed();
 }
 
 template<typename Base>
 bool
 AddonWrapper<Base>::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
-                                   Handle<JSPropertyDescriptor> desc,
-                                   ObjectOpResult &result) const
+                                   MutableHandle<JSPropertyDescriptor> desc,
+                                   JS::ObjectOpResult &result) const
 {
     Rooted<JSPropertyDescriptor> interpDesc(cx);
     if (!Interpose(cx, wrapper, nullptr, id, &interpDesc))
         return false;
 
     if (!interpDesc.object())
         return Base::defineProperty(cx, wrapper, id, desc, result);
 
--- a/js/xpconnect/wrappers/AddonWrapper.h
+++ b/js/xpconnect/wrappers/AddonWrapper.h
@@ -23,24 +23,25 @@ template<typename Base>
 class AddonWrapper : public Base {
   public:
     explicit MOZ_CONSTEXPR AddonWrapper(unsigned flags) : Base(flags) { }
 
     virtual bool getOwnPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                           JS::Handle<jsid> id,
                                           JS::MutableHandle<JSPropertyDescriptor> desc) const override;
     virtual bool defineProperty(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
-                                JS::Handle<JSPropertyDescriptor> desc,
+                                JS::MutableHandle<JSPropertyDescriptor> desc,
                                 JS::ObjectOpResult &result) const override;
     virtual bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
                          JS::ObjectOpResult &result) const override;
     virtual bool get(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<JSObject*> receiver,
                      JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const override;
-    virtual bool set(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id, JS::HandleValue v,
-                     JS::HandleValue receiver, JS::ObjectOpResult &result) const override;
+    virtual bool set(JSContext *cx, JS::HandleObject wrapper, JS::HandleObject receiver,
+                     JS::HandleId id, JS::MutableHandleValue vp,
+                     JS::ObjectOpResult &result) const override;
 
     virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                        JS::Handle<jsid> id,
                                        JS::MutableHandle<JSPropertyDescriptor> desc) const override;
 
     static const AddonWrapper singleton;
 };
 
--- a/js/xpconnect/wrappers/ChromeObjectWrapper.cpp
+++ b/js/xpconnect/wrappers/ChromeObjectWrapper.cpp
@@ -16,26 +16,27 @@ using namespace JS;
 
 namespace xpc {
 
 const ChromeObjectWrapper ChromeObjectWrapper::singleton;
 
 bool
 ChromeObjectWrapper::defineProperty(JSContext *cx, HandleObject wrapper,
                                     HandleId id,
-                                    Handle<JSPropertyDescriptor> desc,
+                                    MutableHandle<JSPropertyDescriptor> desc,
                                     JS::ObjectOpResult &result) const
 {
     if (!AccessCheck::checkPassToPrivilegedCode(cx, wrapper, desc.value()))
         return false;
     return ChromeObjectWrapperBase::defineProperty(cx, wrapper, id, desc, result);
 }
 
 bool
-ChromeObjectWrapper::set(JSContext *cx, HandleObject wrapper, HandleId id, HandleValue v,
-                         HandleValue receiver, ObjectOpResult &result) const
+ChromeObjectWrapper::set(JSContext *cx, HandleObject wrapper,
+                         HandleObject receiver, HandleId id,
+                         MutableHandleValue vp, ObjectOpResult &result) const
 {
-    if (!AccessCheck::checkPassToPrivilegedCode(cx, wrapper, v))
+    if (!AccessCheck::checkPassToPrivilegedCode(cx, wrapper, vp))
         return false;
-    return ChromeObjectWrapperBase::set(cx, wrapper, id, v, receiver, result);
+    return ChromeObjectWrapperBase::set(cx, wrapper, receiver, id, vp, result);
 }
 
 }
--- a/js/xpconnect/wrappers/ChromeObjectWrapper.h
+++ b/js/xpconnect/wrappers/ChromeObjectWrapper.h
@@ -24,20 +24,21 @@ struct ExposedPropertiesOnly;
 
 class ChromeObjectWrapper : public ChromeObjectWrapperBase
 {
   public:
     MOZ_CONSTEXPR ChromeObjectWrapper() : ChromeObjectWrapperBase(0) {}
 
     virtual bool defineProperty(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                 JS::Handle<jsid> id,
-                                JS::Handle<JSPropertyDescriptor> desc,
+                                JS::MutableHandle<JSPropertyDescriptor> desc,
                                 JS::ObjectOpResult &result) const override;
-    virtual bool set(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id,
-                     JS::HandleValue v, JS::HandleValue receiver,
+    virtual bool set(JSContext *cx, JS::Handle<JSObject*> wrapper,
+                     JS::Handle<JSObject*> receiver, JS::Handle<jsid> id,
+                     JS::MutableHandle<JS::Value> vp,
                      JS::ObjectOpResult &result) const override;
 
     static const ChromeObjectWrapper singleton;
 };
 
 } /* namespace xpc */
 
 #endif /* __ChromeObjectWrapper_h__ */
--- a/js/xpconnect/wrappers/FilteringWrapper.cpp
+++ b/js/xpconnect/wrappers/FilteringWrapper.cpp
@@ -229,17 +229,17 @@ CrossOriginXrayWrapper::ownPropertyKeys(
     // the underlying native object may report. Override the inherited trap to
     // avoid passing JSITER_OWNONLY as a flag.
     return SecurityXrayDOM::getPropertyKeys(cx, wrapper, JSITER_HIDDEN, props);
 }
 
 bool
 CrossOriginXrayWrapper::defineProperty(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                        JS::Handle<jsid> id,
-                                       JS::Handle<JSPropertyDescriptor> desc,
+                                       JS::MutableHandle<JSPropertyDescriptor> desc,
                                        JS::ObjectOpResult &result) const
 {
     JS_ReportError(cx, "Permission denied to define property on cross-origin object");
     return false;
 }
 
 bool
 CrossOriginXrayWrapper::delete_(JSContext *cx, JS::Handle<JSObject*> wrapper,
--- a/js/xpconnect/wrappers/FilteringWrapper.h
+++ b/js/xpconnect/wrappers/FilteringWrapper.h
@@ -68,17 +68,17 @@ class CrossOriginXrayWrapper : public Se
   public:
     explicit CrossOriginXrayWrapper(unsigned flags);
 
     virtual bool getOwnPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                           JS::Handle<jsid> id,
                                           JS::MutableHandle<JSPropertyDescriptor> desc) const override;
     virtual bool defineProperty(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                 JS::Handle<jsid> id,
-                                JS::Handle<JSPropertyDescriptor> desc,
+                                JS::MutableHandle<JSPropertyDescriptor> desc,
                                 JS::ObjectOpResult &result) const override;
     virtual bool ownPropertyKeys(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                  JS::AutoIdVector &props) const override;
     virtual bool delete_(JSContext *cx, JS::Handle<JSObject*> wrapper,
                          JS::Handle<jsid> id, JS::ObjectOpResult &result) const override;
 
     virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                        JS::Handle<jsid> id,
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -588,17 +588,17 @@ JSXrayTraits::delete_(JSContext *cx, Han
         if (desc.object())
             return JS_DeletePropertyById(cx, target, id, result);
     }
     return result.succeed();
 }
 
 bool
 JSXrayTraits::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
-                             Handle<JSPropertyDescriptor> desc,
+                             MutableHandle<JSPropertyDescriptor> desc,
                              Handle<JSPropertyDescriptor> existingDesc,
                              ObjectOpResult &result,
                              bool *defined)
 {
     *defined = false;
     RootedObject holder(cx, ensureHolder(cx, wrapper));
     if (!holder)
         return false;
@@ -632,20 +632,19 @@ JSXrayTraits::defineProperty(JSContext *
             JS_ReportError(cx, "Not allowed to overwrite accessor property on [Object] or [Array] XrayWrapper");
             return false;
         }
         if (existingDesc.object() && existingDesc.object() != wrapper) {
             JS_ReportError(cx, "Not allowed to shadow non-own Xray-resolved property on [Object] or [Array] XrayWrapper");
             return false;
         }
 
-        Rooted<JSPropertyDescriptor> wrappedDesc(cx, desc);
         JSAutoCompartment ac(cx, target);
-        if (!JS_WrapPropertyDescriptor(cx, &wrappedDesc) ||
-            !JS_DefinePropertyById(cx, target, id, wrappedDesc, result))
+        if (!JS_WrapPropertyDescriptor(cx, desc) ||
+            !JS_DefinePropertyById(cx, target, id, desc, result))
         {
             return false;
         }
         *defined = true;
         return true;
     }
 
     return true;
@@ -1411,17 +1410,17 @@ XPCWrappedNativeXrayTraits::resolveOwnPr
     // in the wrapper's compartment here, not the wrappee.
     MOZ_ASSERT(js::IsObjectInContextCompartment(wrapper, cx));
 
     return JS_GetPropertyDescriptorById(cx, holder, id, desc);
 }
 
 bool
 XPCWrappedNativeXrayTraits::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
-                                           Handle<JSPropertyDescriptor> desc,
+                                           MutableHandle<JSPropertyDescriptor> desc,
                                            Handle<JSPropertyDescriptor> existingDesc,
                                            JS::ObjectOpResult &result, bool *defined)
 {
     *defined = false;
     RootedObject holder(cx, singleton.ensureHolder(cx, wrapper));
 
     // Check for an indexed property on a Window.  If that's happening, do
     // nothing but claim we defined it so it won't get added as an expando.
@@ -1572,17 +1571,17 @@ DOMXrayTraits::resolveOwnProperty(JSCont
         return true;
 
     return JS_DefinePropertyById(cx, holder, id, desc) &&
            JS_GetPropertyDescriptorById(cx, holder, id, desc);
 }
 
 bool
 DOMXrayTraits::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
-                              Handle<JSPropertyDescriptor> desc,
+                              MutableHandle<JSPropertyDescriptor> desc,
                               Handle<JSPropertyDescriptor> existingDesc,
                               JS::ObjectOpResult &result, bool *defined)
 {
     // Check for an indexed property on a Window.  If that's happening, do
     // nothing but claim we defined it so it won't get added as an expando.
     if (IsWindow(cx, wrapper)) {
         int32_t index = GetArrayIndexFromId(cx, id);
         if (IsArrayIndex(index)) {
@@ -1926,17 +1925,17 @@ XrayWrapper<Base, Traits>::getOwnPropert
 // object. Manually re-apply Xrays if necessary.
 //
 // NB: In order to satisfy the invariants of WaiveXray, we need to pass
 // in an object sans security wrapper, which means we need to strip off any
 // potential same-compartment security wrapper that may have been applied
 // to the content object. This is ok, because the the expando object is only
 // ever accessed by code across the compartment boundary.
 static bool
-RecreateLostWaivers(JSContext *cx, const JSPropertyDescriptor *orig,
+RecreateLostWaivers(JSContext *cx, JSPropertyDescriptor *orig,
                     MutableHandle<JSPropertyDescriptor> wrapped)
 {
     // Compute whether the original objects were waived, and implicitly, whether
     // they were objects at all.
     bool valueWasWaived =
         orig->value.isObject() &&
         WrapperFactory::HasWaiveXrayFlag(&orig->value.toObject());
     bool getterWasWaived =
@@ -1971,17 +1970,17 @@ RecreateLostWaivers(JSContext *cx, const
     }
 
     return true;
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::defineProperty(JSContext *cx, HandleObject wrapper,
-                                          HandleId id, Handle<JSPropertyDescriptor> desc,
+                                          HandleId id, MutableHandle<JSPropertyDescriptor> desc,
                                           ObjectOpResult &result) const
 {
     assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::SET);
 
     Rooted<JSPropertyDescriptor> existing_desc(cx);
     if (!JS_GetPropertyDescriptorById(cx, wrapper, id, &existing_desc))
         return false;
 
@@ -2076,25 +2075,25 @@ XrayWrapper<Base, Traits>::get(JSContext
     // Skip our Base if it isn't already ProxyHandler.
     // NB: None of the functions we call are prepared for the receiver not
     // 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, HandleId id, HandleValue v,
-                               HandleValue receiver, ObjectOpResult &result) const
+XrayWrapper<Base, Traits>::set(JSContext *cx, HandleObject wrapper,
+                               HandleObject receiver, HandleId id,
+                               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.
-    RootedValue wrapperValue(cx, ObjectValue(*wrapper));
-    return js::BaseProxyHandler::set(cx, wrapper, id, v, wrapperValue, result);
+    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
@@ -128,17 +128,17 @@ public:
 
     virtual bool resolveNativeProperty(JSContext *cx, JS::HandleObject wrapper,
                                        JS::HandleObject holder, JS::HandleId id,
                                        JS::MutableHandle<JSPropertyDescriptor> desc) override;
     virtual bool resolveOwnProperty(JSContext *cx, const js::Wrapper &jsWrapper, JS::HandleObject wrapper,
                                     JS::HandleObject holder, JS::HandleId id,
                                     JS::MutableHandle<JSPropertyDescriptor> desc) override;
     bool defineProperty(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id,
-                        JS::Handle<JSPropertyDescriptor> desc,
+                        JS::MutableHandle<JSPropertyDescriptor> desc,
                         JS::Handle<JSPropertyDescriptor> existingDesc,
                         JS::ObjectOpResult &result, bool *defined);
     virtual bool enumerateNames(JSContext *cx, JS::HandleObject wrapper, unsigned flags,
                                 JS::AutoIdVector &props);
     static bool call(JSContext *cx, JS::HandleObject wrapper,
                      const JS::CallArgs &args, const js::Wrapper& baseInstance);
     static bool construct(JSContext *cx, JS::HandleObject wrapper,
                           const JS::CallArgs &args, const js::Wrapper& baseInstance);
@@ -180,17 +180,17 @@ public:
         // MOZ_CRASH("resolveNativeProperty hook should never be called with HasPrototype = 1");
         //       but we can't do that yet because XrayUtils::HasNativeProperty calls this.
         return true;
     }
     virtual bool resolveOwnProperty(JSContext *cx, const js::Wrapper &jsWrapper, JS::HandleObject wrapper,
                                     JS::HandleObject holder, JS::HandleId id,
                                     JS::MutableHandle<JSPropertyDescriptor> desc) override;
     bool defineProperty(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id,
-                        JS::Handle<JSPropertyDescriptor> desc,
+                        JS::MutableHandle<JSPropertyDescriptor> desc,
                         JS::Handle<JSPropertyDescriptor> existingDesc,
                         JS::ObjectOpResult &result, bool *defined);
     virtual bool enumerateNames(JSContext *cx, JS::HandleObject wrapper, unsigned flags,
                                 JS::AutoIdVector &props);
     static bool call(JSContext *cx, JS::HandleObject wrapper,
                      const JS::CallArgs &args, const js::Wrapper& baseInstance);
     static bool construct(JSContext *cx, JS::HandleObject wrapper,
                           const JS::CallArgs &args, const js::Wrapper& baseInstance);
@@ -223,17 +223,17 @@ public:
 
     virtual bool resolveOwnProperty(JSContext *cx, const js::Wrapper &jsWrapper, JS::HandleObject wrapper,
                                     JS::HandleObject holder, JS::HandleId id,
                                     JS::MutableHandle<JSPropertyDescriptor> desc) override;
 
     bool delete_(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id, JS::ObjectOpResult &result);
 
     bool defineProperty(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id,
-                        JS::Handle<JSPropertyDescriptor> desc,
+                        JS::MutableHandle<JSPropertyDescriptor> desc,
                         JS::Handle<JSPropertyDescriptor> existingDesc,
                         JS::ObjectOpResult &result, bool *defined);
 
     virtual bool enumerateNames(JSContext *cx, JS::HandleObject wrapper, unsigned flags,
                                 JS::AutoIdVector &props);
 
     static bool call(JSContext *cx, JS::HandleObject wrapper,
                      const JS::CallArgs &args, const js::Wrapper& baseInstance)
@@ -341,17 +341,17 @@ public:
         MOZ_CRASH("resolveNativeProperty hook should never be called with HasPrototype = 1");
     }
 
     virtual bool resolveOwnProperty(JSContext *cx, const js::Wrapper &jsWrapper, JS::HandleObject wrapper,
                                     JS::HandleObject holder, JS::HandleId id,
                                     JS::MutableHandle<JSPropertyDescriptor> desc) override;
 
     bool defineProperty(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id,
-                        JS::Handle<JSPropertyDescriptor> desc,
+                        JS::MutableHandle<JSPropertyDescriptor> desc,
                         JS::Handle<JSPropertyDescriptor> existingDesc,
                         JS::ObjectOpResult &result, bool *defined)
     {
         *defined = false;
         return true;
     }
 
     virtual bool enumerateNames(JSContext *cx, JS::HandleObject wrapper, unsigned flags,
@@ -415,17 +415,17 @@ class XrayWrapper : public Base {
     MOZ_CONSTEXPR explicit XrayWrapper(unsigned flags)
       : Base(flags | WrapperFactory::IS_XRAY_WRAPPER_FLAG, Traits::HasPrototype)
     { };
 
     /* Standard internal methods. */
     virtual bool getOwnPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
                                           JS::MutableHandle<JSPropertyDescriptor> desc) const override;
     virtual bool defineProperty(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
-                                JS::Handle<JSPropertyDescriptor> desc,
+                                JS::MutableHandle<JSPropertyDescriptor> desc,
                                 JS::ObjectOpResult &result) const override;
     virtual bool ownPropertyKeys(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                  JS::AutoIdVector &props) const override;
     virtual bool delete_(JSContext *cx, JS::Handle<JSObject*> wrapper,
                          JS::Handle<jsid> id, JS::ObjectOpResult &result) const override;
     virtual bool enumerate(JSContext *cx, JS::Handle<JSObject*> wrapper,
                            JS::MutableHandle<JSObject*> objp) const override;
     virtual bool getPrototype(JSContext *cx, JS::HandleObject wrapper,
@@ -436,18 +436,18 @@ class XrayWrapper : public Base {
                                        bool *succeeded) const override;
     virtual bool preventExtensions(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                    JS::ObjectOpResult &result) const override;
     virtual bool isExtensible(JSContext *cx, JS::Handle<JSObject*> wrapper, bool *extensible) const override;
     virtual bool has(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
                      bool *bp) const override;
     virtual bool get(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<JSObject*> receiver,
                      JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const override;
-    virtual bool set(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
-                     JS::Handle<JS::Value> v, JS::Handle<JS::Value> receiver,
+    virtual bool set(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<JSObject*> receiver,
+                     JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp,
                      JS::ObjectOpResult &result) const override;
     virtual bool call(JSContext *cx, JS::Handle<JSObject*> wrapper,
                       const JS::CallArgs &args) const override;
     virtual bool construct(JSContext *cx, JS::Handle<JSObject*> wrapper,
                            const JS::CallArgs &args) const override;
 
     /* SpiderMonkey extensions. */
     virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
@@ -510,18 +510,18 @@ public:
                                           JS::MutableHandle<JSPropertyDescriptor> desc) const override;
 
     // 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 override;
     virtual bool get(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<JSObject*> receiver,
                      JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const override;
-    virtual bool set(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
-                     JS::Handle<JS::Value> v, JS::Handle<JS::Value> receiver,
+    virtual bool set(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<JSObject*> receiver,
+                     JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp,
                      JS::ObjectOpResult &result) const override;
 
     virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> proxy,
                                        JS::Handle<jsid> id,
                                        JS::MutableHandle<JSPropertyDescriptor> desc) const override;
     virtual bool hasOwn(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
                         bool *bp) const override;
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> proxy,