diff --git a/dom/base/WindowNamedPropertiesHandler.cpp b/dom/base/WindowNamedPropertiesHandler.cpp index 45935869603f..a0c513a05ae4 100644 --- a/dom/base/WindowNamedPropertiesHandler.cpp +++ b/dom/base/WindowNamedPropertiesHandler.cpp @@ -159,7 +159,7 @@ bool WindowNamedPropertiesHandler::defineProperty(JSContext* aCx, JS::Handle aProxy, JS::Handle aId, - JS::Handle aDesc, + JS::MutableHandle aDesc, JS::ObjectOpResult &result) const { ErrorResult rv; diff --git a/dom/base/WindowNamedPropertiesHandler.h b/dom/base/WindowNamedPropertiesHandler.h index 3bcdee510579..67ae7e585441 100644 --- a/dom/base/WindowNamedPropertiesHandler.h +++ b/dom/base/WindowNamedPropertiesHandler.h @@ -28,7 +28,7 @@ public: virtual bool defineProperty(JSContext* aCx, JS::Handle aProxy, JS::Handle aId, - JS::Handle aDesc, + JS::MutableHandle aDesc, JS::ObjectOpResult &result) const override; virtual bool ownPropNames(JSContext* aCx, JS::Handle aProxy, unsigned flags, diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index e3909828da9c..84b8da8a97d5 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -621,7 +621,7 @@ public: virtual bool defineProperty(JSContext* cx, JS::Handle proxy, JS::Handle id, - JS::Handle desc, + JS::MutableHandle desc, JS::ObjectOpResult &result) const override; virtual bool ownPropertyKeys(JSContext *cx, JS::Handle proxy, @@ -643,8 +643,9 @@ public: JS::Handle id, JS::MutableHandle vp) const override; virtual bool set(JSContext *cx, JS::Handle proxy, - JS::Handle id, JS::Handle v, - JS::Handle receiver, + JS::Handle receiver, + JS::Handle id, + JS::MutableHandle vp, JS::ObjectOpResult &result) const override; // SpiderMonkey extensions @@ -781,7 +782,7 @@ bool nsOuterWindowProxy::defineProperty(JSContext* cx, JS::Handle proxy, JS::Handle id, - JS::Handle desc, + JS::MutableHandle desc, JS::ObjectOpResult &result) const { int32_t index = GetArrayIndexFromId(cx, id); @@ -908,9 +909,9 @@ nsOuterWindowProxy::get(JSContext *cx, JS::Handle proxy, bool nsOuterWindowProxy::set(JSContext *cx, JS::Handle proxy, + JS::Handle receiver, JS::Handle id, - JS::Handle v, - JS::Handle receiver, + JS::MutableHandle vp, JS::ObjectOpResult &result) const { int32_t index = GetArrayIndexFromId(cx, id); @@ -920,7 +921,7 @@ nsOuterWindowProxy::set(JSContext *cx, JS::Handle proxy, return result.failReadOnly(); } - return js::Wrapper::set(cx, proxy, id, v, receiver, result); + return js::Wrapper::set(cx, proxy, receiver, id, vp, result); } bool diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index aa4c3339bbe4..89c18e460fb5 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -1439,7 +1439,7 @@ XrayResolveOwnProperty(JSContext* cx, JS::Handle wrapper, bool XrayDefineProperty(JSContext* cx, JS::Handle wrapper, JS::Handle obj, JS::Handle id, - JS::Handle desc, + JS::MutableHandle desc, JS::ObjectOpResult &result, bool *defined) { if (!js::IsProxy(obj)) diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index b6231fce4bbf..83e33ab2afab 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -2464,7 +2464,7 @@ XrayResolveOwnProperty(JSContext* cx, JS::Handle wrapper, bool XrayDefineProperty(JSContext* cx, JS::Handle wrapper, JS::Handle obj, JS::Handle id, - JS::Handle desc, + JS::MutableHandle desc, JS::ObjectOpResult &result, bool *defined); diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index ccd82c7ca6a6..492952ac54df 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -9805,7 +9805,7 @@ class CGProxySpecialOperation(CGPerSignatureCall): 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" @@ -9830,12 +9830,12 @@ class CGProxySpecialOperation(CGPerSignatureCall): 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" } @@ -9880,10 +9880,10 @@ class CGProxyIndexedOperation(CGProxySpecialOperation): 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) @@ -9941,9 +9941,9 @@ 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): @@ -9971,10 +9971,10 @@ class CGProxyNamedOperation(CGProxySpecialOperation): 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 @@ -10072,9 +10072,9 @@ 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): @@ -10244,7 +10244,7 @@ class CGDOMJSProxyHandler_defineProperty(ClassMethod): args = [Argument('JSContext*', 'cx'), Argument('JS::Handle', 'proxy'), Argument('JS::Handle', 'id'), - Argument('JS::Handle', 'desc'), + Argument('JS::MutableHandle', 'desc'), Argument('JS::ObjectOpResult&', 'opresult'), Argument('bool*', 'defined')] ClassMethod.__init__(self, "defineProperty", "bool", args, virtual=True, override=True, const=True) @@ -10691,7 +10691,7 @@ class CGDOMJSProxyHandler_setCustom(ClassMethod): args = [Argument('JSContext*', 'cx'), Argument('JS::Handle', 'proxy'), Argument('JS::Handle', 'id'), - Argument('JS::Handle', 'v'), + Argument('JS::MutableHandle', 'vp'), Argument('bool*', 'done')] ClassMethod.__init__(self, "setCustom", "bool", args, virtual=True, override=True, const=True) self.descriptor = descriptor @@ -10716,7 +10716,7 @@ class CGDOMJSProxyHandler_setCustom(ClassMethod): 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" @@ -10741,7 +10741,7 @@ class CGDOMJSProxyHandler_setCustom(ClassMethod): """, callSetter=CGProxyIndexedSetter(self.descriptor, - argumentHandleValue="v").define()) + argumentMutableValue="vp").define()) else: setIndexed = "" diff --git a/dom/bindings/DOMJSProxyHandler.cpp b/dom/bindings/DOMJSProxyHandler.cpp index c62e07bd0a81..0a034a120533 100644 --- a/dom/bindings/DOMJSProxyHandler.cpp +++ b/dom/bindings/DOMJSProxyHandler.cpp @@ -195,7 +195,7 @@ BaseDOMProxyHandler::getOwnPropertyDescriptor(JSContext* cx, bool DOMProxyHandler::defineProperty(JSContext* cx, JS::Handle proxy, JS::Handle id, - Handle desc, + MutableHandle desc, JS::ObjectOpResult &result, bool *defined) const { if (desc.hasGetterObject() && desc.setter() == JS_StrictPropertyStub) { @@ -219,14 +219,13 @@ DOMProxyHandler::defineProperty(JSContext* cx, JS::Handle proxy, JS:: } bool -DOMProxyHandler::set(JSContext *cx, Handle proxy, Handle id, - Handle v, Handle receiver, - ObjectOpResult &result) const +DOMProxyHandler::set(JSContext *cx, Handle proxy, Handle receiver, + Handle id, MutableHandle 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) { @@ -253,7 +252,7 @@ DOMProxyHandler::set(JSContext *cx, Handle proxy, Handle id, } } - return js::SetPropertyIgnoringNamedGetter(cx, proxy, id, v, receiver, desc, result); + return js::SetPropertyIgnoringNamedGetter(cx, proxy, id, vp, receiver, &desc, result); } bool @@ -351,7 +350,7 @@ IdToInt32(JSContext* cx, JS::Handle id) bool DOMProxyHandler::setCustom(JSContext* cx, JS::Handle proxy, JS::Handle id, - JS::Handle v, bool *done) const + JS::MutableHandle vp, bool *done) const { *done = false; return true; diff --git a/dom/bindings/DOMJSProxyHandler.h b/dom/bindings/DOMJSProxyHandler.h index c154fe2a64bd..fcef8e089d65 100644 --- a/dom/bindings/DOMJSProxyHandler.h +++ b/dom/bindings/DOMJSProxyHandler.h @@ -105,14 +105,14 @@ public: {} bool defineProperty(JSContext* cx, JS::Handle proxy, JS::Handle id, - JS::Handle desc, + JS::MutableHandle desc, JS::ObjectOpResult &result) const override { bool unused; return defineProperty(cx, proxy, id, desc, result, &unused); } virtual bool defineProperty(JSContext* cx, JS::Handle proxy, JS::Handle id, - JS::Handle desc, + JS::MutableHandle desc, JS::ObjectOpResult &result, bool *defined) const; bool delete_(JSContext* cx, JS::Handle proxy, JS::Handle id, JS::ObjectOpResult &result) const override; @@ -122,8 +122,8 @@ public: const override; bool has(JSContext* cx, JS::Handle proxy, JS::Handle id, bool* bp) const override; - bool set(JSContext *cx, JS::Handle proxy, JS::Handle id, - JS::Handle v, JS::Handle receiver, JS::ObjectOpResult &result) + bool set(JSContext *cx, JS::Handle proxy, JS::Handle receiver, + JS::Handle id, JS::MutableHandle vp, JS::ObjectOpResult &result) const override; /* @@ -132,7 +132,7 @@ public: * *done to false. */ virtual bool setCustom(JSContext* cx, JS::Handle proxy, JS::Handle id, - JS::Handle v, bool *done) const; + JS::MutableHandle vp, bool *done) const; static JSObject* GetExpandoObject(JSObject* obj); diff --git a/js/ipc/JavaScriptBase.h b/js/ipc/JavaScriptBase.h index e8f7a134d51f..cc9791c29016 100644 --- a/js/ipc/JavaScriptBase.h +++ b/js/ipc/JavaScriptBase.h @@ -71,9 +71,10 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base 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, @@ -160,9 +161,10 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base 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, diff --git a/js/ipc/PJavaScript.ipdl b/js/ipc/PJavaScript.ipdl index 4f000fdf2887..89a6476a8dd9 100644 --- a/js/ipc/PJavaScript.ipdl +++ b/js/ipc/PJavaScript.ipdl @@ -33,7 +33,7 @@ both: 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); diff --git a/js/ipc/WrapperAnswer.cpp b/js/ipc/WrapperAnswer.cpp index f1ec789354f7..73bfb7d38799 100644 --- a/js/ipc/WrapperAnswer.cpp +++ b/js/ipc/WrapperAnswer.cpp @@ -308,17 +308,26 @@ WrapperAnswer::RecvGet(const ObjectId &objId, const ObjectVariant &receiverVar, } 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); @@ -329,12 +338,12 @@ WrapperAnswer::RecvSet(const ObjectId &objId, const JSIDVariant &idVar, const JS 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); diff --git a/js/ipc/WrapperAnswer.h b/js/ipc/WrapperAnswer.h index d1a220bcc422..747f580b2acf 100644 --- a/js/ipc/WrapperAnswer.h +++ b/js/ipc/WrapperAnswer.h @@ -37,8 +37,9 @@ class WrapperAnswer : public virtual JavaScriptShared 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); diff --git a/js/ipc/WrapperOwner.cpp b/js/ipc/WrapperOwner.cpp index f0ba66954fd2..6992001ebbaf 100644 --- a/js/ipc/WrapperOwner.cpp +++ b/js/ipc/WrapperOwner.cpp @@ -97,7 +97,7 @@ class CPOWProxyHandler : public BaseProxyHandler virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, MutableHandle desc) const override; virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id, - Handle desc, + MutableHandle desc, ObjectOpResult &result) const override; virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const override; @@ -110,8 +110,9 @@ class CPOWProxyHandler : public BaseProxyHandler 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; @@ -212,7 +213,7 @@ WrapperOwner::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, Handle bool CPOWProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id, - Handle desc, + MutableHandle desc, ObjectOpResult &result) const { FORWARD(defineProperty, (cx, proxy, id, desc, result)); @@ -220,7 +221,7 @@ CPOWProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id, bool WrapperOwner::defineProperty(JSContext *cx, HandleObject proxy, HandleId id, - Handle desc, + MutableHandle desc, ObjectOpResult &result) { ObjectId objId = idOf(proxy); @@ -516,37 +517,41 @@ WrapperOwner::get(JSContext *cx, HandleObject proxy, HandleObject receiver, } 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 diff --git a/js/ipc/WrapperOwner.h b/js/ipc/WrapperOwner.h index 00afe20fbf00..1d001fc609e6 100644 --- a/js/ipc/WrapperOwner.h +++ b/js/ipc/WrapperOwner.h @@ -32,7 +32,7 @@ class WrapperOwner : public virtual JavaScriptShared bool getOwnPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, JS::MutableHandle desc); bool defineProperty(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, - JS::Handle desc, + JS::MutableHandle desc, JS::ObjectOpResult &result); bool ownPropertyKeys(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props); bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, @@ -42,8 +42,8 @@ class WrapperOwner : public virtual JavaScriptShared 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); @@ -128,8 +128,9 @@ class WrapperOwner : public virtual JavaScriptShared 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; diff --git a/js/public/Class.h b/js/public/Class.h index ffd092181ce9..fc12ffb736b7 100644 --- a/js/public/Class.h +++ b/js/public/Class.h @@ -333,8 +333,8 @@ typedef bool (* LookupPropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleObject objp, JS::MutableHandle propp); typedef bool -(* DefinePropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle 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); @@ -342,8 +342,8 @@ 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 desc); diff --git a/js/public/Proxy.h b/js/public/Proxy.h index eccae7f0683a..6789dbecee03 100644 --- a/js/public/Proxy.h +++ b/js/public/Proxy.h @@ -18,7 +18,6 @@ namespace js { using JS::AutoIdVector; using JS::CallArgs; -using JS::Handle; using JS::HandleId; using JS::HandleObject; using JS::HandleValue; @@ -253,7 +252,7 @@ class JS_FRIEND_API(BaseProxyHandler) virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, MutableHandle desc) const = 0; virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id, - Handle desc, + MutableHandle desc, ObjectOpResult &result) const = 0; virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const = 0; @@ -295,8 +294,8 @@ class JS_FRIEND_API(BaseProxyHandler) 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 @@ -374,7 +373,7 @@ class JS_FRIEND_API(DirectProxyHandler) : public BaseProxyHandler virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, MutableHandle desc) const override; virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id, - Handle desc, + MutableHandle desc, ObjectOpResult &result) const override; virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const override; @@ -395,8 +394,9 @@ class JS_FRIEND_API(DirectProxyHandler) : public BaseProxyHandler 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; diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index 38b443c7cc0e..90e6f727d9b4 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -1751,8 +1751,8 @@ ReportPropertyError(JSContext *cx, } bool -TypedObject::obj_defineProperty(JSContext *cx, HandleObject obj, HandleId id, - Handle desc, +TypedObject::obj_defineProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue v, + GetterOp getter, SetterOp setter, unsigned attrs, ObjectOpResult &result) { Rooted typedObj(cx, &obj->as()); @@ -1904,8 +1904,8 @@ TypedObject::obj_getArrayElement(JSContext *cx, } 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 typedObj(cx, &obj->as()); @@ -1919,7 +1919,7 @@ TypedObject::obj_setProperty(JSContext *cx, HandleObject obj, HandleId id, Handl 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; @@ -1929,8 +1929,8 @@ TypedObject::obj_setProperty(JSContext *cx, HandleObject obj, HandleId id, Handl 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, @@ -1941,7 +1941,7 @@ TypedObject::obj_setProperty(JSContext *cx, HandleObject obj, HandleId id, Handl Rooted elementType(cx); elementType = &typedObj->typeDescr().as().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(); } @@ -1955,19 +1955,19 @@ TypedObject::obj_setProperty(JSContext *cx, HandleObject obj, HandleId id, Handl 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 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 diff --git a/js/src/builtin/TypedObject.h b/js/src/builtin/TypedObject.h index 7c19bc822c62..1b00fab42ff5 100644 --- a/js/src/builtin/TypedObject.h +++ b/js/src/builtin/TypedObject.h @@ -528,8 +528,8 @@ class TypedObject : public JSObject 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 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); @@ -540,8 +540,8 @@ class TypedObject : public JSObject 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 desc); diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 9a3a0bd80547..743b80fd3595 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -8364,7 +8364,7 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_ 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; } diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 9aef78083c7e..8a63c3d9a82f 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -429,6 +429,7 @@ 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); @@ -442,21 +443,21 @@ SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValu return true; } - RootedValue receiver(cx, ObjectValue(*obj)); ObjectOpResult result; if (MOZ_LIKELY(!obj->getOps()->setProperty)) { if (!NativeSetProperty( - cx, obj.as(), id, value, receiver, + cx, obj.as(), obj.as(), 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); diff --git a/js/src/js.msg b/js/src/js.msg index 64ba893bafd9..d8b89879c90f 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -82,7 +82,6 @@ MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE, 0, JSEXN_TYPEERR, "reduce of empty array 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}") diff --git a/js/src/jsapi-tests/testSetPropertyIgnoringNamedGetter.cpp b/js/src/jsapi-tests/testSetPropertyIgnoringNamedGetter.cpp index 4ab1ec36d8fd..fd9bcfd228af 100644 --- a/js/src/jsapi-tests/testSetPropertyIgnoringNamedGetter.cpp +++ b/js/src/jsapi-tests/testSetPropertyIgnoringNamedGetter.cpp @@ -27,13 +27,13 @@ class CustomProxyHandler : public DirectProxyHandler { 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 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: diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 29458973f89c..e1809307419f 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -147,7 +147,7 @@ JS::ObjectOpResult::reportStrictErrorOrWarning(JSContext *cx, HandleObject obj, 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); @@ -2205,12 +2205,10 @@ DefinePropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleValue val // 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) @@ -2830,13 +2828,13 @@ JS_GetUCProperty(JSContext *cx, HandleObject obj, const char16_t *name, size_t n 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) @@ -2847,60 +2845,66 @@ JS_ForwardSetPropertyTo(JSContext *cx, HandleObject obj, HandleId id, HandleValu 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); + assertSameCompartment(cx, obj, vp); - RootedValue receiver(cx, ObjectValue(*obj)); 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) diff --git a/js/src/jsapi.h b/js/src/jsapi.h index d717aa5e1a48..3ac22f8dba50 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -2600,18 +2600,6 @@ class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations< 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); diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 9285e859ac73..c350d014e1e7 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -364,7 +364,8 @@ SetArrayElement(JSContext *cx, HandleObject obj, double index, HandleValue v) if (!ToId(cx, index, &id)) return false; - return SetProperty(cx, obj, id, v); + RootedValue tmp(cx, v); + return SetProperty(cx, obj, obj, id, &tmp); } /* @@ -433,7 +434,7 @@ 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); } /* @@ -1269,10 +1270,11 @@ InitArrayElements(JSContext *cx, HandleObject obj, uint32_t start, uint32_t coun do { value = *vector++; indexv = DoubleValue(index); - if (!ValueToId(cx, indexv, &id)) - return false; - if (!SetProperty(cx, obj, id, value)) + if (!ValueToId(cx, indexv, &id) || + !SetProperty(cx, obj, obj, id, &value)) + { return false; + } index += 1; } while (vector != end); diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h index a02bbf7f1f2b..b9810b97b5dc 100644 --- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -332,6 +332,26 @@ CallJSDeletePropertyOp(JSContext *cx, JSDeletePropertyOp op, HandleObject receiv 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) { diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index aeb327da462a..dcfdc67aaf2d 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -359,8 +359,8 @@ extern JS_FRIEND_API(bool) proxy_LookupProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleObject objp, JS::MutableHandle propp); extern JS_FRIEND_API(bool) -proxy_DefineProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle 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); @@ -368,8 +368,8 @@ 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 desc); @@ -2632,8 +2632,8 @@ ForwardToNative(JSContext *cx, JSNative native, const JS::CallArgs &args); */ JS_FRIEND_API(bool) SetPropertyIgnoringNamedGetter(JSContext *cx, JS::HandleObject obj, JS::HandleId id, - JS::HandleValue v, JS::HandleValue receiver, - JS::Handle ownDesc, + JS::MutableHandleValue vp, JS::HandleObject receiver, + JS::MutableHandle ownDesc, JS::ObjectOpResult &result); JS_FRIEND_API(void) diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index c6c3849897d0..7f762c2181db 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -689,7 +689,7 @@ js::StandardDefineProperty(JSContext *cx, HandleObject obj, HandleId id, if (obj->is()) { Rooted 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); } @@ -1584,26 +1584,25 @@ js::CreateThisForFunction(JSContext *cx, HandleObject callee, NewObjectKind newK } /* 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) @@ -3193,30 +3192,23 @@ js::GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, return true; } -bool -js::DefineProperty(JSContext *cx, HandleObject obj, HandleId id, Handle desc, - ObjectOpResult &result) -{ - if (DefinePropertyOp op = obj->getOps()->defineProperty) - return op(cx, obj, id, desc, result); - return NativeDefineProperty(cx, obj.as(), 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 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(), id, desc, result); + return NativeDefineProperty(cx, obj.as(), id, value, getter, setter, attrs, + result); } bool @@ -3279,6 +3271,22 @@ js::DefineElement(ExclusiveContext *cx, HandleObject obj, uint32_t index, Handle 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 ***************************************************/ diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 12102433dac5..363b8e21077c 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -478,12 +478,12 @@ class JSObject : public js::gc::Cell 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); @@ -768,10 +768,6 @@ extern bool StandardDefineProperty(JSContext *cx, HandleObject obj, HandleId id, Handle desc); -extern bool -DefineProperty(JSContext *cx, HandleObject obj, HandleId id, - Handle desc, ObjectOpResult &result); - extern bool DefineProperty(ExclusiveContext *cx, HandleObject obj, HandleId id, HandleValue value, JSGetterOp getter, JSSetterOp setter, unsigned attrs, ObjectOpResult &result); @@ -853,52 +849,49 @@ 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) -{ - RootedValue receiver(cx, ObjectValue(*obj)); - ObjectOpResult result; - return SetProperty(cx, obj, id, v, receiver, result) && - result.checkStrict(cx, obj, id); -} - -inline bool -SetProperty(JSContext *cx, HandleObject obj, PropertyName *name, HandleValue v, - HandleValue receiver, ObjectOpResult &result) +SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, PropertyName *name, + MutableHandleValue vp, ObjectOpResult &result) { RootedId id(cx, NameToId(name)); - return SetProperty(cx, obj, id, v, receiver, result); + return SetProperty(cx, obj, receiver, id, vp, result); } inline bool -SetProperty(JSContext *cx, HandleObject obj, PropertyName *name, HandleValue v) +SetElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index, + MutableHandleValue vp, ObjectOpResult &result); + +inline bool +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 @@ -906,14 +899,17 @@ SetElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v, * 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]`. */ diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index b243dab2ccc8..995ee17a9222 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -2168,7 +2168,7 @@ class MOZ_STACK_CLASS StringRegExpGuard // 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 ®Exp() { return *re_; } diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index c1d4d0d92e37..32249ccbfa44 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -117,7 +117,7 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id, MutableHandle desc) const override; virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, - Handle desc, + MutableHandle desc, ObjectOpResult &result) const override; virtual bool ownPropertyKeys(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const override; @@ -137,8 +137,8 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper 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; @@ -185,7 +185,7 @@ class JS_FRIEND_API(SecurityWrapper) : public Base bool *bp) const override; virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, - Handle desc, + MutableHandle desc, ObjectOpResult &result) const override; virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) const override; virtual bool preventExtensions(JSContext *cx, HandleObject wrapper, diff --git a/js/src/proxy/BaseProxyHandler.cpp b/js/src/proxy/BaseProxyHandler.cpp index be618522e84e..5e4d268f858d 100644 --- a/js/src/proxy/BaseProxyHandler.cpp +++ b/js/src/proxy/BaseProxyHandler.cpp @@ -61,7 +61,8 @@ BaseProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver, 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 @@ -71,8 +72,8 @@ BaseProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver, } 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); @@ -87,16 +88,15 @@ BaseProxyHandler::set(JSContext *cx, HandleObject proxy, HandleId id, HandleValu // 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 ownDesc_, +js::SetPropertyIgnoringNamedGetter(JSContext *cx, HandleObject obj, HandleId id, + MutableHandleValue vp, HandleObject receiver, + MutableHandle ownDesc, ObjectOpResult &result) { - Rooted ownDesc(cx, ownDesc_); - // Step 4. if (!ownDesc.object()) { // The spec calls this variable "parent", but that word has weird @@ -105,33 +105,31 @@ js::SetPropertyIgnoringNamedGetter(JSContext *cx, HandleObject obj, HandleId id, 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. @@ -142,10 +140,10 @@ js::SetPropertyIgnoringNamedGetter(JSContext *cx, HandleObject obj, HandleId id, // 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); } @@ -157,7 +155,7 @@ js::SetPropertyIgnoringNamedGetter(JSContext *cx, HandleObject obj, HandleId id, 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(); } diff --git a/js/src/proxy/CrossCompartmentWrapper.cpp b/js/src/proxy/CrossCompartmentWrapper.cpp index 00eed755df21..28f9ea4263ff 100644 --- a/js/src/proxy/CrossCompartmentWrapper.cpp +++ b/js/src/proxy/CrossCompartmentWrapper.cpp @@ -49,13 +49,13 @@ CrossCompartmentWrapper::getOwnPropertyDescriptor(JSContext *cx, HandleObject wr bool CrossCompartmentWrapper::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, - Handle desc, + MutableHandle desc, ObjectOpResult &result) const { Rooted 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); } @@ -169,15 +169,14 @@ CrossCompartmentWrapper::get(JSContext *cx, HandleObject wrapper, HandleObject r } 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); } diff --git a/js/src/proxy/DeadObjectProxy.cpp b/js/src/proxy/DeadObjectProxy.cpp index 9dd1523e3480..115dde998087 100644 --- a/js/src/proxy/DeadObjectProxy.cpp +++ b/js/src/proxy/DeadObjectProxy.cpp @@ -32,7 +32,7 @@ DeadObjectProxy::getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, H bool DeadObjectProxy::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, - Handle desc, + MutableHandle desc, ObjectOpResult &result) const { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT); diff --git a/js/src/proxy/DeadObjectProxy.h b/js/src/proxy/DeadObjectProxy.h index b2ca32a27ea8..25347d7b5493 100644 --- a/js/src/proxy/DeadObjectProxy.h +++ b/js/src/proxy/DeadObjectProxy.h @@ -22,7 +22,7 @@ class DeadObjectProxy : public BaseProxyHandler virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id, MutableHandle desc) const override; virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, - Handle desc, + MutableHandle desc, ObjectOpResult &result) const override; virtual bool ownPropertyKeys(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const override; diff --git a/js/src/proxy/DirectProxyHandler.cpp b/js/src/proxy/DirectProxyHandler.cpp index c9603cc44a28..d6c671422bb7 100644 --- a/js/src/proxy/DirectProxyHandler.cpp +++ b/js/src/proxy/DirectProxyHandler.cpp @@ -34,7 +34,7 @@ DirectProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, bool DirectProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id, - Handle desc, + MutableHandle desc, ObjectOpResult &result) const { assertEnteredPolicy(cx, proxy, id, SET); @@ -216,12 +216,12 @@ DirectProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver } 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().target()); - return SetProperty(cx, target, id, v, receiver, result); + return SetProperty(cx, target, receiver, id, vp, result); } bool diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp index 2ce94d9b6aac..e203ba7fada4 100644 --- a/js/src/proxy/Proxy.cpp +++ b/js/src/proxy/Proxy.cpp @@ -134,7 +134,7 @@ Proxy::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, bool Proxy::defineProperty(JSContext *cx, HandleObject proxy, HandleId id, - Handle desc, ObjectOpResult &result) + MutableHandle desc, ObjectOpResult &result) { JS_CHECK_RECURSION(cx, return false); const BaseProxyHandler *handler = proxy->as().handler(); @@ -307,8 +307,8 @@ Proxy::callProp(JSContext *cx, HandleObject proxy, HandleObject receiver, Handle } 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().handler(); @@ -321,9 +321,9 @@ Proxy::set(JSContext *cx, HandleObject proxy, HandleId id, HandleValue v, Handle // 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 @@ -559,11 +559,17 @@ js::proxy_LookupProperty(JSContext *cx, HandleObject obj, HandleId id, } bool -js::proxy_DefineProperty(JSContext *cx, HandleObject obj, HandleId id, - Handle 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 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 @@ -580,10 +586,10 @@ js::proxy_GetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, Ha } 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 diff --git a/js/src/proxy/Proxy.h b/js/src/proxy/Proxy.h index 609616e777d4..cd8e2a7cda8e 100644 --- a/js/src/proxy/Proxy.h +++ b/js/src/proxy/Proxy.h @@ -29,7 +29,7 @@ class Proxy static bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, MutableHandle desc); static bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id, - Handle desc, ObjectOpResult &result); + MutableHandle 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); @@ -42,8 +42,8 @@ class Proxy 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); diff --git a/js/src/proxy/ScriptedDirectProxyHandler.cpp b/js/src/proxy/ScriptedDirectProxyHandler.cpp index 6c4154b7ecd0..3af2c149c15b 100644 --- a/js/src/proxy/ScriptedDirectProxyHandler.cpp +++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp @@ -550,7 +550,7 @@ ScriptedDirectProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObject // ES6 draft rev 31 (15 Jan 2015) 9.5.6 Proxy.[[DefineOwnProperty]](P, Desc) bool ScriptedDirectProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id, - Handle desc, + MutableHandle desc, ObjectOpResult &result) const { // steps 2-4 @@ -922,8 +922,8 @@ ScriptedDirectProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject // 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)); @@ -940,7 +940,7 @@ ScriptedDirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleId id, // 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); @@ -949,8 +949,8 @@ ScriptedDirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleId id, 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)) @@ -969,7 +969,7 @@ ScriptedDirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleId id, 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); diff --git a/js/src/proxy/ScriptedDirectProxyHandler.h b/js/src/proxy/ScriptedDirectProxyHandler.h index f4a6969d4a2a..5ff4f8fdd8da 100644 --- a/js/src/proxy/ScriptedDirectProxyHandler.h +++ b/js/src/proxy/ScriptedDirectProxyHandler.h @@ -22,7 +22,7 @@ class ScriptedDirectProxyHandler : public BaseProxyHandler { virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, MutableHandle desc) const override; virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id, - Handle desc, + MutableHandle desc, ObjectOpResult &result) const override; virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const override; @@ -46,8 +46,8 @@ class ScriptedDirectProxyHandler : public BaseProxyHandler { 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; diff --git a/js/src/proxy/ScriptedIndirectProxyHandler.cpp b/js/src/proxy/ScriptedIndirectProxyHandler.cpp index 39ce5558d025..c1e8df4bdc19 100644 --- a/js/src/proxy/ScriptedIndirectProxyHandler.cpp +++ b/js/src/proxy/ScriptedIndirectProxyHandler.cpp @@ -10,7 +10,6 @@ #include "jsapi.h" #include "jscntxt.h" -#include "jscntxtinlines.h" #include "jsobjinlines.h" using namespace js; @@ -197,7 +196,7 @@ ScriptedIndirectProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObje bool ScriptedIndirectProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id, - Handle desc, + MutableHandle desc, ObjectOpResult &result) const { RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy)); @@ -304,55 +303,30 @@ ScriptedIndirectProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObjec } 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 @@ -383,7 +357,7 @@ ScriptedIndirectProxyHandler::derivedSet(JSContext *cx, HandleObject proxy, Hand 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; @@ -394,21 +368,22 @@ ScriptedIndirectProxyHandler::derivedSet(JSContext *cx, HandleObject proxy, Hand 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 diff --git a/js/src/proxy/ScriptedIndirectProxyHandler.h b/js/src/proxy/ScriptedIndirectProxyHandler.h index 3bd5f65bd8a5..67104c0a87dd 100644 --- a/js/src/proxy/ScriptedIndirectProxyHandler.h +++ b/js/src/proxy/ScriptedIndirectProxyHandler.h @@ -23,7 +23,7 @@ class ScriptedIndirectProxyHandler : public BaseProxyHandler virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, MutableHandle desc) const override; virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id, - Handle desc, + MutableHandle desc, ObjectOpResult &result) const override; virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const override; @@ -37,8 +37,8 @@ class ScriptedIndirectProxyHandler : public BaseProxyHandler 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, @@ -55,8 +55,8 @@ class ScriptedIndirectProxyHandler : public BaseProxyHandler 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() */ diff --git a/js/src/proxy/SecurityWrapper.cpp b/js/src/proxy/SecurityWrapper.cpp index a498b936949d..c90d6b8cdbda 100644 --- a/js/src/proxy/SecurityWrapper.cpp +++ b/js/src/proxy/SecurityWrapper.cpp @@ -103,8 +103,8 @@ SecurityWrapper::boxedValue_unbox(JSContext *cx, HandleObject obj, Mutable template bool -SecurityWrapper::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, - Handle desc, +SecurityWrapper::defineProperty(JSContext *cx, HandleObject wrapper, + HandleId id, MutableHandle desc, ObjectOpResult &result) const { if (desc.getter() || desc.setter()) { diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index a94e9ecc691e..49108401a589 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -7637,7 +7637,7 @@ DebuggerEnv_setVariable(JSContext *cx, unsigned argc, Value *vp) } /* Just set the property. */ - if (!SetProperty(cx, env, id, v)) + if (!SetProperty(cx, env, env, id, &v)) return false; } diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 1d045fbaf829..71c04d40abd6 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -612,7 +612,11 @@ class GlobalObject : public NativeObject 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, diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h index d64ff23b3514..79131f83afc9 100644 --- a/js/src/vm/Interpreter-inl.h +++ b/js/src/vm/Interpreter-inl.h @@ -308,6 +308,7 @@ SetNameOperation(JSContext *cx, JSScript *script, jsbytecode *pc, HandleObject s 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 @@ -315,13 +316,12 @@ SetNameOperation(JSContext *cx, JSScript *script, jsbytecode *pc, HandleObject s 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(), id, val, receiver, Unqualified, - result); + ok = NativeSetProperty(cx, scope.as(), scope.as(), 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); } @@ -336,7 +336,8 @@ InitPropertyOperation(JSContext *cx, JSOp op, HandleObject obj, HandleId id, Han } MOZ_ASSERT(obj->as().layout().lookup(id)); - return PutProperty(cx, obj, id, rhs, false); + RootedValue v(cx, rhs); + return PutProperty(cx, obj, id, &v, false); } inline bool diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 5de9085ffb3f..71706ad1fd67 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -313,20 +313,52 @@ GetNameOperation(JSContext *cx, InterpreterFrame *fp, jsbytecode *pc, MutableHan } 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(), obj.as(), 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 @@ -584,7 +616,8 @@ js::InvokeConstructor(JSContext *cx, Value fval, unsigned argc, const Value *arg } 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 @@ -592,16 +625,7 @@ js::InvokeGetter(JSContext *cx, JSObject *obj, Value fval, MutableHandleValue rv */ 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 @@ -1379,7 +1403,7 @@ SetObjectElementOperation(JSContext *cx, Handle obj, HandleId id, con 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 @@ -3861,8 +3885,7 @@ js::DefFunOperation(JSContext *cx, HandleScript script, HandleObject scopeChain, */ /* Step 5f. */ - RootedId id(cx, NameToId(name)); - return PutProperty(cx, parent, id, rval, script->strict()); + return PutProperty(cx, parent, name, &rval, script->strict()); } bool diff --git a/js/src/vm/Interpreter.h b/js/src/vm/Interpreter.h index 20e75e7439a7..0d34b77a99f4 100644 --- a/js/src/vm/Interpreter.h +++ b/js/src/vm/Interpreter.h @@ -76,14 +76,12 @@ Invoke(JSContext *cx, const Value &thisv, const Value &fval, unsigned argc, cons 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 diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h index e406f179c92a..c783a591ddfc 100644 --- a/js/src/vm/NativeObject-inl.h +++ b/js/src/vm/NativeObject-inl.h @@ -73,7 +73,8 @@ NativeObject::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. @@ -84,7 +85,8 @@ NativeObject::setDenseElementWithType(ExclusiveContext *cx, uint32_t index, cons } 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); diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index 13d570750694..b5ccd5295749 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -981,59 +981,6 @@ NativeObject::addDataProperty(ExclusiveContext *cx, HandlePropertyName name, return addProperty(cx, self, id, nullptr, nullptr, slot, attrs, 0); } -template -bool -js::NativeLookupOwnProperty(ExclusiveContext *cx, - typename MaybeRooted::HandleType obj, - typename MaybeRooted::HandleType id, - typename MaybeRooted::MutableHandleType propp) -{ - bool done; - return LookupOwnPropertyInline(cx, obj, id, propp, &done); -} - -template bool -js::NativeLookupOwnProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId id, - MutableHandleShape propp); - -template bool -js::NativeLookupOwnProperty(ExclusiveContext *cx, NativeObject *obj, jsid id, - FakeMutableHandle propp); - -template -bool -js::NativeLookupProperty(ExclusiveContext *cx, - typename MaybeRooted::HandleType obj, - typename MaybeRooted::HandleType id, - typename MaybeRooted::MutableHandleType objp, - typename MaybeRooted::MutableHandleType propp) -{ - return LookupPropertyInline(cx, obj, id, objp, propp); -} - -template bool -js::NativeLookupProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId id, - MutableHandleObject objp, MutableHandleShape propp); - -template bool -js::NativeLookupProperty(ExclusiveContext *cx, NativeObject *obj, jsid id, - FakeMutableHandle objp, - FakeMutableHandle 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(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 @@ -1130,8 +1077,8 @@ UpdateShapeTypeAndValue(ExclusiveContext *cx, NativeObject *obj, Shape *shape, c } 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, @@ -1220,13 +1167,10 @@ DefinePropertyOrElement(ExclusiveContext *cx, HandleNativeObject obj, HandleId i 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(); @@ -1341,19 +1285,18 @@ CheckAccessorRedefinition(ExclusiveContext *cx, HandleObject obj, HandleShape sh } bool -js::NativeDefineProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId id, - Handle 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; /* @@ -1361,7 +1304,7 @@ js::NativeDefineProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId * 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(cx, obj, id, &shape)) return false; if (shape) { @@ -1395,7 +1338,7 @@ js::NativeDefineProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId 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()|. @@ -1457,8 +1400,8 @@ js::NativeDefineProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId 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 { @@ -1500,20 +1443,60 @@ js::NativeDefineProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId return result.succeed(); } +template 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::HandleType obj, + typename MaybeRooted::HandleType id, + typename MaybeRooted::MutableHandleType propp) { - Rooted desc(cx); - desc.initFields(obj, value, attrs, getter, setter); - return NativeDefineProperty(cx, obj, id, desc, result); + bool done; + return LookupOwnPropertyInline(cx, obj, id, propp, &done); +} + +template bool +js::NativeLookupOwnProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId id, + MutableHandleShape propp); + +template bool +js::NativeLookupOwnProperty(ExclusiveContext *cx, NativeObject *obj, jsid id, + FakeMutableHandle propp); + +template +bool +js::NativeLookupProperty(ExclusiveContext *cx, + typename MaybeRooted::HandleType obj, + typename MaybeRooted::HandleType id, + typename MaybeRooted::MutableHandleType objp, + typename MaybeRooted::MutableHandleType propp) +{ + return LookupPropertyInline(cx, obj, id, objp, propp); +} + +template bool +js::NativeLookupProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId id, + MutableHandleObject objp, MutableHandleShape propp); + +template bool +js::NativeLookupProperty(ExclusiveContext *cx, NativeObject *obj, jsid id, + FakeMutableHandle objp, + FakeMutableHandle 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(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); @@ -1521,8 +1504,8 @@ js::NativeDefineProperty(ExclusiveContext *cx, HandleNativeObject obj, PropertyN 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) { @@ -1567,7 +1550,6 @@ js::NativeDefineProperty(ExclusiveContext *cx, HandleNativeObject obj, PropertyN return NativeDefineProperty(cx, obj, id, value, getter, setter, attrs); } - /*** [[HasProperty]] *****************************************************************************/ // ES6 draft rev31 9.1.7.1 OrdinaryHasProperty @@ -1620,7 +1602,6 @@ js::NativeHasProperty(JSContext *cx, HandleNativeObject obj, HandleId id, bool * } } - /*** [[Get]] *************************************************************************************/ static inline bool @@ -1630,7 +1611,7 @@ CallGetter(JSContext* cx, HandleObject receiver, HandleShape shape, MutableHandl 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()); @@ -1946,7 +1927,6 @@ js::GetPropertyForNameLookup(JSContext *cx, HandleObject obj, HandleId id, Mutab return NativeGetPropertyInline(cx, obj.as(), obj, id, NameLookup, vp); } - /*** [[Set]] *************************************************************************************/ static bool @@ -1978,18 +1958,13 @@ MaybeReportUndeclaredVarAssignment(JSContext *cx, JSString *propname) * 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 @@ -2042,8 +2017,6 @@ js::SetPropertyByDefining(JSContext *cx, HandleObject obj, HandleId id, HandleVa if (!receiver->is()) 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 nativeReceiver(cx, &receiver->as()); return DefinePropertyOrElement(cx, nativeReceiver, id, getter, setter, attrs, v, true, result); } @@ -2051,15 +2024,15 @@ js::SetPropertyByDefining(JSContext *cx, HandleObject obj, HandleId id, HandleVa // 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()); 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); } /* @@ -2068,20 +2041,22 @@ js::SetPropertyOnProto(JSContext *cx, HandleObject obj, HandleId id, HandleValue * * 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()); + MOZ_ASSERT(!receiver->is()); - 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); } /* @@ -2089,12 +2064,12 @@ SetNonexistentProperty(JSContext *cx, HandleNativeObject obj, HandleId id, Handl * 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 @@ -2116,152 +2091,128 @@ SetDenseOrTypedArrayElement(JSContext *cx, HandleNativeObject obj, uint32_t inde 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() || !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()); // 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. + /* 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); + } - // 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); - } - - // 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() && id == NameToId(cx->names().length)) { Rooted arr(cx, &pobj->as()); - 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() && 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); @@ -2276,7 +2227,7 @@ js::NativeSetProperty(JSContext *cx, HandleNativeObject obj, HandleId id, Handle 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. @@ -2290,7 +2241,7 @@ js::NativeSetProperty(JSContext *cx, HandleNativeObject obj, HandleId id, Handle 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 @@ -2307,23 +2258,23 @@ js::NativeSetProperty(JSContext *cx, HandleNativeObject obj, HandleId id, Handle 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(); } } 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]] **********************************************************************************/ diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index 414ae01b8c39..89e81ea9e74e 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -1255,11 +1255,6 @@ IsObjectValueInCompartment(Value v, JSCompartment *comp) * (9.4.2), Strings (9.4.3), and so on. */ -extern bool -NativeDefineProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId id, - Handle desc, - ObjectOpResult &result); - extern bool NativeDefineProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId id, HandleValue value, JSGetterOp getter, JSSetterOp setter, unsigned attrs, @@ -1312,12 +1307,12 @@ NativeGetElement(JSContext *cx, HandleNativeObject obj, uint32_t index, MutableH } 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 @@ -1332,12 +1327,12 @@ enum QualifiedBool { }; 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); @@ -1448,21 +1443,21 @@ js::GetPropertyNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, V } 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(), id, v, receiver, Qualified, result); + return JSObject::nonNativeSetProperty(cx, obj, receiver, id, vp, result); + return NativeSetProperty(cx, obj.as(), 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(), index, v, receiver, result); + return JSObject::nonNativeSetElement(cx, obj, receiver, index, vp, result); + return NativeSetElement(cx, obj.as(), receiver, index, vp, result); } #endif /* vm_NativeObject_h */ diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 630bfc27f5fa..11320089f87a 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -298,7 +298,7 @@ CallObject::createHollowForDebug(JSContext *cx, HandleFunction callee) 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; } @@ -469,11 +469,12 @@ with_LookupProperty(JSContext *cx, HandleObject obj, HandleId id, } static bool -with_DefineProperty(JSContext *cx, HandleObject obj, HandleId id, Handle desc, +with_DefineProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue value, + JSGetterOp getter, JSSetterOp setter, unsigned attrs, ObjectOpResult &result) { RootedObject actual(cx, &obj->as().object()); - return DefineProperty(cx, actual, id, desc, result); + return DefineProperty(cx, actual, id, value, getter, setter, attrs, result); } static bool @@ -492,14 +493,14 @@ with_GetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleI } 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().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 @@ -930,8 +931,8 @@ uninitialized_GetProperty(JSContext *cx, HandleObject obj, HandleObject receiver } 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; @@ -1593,8 +1594,8 @@ class DebugScopeProxy : public BaseProxyHandler } } - 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 debugScope(cx, &proxy->as()); Rooted scope(cx, &proxy->as().scope()); @@ -1603,25 +1604,21 @@ class DebugScopeProxy : public BaseProxyHandler 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 desc, + MutableHandle desc, ObjectOpResult &result) const override { Rooted scope(cx, &proxy->as().scope()); diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 8a578b7224ab..211369db6a71 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -336,10 +336,10 @@ js::intrinsic_UnsafePutElements(JSContext *cx, unsigned argc, Value *vp) if (IsAnyTypedArray(arrobj.get()) || arrobj->is()) { MOZ_ASSERT_IF(IsAnyTypedArray(arrobj.get()), idx < AnyTypedArrayLength(arrobj.get())); MOZ_ASSERT_IF(arrobj->is(), idx < uint32_t(arrobj->as().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().getDenseInitializedLength()); diff --git a/js/src/vm/Shape-inl.h b/js/src/vm/Shape-inl.h index 07bc1a4d480b..962982f9deb7 100644 --- a/js/src/vm/Shape-inl.h +++ b/js/src/vm/Shape-inl.h @@ -39,6 +39,30 @@ Shape::search(ExclusiveContext *cx, jsid id) 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()); // 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) { diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h index f6e570d5fb07..ce10e5d21f84 100644 --- a/js/src/vm/Shape.h +++ b/js/src/vm/Shape.h @@ -1019,7 +1019,16 @@ class Shape : public gc::TenuredCell 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()) diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index 806126498471..309e734ef08d 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -679,16 +679,16 @@ UnboxedPlainObject::obj_lookupProperty(JSContext *cx, HandleObject obj, } /* static */ bool -UnboxedPlainObject::obj_defineProperty(JSContext *cx, HandleObject obj, HandleId id, - Handle 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().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().setValue(cx, *property, desc.value())) + if (obj->as().setValue(cx, *property, v)) return true; } @@ -697,8 +697,7 @@ UnboxedPlainObject::obj_defineProperty(JSContext *cx, HandleObject obj, HandleId 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. @@ -707,9 +706,9 @@ UnboxedPlainObject::obj_defineProperty(JSContext *cx, HandleObject obj, HandleId 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 @@ -758,38 +757,36 @@ UnboxedPlainObject::obj_getProperty(JSContext *cx, HandleObject obj, HandleObjec } /* 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().layout(); if (const UnboxedLayout::Property *property = layout.lookup(id)) { - if (receiver.isObject() && obj == &receiver.toObject()) { - if (obj->as().setValue(cx, *property, v)) + if (obj == receiver) { + if (obj->as().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().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 diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h index dc56ca431244..84f0992e20ec 100644 --- a/js/src/vm/UnboxedObject.h +++ b/js/src/vm/UnboxedObject.h @@ -192,8 +192,8 @@ class UnboxedPlainObject : public JSObject HandleId id, MutableHandleObject objp, MutableHandleShape propp); - static bool obj_defineProperty(JSContext *cx, HandleObject obj, HandleId id, - Handle 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); @@ -201,8 +201,8 @@ class UnboxedPlainObject : public JSObject 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 desc); diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index bc9743acc995..00cd52610909 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -33,7 +33,7 @@ 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 " diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp index 6d5c2bf79b44..1ed3a083fd6d 100644 --- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -733,12 +733,12 @@ xpc::SandboxProxyHandler::get(JSContext *cx, JS::Handle proxy, bool xpc::SandboxProxyHandler::set(JSContext *cx, JS::Handle proxy, + JS::Handle receiver, JS::Handle id, - JS::Handle v, - JS::Handle receiver, + JS::MutableHandle vp, JS::ObjectOpResult &result) const { - return BaseProxyHandler::set(cx, proxy, id, v, receiver, result); + return BaseProxyHandler::set(cx, proxy, receiver, id, vp, result); } bool diff --git a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp index 2c45cb9d1e13..e1a79531ec88 100644 --- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp +++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp @@ -426,6 +426,14 @@ XPC_WN_OnlyIWrite_AddPropertyStub(JSContext *cx, HandleObject obj, HandleId id, 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) @@ -644,7 +652,7 @@ const XPCWrappedNativeJSClass XPC_WN_NoHelper_JSClass = { 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 @@ -1353,6 +1361,14 @@ XPC_WN_OnlyIWrite_Proto_AddPropertyStub(JSContext *cx, HandleObject obj, HandleI 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) { @@ -1388,7 +1404,7 @@ const js::Class XPC_WN_NoMods_WithCall_Proto_JSClass = { 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; @@ -1413,7 +1429,7 @@ const js::Class XPC_WN_NoMods_NoCall_Proto_JSClass = { 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; @@ -1508,7 +1524,7 @@ const js::Class XPC_WN_Tearoff_JSClass = { 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; diff --git a/js/xpconnect/tests/unit/test_xpcwn_tamperproof.js b/js/xpconnect/tests/unit/test_xpcwn_tamperproof.js deleted file mode 100644 index 7e1a83b93eda..000000000000 --- 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 . - -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" - }); -} diff --git a/js/xpconnect/tests/unit/xpcshell.ini b/js/xpconnect/tests/unit/xpcshell.ini index a91f5c9f4424..f66462cf60c2 100644 --- a/js/xpconnect/tests/unit/xpcshell.ini +++ b/js/xpconnect/tests/unit/xpcshell.ini @@ -109,6 +109,5 @@ 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 diff --git a/js/xpconnect/wrappers/AddonWrapper.cpp b/js/xpconnect/wrappers/AddonWrapper.cpp index dc76f46221d1..1fc0909820a2 100644 --- a/js/xpconnect/wrappers/AddonWrapper.cpp +++ b/js/xpconnect/wrappers/AddonWrapper.cpp @@ -119,24 +119,24 @@ AddonWrapper::get(JSContext *cx, JS::Handle wrapper, JS::Handle template bool -AddonWrapper::set(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id, JS::HandleValue v, - JS::HandleValue receiver, JS::ObjectOpResult &result) const +AddonWrapper::set(JSContext *cx, JS::HandleObject wrapper, JS::HandleObject receiver, + JS::HandleId id, JS::MutableHandleValue vp, + JS::ObjectOpResult &result) const { Rooted 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(); } @@ -147,8 +147,8 @@ AddonWrapper::set(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id template bool AddonWrapper::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, - Handle desc, - ObjectOpResult &result) const + MutableHandle desc, + JS::ObjectOpResult &result) const { Rooted interpDesc(cx); if (!Interpose(cx, wrapper, nullptr, id, &interpDesc)) diff --git a/js/xpconnect/wrappers/AddonWrapper.h b/js/xpconnect/wrappers/AddonWrapper.h index f8ec03a2af68..2c5eaa2ec02b 100644 --- a/js/xpconnect/wrappers/AddonWrapper.h +++ b/js/xpconnect/wrappers/AddonWrapper.h @@ -28,14 +28,15 @@ class AddonWrapper : public Base { JS::Handle id, JS::MutableHandle desc) const override; virtual bool defineProperty(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, - JS::Handle desc, + JS::MutableHandle 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 wrapper, JS::Handle receiver, JS::Handle id, JS::MutableHandle 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 wrapper, JS::Handle id, diff --git a/js/xpconnect/wrappers/ChromeObjectWrapper.cpp b/js/xpconnect/wrappers/ChromeObjectWrapper.cpp index 0b1f31eba4ca..afd264b413cb 100644 --- a/js/xpconnect/wrappers/ChromeObjectWrapper.cpp +++ b/js/xpconnect/wrappers/ChromeObjectWrapper.cpp @@ -21,7 +21,7 @@ const ChromeObjectWrapper ChromeObjectWrapper::singleton; bool ChromeObjectWrapper::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, - Handle desc, + MutableHandle desc, JS::ObjectOpResult &result) const { if (!AccessCheck::checkPassToPrivilegedCode(cx, wrapper, desc.value())) @@ -30,12 +30,13 @@ ChromeObjectWrapper::defineProperty(JSContext *cx, HandleObject wrapper, } 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); } } diff --git a/js/xpconnect/wrappers/ChromeObjectWrapper.h b/js/xpconnect/wrappers/ChromeObjectWrapper.h index f2dc09d3affd..b304a1519f87 100644 --- a/js/xpconnect/wrappers/ChromeObjectWrapper.h +++ b/js/xpconnect/wrappers/ChromeObjectWrapper.h @@ -29,10 +29,11 @@ class ChromeObjectWrapper : public ChromeObjectWrapperBase virtual bool defineProperty(JSContext *cx, JS::Handle wrapper, JS::Handle id, - JS::Handle desc, + JS::MutableHandle 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 wrapper, + JS::Handle receiver, JS::Handle id, + JS::MutableHandle vp, JS::ObjectOpResult &result) const override; static const ChromeObjectWrapper singleton; diff --git a/js/xpconnect/wrappers/FilteringWrapper.cpp b/js/xpconnect/wrappers/FilteringWrapper.cpp index 15194068df36..94fb116b75b0 100644 --- a/js/xpconnect/wrappers/FilteringWrapper.cpp +++ b/js/xpconnect/wrappers/FilteringWrapper.cpp @@ -234,7 +234,7 @@ CrossOriginXrayWrapper::ownPropertyKeys(JSContext *cx, JS::Handle wra bool CrossOriginXrayWrapper::defineProperty(JSContext *cx, JS::Handle wrapper, JS::Handle id, - JS::Handle desc, + JS::MutableHandle desc, JS::ObjectOpResult &result) const { JS_ReportError(cx, "Permission denied to define property on cross-origin object"); diff --git a/js/xpconnect/wrappers/FilteringWrapper.h b/js/xpconnect/wrappers/FilteringWrapper.h index 1d5b99190ebb..c2c8089aac9c 100644 --- a/js/xpconnect/wrappers/FilteringWrapper.h +++ b/js/xpconnect/wrappers/FilteringWrapper.h @@ -73,7 +73,7 @@ class CrossOriginXrayWrapper : public SecurityXrayDOM { JS::MutableHandle desc) const override; virtual bool defineProperty(JSContext *cx, JS::Handle wrapper, JS::Handle id, - JS::Handle desc, + JS::MutableHandle desc, JS::ObjectOpResult &result) const override; virtual bool ownPropertyKeys(JSContext *cx, JS::Handle wrapper, JS::AutoIdVector &props) const override; diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 19db3ba00ad4..db353027b275 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -593,7 +593,7 @@ JSXrayTraits::delete_(JSContext *cx, HandleObject wrapper, HandleId id, ObjectOp bool JSXrayTraits::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, - Handle desc, + MutableHandle desc, Handle existingDesc, ObjectOpResult &result, bool *defined) @@ -637,10 +637,9 @@ JSXrayTraits::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, return false; } - Rooted 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; } @@ -1416,7 +1415,7 @@ XPCWrappedNativeXrayTraits::resolveOwnProperty(JSContext *cx, const Wrapper &jsW bool XPCWrappedNativeXrayTraits::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, - Handle desc, + MutableHandle desc, Handle existingDesc, JS::ObjectOpResult &result, bool *defined) { @@ -1577,7 +1576,7 @@ DOMXrayTraits::resolveOwnProperty(JSContext *cx, const Wrapper &jsWrapper, Handl bool DOMXrayTraits::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, - Handle desc, + MutableHandle desc, Handle existingDesc, JS::ObjectOpResult &result, bool *defined) { @@ -1931,7 +1930,7 @@ XrayWrapper::getOwnPropertyDescriptor(JSContext *cx, HandleObject // 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 wrapped) { // Compute whether the original objects were waived, and implicitly, whether @@ -1976,7 +1975,7 @@ RecreateLostWaivers(JSContext *cx, const JSPropertyDescriptor *orig, template bool XrayWrapper::defineProperty(JSContext *cx, HandleObject wrapper, - HandleId id, Handle desc, + HandleId id, MutableHandle desc, ObjectOpResult &result) const { assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::SET); @@ -2081,15 +2080,15 @@ XrayWrapper::get(JSContext *cx, HandleObject wrapper, template bool -XrayWrapper::set(JSContext *cx, HandleObject wrapper, HandleId id, HandleValue v, - HandleValue receiver, ObjectOpResult &result) const +XrayWrapper::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 diff --git a/js/xpconnect/wrappers/XrayWrapper.h b/js/xpconnect/wrappers/XrayWrapper.h index 5e196804c50b..4898569f004c 100644 --- a/js/xpconnect/wrappers/XrayWrapper.h +++ b/js/xpconnect/wrappers/XrayWrapper.h @@ -133,7 +133,7 @@ public: JS::HandleObject holder, JS::HandleId id, JS::MutableHandle desc) override; bool defineProperty(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id, - JS::Handle desc, + JS::MutableHandle desc, JS::Handle existingDesc, JS::ObjectOpResult &result, bool *defined); virtual bool enumerateNames(JSContext *cx, JS::HandleObject wrapper, unsigned flags, @@ -185,7 +185,7 @@ public: JS::HandleObject holder, JS::HandleId id, JS::MutableHandle desc) override; bool defineProperty(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id, - JS::Handle desc, + JS::MutableHandle desc, JS::Handle existingDesc, JS::ObjectOpResult &result, bool *defined); virtual bool enumerateNames(JSContext *cx, JS::HandleObject wrapper, unsigned flags, @@ -228,7 +228,7 @@ public: 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 desc, + JS::MutableHandle desc, JS::Handle existingDesc, JS::ObjectOpResult &result, bool *defined); @@ -346,7 +346,7 @@ public: JS::MutableHandle desc) override; bool defineProperty(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id, - JS::Handle desc, + JS::MutableHandle desc, JS::Handle existingDesc, JS::ObjectOpResult &result, bool *defined) { @@ -420,7 +420,7 @@ class XrayWrapper : public Base { virtual bool getOwnPropertyDescriptor(JSContext *cx, JS::Handle wrapper, JS::Handle id, JS::MutableHandle desc) const override; virtual bool defineProperty(JSContext *cx, JS::Handle wrapper, JS::Handle id, - JS::Handle desc, + JS::MutableHandle desc, JS::ObjectOpResult &result) const override; virtual bool ownPropertyKeys(JSContext *cx, JS::Handle wrapper, JS::AutoIdVector &props) const override; @@ -441,8 +441,8 @@ class XrayWrapper : public Base { bool *bp) const override; virtual bool get(JSContext *cx, JS::Handle wrapper, JS::Handle receiver, JS::Handle id, JS::MutableHandle vp) const override; - virtual bool set(JSContext *cx, JS::Handle wrapper, JS::Handle id, - JS::Handle v, JS::Handle receiver, + virtual bool set(JSContext *cx, JS::Handle wrapper, JS::Handle receiver, + JS::Handle id, JS::MutableHandle vp, JS::ObjectOpResult &result) const override; virtual bool call(JSContext *cx, JS::Handle wrapper, const JS::CallArgs &args) const override; @@ -515,8 +515,8 @@ public: bool *bp) const override; virtual bool get(JSContext *cx, JS::Handle proxy, JS::Handle receiver, JS::Handle id, JS::MutableHandle vp) const override; - virtual bool set(JSContext *cx, JS::Handle proxy, JS::Handle id, - JS::Handle v, JS::Handle receiver, + virtual bool set(JSContext *cx, JS::Handle proxy, JS::Handle receiver, + JS::Handle id, JS::MutableHandle vp, JS::ObjectOpResult &result) const override; virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle proxy,