From d1204e0adbcbd6ac32ebc10e3066850946b51b13 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Wed, 4 Feb 2015 10:20:04 -0600 Subject: [PATCH] Bug 1113369, part 5 - [[Delete]] ObjectOpResult support. r=Waldo, r=bz in dom, r=dvander in js/ipc, r=bholley in js/xpconnect. --- dom/base/WindowNamedPropertiesHandler.cpp | 6 +- dom/base/WindowNamedPropertiesHandler.h | 2 +- dom/base/nsGlobalWindow.cpp | 15 ++--- dom/bindings/Codegen.py | 52 +++++++++------ dom/bindings/DOMJSProxyHandler.cpp | 7 +- dom/bindings/DOMJSProxyHandler.h | 4 +- dom/indexedDB/KeyPath.cpp | 10 +-- dom/plugins/base/nsJSNPRuntime.cpp | 49 +++++++------- dom/xbl/nsXBLProtoImpl.cpp | 4 +- js/ipc/JavaScriptBase.h | 9 ++- js/ipc/PJavaScript.ipdl | 2 +- js/ipc/WrapperAnswer.cpp | 10 ++- js/ipc/WrapperAnswer.h | 3 +- js/ipc/WrapperOwner.cpp | 14 ++-- js/ipc/WrapperOwner.h | 5 +- js/public/Class.h | 12 ++-- js/public/Proxy.h | 6 +- js/src/builtin/TypedObject.cpp | 10 ++- js/src/builtin/TypedObject.h | 3 +- js/src/jit/BaselineCompiler.cpp | 12 ++-- js/src/jit/CodeGenerator.cpp | 8 +-- js/src/js.msg | 5 ++ js/src/jsapi.cpp | 40 ++++++++---- js/src/jsapi.h | 12 ++-- js/src/jsarray.cpp | 45 +++++++------ js/src/jscntxtinlines.h | 9 ++- js/src/jsfriendapi.h | 3 +- js/src/jsobj.cpp | 10 +-- js/src/jsobj.h | 4 +- js/src/jsobjinlines.h | 10 +-- js/src/json.cpp | 8 +-- js/src/jswrapper.h | 3 +- js/src/proxy/CrossCompartmentWrapper.cpp | 5 +- js/src/proxy/DeadObjectProxy.cpp | 3 +- js/src/proxy/DeadObjectProxy.h | 3 +- js/src/proxy/DirectProxyHandler.cpp | 5 +- js/src/proxy/Proxy.cpp | 21 +++--- js/src/proxy/Proxy.h | 2 +- js/src/proxy/ScriptedDirectProxyHandler.cpp | 49 +++++++------- js/src/proxy/ScriptedDirectProxyHandler.h | 3 +- js/src/proxy/ScriptedIndirectProxyHandler.cpp | 16 +++-- js/src/proxy/ScriptedIndirectProxyHandler.h | 3 +- js/src/tests/js1_6/Array/regress-304828.js | 2 +- js/src/vm/ArgumentsObject.cpp | 13 ++-- js/src/vm/Debugger.cpp | 6 +- js/src/vm/Interpreter.cpp | 64 +++++++++++-------- js/src/vm/Interpreter.h | 4 +- js/src/vm/NativeObject.cpp | 15 ++--- js/src/vm/NativeObject.h | 2 +- js/src/vm/ScopeObject.cpp | 13 ++-- js/src/vm/UnboxedObject.cpp | 4 +- js/src/vm/UnboxedObject.h | 3 +- js/src/vm/Xdr.h | 4 +- js/xpconnect/src/XPCWrappedNativeJSOps.cpp | 8 +-- js/xpconnect/wrappers/AddonWrapper.cpp | 5 +- js/xpconnect/wrappers/AddonWrapper.h | 3 +- js/xpconnect/wrappers/FilteringWrapper.cpp | 2 +- js/xpconnect/wrappers/FilteringWrapper.h | 2 +- js/xpconnect/wrappers/XrayWrapper.cpp | 13 ++-- js/xpconnect/wrappers/XrayWrapper.h | 10 +-- 60 files changed, 372 insertions(+), 303 deletions(-) diff --git a/dom/base/WindowNamedPropertiesHandler.cpp b/dom/base/WindowNamedPropertiesHandler.cpp index 3f4c9ab64bd..a0c513a05ae 100644 --- a/dom/base/WindowNamedPropertiesHandler.cpp +++ b/dom/base/WindowNamedPropertiesHandler.cpp @@ -210,10 +210,10 @@ WindowNamedPropertiesHandler::ownPropNames(JSContext* aCx, bool WindowNamedPropertiesHandler::delete_(JSContext* aCx, JS::Handle aProxy, - JS::Handle aId, bool* aBp) const + JS::Handle aId, + JS::ObjectOpResult &aResult) const { - *aBp = false; - return true; + return aResult.failCantDeleteWindowNamedProperty(); } static bool diff --git a/dom/base/WindowNamedPropertiesHandler.h b/dom/base/WindowNamedPropertiesHandler.h index ab2dfd0ea3c..1305517ab2b 100644 --- a/dom/base/WindowNamedPropertiesHandler.h +++ b/dom/base/WindowNamedPropertiesHandler.h @@ -35,7 +35,7 @@ public: JS::AutoIdVector& aProps) const MOZ_OVERRIDE; virtual bool delete_(JSContext* aCx, JS::Handle aProxy, JS::Handle aId, - bool* aBp) const MOZ_OVERRIDE; + JS::ObjectOpResult &aResult) const MOZ_OVERRIDE; virtual bool preventExtensions(JSContext* aCx, JS::Handle aProxy, bool *succeeded) const MOZ_OVERRIDE diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index bcafa4a64ec..eb8fa337bc5 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -629,7 +629,7 @@ public: JS::AutoIdVector &props) const MOZ_OVERRIDE; virtual bool delete_(JSContext *cx, JS::Handle proxy, JS::Handle id, - bool *bp) const MOZ_OVERRIDE; + JS::ObjectOpResult &result) const MOZ_OVERRIDE; virtual bool enumerate(JSContext *cx, JS::Handle proxy, JS::MutableHandle vp) const MOZ_OVERRIDE; virtual bool preventExtensions(JSContext *cx, @@ -825,23 +825,20 @@ nsOuterWindowProxy::ownPropertyKeys(JSContext *cx, bool nsOuterWindowProxy::delete_(JSContext *cx, JS::Handle proxy, - JS::Handle id, bool *bp) const + JS::Handle id, JS::ObjectOpResult &result) const { if (nsCOMPtr frame = GetSubframeWindow(cx, proxy, id)) { - // Reject (which means throw if strict, else return false) the delete. - // Except we don't even know whether we're strict. See bug 803157. - *bp = false; - return true; + // Fail (which means throw if strict, else return false). + return result.failCantDeleteWindowElement(); } int32_t index = GetArrayIndexFromId(cx, id); if (IsArrayIndex(index)) { // Indexed, but not supported. Spec says return true. - *bp = true; - return true; + return result.succeed(); } - return js::Wrapper::delete_(cx, proxy, id, bp); + return js::Wrapper::delete_(cx, proxy, id, result); } bool diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 9e6fc03b09e..6bebe79707f 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -10307,7 +10307,7 @@ class CGDOMJSProxyHandler_delete(ClassMethod): args = [Argument('JSContext*', 'cx'), Argument('JS::Handle', 'proxy'), Argument('JS::Handle', 'id'), - Argument('bool*', 'bp')] + Argument('JS::ObjectOpResult&', 'opresult')] ClassMethod.__init__(self, "delete_", "bool", args, virtual=True, override=True, const=True) self.descriptor = descriptor @@ -10316,6 +10316,12 @@ class CGDOMJSProxyHandler_delete(ClassMethod): def getDeleterBody(type, foundVar=None): """ type should be "Named" or "Indexed" + + The possible outcomes: + - an error happened (the emitted code returns false) + - own property not found (foundVar=false, deleteSucceeded=true) + - own property found and deleted (foundVar=true, deleteSucceeded=true) + - own property found but can't be deleted (foundVar=true, deleteSucceeded=false) """ assert type in ("Named", "Indexed") deleter = self.descriptor.operations[type + 'Deleter'] @@ -10324,29 +10330,34 @@ class CGDOMJSProxyHandler_delete(ClassMethod): raise TypeError("Can't handle a deleter on an interface " "that has unforgeables. Figure out how " "that should work!") - decls = "" - if (not deleter.signatures()[0][0].isPrimitive() or - deleter.signatures()[0][0].nullable() or - deleter.signatures()[0][0].tag() != IDLType.Tags.bool): - setBp = "*bp = true;\n" - else: - decls += "bool result;\n" + # See if the deleter method is fallible. + t = deleter.signatures()[0][0] + if t.isPrimitive() and not t.nullable() and t.tag() == IDLType.Tags.bool: + # The deleter method has a boolean out-parameter. When a + # property is found, the out-param indicates whether it was + # successfully deleted. + decls = "bool result;\n" if foundVar is None: foundVar = "found" decls += "bool found = false;\n" - setBp = fill( + setDS = fill( """ - if (${foundVar}) { - *bp = result; - } else { - *bp = true; + if (!${foundVar}) { + deleteSucceeded = true; } """, foundVar=foundVar) + else: + # No boolean out-parameter: if a property is found, + # deleting it always succeeds. + decls = "" + setDS = "deleteSucceeded = true;\n" + deleterClass = globals()["CGProxy%sDeleter" % type] body = (decls + - deleterClass(self.descriptor, resultVar="result", foundVar=foundVar).define() + - setBp) + deleterClass(self.descriptor, resultVar="deleteSucceeded", + foundVar=foundVar).define() + + setDS) elif getattr(self.descriptor, "supports%sProperties" % type)(): presenceCheckerClass = globals()["CGProxy%sPresenceChecker" % type] foundDecl = "" @@ -10357,7 +10368,7 @@ class CGDOMJSProxyHandler_delete(ClassMethod): """ $*{foundDecl} $*{presenceChecker} - *bp = !${foundVar}; + deleteSucceeded = !${foundVar}; """, foundDecl=foundDecl, presenceChecker=presenceCheckerClass(self.descriptor, foundVar=foundVar).define(), @@ -10378,9 +10389,9 @@ class CGDOMJSProxyHandler_delete(ClassMethod): """ int32_t index = GetArrayIndexFromId(cx, id); if (IsArrayIndex(index)) { + bool deleteSucceeded; $*{indexedBody} - // We always return here, even if the property was not found - return true; + return deleteSucceeded ? opresult.succeed() : opresult.failCantDelete(); } """, indexedBody=indexedBody) @@ -10393,9 +10404,10 @@ class CGDOMJSProxyHandler_delete(ClassMethod): delete += fill( """ bool found = false; + bool deleteSucceeded; $*{namedBody} if (found) { - return true; + return deleteSucceeded ? opresult.succeed() : opresult.failCantDelete(); } """, namedBody=namedBody) @@ -10413,7 +10425,7 @@ class CGDOMJSProxyHandler_delete(ClassMethod): delete += dedent(""" - return dom::DOMProxyHandler::delete_(cx, proxy, id, bp); + return dom::DOMProxyHandler::delete_(cx, proxy, id, opresult); """) return delete diff --git a/dom/bindings/DOMJSProxyHandler.cpp b/dom/bindings/DOMJSProxyHandler.cpp index aac02c4ff72..86c804834c2 100644 --- a/dom/bindings/DOMJSProxyHandler.cpp +++ b/dom/bindings/DOMJSProxyHandler.cpp @@ -260,15 +260,14 @@ DOMProxyHandler::set(JSContext *cx, Handle proxy, Handle r bool DOMProxyHandler::delete_(JSContext* cx, JS::Handle proxy, - JS::Handle id, bool* bp) const + JS::Handle id, JS::ObjectOpResult &result) const { JS::Rooted expando(cx); if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) { - return JS_DeletePropertyById2(cx, expando, id, bp); + return JS_DeletePropertyById(cx, expando, id, result); } - *bp = true; - return true; + return result.succeed(); } bool diff --git a/dom/bindings/DOMJSProxyHandler.h b/dom/bindings/DOMJSProxyHandler.h index 2b3222044be..0acb2bd2b6f 100644 --- a/dom/bindings/DOMJSProxyHandler.h +++ b/dom/bindings/DOMJSProxyHandler.h @@ -114,8 +114,8 @@ public: virtual bool defineProperty(JSContext* cx, JS::Handle proxy, JS::Handle id, JS::MutableHandle desc, JS::ObjectOpResult &result, bool *defined) const; - bool delete_(JSContext* cx, JS::Handle proxy, - JS::Handle id, bool* bp) const MOZ_OVERRIDE; + bool delete_(JSContext* cx, JS::Handle proxy, JS::Handle id, + JS::ObjectOpResult &result) const MOZ_OVERRIDE; bool preventExtensions(JSContext *cx, JS::Handle proxy, bool *succeeded) const MOZ_OVERRIDE; bool isExtensible(JSContext *cx, JS::Handle proxy, bool *extensible) diff --git a/dom/indexedDB/KeyPath.cpp b/dom/indexedDB/KeyPath.cpp index 8982606e69d..beb19f2f1b6 100644 --- a/dom/indexedDB/KeyPath.cpp +++ b/dom/indexedDB/KeyPath.cpp @@ -200,11 +200,11 @@ GetJSValFromKeyPathString(JSContext* aCx, if (targetObject) { // If this fails, we lose, and the web page sees a magical property // appear on the object :-( - bool succeeded; - if (!JS_DeleteUCProperty2(aCx, targetObject, - targetObjectPropName.get(), - targetObjectPropName.Length(), - &succeeded)) { + JS::ObjectOpResult succeeded; + if (!JS_DeleteUCProperty(aCx, targetObject, + targetObjectPropName.get(), + targetObjectPropName.Length(), + succeeded)) { IDB_REPORT_INTERNAL_ERR(); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } diff --git a/dom/plugins/base/nsJSNPRuntime.cpp b/dom/plugins/base/nsJSNPRuntime.cpp index b0007935794..98bccd0a5e1 100644 --- a/dom/plugins/base/nsJSNPRuntime.cpp +++ b/dom/plugins/base/nsJSNPRuntime.cpp @@ -161,7 +161,8 @@ static bool NPObjWrapper_AddProperty(JSContext *cx, JS::Handle obj, JS::Handle id, JS::MutableHandle vp); static bool -NPObjWrapper_DelProperty(JSContext *cx, JS::Handle obj, JS::Handle id, bool *succeeded); +NPObjWrapper_DelProperty(JSContext *cx, JS::Handle obj, JS::Handle id, + JS::ObjectOpResult &result); static bool NPObjWrapper_SetProperty(JSContext *cx, JS::Handle obj, JS::Handle id, @@ -975,33 +976,33 @@ nsJSObjWrapper::NP_RemoveProperty(NPObject *npobj, NPIdentifier npid) } nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj; - bool ok = false; AutoJSExceptionReporter reporter(cx); - bool deleted = false; + JS::ObjectOpResult result; JS::Rooted obj(cx, npjsobj->mJSObj); JSAutoCompartment ac(cx, obj); NS_ASSERTION(NPIdentifierIsInt(npid) || NPIdentifierIsString(npid), "id must be either string or int!\n"); JS::Rooted id(cx, NPIdentifierToJSId(npid)); - ok = ::JS_DeletePropertyById2(cx, obj, id, &deleted); - if (ok && deleted) { + if (!::JS_DeletePropertyById(cx, obj, id, result)) + return false; + + if (result) { // FIXME: See bug 425823, we shouldn't need to do this, and once // that bug is fixed we can remove this code. - bool hasProp; - ok = ::JS_HasPropertyById(cx, obj, id, &hasProp); + if (!::JS_HasPropertyById(cx, obj, id, &hasProp)) + return false; + if (!hasProp) + return true; - if (ok && hasProp) { - // The property might have been deleted, but it got - // re-resolved, so no, it's not really deleted. - - deleted = false; - } + // The property might have been deleted, but it got + // re-resolved, so no, it's not really deleted. + result.failCantDelete(); } - return ok && deleted; + return result.reportError(cx, obj, id); } //static @@ -1274,7 +1275,8 @@ NPObjWrapper_AddProperty(JSContext *cx, JS::Handle obj, JS::Handle obj, JS::Handle id, bool *succeeded) +NPObjWrapper_DelProperty(JSContext *cx, JS::Handle obj, JS::Handle id, + JS::ObjectOpResult &result) { NPObject *npobj = GetNPObject(cx, obj); @@ -1294,15 +1296,18 @@ NPObjWrapper_DelProperty(JSContext *cx, JS::Handle obj, JS::Handle_class->removeProperty(npobj, identifier); - - return ReportExceptionIfPending(cx); + // This removeProperty hook may throw an exception and return false; or just + // return false without an exception pending, which behaves like `delete + // obj.prop` returning false: in strict mode it becomes a TypeError. Legacy + // code---nothing else that uses the JSAPI works this way anymore. + bool succeeded = npobj->_class->removeProperty(npobj, identifier); + if (!ReportExceptionIfPending(cx)) + return false; + return succeeded ? result.succeed() : result.failCantDelete(); } static bool diff --git a/dom/xbl/nsXBLProtoImpl.cpp b/dom/xbl/nsXBLProtoImpl.cpp index 6131c63f61c..5e48f5e65ae 100644 --- a/dom/xbl/nsXBLProtoImpl.cpp +++ b/dom/xbl/nsXBLProtoImpl.cpp @@ -342,8 +342,8 @@ nsXBLProtoImpl::UndefineFields(JSContext *cx, JS::Handle obj) const bool hasProp; if (::JS_AlreadyHasOwnUCProperty(cx, obj, s, name.Length(), &hasProp) && hasProp) { - bool dummy; - ::JS_DeleteUCProperty2(cx, obj, s, name.Length(), &dummy); + JS::ObjectOpResult ignored; + ::JS_DeleteUCProperty(cx, obj, s, name.Length(), ignored); } } } diff --git a/js/ipc/JavaScriptBase.h b/js/ipc/JavaScriptBase.h index 49a39088533..fcf72e6eda9 100644 --- a/js/ipc/JavaScriptBase.h +++ b/js/ipc/JavaScriptBase.h @@ -56,8 +56,8 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base return Answer::RecvDefineProperty(ObjectId::deserialize(objId), id, flags, rs); } bool RecvDelete(const uint64_t &objId, const JSIDVariant &id, - ReturnStatus *rs, bool *success) { - return Answer::RecvDelete(ObjectId::deserialize(objId), id, rs, success); + ReturnStatus *rs) { + return Answer::RecvDelete(ObjectId::deserialize(objId), id, rs); } bool RecvHas(const uint64_t &objId, const JSIDVariant &id, @@ -147,9 +147,8 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base ReturnStatus *rs) { return Base::SendDefineProperty(objId.serialize(), id, flags, rs); } - bool SendDelete(const ObjectId &objId, const JSIDVariant &id, - ReturnStatus *rs, bool *success) { - return Base::SendDelete(objId.serialize(), id, rs, success); + bool SendDelete(const ObjectId &objId, const JSIDVariant &id, ReturnStatus *rs) { + return Base::SendDelete(objId.serialize(), id, rs); } bool SendHas(const ObjectId &objId, const JSIDVariant &id, diff --git a/js/ipc/PJavaScript.ipdl b/js/ipc/PJavaScript.ipdl index 1f17b2bcac3..68bef1b9738 100644 --- a/js/ipc/PJavaScript.ipdl +++ b/js/ipc/PJavaScript.ipdl @@ -28,7 +28,7 @@ both: prio(high) sync GetPropertyDescriptor(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, PPropertyDescriptor result); prio(high) sync GetOwnPropertyDescriptor(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, PPropertyDescriptor result); prio(high) sync DefineProperty(uint64_t objId, JSIDVariant id, PPropertyDescriptor descriptor) returns (ReturnStatus rs); - prio(high) sync Delete(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool successful); + prio(high) sync Delete(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs); prio(high) sync Has(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has); prio(high) sync HasOwn(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has); diff --git a/js/ipc/WrapperAnswer.cpp b/js/ipc/WrapperAnswer.cpp index 8b2b12b1963..44a45a69b58 100644 --- a/js/ipc/WrapperAnswer.cpp +++ b/js/ipc/WrapperAnswer.cpp @@ -195,14 +195,12 @@ WrapperAnswer::RecvDefineProperty(const ObjectId &objId, const JSIDVariant &idVa } bool -WrapperAnswer::RecvDelete(const ObjectId &objId, const JSIDVariant &idVar, ReturnStatus *rs, - bool *success) +WrapperAnswer::RecvDelete(const ObjectId &objId, const JSIDVariant &idVar, ReturnStatus *rs) { AutoJSAPI jsapi; if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects()))) return false; JSContext *cx = jsapi.cx(); - *success = false; RootedObject obj(cx, findObjectById(cx, objId)); if (!obj) @@ -214,10 +212,10 @@ WrapperAnswer::RecvDelete(const ObjectId &objId, const JSIDVariant &idVar, Retur if (!fromJSIDVariant(cx, idVar, &id)) return fail(cx, rs); - if (!JS_DeletePropertyById2(cx, obj, id, success)) + ObjectOpResult success; + if (!JS_DeletePropertyById(cx, obj, id, success)) return fail(cx, rs); - - return ok(rs); + return ok(rs, success); } bool diff --git a/js/ipc/WrapperAnswer.h b/js/ipc/WrapperAnswer.h index 785cc37c4ad..5b5b94d7023 100644 --- a/js/ipc/WrapperAnswer.h +++ b/js/ipc/WrapperAnswer.h @@ -29,8 +29,7 @@ class WrapperAnswer : public virtual JavaScriptShared PPropertyDescriptor *out); bool RecvDefineProperty(const ObjectId &objId, const JSIDVariant &id, const PPropertyDescriptor &flags, ReturnStatus *rs); - bool RecvDelete(const ObjectId &objId, const JSIDVariant &id, - ReturnStatus *rs, bool *success); + bool RecvDelete(const ObjectId &objId, const JSIDVariant &id, ReturnStatus *rs); bool RecvHas(const ObjectId &objId, const JSIDVariant &id, ReturnStatus *rs, bool *bp); diff --git a/js/ipc/WrapperOwner.cpp b/js/ipc/WrapperOwner.cpp index 0b9fd16606c..6a9684b8d9d 100644 --- a/js/ipc/WrapperOwner.cpp +++ b/js/ipc/WrapperOwner.cpp @@ -94,7 +94,8 @@ class CPOWProxyHandler : public BaseProxyHandler ObjectOpResult &result) const MOZ_OVERRIDE; virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE; + virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, + ObjectOpResult &result) const MOZ_OVERRIDE; virtual bool enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp) const MOZ_OVERRIDE; virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE; virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE; @@ -248,13 +249,14 @@ WrapperOwner::ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &p } bool -CPOWProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const +CPOWProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, + ObjectOpResult &result) const { - FORWARD(delete_, (cx, proxy, id, bp)); + FORWARD(delete_, (cx, proxy, id, result)); } bool -WrapperOwner::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) +WrapperOwner::delete_(JSContext *cx, HandleObject proxy, HandleId id, ObjectOpResult &result) { ObjectId objId = idOf(proxy); @@ -263,12 +265,12 @@ WrapperOwner::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) return false; ReturnStatus status; - if (!SendDelete(objId, idVar, &status, bp)) + if (!SendDelete(objId, idVar, &status)) return ipcfail(cx); LOG_STACK(); - return ok(cx, status); + return ok(cx, status, result); } bool diff --git a/js/ipc/WrapperOwner.h b/js/ipc/WrapperOwner.h index ad4d2ff2ad9..a91a81b4098 100644 --- a/js/ipc/WrapperOwner.h +++ b/js/ipc/WrapperOwner.h @@ -35,7 +35,8 @@ class WrapperOwner : public virtual JavaScriptShared 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, bool *bp); + bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, + JS::ObjectOpResult &result); bool preventExtensions(JSContext *cx, JS::HandleObject proxy, bool *succeeded); bool isExtensible(JSContext *cx, JS::HandleObject proxy, bool *extensible); bool has(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp); @@ -118,7 +119,7 @@ class WrapperOwner : public virtual JavaScriptShared const PPropertyDescriptor &flags, ReturnStatus *rs) = 0; virtual bool SendDelete(const ObjectId &objId, const JSIDVariant &id, - ReturnStatus *rs, bool *success) = 0; + ReturnStatus *rs) = 0; virtual bool SendHas(const ObjectId &objId, const JSIDVariant &id, ReturnStatus *rs, bool *bp) = 0; diff --git a/js/public/Class.h b/js/public/Class.h index a3f05ac114e..aec62d41378 100644 --- a/js/public/Class.h +++ b/js/public/Class.h @@ -122,6 +122,9 @@ class ObjectOpResult JS_PUBLIC_API(bool) failReadOnly(); JS_PUBLIC_API(bool) failGetterOnly(); JS_PUBLIC_API(bool) failCantSetInterposed(); + JS_PUBLIC_API(bool) failCantDelete(); + JS_PUBLIC_API(bool) failCantDeleteWindowElement(); + JS_PUBLIC_API(bool) failCantDeleteWindowNamedProperty(); uint32_t failureCode() const { MOZ_ASSERT(!ok()); @@ -192,17 +195,17 @@ typedef bool // If an error occurred, return false as per normal JSAPI error practice. // // If no error occurred, but the deletion attempt wasn't allowed (perhaps -// because the property was non-configurable), set *succeeded to false and +// because the property was non-configurable), call result.fail() and // return true. This will cause |delete obj[id]| to evaluate to false in // non-strict mode code, and to throw a TypeError in strict mode code. // // If no error occurred and the deletion wasn't disallowed (this is *not* the // same as saying that a deletion actually occurred -- deleting a non-existent // property, or an inherited property, is allowed -- it's just pointless), -// set *succeeded to true and return true. +// call result.succeed() and return true. typedef bool (* JSDeletePropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, - bool *succeeded); + JS::ObjectOpResult &result); // The type of ObjectOps::enumerate. This callback overrides a portion of SpiderMonkey's default // [[Enumerate]] internal method. When an ordinary object is enumerated, that object and each object @@ -303,7 +306,8 @@ typedef bool (* GetOwnPropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandle desc); typedef bool -(* DeletePropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool *succeeded); +(* DeletePropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, + JS::ObjectOpResult &result); typedef bool (* WatchOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable); diff --git a/js/public/Proxy.h b/js/public/Proxy.h index c27097ec1ac..13c5917e093 100644 --- a/js/public/Proxy.h +++ b/js/public/Proxy.h @@ -256,7 +256,9 @@ class JS_FRIEND_API(BaseProxyHandler) ObjectOpResult &result) const = 0; virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const = 0; - virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const = 0; + virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, + ObjectOpResult &result) const = 0; + /* * Because [[Enumerate]] is one of the standard traps it should be overridden. * However for convenience BaseProxyHandler includes a pure virtual implementation, @@ -374,7 +376,7 @@ class JS_FRIEND_API(DirectProxyHandler) : public BaseProxyHandler virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE; virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, - bool *bp) const MOZ_OVERRIDE; + ObjectOpResult &result) const MOZ_OVERRIDE; virtual bool enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp) const MOZ_OVERRIDE; virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index efeeb1d3f25..add879c2166 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -2059,18 +2059,16 @@ IsOwnId(JSContext *cx, HandleObject obj, HandleId id) } bool -TypedObject::obj_deleteProperty(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded) +TypedObject::obj_deleteProperty(JSContext *cx, HandleObject obj, HandleId id, ObjectOpResult &result) { if (IsOwnId(cx, obj, id)) return ReportPropertyError(cx, JSMSG_CANT_DELETE, id); RootedObject proto(cx, obj->getProto()); - if (!proto) { - *succeeded = false; - return true; - } + if (!proto) + return result.succeed(); - return DeleteProperty(cx, proto, id, succeeded); + return DeleteProperty(cx, proto, id, result); } bool diff --git a/js/src/builtin/TypedObject.h b/js/src/builtin/TypedObject.h index 99a230c27f6..1b00fab42ff 100644 --- a/js/src/builtin/TypedObject.h +++ b/js/src/builtin/TypedObject.h @@ -546,7 +546,8 @@ class TypedObject : public JSObject static bool obj_getOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, MutableHandle desc); - static bool obj_deleteProperty(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded); + static bool obj_deleteProperty(JSContext *cx, HandleObject obj, HandleId id, + ObjectOpResult &result); static bool obj_enumerate(JSContext *cx, HandleObject obj, AutoIdVector &properties); diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 09e054ecfe2..29ed71f908e 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -2005,8 +2005,10 @@ BaselineCompiler::emit_JSOP_STRICTSETELEM() } typedef bool (*DeleteElementFn)(JSContext *, HandleValue, HandleValue, bool *); -static const VMFunction DeleteElementStrictInfo = FunctionInfo(DeleteElement); -static const VMFunction DeleteElementNonStrictInfo = FunctionInfo(DeleteElement); +static const VMFunction DeleteElementStrictInfo + = FunctionInfo(DeleteElementJit); +static const VMFunction DeleteElementNonStrictInfo + = FunctionInfo(DeleteElementJit); bool BaselineCompiler::emit_JSOP_DELELEM() @@ -2170,8 +2172,10 @@ BaselineCompiler::emit_JSOP_GETXPROP() } typedef bool (*DeletePropertyFn)(JSContext *, HandleValue, HandlePropertyName, bool *); -static const VMFunction DeletePropertyStrictInfo = FunctionInfo(DeleteProperty); -static const VMFunction DeletePropertyNonStrictInfo = FunctionInfo(DeleteProperty); +static const VMFunction DeletePropertyStrictInfo = + FunctionInfo(DeletePropertyJit); +static const VMFunction DeletePropertyNonStrictInfo = + FunctionInfo(DeletePropertyJit); bool BaselineCompiler::emit_JSOP_DELPROP() diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index cc4a31c130d..e02437ec31d 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -8147,9 +8147,9 @@ CodeGenerator::visitCallSetProperty(LCallSetProperty *ins) typedef bool (*DeletePropertyFn)(JSContext *, HandleValue, HandlePropertyName, bool *); static const VMFunction DeletePropertyStrictInfo = - FunctionInfo(DeleteProperty); + FunctionInfo(DeletePropertyJit); static const VMFunction DeletePropertyNonStrictInfo = - FunctionInfo(DeleteProperty); + FunctionInfo(DeletePropertyJit); void CodeGenerator::visitCallDeleteProperty(LCallDeleteProperty *lir) @@ -8165,9 +8165,9 @@ CodeGenerator::visitCallDeleteProperty(LCallDeleteProperty *lir) typedef bool (*DeleteElementFn)(JSContext *, HandleValue, HandleValue, bool *); static const VMFunction DeleteElementStrictInfo = - FunctionInfo(DeleteElement); + FunctionInfo(DeleteElementJit); static const VMFunction DeleteElementNonStrictInfo = - FunctionInfo(DeleteElement); + FunctionInfo(DeleteElementJit); void CodeGenerator::visitCallDeleteElement(LCallDeleteElement *lir) diff --git a/js/src/js.msg b/js/src/js.msg index 8fce9da6bb5..a987cf9a8d3 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -340,6 +340,7 @@ MSG_DEF(JSMSG_CANT_CHANGE_EXTENSIBILITY, 0, JSEXN_TYPEERR, "can't change object' MSG_DEF(JSMSG_CANT_DEFINE_INVALID, 0, JSEXN_TYPEERR, "proxy can't define an incompatible property descriptor") MSG_DEF(JSMSG_CANT_DEFINE_NEW, 0, JSEXN_TYPEERR, "proxy can't define a new property on a non-extensible object") MSG_DEF(JSMSG_CANT_DEFINE_NE_AS_NC, 0, JSEXN_TYPEERR, "proxy can't define a non-existent property as non-configurable") +MSG_DEF(JSMSG_PROXY_DELETE_RETURNED_FALSE, 1, JSEXN_TYPEERR, "can't delete property '{0}': proxy deleteProperty handler returned false") MSG_DEF(JSMSG_CANT_REPORT_AS_NON_EXTENSIBLE, 0, JSEXN_TYPEERR, "proxy can't report an extensible object as non-extensible") MSG_DEF(JSMSG_CANT_REPORT_C_AS_NC, 0, JSEXN_TYPEERR, "proxy can't report existing configurable property as non-configurable") MSG_DEF(JSMSG_CANT_REPORT_E_AS_NE, 0, JSEXN_TYPEERR, "proxy can't report an existing own property as non-existent on a non-extensible object") @@ -472,3 +473,7 @@ MSG_DEF(JSMSG_ATOMICS_WAIT_NOT_ALLOWED, 0, JSEXN_ERR, "waiting is not allowed o // XPConnect wrappers MSG_DEF(JSMSG_CANT_SET_INTERPOSED, 1, JSEXN_TYPEERR, "unable to set interposed data property '{0}'") + +// DOM +MSG_DEF(JSMSG_CANT_DELETE_WINDOW_ELEMENT, 0, JSEXN_TYPEERR, "can't delete elements from a Window object") +MSG_DEF(JSMSG_CANT_DELETE_WINDOW_NAMED_PROPERTY, 1, JSEXN_TYPEERR, "can't delete property {0} from window's named properties object") diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 72c51628c5a..42d9e0690c8 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -192,6 +192,24 @@ JS::ObjectOpResult::failCantSetInterposed() return fail(JSMSG_CANT_SET_INTERPOSED); } +JS_PUBLIC_API(bool) +JS::ObjectOpResult::failCantDelete() +{ + return fail(JSMSG_CANT_DELETE); +} + +JS_PUBLIC_API(bool) +JS::ObjectOpResult::failCantDeleteWindowElement() +{ + return fail(JSMSG_CANT_DELETE_WINDOW_ELEMENT); +} + +JS_PUBLIC_API(bool) +JS::ObjectOpResult::failCantDeleteWindowNamedProperty() +{ + return fail(JSMSG_CANT_DELETE_WINDOW_NAMED_PROPERTY); +} + JS_PUBLIC_API(int64_t) JS_Now() { @@ -2909,7 +2927,7 @@ JS_SetUCProperty(JSContext *cx, HandleObject obj, const char16_t *name, size_t n } JS_PUBLIC_API(bool) -JS_DeletePropertyById2(JSContext *cx, HandleObject obj, HandleId id, bool *result) +JS_DeletePropertyById(JSContext *cx, HandleObject obj, HandleId id, ObjectOpResult &result) { AssertHeapIsIdle(cx); CHECK_REQUEST(cx); @@ -2919,7 +2937,7 @@ JS_DeletePropertyById2(JSContext *cx, HandleObject obj, HandleId id, bool *resul } JS_PUBLIC_API(bool) -JS_DeleteElement2(JSContext *cx, HandleObject obj, uint32_t index, bool *result) +JS_DeleteElement(JSContext *cx, HandleObject obj, uint32_t index, ObjectOpResult &result) { AssertHeapIsIdle(cx); CHECK_REQUEST(cx); @@ -2929,7 +2947,7 @@ JS_DeleteElement2(JSContext *cx, HandleObject obj, uint32_t index, bool *result) } JS_PUBLIC_API(bool) -JS_DeleteProperty2(JSContext *cx, HandleObject obj, const char *name, bool *result) +JS_DeleteProperty(JSContext *cx, HandleObject obj, const char *name, ObjectOpResult &result) { CHECK_REQUEST(cx); assertSameCompartment(cx, obj); @@ -2942,8 +2960,8 @@ JS_DeleteProperty2(JSContext *cx, HandleObject obj, const char *name, bool *resu } JS_PUBLIC_API(bool) -JS_DeleteUCProperty2(JSContext *cx, HandleObject obj, const char16_t *name, size_t namelen, - bool *result) +JS_DeleteUCProperty(JSContext *cx, HandleObject obj, const char16_t *name, size_t namelen, + ObjectOpResult &result) { CHECK_REQUEST(cx); assertSameCompartment(cx, obj); @@ -2958,22 +2976,22 @@ JS_DeleteUCProperty2(JSContext *cx, HandleObject obj, const char16_t *name, size JS_PUBLIC_API(bool) JS_DeletePropertyById(JSContext *cx, HandleObject obj, HandleId id) { - bool junk; - return JS_DeletePropertyById2(cx, obj, id, &junk); + ObjectOpResult ignored; + return JS_DeletePropertyById(cx, obj, id, ignored); } JS_PUBLIC_API(bool) JS_DeleteElement(JSContext *cx, HandleObject obj, uint32_t index) { - bool junk; - return JS_DeleteElement2(cx, obj, index, &junk); + ObjectOpResult ignored; + return JS_DeleteElement(cx, obj, index, ignored); } JS_PUBLIC_API(bool) JS_DeleteProperty(JSContext *cx, HandleObject obj, const char *name) { - bool junk; - return JS_DeleteProperty2(cx, obj, name, &junk); + ObjectOpResult ignored; + return JS_DeleteProperty(cx, obj, name, ignored); } JS_PUBLIC_API(void) diff --git a/js/src/jsapi.h b/js/src/jsapi.h index df2b2763ecc..3d6a17211e9 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -2848,13 +2848,15 @@ extern JS_PUBLIC_API(bool) JS_DeleteProperty(JSContext *cx, JS::HandleObject obj, const char *name); extern JS_PUBLIC_API(bool) -JS_DeleteProperty2(JSContext *cx, JS::HandleObject obj, const char *name, bool *succeeded); +JS_DeleteProperty(JSContext *cx, JS::HandleObject obj, const char *name, + JS::ObjectOpResult &result); extern JS_PUBLIC_API(bool) JS_DeletePropertyById(JSContext *cx, JS::HandleObject obj, jsid id); extern JS_PUBLIC_API(bool) -JS_DeletePropertyById2(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool *succeeded); +JS_DeletePropertyById(JSContext *cx, JS::HandleObject obj, JS::HandleId id, + JS::ObjectOpResult &result); extern JS_PUBLIC_API(bool) JS_DefineUCProperty(JSContext *cx, JS::HandleObject obj, const char16_t *name, size_t namelen, @@ -2915,8 +2917,8 @@ JS_SetUCProperty(JSContext *cx, JS::HandleObject obj, JS::HandleValue v); extern JS_PUBLIC_API(bool) -JS_DeleteUCProperty2(JSContext *cx, JS::HandleObject obj, const char16_t *name, size_t namelen, - bool *succeeded); +JS_DeleteUCProperty(JSContext *cx, JS::HandleObject obj, const char16_t *name, size_t namelen, + JS::ObjectOpResult &result); extern JS_PUBLIC_API(JSObject *) JS_NewArrayObject(JSContext *cx, const JS::HandleValueArray& contents); @@ -3001,7 +3003,7 @@ extern JS_PUBLIC_API(bool) JS_DeleteElement(JSContext *cx, JS::HandleObject obj, uint32_t index); extern JS_PUBLIC_API(bool) -JS_DeleteElement2(JSContext *cx, JS::HandleObject obj, uint32_t index, bool *succeeded); +JS_DeleteElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::ObjectOpResult &result); /* * Assign 'undefined' to all of the object's non-reserved slots. Note: this is diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 0e91ca392bc..9ec54b16c31 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -374,13 +374,13 @@ SetArrayElement(JSContext *cx, HandleObject obj, double index, HandleValue v) * If an error occurs while attempting to delete the element (that is, the call * to [[Delete]] threw), return false. * - * Otherwise set *succeeded to indicate whether the deletion attempt succeeded - * (that is, whether the call to [[Delete]] returned true or false). (Deletes - * generally fail only when the property is non-configurable, but proxies may - * implement different semantics.) + * Otherwise call result.succeed() or result.fail() to indicate whether the + * deletion attempt succeeded (that is, whether the call to [[Delete]] returned + * true or false). (Deletes generally fail only when the property is + * non-configurable, but proxies may implement different semantics.) */ static bool -DeleteArrayElement(JSContext *cx, HandleObject obj, double index, bool *succeeded) +DeleteArrayElement(JSContext *cx, HandleObject obj, double index, ObjectOpResult &result) { MOZ_ASSERT(index >= 0); MOZ_ASSERT(floor(index) == index); @@ -403,31 +403,30 @@ DeleteArrayElement(JSContext *cx, HandleObject obj, double index, bool *succeede } } - *succeeded = true; - return true; + return result.succeed(); } RootedId id(cx); if (!ToId(cx, index, &id)) return false; - return DeleteProperty(cx, obj, id, succeeded); + return DeleteProperty(cx, obj, id, result); } -/* ES6 20130308 draft 9.3.5 */ +/* ES6 draft rev 32 (2 Febr 2015) 7.3.7 */ static bool DeletePropertyOrThrow(JSContext *cx, HandleObject obj, double index) { - bool succeeded; - if (!DeleteArrayElement(cx, obj, index, &succeeded)) + ObjectOpResult success; + if (!DeleteArrayElement(cx, obj, index, success)) return false; - if (succeeded) - return true; - - RootedId id(cx); - RootedValue indexv(cx, NumberValue(index)); - if (!ValueToId(cx, indexv, &id)) - return false; - return obj->reportNotConfigurable(cx, id, JSREPORT_ERROR); + if (!success) { + RootedId id(cx); + RootedValue indexv(cx, NumberValue(index)); + if (!ValueToId(cx, indexv, &id)) + return false; + return success.reportError(cx, obj, id); + } + return true; } bool @@ -621,8 +620,8 @@ js::ArraySetLength(JSContext *cx, Handle arr, HandleId id, oldLen--; /* Steps 15b-d. */ - bool deleteSucceeded; - if (!DeleteElement(cx, arr, oldLen, &deleteSucceeded)) + ObjectOpResult deleteSucceeded; + if (!DeleteElement(cx, arr, oldLen, deleteSucceeded)) return false; if (!deleteSucceeded) { newLen = oldLen + 1; @@ -681,8 +680,8 @@ js::ArraySetLength(JSContext *cx, Handle arr, HandleId id, index = indexes[i]; /* Steps 15b-d. */ - bool deleteSucceeded; - if (!DeleteElement(cx, arr, index, &deleteSucceeded)) + ObjectOpResult deleteSucceeded; + if (!DeleteElement(cx, arr, index, deleteSucceeded)) return false; if (!deleteSucceeded) { newLen = index + 1; diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h index 044b0674fab..0a6ba7e19f8 100644 --- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -320,17 +320,16 @@ CallJSSetterOp(JSContext *cx, SetterOp op, HandleObject obj, HandleId id, Mutabl return op(cx, obj, id, vp, result); } -static inline bool +inline bool CallJSDeletePropertyOp(JSContext *cx, JSDeletePropertyOp op, HandleObject receiver, HandleId id, - bool *succeeded) + ObjectOpResult &result) { JS_CHECK_RECURSION(cx, return false); assertSameCompartment(cx, receiver, id); if (op) - return op(cx, receiver, id, succeeded); - *succeeded = true; - return true; + return op(cx, receiver, id, result); + return result.succeed(); } inline bool diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index b6f10e37429..5cd07133591 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -375,7 +375,8 @@ extern JS_FRIEND_API(bool) proxy_GetOwnPropertyDescriptor(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandle desc); extern JS_FRIEND_API(bool) -proxy_DeleteProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool *succeeded); +proxy_DeleteProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, + JS::ObjectOpResult &result); extern JS_FRIEND_API(void) proxy_Trace(JSTracer *trc, JSObject *obj); diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index c966e7dbf29..b6fb2f05eb1 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -738,8 +738,8 @@ DefinePropertyOnObject(JSContext *cx, HandleNativeObject obj, HandleId id, const * redefining it or we had invoked its setter to change its value). */ if (callDelProperty) { - bool ignored; - if (!CallJSDeletePropertyOp(cx, obj->getClass()->delProperty, obj, id, &ignored)) + ObjectOpResult ignored; + if (!CallJSDeletePropertyOp(cx, obj->getClass()->delProperty, obj, id, ignored)) return false; } @@ -2571,9 +2571,11 @@ DefineConstructorAndPrototype(JSContext *cx, HandleObject obj, JSProtoKey key, H bad: if (named) { - bool succeeded; + ObjectOpResult ignored; RootedId id(cx, AtomToId(atom)); - DeleteProperty(cx, obj, id, &succeeded); + + // XXX FIXME - absurd to call this here; instead define the property last. + DeleteProperty(cx, obj, id, ignored); } if (cached) ClearClassObject(obj, key); diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 593d3a67d9c..e20d1dde473 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -918,10 +918,10 @@ PutProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, MutableHan * ES6 [[Delete]]. Equivalent to the JS code `delete obj[id]`. */ inline bool -DeleteProperty(JSContext *cx, js::HandleObject obj, js::HandleId id, bool *succeeded); +DeleteProperty(JSContext *cx, HandleObject obj, HandleId id, ObjectOpResult &result); inline bool -DeleteElement(JSContext *cx, js::HandleObject obj, uint32_t index, bool *succeeded); +DeleteElement(JSContext *cx, HandleObject obj, uint32_t index, ObjectOpResult &result); /*** SpiderMonkey nonstandard internal methods ***************************************************/ diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 80c473cba5b..abcf44cbb87 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -182,21 +182,21 @@ js::GetElementNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t in } inline bool -js::DeleteProperty(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded) +js::DeleteProperty(JSContext *cx, HandleObject obj, HandleId id, ObjectOpResult &result) { MarkTypePropertyNonData(cx, obj, id); if (DeletePropertyOp op = obj->getOps()->deleteProperty) - return op(cx, obj, id, succeeded); - return NativeDeleteProperty(cx, obj.as(), id, succeeded); + return op(cx, obj, id, result); + return NativeDeleteProperty(cx, obj.as(), id, result); } inline bool -js::DeleteElement(JSContext *cx, HandleObject obj, uint32_t index, bool *succeeded) +js::DeleteElement(JSContext *cx, HandleObject obj, uint32_t index, ObjectOpResult &result) { RootedId id(cx); if (!IndexToId(cx, index, &id)) return false; - return DeleteProperty(cx, obj, id, succeeded); + return DeleteProperty(cx, obj, id, result); } diff --git a/js/src/json.cpp b/js/src/json.cpp index 347dcc3cb34..a1b8ff71b1c 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -712,8 +712,8 @@ Walk(JSContext *cx, HandleObject holder, HandleId name, HandleValue reviver, Mut if (newElement.isUndefined()) { /* Step 2a(iii)(2). */ - bool succeeded; - if (!DeleteProperty(cx, obj, id, &succeeded)) + ObjectOpResult ignored; + if (!DeleteProperty(cx, obj, id, ignored)) return false; } else { /* Step 2a(iii)(3). */ @@ -740,8 +740,8 @@ Walk(JSContext *cx, HandleObject holder, HandleId name, HandleValue reviver, Mut if (newElement.isUndefined()) { /* Step 2b(ii)(2). */ - bool succeeded; - if (!DeleteProperty(cx, obj, id, &succeeded)) + ObjectOpResult ignored; + if (!DeleteProperty(cx, obj, id, ignored)) return false; } else { /* Step 2b(ii)(3). */ diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index c360681ada5..485980d0100 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -121,7 +121,8 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper ObjectOpResult &result) const MOZ_OVERRIDE; virtual bool ownPropertyKeys(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE; + virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, + ObjectOpResult &result) const MOZ_OVERRIDE; virtual bool enumerate(JSContext *cx, HandleObject wrapper, MutableHandleObject objp) const MOZ_OVERRIDE; virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const MOZ_OVERRIDE; diff --git a/js/src/proxy/CrossCompartmentWrapper.cpp b/js/src/proxy/CrossCompartmentWrapper.cpp index df54717b833..9907bb19736 100644 --- a/js/src/proxy/CrossCompartmentWrapper.cpp +++ b/js/src/proxy/CrossCompartmentWrapper.cpp @@ -70,11 +70,12 @@ CrossCompartmentWrapper::ownPropertyKeys(JSContext *cx, HandleObject wrapper, } bool -CrossCompartmentWrapper::delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const +CrossCompartmentWrapper::delete_(JSContext *cx, HandleObject wrapper, HandleId id, + ObjectOpResult &result) const { PIERCE(cx, wrapper, NOTHING, - Wrapper::delete_(cx, wrapper, id, bp), + Wrapper::delete_(cx, wrapper, id, result), NOTHING); } diff --git a/js/src/proxy/DeadObjectProxy.cpp b/js/src/proxy/DeadObjectProxy.cpp index b3d3adc1957..165ff8576c6 100644 --- a/js/src/proxy/DeadObjectProxy.cpp +++ b/js/src/proxy/DeadObjectProxy.cpp @@ -48,7 +48,8 @@ DeadObjectProxy::ownPropertyKeys(JSContext *cx, HandleObject wrapper, } bool -DeadObjectProxy::delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const +DeadObjectProxy::delete_(JSContext *cx, HandleObject wrapper, HandleId id, + ObjectOpResult &result) const { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT); return false; diff --git a/js/src/proxy/DeadObjectProxy.h b/js/src/proxy/DeadObjectProxy.h index fa9a410abb5..ea52cbeba16 100644 --- a/js/src/proxy/DeadObjectProxy.h +++ b/js/src/proxy/DeadObjectProxy.h @@ -26,7 +26,8 @@ class DeadObjectProxy : public BaseProxyHandler ObjectOpResult &result) const MOZ_OVERRIDE; virtual bool ownPropertyKeys(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE; + virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, + ObjectOpResult &result) const MOZ_OVERRIDE; virtual bool enumerate(JSContext *cx, HandleObject wrapper, MutableHandleObject objp) const MOZ_OVERRIDE; virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const MOZ_OVERRIDE; diff --git a/js/src/proxy/DirectProxyHandler.cpp b/js/src/proxy/DirectProxyHandler.cpp index f4e68606d3b..cec55a04cee 100644 --- a/js/src/proxy/DirectProxyHandler.cpp +++ b/js/src/proxy/DirectProxyHandler.cpp @@ -52,11 +52,12 @@ DirectProxyHandler::ownPropertyKeys(JSContext *cx, HandleObject proxy, } bool -DirectProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const +DirectProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, + ObjectOpResult &result) const { assertEnteredPolicy(cx, proxy, id, SET); RootedObject target(cx, proxy->as().target()); - return DeleteProperty(cx, target, id, bp); + return DeleteProperty(cx, target, id, result); } bool diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp index 46e0a288985..ea56469d07b 100644 --- a/js/src/proxy/Proxy.cpp +++ b/js/src/proxy/Proxy.cpp @@ -159,15 +159,18 @@ Proxy::ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) } bool -Proxy::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) +Proxy::delete_(JSContext *cx, HandleObject proxy, HandleId id, ObjectOpResult &result) { JS_CHECK_RECURSION(cx, return false); const BaseProxyHandler *handler = proxy->as().handler(); - *bp = true; // default result if we refuse to perform this action AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::SET, true); - if (!policy.allowed()) - return policy.returnValue(); - return proxy->as().handler()->delete_(cx, proxy, id, bp); + if (!policy.allowed()) { + bool ok = policy.returnValue(); + if (ok) + result.succeed(); + return ok; + } + return proxy->as().handler()->delete_(cx, proxy, id, result); } JS_FRIEND_API(bool) @@ -597,13 +600,11 @@ js::proxy_GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, } bool -js::proxy_DeleteProperty(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded) +js::proxy_DeleteProperty(JSContext *cx, HandleObject obj, HandleId id, ObjectOpResult &result) { - bool deleted; - if (!Proxy::delete_(cx, obj, id, &deleted)) + if (!Proxy::delete_(cx, obj, id, result)) return false; - *succeeded = deleted; - return SuppressDeletedProperty(cx, obj, id); + return SuppressDeletedProperty(cx, obj, id); // XXX is this necessary? } void diff --git a/js/src/proxy/Proxy.h b/js/src/proxy/Proxy.h index e79e3f9defa..64b4abd434e 100644 --- a/js/src/proxy/Proxy.h +++ b/js/src/proxy/Proxy.h @@ -31,7 +31,7 @@ class Proxy static bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id, MutableHandle desc, ObjectOpResult &result); static bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props); - static bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp); + static bool delete_(JSContext *cx, HandleObject proxy, HandleId id, ObjectOpResult &result); static bool enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp); static bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible); static bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded); diff --git a/js/src/proxy/ScriptedDirectProxyHandler.cpp b/js/src/proxy/ScriptedDirectProxyHandler.cpp index 7ed26697ba2..13492af2991 100644 --- a/js/src/proxy/ScriptedDirectProxyHandler.cpp +++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp @@ -689,9 +689,10 @@ ScriptedDirectProxyHandler::ownPropertyKeys(JSContext *cx, HandleObject proxy, cx->names().ownKeys); } -// ES6 (5 April 2014) 9.5.10 Proxy.[[Delete]](P) +// ES6 draft rev 32 (2 Feb 2014) 9.5.10 Proxy.[[Delete]](P) bool -ScriptedDirectProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const +ScriptedDirectProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, + ObjectOpResult &result) const { // step 2 RootedObject handler(cx, GetDirectProxyHandlerObject(proxy)); @@ -702,19 +703,19 @@ ScriptedDirectProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId return false; } - // step 4 + // steps 4-5 RootedObject target(cx, proxy->as().target()); - // step 5 + // steps 6-7 RootedValue trap(cx); if (!GetProperty(cx, handler, handler, cx->names().deleteProperty, &trap)) return false; - // step 7 - if (trap.isUndefined()) - return DirectProxyHandler::delete_(cx, proxy, id, bp); - // step 8 + if (trap.isUndefined()) + return DirectProxyHandler::delete_(cx, proxy, id, result); + + // steps 9-10 RootedValue value(cx); if (!IdToStringOrSymbol(cx, id, &value)) return false; @@ -726,28 +727,24 @@ ScriptedDirectProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId if (!Invoke(cx, ObjectValue(*handler), trap, ArrayLength(argv), argv, &trapResult)) return false; - // step 9 - if (ToBoolean(trapResult)) { - // step 12 - Rooted desc(cx); - if (!GetOwnPropertyDescriptor(cx, target, id, &desc)) - return false; + // step 11 + if (!ToBoolean(trapResult)) + return result.fail(JSMSG_PROXY_DELETE_RETURNED_FALSE); - // step 14-15 - if (desc.object() && desc.isPermanent()) { - RootedValue v(cx, IdToValue(id)); - ReportValueError(cx, JSMSG_CANT_DELETE, JSDVG_IGNORE_STACK, v, js::NullPtr()); - return false; - } + // steps 12-13 + Rooted desc(cx); + if (!GetOwnPropertyDescriptor(cx, target, id, &desc)) + return false; - // step 16 - *bp = true; - return true; + // step 14-15 + if (desc.object() && desc.isPermanent()) { + RootedValue v(cx, IdToValue(id)); + ReportValueError(cx, JSMSG_CANT_DELETE, JSDVG_IGNORE_STACK, v, js::NullPtr()); + return false; } - // step 11 - *bp = false; - return true; + // step 16 + return result.succeed(); } // ES6 (14 October, 2014) 9.5.11 Proxy.[[Enumerate]] diff --git a/js/src/proxy/ScriptedDirectProxyHandler.h b/js/src/proxy/ScriptedDirectProxyHandler.h index dbcf83f65c6..db1e194dd13 100644 --- a/js/src/proxy/ScriptedDirectProxyHandler.h +++ b/js/src/proxy/ScriptedDirectProxyHandler.h @@ -26,7 +26,8 @@ class ScriptedDirectProxyHandler : public DirectProxyHandler { ObjectOpResult &result) const MOZ_OVERRIDE; virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE; + virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, + ObjectOpResult &result) const MOZ_OVERRIDE; virtual bool enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp) const MOZ_OVERRIDE; /* These two are standard internal methods but aren't implemented to spec yet. */ diff --git a/js/src/proxy/ScriptedIndirectProxyHandler.cpp b/js/src/proxy/ScriptedIndirectProxyHandler.cpp index 855bb7db738..37a2bbe7682 100644 --- a/js/src/proxy/ScriptedIndirectProxyHandler.cpp +++ b/js/src/proxy/ScriptedIndirectProxyHandler.cpp @@ -219,13 +219,21 @@ ScriptedIndirectProxyHandler::ownPropertyKeys(JSContext *cx, HandleObject proxy, } bool -ScriptedIndirectProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const +ScriptedIndirectProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, + ObjectOpResult &result) const { RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy)); RootedValue fval(cx), value(cx); - return GetFundamentalTrap(cx, handler, cx->names().delete_, &fval) && - Trap1(cx, handler, fval, id, &value) && - ValueToBool(value, bp); + if (!GetFundamentalTrap(cx, handler, cx->names().delete_, &fval)) + return false; + if (!Trap1(cx, handler, fval, id, &value)) + return false; + + if (ToBoolean(value)) + result.succeed(); + else + result.fail(JSMSG_PROXY_DELETE_RETURNED_FALSE); + return true; } bool diff --git a/js/src/proxy/ScriptedIndirectProxyHandler.h b/js/src/proxy/ScriptedIndirectProxyHandler.h index 573fb658bfc..da16186a207 100644 --- a/js/src/proxy/ScriptedIndirectProxyHandler.h +++ b/js/src/proxy/ScriptedIndirectProxyHandler.h @@ -27,7 +27,8 @@ class ScriptedIndirectProxyHandler : public BaseProxyHandler ObjectOpResult &result) const MOZ_OVERRIDE; virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE; + virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, + ObjectOpResult &result) const MOZ_OVERRIDE; virtual bool enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp) const MOZ_OVERRIDE; virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE; diff --git a/js/src/tests/js1_6/Array/regress-304828.js b/js/src/tests/js1_6/Array/regress-304828.js index 10713aa4ae0..0b15e21d284 100644 --- a/js/src/tests/js1_6/Array/regress-304828.js +++ b/js/src/tests/js1_6/Array/regress-304828.js @@ -86,7 +86,7 @@ reportCompare("f", value[5], summary + ': push String object index 5'); // pop value = 'abc'; -expect = "TypeError: property Array.prototype.pop.call(...) is non-configurable and can't be deleted"; +expect = "TypeError: property 2 is non-configurable and can't be deleted"; try { actual = Array.prototype.pop.call(value); diff --git a/js/src/vm/ArgumentsObject.cpp b/js/src/vm/ArgumentsObject.cpp index 1e4b41742cd..7f295ea2408 100644 --- a/js/src/vm/ArgumentsObject.cpp +++ b/js/src/vm/ArgumentsObject.cpp @@ -274,7 +274,7 @@ ArgumentsObject::createForIon(JSContext *cx, jit::JitFrameLayout *frame, HandleO } static bool -args_delProperty(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded) +args_delProperty(JSContext *cx, HandleObject obj, HandleId id, ObjectOpResult &result) { ArgumentsObject &argsobj = obj->as(); if (JSID_IS_INT(id)) { @@ -286,8 +286,7 @@ args_delProperty(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded) } else if (JSID_IS_ATOM(id, cx->names().callee)) { argsobj.as().clearCallee(); } - *succeeded = true; - return true; + return result.succeed(); } static bool @@ -353,8 +352,8 @@ ArgSetter(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp, * that we must define the property instead of setting it in case the user * has changed the prototype to an object that has a setter for this id. */ - bool succeeded; - return NativeDeleteProperty(cx, argsobj, id, &succeeded) && + ObjectOpResult ignored; + return NativeDeleteProperty(cx, argsobj, id, ignored) && NativeDefineProperty(cx, argsobj, id, vp, nullptr, nullptr, attrs, result); } @@ -469,8 +468,8 @@ StrictArgSetter(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue * simple data property. Note that we rely on args_delProperty to clear the * corresponding reserved slot so the GC can collect its value. */ - bool succeeded; - return NativeDeleteProperty(cx, argsobj, id, &succeeded) && + ObjectOpResult ignored; + return NativeDeleteProperty(cx, argsobj, id, ignored) && NativeDefineProperty(cx, argsobj, id, vp, nullptr, nullptr, attrs, result); } diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 57cf542f62b..882bdc915a5 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -6803,10 +6803,10 @@ DebuggerObject_deleteProperty(JSContext *cx, unsigned argc, Value *vp) ac.emplace(cx, obj); ErrorCopier ec(ac); - bool succeeded; - if (!DeleteProperty(cx, obj, id, &succeeded)) + ObjectOpResult result; + if (!DeleteProperty(cx, obj, id, result)) return false; - args.rval().setBoolean(succeeded); + args.rval().setBoolean(result.ok()); return true; } diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index c51a695a40a..a8c8e295474 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -2333,15 +2333,15 @@ CASE(JSOP_STRICTDELPROP) RootedObject &obj = rootObject0; FETCH_OBJECT(cx, -1, obj); - bool succeeded; - if (!DeleteProperty(cx, obj, id, &succeeded)) + ObjectOpResult result; + if (!DeleteProperty(cx, obj, id, result)) goto error; - if (!succeeded && JSOp(*REGS.pc) == JSOP_STRICTDELPROP) { - obj->reportNotConfigurable(cx, id); + if (!result && JSOp(*REGS.pc) == JSOP_STRICTDELPROP) { + result.reportError(cx, obj, id); goto error; } MutableHandleValue res = REGS.stackHandleAt(-1); - res.setBoolean(succeeded); + res.setBoolean(result.ok()); } END_CASE(JSOP_DELPROP) @@ -2357,19 +2357,19 @@ CASE(JSOP_STRICTDELELEM) RootedValue &propval = rootValue0; propval = REGS.sp[-1]; - bool succeeded; + ObjectOpResult result; RootedId &id = rootId0; if (!ValueToId(cx, propval, &id)) goto error; - if (!DeleteProperty(cx, obj, id, &succeeded)) + if (!DeleteProperty(cx, obj, id, result)) goto error; - if (!succeeded && JSOp(*REGS.pc) == JSOP_STRICTDELELEM) { - obj->reportNotConfigurable(cx, id); + if (!result && JSOp(*REGS.pc) == JSOP_STRICTDELELEM) { + result.reportError(cx, obj, id); goto error; } MutableHandleValue res = REGS.stackHandleAt(-2); - res.setBoolean(succeeded); + res.setBoolean(result.ok()); REGS.sp--; } END_CASE(JSOP_DELELEM) @@ -3833,29 +3833,35 @@ js::GetAndClearException(JSContext *cx, MutableHandleValue res) template bool -js::DeleteProperty(JSContext *cx, HandleValue v, HandlePropertyName name, bool *bp) +js::DeletePropertyJit(JSContext *cx, HandleValue v, HandlePropertyName name, bool *bp) { RootedObject obj(cx, ToObjectFromStack(cx, v)); if (!obj) return false; RootedId id(cx, NameToId(name)); - if (!DeleteProperty(cx, obj, id, bp)) + ObjectOpResult result; + if (!DeleteProperty(cx, obj, id, result)) return false; - if (strict && !*bp) { - obj->reportNotConfigurable(cx, NameToId(name)); - return false; + if (strict) { + if (!result) + return result.reportError(cx, obj, id); + *bp = true; + } else { + *bp = result.ok(); } return true; } -template bool js::DeleteProperty (JSContext *cx, HandleValue val, HandlePropertyName name, bool *bp); -template bool js::DeleteProperty(JSContext *cx, HandleValue val, HandlePropertyName name, bool *bp); +template bool js::DeletePropertyJit (JSContext *cx, HandleValue val, HandlePropertyName name, + bool *bp); +template bool js::DeletePropertyJit(JSContext *cx, HandleValue val, HandlePropertyName name, + bool *bp); template bool -js::DeleteElement(JSContext *cx, HandleValue val, HandleValue index, bool *bp) +js::DeleteElementJit(JSContext *cx, HandleValue val, HandleValue index, bool *bp) { RootedObject obj(cx, ToObjectFromStack(cx, val)); if (!obj) @@ -3864,18 +3870,22 @@ js::DeleteElement(JSContext *cx, HandleValue val, HandleValue index, bool *bp) RootedId id(cx); if (!ValueToId(cx, index, &id)) return false; - if (!DeleteProperty(cx, obj, id, bp)) + ObjectOpResult result; + if (!DeleteProperty(cx, obj, id, result)) return false; - if (strict && !*bp) { - obj->reportNotConfigurable(cx, id); - return false; + if (strict) { + if (!result) + return result.reportError(cx, obj, id); + *bp = true; + } else { + *bp = result.ok(); } return true; } -template bool js::DeleteElement (JSContext *, HandleValue, HandleValue, bool *succeeded); -template bool js::DeleteElement(JSContext *, HandleValue, HandleValue, bool *succeeded); +template bool js::DeleteElementJit (JSContext *, HandleValue, HandleValue, bool *succeeded); +template bool js::DeleteElementJit(JSContext *, HandleValue, HandleValue, bool *succeeded); bool js::GetElement(JSContext *cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue vp) @@ -3974,11 +3984,11 @@ js::DeleteNameOperation(JSContext *cx, HandlePropertyName name, HandleObject sco return false; } - bool succeeded; + ObjectOpResult result; RootedId id(cx, NameToId(name)); - if (!DeleteProperty(cx, scope, id, &succeeded)) + if (!DeleteProperty(cx, scope, id, result)) return false; - res.setBoolean(succeeded); + res.setBoolean(result.ok()); return true; } diff --git a/js/src/vm/Interpreter.h b/js/src/vm/Interpreter.h index 60ab81d9bb2..0d34b77a99f 100644 --- a/js/src/vm/Interpreter.h +++ b/js/src/vm/Interpreter.h @@ -343,11 +343,11 @@ UrshValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, Mutabl template bool -DeleteProperty(JSContext *ctx, HandleValue val, HandlePropertyName name, bool *bv); +DeletePropertyJit(JSContext *ctx, HandleValue val, HandlePropertyName name, bool *bv); template bool -DeleteElement(JSContext *cx, HandleValue val, HandleValue index, bool *bv); +DeleteElementJit(JSContext *cx, HandleValue val, HandleValue index, bool *bv); bool DefFunOperation(JSContext *cx, HandleScript script, HandleObject scopeChain, HandleFunction funArg); diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index 4f728dc1341..2ca1b5231df 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -2322,7 +2322,8 @@ js::NativeSetElement(JSContext *cx, HandleNativeObject obj, HandleObject receive // ES6 draft rev31 9.1.10 [[Delete]] bool -js::NativeDeleteProperty(JSContext *cx, HandleNativeObject obj, HandleId id, bool *succeeded) +js::NativeDeleteProperty(JSContext *cx, HandleNativeObject obj, HandleId id, + ObjectOpResult &result) { // Steps 2-3. RootedShape shape(cx); @@ -2333,20 +2334,18 @@ js::NativeDeleteProperty(JSContext *cx, HandleNativeObject obj, HandleId id, boo if (!shape) { // If no property call the class's delProperty hook, passing succeeded // as the result parameter. This always succeeds when there is no hook. - return CallJSDeletePropertyOp(cx, obj->getClass()->delProperty, obj, id, succeeded); + return CallJSDeletePropertyOp(cx, obj->getClass()->delProperty, obj, id, result); } cx->runtime()->gc.poke(); // Step 6. Non-configurable property. - if (GetShapeAttributes(obj, shape) & JSPROP_PERMANENT) { - *succeeded = false; - return true; - } + if (GetShapeAttributes(obj, shape) & JSPROP_PERMANENT) + return result.failCantDelete(); - if (!CallJSDeletePropertyOp(cx, obj->getClass()->delProperty, obj, id, succeeded)) + if (!CallJSDeletePropertyOp(cx, obj->getClass()->delProperty, obj, id, result)) return false; - if (!*succeeded) + if (!result) return true; // Step 5. diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index 9121ecd44a6..dd8f4e10e92 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -1326,7 +1326,7 @@ NativeSetElement(JSContext *cx, HandleNativeObject obj, HandleObject receiver, u MutableHandleValue vp, ObjectOpResult &result); extern bool -NativeDeleteProperty(JSContext *cx, HandleNativeObject obj, HandleId id, bool *succeeded); +NativeDeleteProperty(JSContext *cx, HandleNativeObject obj, HandleId id, ObjectOpResult &result); /*** SpiderMonkey nonstandard internal methods ***************************************************/ diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index f3e7bcddfe4..640e2cefed8 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -513,10 +513,10 @@ with_GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, } static bool -with_DeleteProperty(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded) +with_DeleteProperty(JSContext *cx, HandleObject obj, HandleId id, ObjectOpResult &result) { RootedObject actual(cx, &obj->as().object()); - return DeleteProperty(cx, actual, id, succeeded); + return DeleteProperty(cx, actual, id, result); } static JSObject * @@ -956,7 +956,7 @@ uninitialized_GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId } static bool -uninitialized_DeleteProperty(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded) +uninitialized_DeleteProperty(JSContext *cx, HandleObject obj, HandleId id, ObjectOpResult &result) { ReportUninitializedLexicalId(cx, id); return false; @@ -1714,11 +1714,10 @@ class DebugScopeProxy : public BaseProxyHandler return true; } - bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE + bool delete_(JSContext *cx, HandleObject proxy, HandleId id, + ObjectOpResult &result) const MOZ_OVERRIDE { - RootedValue idval(cx, IdToValue(id)); - return ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_CANT_DELETE, - JSDVG_IGNORE_STACK, idval, NullPtr(), nullptr, nullptr); + return result.fail(JSMSG_CANT_DELETE); } }; diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index ddab7691643..0ec15fee308 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -445,11 +445,11 @@ UnboxedPlainObject::obj_getOwnPropertyDescriptor(JSContext *cx, HandleObject obj /* static */ bool UnboxedPlainObject::obj_deleteProperty(JSContext *cx, HandleObject obj, HandleId id, - bool *succeeded) + ObjectOpResult &result) { if (!convertToNative(cx, obj)) return false; - return DeleteProperty(cx, obj, id, succeeded); + return DeleteProperty(cx, obj, id, result); } /* static */ bool diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h index 7f1ad068dad..8eaab499e43 100644 --- a/js/src/vm/UnboxedObject.h +++ b/js/src/vm/UnboxedObject.h @@ -179,7 +179,8 @@ class UnboxedPlainObject : public JSObject static bool obj_getOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, MutableHandle desc); - static bool obj_deleteProperty(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded); + static bool obj_deleteProperty(JSContext *cx, HandleObject obj, HandleId id, + ObjectOpResult &result); static bool obj_enumerate(JSContext *cx, HandleObject obj, AutoIdVector &properties); static bool obj_watch(JSContext *cx, HandleObject obj, HandleId id, HandleObject callable); diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index 667b54fbe09..f424a032564 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -29,11 +29,11 @@ namespace js { * * https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode */ -static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 242; +static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 243; static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND); -static_assert(JSErr_Limit == 376, +static_assert(JSErr_Limit == 379, "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/XPCWrappedNativeJSOps.cpp b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp index 0dd56307e55..b0d3a22980c 100644 --- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp +++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp @@ -443,7 +443,7 @@ XPC_WN_CannotModifyPropertyStub(JSContext *cx, HandleObject obj, HandleId id, static bool XPC_WN_CantDeletePropertyStub(JSContext *cx, HandleObject obj, HandleId id, - bool *succeeded) + ObjectOpResult &result) { return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx); } @@ -716,15 +716,15 @@ XPC_WN_MaybeResolvingSetPropertyStub(JSContext *cx, HandleObject obj, HandleId i } static bool -XPC_WN_MaybeResolvingDeletePropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded) +XPC_WN_MaybeResolvingDeletePropertyStub(JSContext *cx, HandleObject obj, HandleId id, + ObjectOpResult &result) { XPCCallContext ccx(JS_CALLER, cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); if (ccx.GetResolvingWrapper() == wrapper) { - *succeeded = true; - return true; + return result.succeed(); } return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx); } diff --git a/js/xpconnect/wrappers/AddonWrapper.cpp b/js/xpconnect/wrappers/AddonWrapper.cpp index b5160cebfbb..50e1620660f 100644 --- a/js/xpconnect/wrappers/AddonWrapper.cpp +++ b/js/xpconnect/wrappers/AddonWrapper.cpp @@ -163,14 +163,15 @@ AddonWrapper::defineProperty(JSContext *cx, HandleObject wrapper, HandleId template bool -AddonWrapper::delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const +AddonWrapper::delete_(JSContext *cx, HandleObject wrapper, HandleId id, + ObjectOpResult &result) const { Rooted desc(cx); if (!Interpose(cx, wrapper, nullptr, id, &desc)) return false; if (!desc.object()) - return Base::delete_(cx, wrapper, id, bp); + return Base::delete_(cx, wrapper, id, result); js::ReportErrorWithId(cx, "unable to delete interposed property %s", id); return false; diff --git a/js/xpconnect/wrappers/AddonWrapper.h b/js/xpconnect/wrappers/AddonWrapper.h index a63407d6d58..56692f33212 100644 --- a/js/xpconnect/wrappers/AddonWrapper.h +++ b/js/xpconnect/wrappers/AddonWrapper.h @@ -30,7 +30,8 @@ class AddonWrapper : public Base { virtual bool defineProperty(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, JS::MutableHandle desc, JS::ObjectOpResult &result) const MOZ_OVERRIDE; - virtual bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp) const MOZ_OVERRIDE; + virtual bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, + JS::ObjectOpResult &result) const MOZ_OVERRIDE; virtual bool get(JSContext *cx, JS::Handle wrapper, JS::Handle receiver, JS::Handle id, JS::MutableHandle vp) const MOZ_OVERRIDE; virtual bool set(JSContext *cx, JS::HandleObject wrapper, JS::HandleObject receiver, diff --git a/js/xpconnect/wrappers/FilteringWrapper.cpp b/js/xpconnect/wrappers/FilteringWrapper.cpp index b5f25905842..f62556698aa 100644 --- a/js/xpconnect/wrappers/FilteringWrapper.cpp +++ b/js/xpconnect/wrappers/FilteringWrapper.cpp @@ -243,7 +243,7 @@ CrossOriginXrayWrapper::defineProperty(JSContext *cx, JS::Handle wrap bool CrossOriginXrayWrapper::delete_(JSContext *cx, JS::Handle wrapper, - JS::Handle id, bool *bp) const + JS::Handle id, JS::ObjectOpResult &result) const { JS_ReportError(cx, "Permission denied to delete property on cross-origin object"); return false; diff --git a/js/xpconnect/wrappers/FilteringWrapper.h b/js/xpconnect/wrappers/FilteringWrapper.h index 125f204d455..904a6eed39b 100644 --- a/js/xpconnect/wrappers/FilteringWrapper.h +++ b/js/xpconnect/wrappers/FilteringWrapper.h @@ -78,7 +78,7 @@ class CrossOriginXrayWrapper : public SecurityXrayDOM { virtual bool ownPropertyKeys(JSContext *cx, JS::Handle wrapper, JS::AutoIdVector &props) const MOZ_OVERRIDE; virtual bool delete_(JSContext *cx, JS::Handle wrapper, - JS::Handle id, bool *bp) const MOZ_OVERRIDE; + JS::Handle id, JS::ObjectOpResult &result) const MOZ_OVERRIDE; virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle wrapper, JS::Handle id, diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 41d36589fc6..361449e6787 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -543,7 +543,7 @@ JSXrayTraits::resolveOwnProperty(JSContext *cx, const Wrapper &jsWrapper, } bool -JSXrayTraits::delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) +JSXrayTraits::delete_(JSContext *cx, HandleObject wrapper, HandleId id, ObjectOpResult &result) { RootedObject holder(cx, ensureHolder(cx, wrapper)); @@ -560,10 +560,9 @@ JSXrayTraits::delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp if (!getOwnPropertyFromTargetIfSafe(cx, target, wrapper, id, &desc)) return false; if (desc.object()) - return JS_DeletePropertyById2(cx, target, id, bp); + return JS_DeletePropertyById(cx, target, id, result); } - *bp = true; - return true; + return result.succeed(); } bool @@ -2025,7 +2024,7 @@ XrayWrapper::ownPropertyKeys(JSContext *cx, HandleObject wrapper, template bool XrayWrapper::delete_(JSContext *cx, HandleObject wrapper, - HandleId id, bool *bp) const + HandleId id, ObjectOpResult &result) const { assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::SET); @@ -2037,10 +2036,10 @@ XrayWrapper::delete_(JSContext *cx, HandleObject wrapper, if (expando) { JSAutoCompartment ac(cx, expando); - return JS_DeletePropertyById2(cx, expando, id, bp); + return JS_DeletePropertyById(cx, expando, id, result); } - return Traits::singleton.delete_(cx, wrapper, id, bp); + return Traits::singleton.delete_(cx, wrapper, id, result); } template diff --git a/js/xpconnect/wrappers/XrayWrapper.h b/js/xpconnect/wrappers/XrayWrapper.h index 0af88496ed5..7602cdf401d 100644 --- a/js/xpconnect/wrappers/XrayWrapper.h +++ b/js/xpconnect/wrappers/XrayWrapper.h @@ -70,9 +70,9 @@ public: JS::HandleObject wrapper, JS::HandleObject holder, JS::HandleId id, JS::MutableHandle desc); - bool delete_(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id, bool *bp) { - *bp = true; - return true; + bool delete_(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id, + JS::ObjectOpResult &result) { + return result.succeed(); } static const char *className(JSContext *cx, JS::HandleObject wrapper, const js::Wrapper& baseInstance) { @@ -217,7 +217,7 @@ public: JS::HandleObject holder, JS::HandleId id, JS::MutableHandle desc) MOZ_OVERRIDE; - bool delete_(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id, bool *bp); + bool delete_(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id, JS::ObjectOpResult &result); bool defineProperty(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id, JS::MutableHandle desc, @@ -417,7 +417,7 @@ class XrayWrapper : public Base { virtual bool ownPropertyKeys(JSContext *cx, JS::Handle wrapper, JS::AutoIdVector &props) const MOZ_OVERRIDE; virtual bool delete_(JSContext *cx, JS::Handle wrapper, - JS::Handle id, bool *bp) const MOZ_OVERRIDE; + JS::Handle id, JS::ObjectOpResult &result) const MOZ_OVERRIDE; virtual bool enumerate(JSContext *cx, JS::Handle wrapper, JS::MutableHandle objp) const MOZ_OVERRIDE; virtual bool getPrototypeOf(JSContext *cx, JS::HandleObject wrapper,