Bug 1113369, part 6 - [[PreventExtensions]] ObjectOpResult support. r=Waldo, r=bz in dom, r=dvander in js/ipc, r=bholley in js/xpconnect.

This commit is contained in:
Jason Orendorff 2015-02-04 12:01:01 -06:00
parent 64f8ab950a
commit 10eabe9c79
36 changed files with 176 additions and 160 deletions

View File

@ -38,10 +38,9 @@ public:
JS::ObjectOpResult &aResult) const MOZ_OVERRIDE;
virtual bool
preventExtensions(JSContext* aCx, JS::Handle<JSObject*> aProxy,
bool *succeeded) const MOZ_OVERRIDE
JS::ObjectOpResult& aResult) const MOZ_OVERRIDE
{
*succeeded = false;
return true;
return aResult.failCantPreventExtensions();
}
virtual bool
isExtensible(JSContext* aCx, JS::Handle<JSObject*> aProxy,

View File

@ -632,9 +632,9 @@ public:
JS::ObjectOpResult &result) const MOZ_OVERRIDE;
virtual bool enumerate(JSContext *cx, JS::Handle<JSObject*> proxy,
JS::MutableHandle<JSObject*> vp) const MOZ_OVERRIDE;
virtual bool preventExtensions(JSContext *cx,
virtual bool preventExtensions(JSContext* cx,
JS::Handle<JSObject*> proxy,
bool *succeeded) const MOZ_OVERRIDE;
JS::ObjectOpResult& result) const MOZ_OVERRIDE;
virtual bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible)
const MOZ_OVERRIDE;
virtual bool has(JSContext *cx, JS::Handle<JSObject*> proxy,
@ -842,15 +842,14 @@ nsOuterWindowProxy::delete_(JSContext *cx, JS::Handle<JSObject*> proxy,
}
bool
nsOuterWindowProxy::preventExtensions(JSContext *cx,
nsOuterWindowProxy::preventExtensions(JSContext* cx,
JS::Handle<JSObject*> proxy,
bool *succeeded) const
JS::ObjectOpResult& result) const
{
// If [[Extensible]] could be false, then navigating a window could navigate
// to a window that's [[Extensible]] after being at one that wasn't: an
// invariant violation. So never change a window's extensibility.
*succeeded = false;
return true;
return result.failCantPreventExtensions();
}
bool

View File

@ -144,12 +144,11 @@ DOMProxyHandler::EnsureExpandoObject(JSContext* cx, JS::Handle<JSObject*> obj)
}
bool
DOMProxyHandler::preventExtensions(JSContext *cx, JS::Handle<JSObject*> proxy,
bool *succeeded) const
DOMProxyHandler::preventExtensions(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::ObjectOpResult& result) const
{
// always extensible per WebIDL
*succeeded = false;
return true;
return result.failCantPreventExtensions();
}
bool

View File

@ -116,8 +116,8 @@ public:
JS::ObjectOpResult &result, bool *defined) const;
bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
JS::ObjectOpResult &result) const MOZ_OVERRIDE;
bool preventExtensions(JSContext *cx, JS::Handle<JSObject*> proxy,
bool *succeeded) const MOZ_OVERRIDE;
bool preventExtensions(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::ObjectOpResult& result) const MOZ_OVERRIDE;
bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible)
const MOZ_OVERRIDE;
bool has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,

View File

@ -35,10 +35,8 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base
/*** IPC handlers ***/
bool RecvPreventExtensions(const uint64_t &objId, ReturnStatus *rs,
bool *succeeded) {
return Answer::RecvPreventExtensions(ObjectId::deserialize(objId), rs,
succeeded);
bool RecvPreventExtensions(const uint64_t &objId, ReturnStatus *rs) {
return Answer::RecvPreventExtensions(ObjectId::deserialize(objId), rs);
}
bool RecvGetPropertyDescriptor(const uint64_t &objId, const JSIDVariant &id,
ReturnStatus *rs,
@ -127,9 +125,8 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base
bool SendDropObject(const ObjectId &objId) {
return Base::SendDropObject(objId.serialize());
}
bool SendPreventExtensions(const ObjectId &objId, ReturnStatus *rs,
bool *succeeded) {
return Base::SendPreventExtensions(objId.serialize(), rs, succeeded);
bool SendPreventExtensions(const ObjectId &objId, ReturnStatus *rs) {
return Base::SendPreventExtensions(objId.serialize(), rs);
}
bool SendGetPropertyDescriptor(const ObjectId &objId, const JSIDVariant &id,
ReturnStatus *rs,

View File

@ -24,7 +24,7 @@ both:
async DropObject(uint64_t objId);
// These roughly map to the ProxyHandler hooks that CPOWs need.
prio(high) sync PreventExtensions(uint64_t objId) returns (ReturnStatus rs, bool result);
prio(high) sync PreventExtensions(uint64_t objId) returns (ReturnStatus rs);
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);

View File

@ -74,25 +74,23 @@ WrapperAnswer::ok(ReturnStatus *rs, const JS::ObjectOpResult &result)
}
bool
WrapperAnswer::RecvPreventExtensions(const ObjectId &objId, ReturnStatus *rs,
bool *succeeded)
WrapperAnswer::RecvPreventExtensions(const ObjectId &objId, ReturnStatus *rs)
{
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
return false;
JSContext *cx = jsapi.cx();
*succeeded = false;
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(cx, rs);
if (!JS_PreventExtensions(cx, obj, succeeded))
ObjectOpResult success;
if (!JS_PreventExtensions(cx, obj, success))
return fail(cx, rs);
LOG("%s.preventExtensions()", ReceiverObj(objId));
return ok(rs);
return ok(rs, success);
}
static void

View File

@ -18,8 +18,7 @@ class WrapperAnswer : public virtual JavaScriptShared
public:
explicit WrapperAnswer(JSRuntime *rt) : JavaScriptShared(rt) {}
bool RecvPreventExtensions(const ObjectId &objId, ReturnStatus *rs,
bool *succeeded);
bool RecvPreventExtensions(const ObjectId &objId, ReturnStatus *rs);
bool RecvGetPropertyDescriptor(const ObjectId &objId, const JSIDVariant &id,
ReturnStatus *rs,
PPropertyDescriptor *out);

View File

@ -97,7 +97,8 @@ class CPOWProxyHandler : public BaseProxyHandler
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 preventExtensions(JSContext *cx, HandleObject proxy,
ObjectOpResult &result) const MOZ_OVERRIDE;
virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
@ -487,23 +488,23 @@ WrapperOwner::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, Au
}
bool
CPOWProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const
CPOWProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy, ObjectOpResult &result) const
{
FORWARD(preventExtensions, (cx, proxy, succeeded));
FORWARD(preventExtensions, (cx, proxy, result));
}
bool
WrapperOwner::preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded)
WrapperOwner::preventExtensions(JSContext *cx, HandleObject proxy, ObjectOpResult &result)
{
ObjectId objId = idOf(proxy);
ReturnStatus status;
if (!SendPreventExtensions(objId, &status, succeeded))
if (!SendPreventExtensions(objId, &status))
return ipcfail(cx);
LOG_STACK();
return ok(cx, status);
return ok(cx, status, result);
}
bool

View File

@ -37,7 +37,7 @@ class WrapperOwner : public virtual JavaScriptShared
bool ownPropertyKeys(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
JS::ObjectOpResult &result);
bool preventExtensions(JSContext *cx, JS::HandleObject proxy, bool *succeeded);
bool preventExtensions(JSContext *cx, JS::HandleObject proxy, JS::ObjectOpResult &result);
bool isExtensible(JSContext *cx, JS::HandleObject proxy, bool *extensible);
bool has(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
bool get(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
@ -106,8 +106,7 @@ class WrapperOwner : public virtual JavaScriptShared
/*** Dummy call handlers ***/
public:
virtual bool SendDropObject(const ObjectId &objId) = 0;
virtual bool SendPreventExtensions(const ObjectId &objId, ReturnStatus *rs,
bool *succeeded) = 0;
virtual bool SendPreventExtensions(const ObjectId &objId, ReturnStatus *rs) = 0;
virtual bool SendGetPropertyDescriptor(const ObjectId &objId, const JSIDVariant &id,
ReturnStatus *rs,
PPropertyDescriptor *out) = 0;

View File

@ -125,6 +125,7 @@ class ObjectOpResult
JS_PUBLIC_API(bool) failCantDelete();
JS_PUBLIC_API(bool) failCantDeleteWindowElement();
JS_PUBLIC_API(bool) failCantDeleteWindowNamedProperty();
JS_PUBLIC_API(bool) failCantPreventExtensions();
uint32_t failureCode() const {
MOZ_ASSERT(!ok());
@ -152,11 +153,13 @@ class ObjectOpResult
}
/*
* Convenience method. Return true if ok() or if strict is false; otherwise
* throw a TypeError and return false.
* The same as checkStrictErrorOrWarning(cx, id, strict), except the
* operation is not associated with a particular property id. This is
* used for [[PreventExtensions]] and [[SetPrototypeOf]]. failureCode()
* must not be an error that has "{0}" in the error message.
*/
bool checkStrict(JSContext *cx, HandleObject obj, HandleId id) {
return checkStrictErrorOrWarning(cx, obj, id, true);
bool checkStrictErrorOrWarning(JSContext *cx, HandleObject obj, bool strict) {
return ok() || reportStrictErrorOrWarning(cx, obj, strict);
}
/* Throw a TypeError. Call this only if !ok(). */
@ -164,8 +167,33 @@ class ObjectOpResult
return reportStrictErrorOrWarning(cx, obj, id, true);
}
/*
* The same as reportError(cx, obj, id), except the operation is not
* associated with a particular property id.
*/
bool reportError(JSContext *cx, HandleObject obj) {
return reportStrictErrorOrWarning(cx, obj, true);
}
/* Helper function for checkStrictErrorOrWarning's slow path. */
JS_PUBLIC_API(bool) reportStrictErrorOrWarning(JSContext *cx, HandleObject obj, HandleId id, bool strict);
JS_PUBLIC_API(bool) reportStrictErrorOrWarning(JSContext *cx, HandleObject obj, bool strict);
/*
* Convenience method. Return true if ok() or if strict is false; otherwise
* throw a TypeError and return false.
*/
bool checkStrict(JSContext *cx, HandleObject obj, HandleId id) {
return checkStrictErrorOrWarning(cx, obj, id, true);
}
/*
* Convenience method. The same as checkStrict(cx, id), except the
* operation is not associated with a particular property id.
*/
bool checkStrict(JSContext *cx, HandleObject obj) {
return checkStrictErrorOrWarning(cx, obj, true);
}
};
}

View File

@ -279,7 +279,8 @@ class JS_FRIEND_API(BaseProxyHandler)
/* Non-standard but conceptual kin to {g,s}etPrototypeOf, so lives here. */
virtual bool setImmutablePrototype(JSContext *cx, HandleObject proxy, bool *succeeded) const;
virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const = 0;
virtual bool preventExtensions(JSContext *cx, HandleObject proxy,
ObjectOpResult &result) const = 0;
virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const = 0;
/*
@ -385,7 +386,8 @@ class JS_FRIEND_API(DirectProxyHandler) : public BaseProxyHandler
bool *bp) const MOZ_OVERRIDE;
virtual bool setImmutablePrototype(JSContext *cx, HandleObject proxy,
bool *succeeded) const MOZ_OVERRIDE;
virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE;
virtual bool preventExtensions(JSContext *cx, HandleObject proxy,
ObjectOpResult &result) const MOZ_OVERRIDE;
virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
virtual bool has(JSContext *cx, HandleObject proxy, HandleId id,
bool *bp) const MOZ_OVERRIDE;

View File

@ -897,21 +897,9 @@ obj_preventExtensions(JSContext *cx, unsigned argc, Value *vp)
if (!args.get(0).isObject())
return true;
// Steps 2-3.
// Steps 2-5.
RootedObject obj(cx, &args.get(0).toObject());
bool status;
if (!PreventExtensions(cx, obj, &status))
return false;
// Step 4.
if (!status) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_CHANGE_EXTENSIBILITY);
return false;
}
// Step 5.
return true;
return PreventExtensions(cx, obj);
}
// ES6 draft rev27 (2014/08/24) 19.1.2.5 Object.freeze(O)

View File

@ -341,6 +341,7 @@ MSG_DEF(JSMSG_CANT_DEFINE_INVALID, 0, JSEXN_TYPEERR, "proxy can't define an
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_PROXY_PREVENTEXTENSIONS_RETURNED_FALSE, 0, JSEXN_TYPEERR, "proxy preventExtensions 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")
@ -471,9 +472,8 @@ MSG_DEF(JSMSG_ATOMICS_BAD_ARRAY, 0, JSEXN_TYPEERR, "invalid array type f
MSG_DEF(JSMSG_ATOMICS_TOO_LONG, 0, JSEXN_RANGEERR, "timeout value too large")
MSG_DEF(JSMSG_ATOMICS_WAIT_NOT_ALLOWED, 0, JSEXN_ERR, "waiting is not allowed on this thread")
// XPConnect wrappers
// XPConnect wrappers and DOM bindings
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")
MSG_DEF(JSMSG_CANT_PREVENT_EXTENSIONS, 0, JSEXN_TYPEERR, "can't prevent extensions on this proxy object")

View File

@ -168,6 +168,17 @@ JS::ObjectOpResult::reportStrictErrorOrWarning(JSContext *cx, HandleObject obj,
return JS_ReportErrorFlagsAndNumber(cx, flags, GetErrorMessage, nullptr, code_);
}
JS_PUBLIC_API(bool)
JS::ObjectOpResult::reportStrictErrorOrWarning(JSContext *cx, HandleObject obj, bool strict)
{
MOZ_ASSERT(code_ != Uninitialized);
MOZ_ASSERT(!ok());
MOZ_ASSERT(!ErrorTakesIdArgument(code_));
unsigned flags = strict ? JSREPORT_ERROR : (JSREPORT_WARNING | JSREPORT_STRICT);
return JS_ReportErrorFlagsAndNumber(cx, flags, GetErrorMessage, nullptr, code_);
}
JS_PUBLIC_API(bool)
JS::ObjectOpResult::failCantRedefineProp()
{
@ -210,6 +221,12 @@ JS::ObjectOpResult::failCantDeleteWindowNamedProperty()
return fail(JSMSG_CANT_DELETE_WINDOW_NAMED_PROPERTY);
}
JS_PUBLIC_API(bool)
JS::ObjectOpResult::failCantPreventExtensions()
{
return fail(JSMSG_CANT_PREVENT_EXTENSIONS);
}
JS_PUBLIC_API(int64_t)
JS_Now()
{
@ -1795,9 +1812,9 @@ JS_IsExtensible(JSContext *cx, HandleObject obj, bool *extensible)
}
JS_PUBLIC_API(bool)
JS_PreventExtensions(JSContext *cx, JS::HandleObject obj, bool *succeeded)
JS_PreventExtensions(JSContext *cx, JS::HandleObject obj, ObjectOpResult &result)
{
return PreventExtensions(cx, obj, succeeded);
return PreventExtensions(cx, obj, result);
}
JS_PUBLIC_API(JSObject *)

View File

@ -2500,12 +2500,12 @@ JS_FreezeObject(JSContext *cx, JS::Handle<JSObject*> obj);
/*
* Attempt to make |obj| non-extensible. If an error occurs while making the
* attempt, return false (with a pending exception set, depending upon the
* nature of the error). If no error occurs, return true with |*succeeded| set
* nature of the error). If no error occurs, return true with |result| set
* to indicate whether the attempt successfully set the [[Extensible]] property
* to false.
*/
extern JS_PUBLIC_API(bool)
JS_PreventExtensions(JSContext *cx, JS::HandleObject obj, bool *succeeded);
JS_PreventExtensions(JSContext *cx, JS::HandleObject obj, JS::ObjectOpResult &result);
extern JS_PUBLIC_API(JSObject *)
JS_New(JSContext *cx, JS::HandleObject ctor, const JS::HandleValueArray& args);

View File

@ -879,15 +879,10 @@ CreateFunctionPrototype(JSContext *cx, JSProtoKey key)
if (!tte)
return nullptr;
bool succeeded;
RootedFunction throwTypeError(cx, NewFunction(cx, tte, ThrowTypeError, 0,
JSFunction::NATIVE_FUN, self, js::NullPtr()));
if (!throwTypeError || !PreventExtensions(cx, throwTypeError, &succeeded))
if (!throwTypeError || !PreventExtensions(cx, throwTypeError))
return nullptr;
if (!succeeded) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_CHANGE_EXTENSIBILITY);
return nullptr;
}
self->setThrowTypeError(throwTypeError);

View File

@ -969,13 +969,8 @@ js::SetIntegrityLevel(JSContext *cx, HandleObject obj, IntegrityLevel level)
assertSameCompartment(cx, obj);
// Steps 3-5. (Steps 1-2 are redundant assertions.)
bool status;
if (!PreventExtensions(cx, obj, &status))
if (!PreventExtensions(cx, obj))
return false;
if (!status) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_CHANGE_EXTENSIBILITY);
return false;
}
// Steps 6-7.
AutoIdVector keys(cx);
@ -3173,35 +3168,38 @@ js::SetPrototype(JSContext *cx, HandleObject obj, HandleObject proto, bool *succ
}
bool
js::PreventExtensions(JSContext *cx, HandleObject obj, bool *succeeded)
js::PreventExtensions(JSContext *cx, HandleObject obj, ObjectOpResult &result)
{
if (obj->is<ProxyObject>())
return js::Proxy::preventExtensions(cx, obj, succeeded);
return js::Proxy::preventExtensions(cx, obj, result);
if (!obj->nonProxyIsExtensible()) {
*succeeded = true;
return true;
}
if (!obj->nonProxyIsExtensible())
return result.succeed();
/*
* Force lazy properties to be resolved by iterating over the objects' own
* properties.
*/
// Force lazy properties to be resolved.
AutoIdVector props(cx);
if (!js::GetPropertyKeys(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY, &props))
return false;
/*
* Convert all dense elements to sparse properties. This will shrink the
* initialized length and capacity of the object to zero and ensure that no
* new dense elements can be added without calling growElements(), which
* checks isExtensible().
*/
if (obj->isNative() && !NativeObject::sparsifyDenseElements(cx, obj.as<NativeObject>()))
return false;
// Convert all dense elements to sparse properties. This will shrink the
// initialized length and capacity of the object to zero and ensure that no
// new dense elements can be added without calling growElements(), which
// checks isExtensible().
if (obj->isNative()) {
if (!NativeObject::sparsifyDenseElements(cx, obj.as<NativeObject>()))
return false;
}
*succeeded = true;
return obj->setFlags(cx, BaseShape::NOT_EXTENSIBLE, JSObject::GENERATE_SHAPE);
if (!obj->setFlags(cx, BaseShape::NOT_EXTENSIBLE, JSObject::GENERATE_SHAPE))
return false;
return result.succeed();
}
bool
js::PreventExtensions(JSContext *cx, HandleObject obj)
{
ObjectOpResult result;
return PreventExtensions(cx, obj, result) && result.checkStrict(cx, obj);
}
bool

View File

@ -84,7 +84,7 @@ class SetObject;
class StrictArgumentsObject;
// Forward declarations, required for later friend declarations.
bool PreventExtensions(JSContext *cx, JS::HandleObject obj, bool *succeeded);
bool PreventExtensions(JSContext *cx, JS::HandleObject obj, JS::ObjectOpResult &result);
bool SetImmutablePrototype(js::ExclusiveContext *cx, JS::HandleObject obj, bool *succeeded);
} /* namespace js */
@ -114,7 +114,7 @@ class JSObject : public js::gc::Cell
friend class js::NewObjectCache;
friend class js::Nursery;
friend class js::gc::RelocationOverlay;
friend bool js::PreventExtensions(JSContext *cx, JS::HandleObject obj, bool *succeeded);
friend bool js::PreventExtensions(JSContext *cx, JS::HandleObject obj, JS::ObjectOpResult &result);
friend bool js::SetImmutablePrototype(js::ExclusiveContext *cx, JS::HandleObject obj,
bool *succeeded);
@ -725,11 +725,15 @@ IsExtensible(ExclusiveContext *cx, HandleObject obj, bool *extensible);
/*
* ES6 [[PreventExtensions]]. Attempt to change the [[Extensible]] bit on |obj|
* to false. Indicate success or failure through the |*succeeded| outparam, or
* to false. Indicate success or failure through the |result| outparam, or
* actual error through the return value.
*/
extern bool
PreventExtensions(JSContext *cx, HandleObject obj, bool *succeeded);
PreventExtensions(JSContext *cx, HandleObject obj, ObjectOpResult &result);
/* Convenience function. As above, but throw on failure. */
extern bool
PreventExtensions(JSContext *cx, HandleObject obj);
/*
* ES6 [[GetOwnPropertyDescriptor]]. Get a description of one of obj's own

View File

@ -131,7 +131,8 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper
virtual bool setImmutablePrototype(JSContext *cx, HandleObject proxy,
bool *succeeded) const MOZ_OVERRIDE;
virtual bool preventExtensions(JSContext *cx, HandleObject wrapper, bool *succeeded) const MOZ_OVERRIDE;
virtual bool preventExtensions(JSContext *cx, HandleObject wrapper,
ObjectOpResult &result) const MOZ_OVERRIDE;
virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) const MOZ_OVERRIDE;
virtual bool has(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool get(JSContext *cx, HandleObject wrapper, HandleObject receiver,
@ -187,7 +188,8 @@ class JS_FRIEND_API(SecurityWrapper) : public Base
MutableHandle<JSPropertyDescriptor> desc,
ObjectOpResult &result) const MOZ_OVERRIDE;
virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) const MOZ_OVERRIDE;
virtual bool preventExtensions(JSContext *cx, HandleObject wrapper, bool *succeeded) const MOZ_OVERRIDE;
virtual bool preventExtensions(JSContext *cx, HandleObject wrapper,
ObjectOpResult &result) const MOZ_OVERRIDE;
virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto,
bool *bp) const MOZ_OVERRIDE;
virtual bool setImmutablePrototype(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE;

View File

@ -117,11 +117,11 @@ CrossCompartmentWrapper::setImmutablePrototype(JSContext *cx, HandleObject wrapp
bool
CrossCompartmentWrapper::preventExtensions(JSContext *cx, HandleObject wrapper,
bool *succeeded) const
ObjectOpResult &result) const
{
PIERCE(cx, wrapper,
NOTHING,
Wrapper::preventExtensions(cx, wrapper, succeeded),
Wrapper::preventExtensions(cx, wrapper, result),
NOTHING);
}

View File

@ -70,7 +70,7 @@ DeadObjectProxy::getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandle
}
bool
DeadObjectProxy::preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const
DeadObjectProxy::preventExtensions(JSContext *cx, HandleObject proxy, ObjectOpResult &result) const
{
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;

View File

@ -31,7 +31,8 @@ class DeadObjectProxy : public BaseProxyHandler
virtual bool enumerate(JSContext *cx, HandleObject wrapper, MutableHandleObject objp) const MOZ_OVERRIDE;
virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
MutableHandleObject protop) const MOZ_OVERRIDE;
virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE;
virtual bool preventExtensions(JSContext *cx, HandleObject proxy,
ObjectOpResult &result) const MOZ_OVERRIDE;
virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;

View File

@ -133,10 +133,10 @@ DirectProxyHandler::setImmutablePrototype(JSContext *cx, HandleObject proxy, boo
}
bool
DirectProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const
DirectProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy, ObjectOpResult &result) const
{
RootedObject target(cx, proxy->as<ProxyObject>().target());
return PreventExtensions(cx, target, succeeded);
return PreventExtensions(cx, target, result);
}
bool

View File

@ -218,11 +218,11 @@ Proxy::setImmutablePrototype(JSContext *cx, HandleObject proxy, bool *succeeded)
}
/* static */ bool
Proxy::preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded)
Proxy::preventExtensions(JSContext *cx, HandleObject proxy, ObjectOpResult &result)
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
return handler->preventExtensions(cx, proxy, succeeded);
return handler->preventExtensions(cx, proxy, result);
}
/* static */ bool

View File

@ -34,7 +34,7 @@ class Proxy
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);
static bool preventExtensions(JSContext *cx, HandleObject proxy, ObjectOpResult &result);
static bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop);
static bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp);
static bool setImmutablePrototype(JSContext *cx, HandleObject proxy, bool *succeeded);

View File

@ -307,10 +307,10 @@ ScriptedDirectProxyHandler::setImmutablePrototype(JSContext *cx, HandleObject pr
return DirectProxyHandler::setImmutablePrototype(cx, proxy, succeeded);
}
// ES6 20141014 9.5.4 Proxy.[[PreventExtensions]]()
// ES6 draft rev 32 (2 Feb 2015) 9.5.4 Proxy.[[PreventExtensions]]()
bool
ScriptedDirectProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy,
bool *succeeded) const
ObjectOpResult &result) const
{
// Steps 1-3.
RootedObject handler(cx, GetDirectProxyHandlerObject(proxy));
@ -329,9 +329,9 @@ ScriptedDirectProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy,
// Step 7.
if (trap.isUndefined())
return DirectProxyHandler::preventExtensions(cx, proxy, succeeded);
return DirectProxyHandler::preventExtensions(cx, proxy, result);
// Steps 8, 10.
// Steps 8-9.
Value argv[] = {
ObjectValue(*target)
};
@ -339,23 +339,19 @@ ScriptedDirectProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy,
if (!Invoke(cx, ObjectValue(*handler), trap, ArrayLength(argv), argv, &trapResult))
return false;
// Step 9.
bool booleanTrapResult = ToBoolean(trapResult);
// Step 11.
if (booleanTrapResult) {
// Steps 10-11.
if (ToBoolean(trapResult)) {
bool extensible;
if (!IsExtensible(cx, target, &extensible))
return false;
if (extensible) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_REPORT_AS_NON_EXTENSIBLE);
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
JSMSG_CANT_REPORT_AS_NON_EXTENSIBLE);
return false;
}
return result.succeed();
}
// Step 12.
*succeeded = booleanTrapResult;
return true;
return result.fail(JSMSG_PROXY_PREVENTEXTENSIONS_RETURNED_FALSE);
}
// ES6 (5 April, 2014) 9.5.3 Proxy.[[IsExtensible]]()

View File

@ -39,7 +39,8 @@ class ScriptedDirectProxyHandler : public DirectProxyHandler {
virtual bool setImmutablePrototype(JSContext *cx, HandleObject proxy,
bool *succeeded) const MOZ_OVERRIDE;
virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE;
virtual bool preventExtensions(JSContext *cx, HandleObject proxy,
ObjectOpResult &result) const MOZ_OVERRIDE;
virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;

View File

@ -131,11 +131,11 @@ static const Class CallConstructHolder = {
const char ScriptedIndirectProxyHandler::family = 0;
bool
ScriptedIndirectProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const
ScriptedIndirectProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy,
ObjectOpResult &result) const
{
// See above.
*succeeded = false;
return true;
// Scripted indirect proxies don't support extensibility changes.
return result.fail(JSMSG_CANT_CHANGE_EXTENSIBILITY);
}
bool

View File

@ -31,7 +31,8 @@ class ScriptedIndirectProxyHandler : public BaseProxyHandler
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 preventExtensions(JSContext *cx, HandleObject proxy,
ObjectOpResult &result) const MOZ_OVERRIDE;
virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,

View File

@ -51,13 +51,12 @@ SecurityWrapper<Base>::setImmutablePrototype(JSContext *cx, HandleObject wrapper
template <class Base>
bool
SecurityWrapper<Base>::preventExtensions(JSContext *cx, HandleObject wrapper,
bool *succeeded) const
ObjectOpResult &result) const
{
// Just like BaseProxyHandler, SecurityWrappers claim by default to always
// be extensible, so as not to leak information about the state of the
// underlying wrapped thing.
*succeeded = false;
return true;
return result.fail(JSMSG_CANT_CHANGE_EXTENSIBILITY);
}
template <class Base>

View File

@ -6820,24 +6820,17 @@ DebuggerObject_sealHelper(JSContext *cx, unsigned argc, Value *vp, SealHelperOp
Maybe<AutoCompartment> ac;
ac.emplace(cx, obj);
ErrorCopier ec(ac);
bool ok;
if (op == OpSeal) {
ok = SetIntegrityLevel(cx, obj, IntegrityLevel::Sealed);
if (!SetIntegrityLevel(cx, obj, IntegrityLevel::Sealed))
return false;
} else if (op == OpFreeze) {
ok = SetIntegrityLevel(cx, obj, IntegrityLevel::Frozen);
if (!SetIntegrityLevel(cx, obj, IntegrityLevel::Frozen))
return false;
} else {
MOZ_ASSERT(op == OpPreventExtensions);
bool succeeded;
ok = PreventExtensions(cx, obj, &succeeded);
if (!ok)
if (!PreventExtensions(cx, obj))
return false;
if (!succeeded) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_CHANGE_EXTENSIBILITY);
return false;
}
}
if (!ok)
return false;
args.rval().setUndefined();
return true;
}

View File

@ -1440,12 +1440,12 @@ class DebugScopeProxy : public BaseProxyHandler
MOZ_CONSTEXPR DebugScopeProxy() : BaseProxyHandler(&family) {}
bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE
bool preventExtensions(JSContext *cx, HandleObject proxy,
ObjectOpResult &result) const MOZ_OVERRIDE
{
// always [[Extensible]], can't be made non-[[Extensible]], like most
// proxies
*succeeded = false;
return true;
return result.fail(JSMSG_CANT_CHANGE_EXTENSIBILITY);
}
bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE

View File

@ -29,11 +29,11 @@ namespace js {
*
* https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
*/
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 243;
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 244;
static const uint32_t XDR_BYTECODE_VERSION =
uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
static_assert(JSErr_Limit == 379,
static_assert(JSErr_Limit == 381,
"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 "

View File

@ -1764,16 +1764,15 @@ XrayToString(JSContext *cx, unsigned argc, Value *vp)
template <typename Base, typename Traits>
bool
XrayWrapper<Base, Traits>::preventExtensions(JSContext *cx, HandleObject wrapper, bool *succeeded)
const
XrayWrapper<Base, Traits>::preventExtensions(JSContext *cx, HandleObject wrapper,
ObjectOpResult &result) const
{
// Xray wrappers are supposed to provide a clean view of the target
// reflector, hiding any modifications by script in the target scope. So
// even if that script freezes the reflector, we don't want to make that
// visible to the caller. DOM reflectors are always extensible by default,
// so we can just return true here.
*succeeded = false;
return true;
// so we can just return failure here.
return result.failCantPreventExtensions();
}
template <typename Base, typename Traits>

View File

@ -426,7 +426,8 @@ class XrayWrapper : public Base {
JS::HandleObject proto, bool *bp) const MOZ_OVERRIDE;
virtual bool setImmutablePrototype(JSContext *cx, JS::HandleObject wrapper,
bool *succeeded) const MOZ_OVERRIDE;
virtual bool preventExtensions(JSContext *cx, JS::Handle<JSObject*> wrapper, bool *succeeded) const MOZ_OVERRIDE;
virtual bool preventExtensions(JSContext *cx, JS::Handle<JSObject*> wrapper,
JS::ObjectOpResult &result) const MOZ_OVERRIDE;
virtual bool isExtensible(JSContext *cx, JS::Handle<JSObject*> wrapper, bool *extensible) const MOZ_OVERRIDE;
virtual bool has(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
bool *bp) const MOZ_OVERRIDE;