Bug 1113369, part 4 - [[Set]] 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-03 19:51:40 -06:00
parent ea302a9012
commit 84c7008b45
68 changed files with 593 additions and 415 deletions

View File

@ -646,8 +646,8 @@ public:
virtual bool set(JSContext *cx, JS::Handle<JSObject*> proxy,
JS::Handle<JSObject*> receiver,
JS::Handle<jsid> id,
bool strict,
JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
JS::MutableHandle<JS::Value> vp,
JS::ObjectOpResult &result) const MOZ_OVERRIDE;
// SpiderMonkey extensions
virtual bool getPropertyDescriptor(JSContext* cx,
@ -917,19 +917,17 @@ bool
nsOuterWindowProxy::set(JSContext *cx, JS::Handle<JSObject*> proxy,
JS::Handle<JSObject*> receiver,
JS::Handle<jsid> id,
bool strict,
JS::MutableHandle<JS::Value> vp) const
JS::MutableHandle<JS::Value> vp,
JS::ObjectOpResult &result) const
{
int32_t index = GetArrayIndexFromId(cx, id);
if (IsArrayIndex(index)) {
// Reject (which means throw if and only if strict) the set.
if (strict) {
// XXXbz This needs to throw, but see bug 828137.
}
return true;
// XXX See bug 828137.
return result.succeed();
}
return js::Wrapper::set(cx, proxy, receiver, id, strict, vp);
return js::Wrapper::set(cx, proxy, receiver, id, vp, result);
}
bool

View File

@ -221,7 +221,7 @@ DOMProxyHandler::defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::
bool
DOMProxyHandler::set(JSContext *cx, Handle<JSObject*> proxy, Handle<JSObject*> receiver,
Handle<jsid> id, bool strict, MutableHandle<JS::Value> vp) const
Handle<jsid> id, MutableHandle<JS::Value> vp, ObjectOpResult &result) const
{
MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
"Should not have a XrayWrapper here");
@ -230,7 +230,7 @@ DOMProxyHandler::set(JSContext *cx, Handle<JSObject*> proxy, Handle<JSObject*> r
return false;
}
if (done) {
return true;
return result.succeed();
}
// Make sure to ignore our named properties when checking for own
@ -255,7 +255,7 @@ DOMProxyHandler::set(JSContext *cx, Handle<JSObject*> proxy, Handle<JSObject*> r
}
return js::SetPropertyIgnoringNamedGetter(cx, this, proxy, receiver, id,
&desc, descIsOwn, strict, vp);
&desc, descIsOwn, vp, result);
}
bool

View File

@ -123,7 +123,7 @@ public:
bool has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
bool* bp) const MOZ_OVERRIDE;
bool set(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<JSObject*> receiver,
JS::Handle<jsid> id, bool strict, JS::MutableHandle<JS::Value> vp)
JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp, JS::ObjectOpResult &result)
const MOZ_OVERRIDE;
/*

View File

@ -164,8 +164,8 @@ static bool
NPObjWrapper_DelProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, bool *succeeded);
static bool
NPObjWrapper_SetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, bool strict,
JS::MutableHandle<JS::Value> vp);
NPObjWrapper_SetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
JS::MutableHandle<JS::Value> vp, JS::ObjectOpResult &result);
static bool
NPObjWrapper_GetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp);
@ -1306,8 +1306,8 @@ NPObjWrapper_DelProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<js
}
static bool
NPObjWrapper_SetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, bool strict,
JS::MutableHandle<JS::Value> vp)
NPObjWrapper_SetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
JS::MutableHandle<JS::Value> vp, JS::ObjectOpResult &result)
{
NPObject *npobj = GetNPObject(cx, obj);
@ -1362,7 +1362,7 @@ NPObjWrapper_SetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<js
return false;
}
return true;
return result.succeed();
}
static bool

View File

@ -74,9 +74,9 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base
return Answer::RecvGet(ObjectId::deserialize(objId), receiverVar, id, rs, result);
}
bool RecvSet(const uint64_t &objId, const ObjectVariant &receiverVar,
const JSIDVariant &id, const bool &strict,
const JSVariant &value, ReturnStatus *rs, JSVariant *result) {
return Answer::RecvSet(ObjectId::deserialize(objId), receiverVar, id, strict, value, rs, result);
const JSIDVariant &id, const JSVariant &value, ReturnStatus *rs,
JSVariant *result) {
return Answer::RecvSet(ObjectId::deserialize(objId), receiverVar, id, value, rs, result);
}
bool RecvIsExtensible(const uint64_t &objId, ReturnStatus *rs,
@ -166,9 +166,9 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base
return Base::SendGet(objId.serialize(), receiverVar, id, rs, result);
}
bool SendSet(const ObjectId &objId, const ObjectVariant &receiverVar,
const JSIDVariant &id, const bool &strict,
const JSVariant &value, ReturnStatus *rs, JSVariant *result) {
return Base::SendSet(objId.serialize(), receiverVar, id, strict, value, rs, result);
const JSIDVariant &id, const JSVariant &value, ReturnStatus *rs,
JSVariant *result) {
return Base::SendSet(objId.serialize(), receiverVar, id, value, rs, result);
}
bool SendIsExtensible(const ObjectId &objId, ReturnStatus *rs,

View File

@ -605,7 +605,8 @@ UnknownPropertyStub(JSContext *cx, HandleObject obj, HandleId id, MutableHandleV
}
bool
UnknownStrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp)
UnknownStrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp,
ObjectOpResult &result)
{
JS_ReportError(cx, "setter could not be wrapped via CPOWs");
return false;

View File

@ -33,7 +33,7 @@ both:
prio(high) sync Has(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has);
prio(high) sync HasOwn(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has);
prio(high) sync Get(uint64_t objId, ObjectVariant receiver, JSIDVariant id) returns (ReturnStatus rs, JSVariant result);
prio(high) sync Set(uint64_t objId, ObjectVariant receiver, JSIDVariant id, bool strict, JSVariant value) returns (ReturnStatus rs, JSVariant result);
prio(high) sync Set(uint64_t objId, ObjectVariant receiver, JSIDVariant id, JSVariant value) returns (ReturnStatus rs, JSVariant result);
prio(high) sync IsExtensible(uint64_t objId) returns (ReturnStatus rs, bool result);
prio(high) sync CallOrConstruct(uint64_t objId, JSParam[] argv, bool construct) returns (ReturnStatus rs, JSVariant result, JSParam[] outparams);

View File

@ -313,8 +313,8 @@ WrapperAnswer::RecvGet(const ObjectId &objId, const ObjectVariant &receiverVar,
bool
WrapperAnswer::RecvSet(const ObjectId &objId, const ObjectVariant &receiverVar,
const JSIDVariant &idVar, const bool &strict, const JSVariant &value,
ReturnStatus *rs, JSVariant *result)
const JSIDVariant &idVar, const JSVariant &value, ReturnStatus *rs,
JSVariant *resultValue)
{
// We may run scripted setters.
AutoEntryScript aes(xpc::NativeGlobal(scopeForTargetObjects()));
@ -322,7 +322,7 @@ WrapperAnswer::RecvSet(const ObjectId &objId, const ObjectVariant &receiverVar,
// The outparam will be written to the buffer, so it must be set even if
// the parent won't read it.
*result = UndefinedVariant();
*resultValue = UndefinedVariant();
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
@ -338,19 +338,19 @@ WrapperAnswer::RecvSet(const ObjectId &objId, const ObjectVariant &receiverVar,
if (!fromJSIDVariant(cx, idVar, &id))
return fail(cx, rs);
MOZ_ASSERT(obj == receiver);
RootedValue val(cx);
if (!fromVariant(cx, value, &val))
return fail(cx, rs);
if (!JS_SetPropertyById(cx, obj, id, val))
ObjectOpResult result;
RootedValue receiverVal(cx, ObjectValue(*receiver));
if (!JS_ForwardSetPropertyTo(cx, obj, id, val, receiverVal, result))
return fail(cx, rs);
if (!toVariant(cx, val, result))
if (!toVariant(cx, val, resultValue))
return fail(cx, rs);
return ok(rs);
return ok(rs, result);
}
bool

View File

@ -40,8 +40,8 @@ class WrapperAnswer : public virtual JavaScriptShared
const JSIDVariant &id,
ReturnStatus *rs, JSVariant *result);
bool RecvSet(const ObjectId &objId, const ObjectVariant &receiverVar,
const JSIDVariant &id, const bool &strict,
const JSVariant &value, ReturnStatus *rs, JSVariant *result);
const JSIDVariant &id, const JSVariant &value, ReturnStatus *rs,
JSVariant *result);
bool RecvIsExtensible(const ObjectId &objId, ReturnStatus *rs,
bool *result);

View File

@ -102,7 +102,8 @@ class CPOWProxyHandler : public BaseProxyHandler
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, bool strict, JS::MutableHandleValue vp) const MOZ_OVERRIDE;
JS::HandleId id, JS::MutableHandleValue vp,
JS::ObjectOpResult &result) const MOZ_OVERRIDE;
virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
@ -434,14 +435,14 @@ WrapperOwner::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
bool
CPOWProxyHandler::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, bool strict, JS::MutableHandleValue vp) const
JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult &result) const
{
FORWARD(set, (cx, proxy, receiver, id, strict, vp));
FORWARD(set, (cx, proxy, receiver, id, vp, result));
}
bool
WrapperOwner::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, bool strict, JS::MutableHandleValue vp)
JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult &result)
{
ObjectId objId = idOf(proxy);
@ -458,16 +459,16 @@ WrapperOwner::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiv
return false;
ReturnStatus status;
JSVariant result;
if (!SendSet(objId, receiverVar, idVar, strict, val, &status, &result))
JSVariant resultValue;
if (!SendSet(objId, receiverVar, idVar, val, &status, &resultValue))
return ipcfail(cx);
LOG_STACK();
if (!ok(cx, status))
if (!ok(cx, status, result))
return false;
return fromVariant(cx, result, vp);
return fromVariant(cx, resultValue, vp);
}
bool

View File

@ -42,7 +42,7 @@ class WrapperOwner : public virtual JavaScriptShared
bool get(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, JS::MutableHandleValue vp);
bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, bool strict, JS::MutableHandleValue vp);
JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult &result);
bool callOrConstruct(JSContext *cx, JS::HandleObject proxy, const JS::CallArgs &args,
bool construct);
@ -128,8 +128,8 @@ class WrapperOwner : public virtual JavaScriptShared
const JSIDVariant &id,
ReturnStatus *rs, JSVariant *result) = 0;
virtual bool SendSet(const ObjectId &objId, const ObjectVariant &receiverVar,
const JSIDVariant &id, const bool &strict,
const JSVariant &value, ReturnStatus *rs, JSVariant *result) = 0;
const JSIDVariant &id, const JSVariant &value,
ReturnStatus *rs, JSVariant *result) = 0;
virtual bool SendIsExtensible(const ObjectId &objId, ReturnStatus *rs,
bool *result) = 0;

View File

@ -121,6 +121,7 @@ class ObjectOpResult
JS_PUBLIC_API(bool) failCantRedefineProp();
JS_PUBLIC_API(bool) failReadOnly();
JS_PUBLIC_API(bool) failGetterOnly();
JS_PUBLIC_API(bool) failCantSetInterposed();
uint32_t failureCode() const {
MOZ_ASSERT(!ok());
@ -162,7 +163,6 @@ class ObjectOpResult
/* Helper function for checkStrictErrorOrWarning's slow path. */
JS_PUBLIC_API(bool) reportStrictErrorOrWarning(JSContext *cx, HandleObject obj, HandleId id, bool strict);
};
}
@ -185,7 +185,7 @@ typedef JSGetterOp JSAddPropertyOp;
// set.
typedef bool
(* JSSetterOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
bool strict, JS::MutableHandleValue vp);
JS::MutableHandleValue vp, JS::ObjectOpResult &result);
// Delete a property named by id in obj.
//
@ -298,7 +298,7 @@ typedef bool
JS::MutableHandleValue vp);
typedef bool
(* SetPropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, JS::HandleId id,
JS::MutableHandleValue vp, bool strict);
JS::MutableHandleValue vp, JS::ObjectOpResult &result);
typedef bool
(* GetOwnPropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
JS::MutableHandle<JSPropertyDescriptor> desc);

View File

@ -291,7 +291,7 @@ class JS_FRIEND_API(BaseProxyHandler)
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandleValue vp) const;
virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, bool strict, MutableHandleValue vp) const;
HandleId id, MutableHandleValue vp, ObjectOpResult &result) const;
/*
* [[Call]] and [[Construct]] are standard internal methods but according
@ -390,7 +390,8 @@ class JS_FRIEND_API(DirectProxyHandler) : public BaseProxyHandler
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, bool strict, MutableHandleValue vp) const MOZ_OVERRIDE;
HandleId id, MutableHandleValue vp,
ObjectOpResult &result) const MOZ_OVERRIDE;
virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;

View File

@ -1910,7 +1910,7 @@ TypedObject::obj_getArrayElement(JSContext *cx,
bool
TypedObject::obj_setProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
MutableHandleValue vp, bool strict)
MutableHandleValue vp, ObjectOpResult &result)
{
Rooted<TypedObject *> typedObj(cx, &obj->as<TypedObject>());
@ -1929,13 +1929,13 @@ TypedObject::obj_setProperty(JSContext *cx, HandleObject obj, HandleObject recei
nullptr, JSMSG_CANT_REDEFINE_ARRAY_LENGTH);
return false;
}
return SetNonWritableProperty(cx, id, strict);
return result.failReadOnly();
}
uint32_t index;
if (IdIsIndex(id, &index)) {
if (obj != receiver)
return SetPropertyByDefining(cx, obj, receiver, id, vp, strict, false);
return SetPropertyByDefining(cx, obj, receiver, id, vp, false, result);
if (index >= uint32_t(typedObj->length())) {
JS_ReportErrorNumber(cx, GetErrorMessage,
@ -1946,7 +1946,9 @@ TypedObject::obj_setProperty(JSContext *cx, HandleObject obj, HandleObject recei
Rooted<TypeDescr*> elementType(cx);
elementType = &typedObj->typeDescr().as<ArrayTypeDescr>().elementType();
size_t offset = elementType->size() * index;
return ConvertAndCopyTo(cx, elementType, typedObj, offset, NullPtr(), vp);
if (!ConvertAndCopyTo(cx, elementType, typedObj, offset, NullPtr(), vp))
return false;
return result.succeed();
}
break;
}
@ -1959,16 +1961,18 @@ TypedObject::obj_setProperty(JSContext *cx, HandleObject obj, HandleObject recei
break;
if (obj != receiver)
return SetPropertyByDefining(cx, obj, receiver, id, vp, strict, false);
return SetPropertyByDefining(cx, obj, receiver, id, vp, false, result);
size_t offset = descr->fieldOffset(fieldIndex);
Rooted<TypeDescr*> fieldType(cx, &descr->fieldDescr(fieldIndex));
RootedAtom fieldName(cx, &descr->fieldName(fieldIndex));
return ConvertAndCopyTo(cx, fieldType, typedObj, offset, fieldName, vp);
if (!ConvertAndCopyTo(cx, fieldType, typedObj, offset, fieldName, vp))
return false;
return result.succeed();
}
}
return SetPropertyOnProto(cx, obj, receiver, id, vp, strict);
return SetPropertyOnProto(cx, obj, receiver, id, vp, result);
}
bool

View File

@ -541,7 +541,7 @@ class TypedObject : public JSObject
uint32_t index, MutableHandleValue vp);
static bool obj_setProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
HandleId id, MutableHandleValue vp, bool strict);
HandleId id, MutableHandleValue vp, ObjectOpResult &result);
static bool obj_getOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
MutableHandle<JSPropertyDescriptor> desc);

View File

@ -287,7 +287,8 @@ namespace ArrayType {
bool LengthGetter(JSContext* cx, JS::CallArgs args);
static bool Getter(JSContext* cx, HandleObject obj, HandleId idval, MutableHandleValue vp);
static bool Setter(JSContext* cx, HandleObject obj, HandleId idval, bool strict, MutableHandleValue vp);
static bool Setter(JSContext* cx, HandleObject obj, HandleId idval, MutableHandleValue vp,
ObjectOpResult &result);
static bool AddressOfElement(JSContext* cx, unsigned argc, jsval* vp);
}
@ -300,9 +301,9 @@ namespace StructType {
bool FieldsArrayGetter(JSContext* cx, JS::CallArgs args);
static bool FieldGetter(JSContext* cx, HandleObject obj, HandleId idval,
MutableHandleValue vp);
static bool FieldSetter(JSContext* cx, HandleObject obj, HandleId idval, bool strict,
MutableHandleValue vp);
MutableHandleValue vp);
static bool FieldSetter(JSContext* cx, HandleObject obj, HandleId idval,
MutableHandleValue vp, ObjectOpResult &result);
static bool AddressOfField(JSContext* cx, unsigned argc, jsval* vp);
static bool Define(JSContext* cx, unsigned argc, jsval* vp);
}
@ -4625,7 +4626,8 @@ ArrayType::Getter(JSContext* cx, HandleObject obj, HandleId idval, MutableHandle
}
bool
ArrayType::Setter(JSContext* cx, HandleObject obj, HandleId idval, bool strict, MutableHandleValue vp)
ArrayType::Setter(JSContext* cx, HandleObject obj, HandleId idval, MutableHandleValue vp,
ObjectOpResult &result)
{
// This should never happen, but we'll check to be safe.
if (!CData::IsCData(obj)) {
@ -4637,7 +4639,7 @@ ArrayType::Setter(JSContext* cx, HandleObject obj, HandleId idval, bool strict,
// CData, regardless of CType.)
JSObject* typeObj = CData::GetCType(obj);
if (CType::GetTypeCode(typeObj) != TYPE_array)
return true;
return result.succeed();
// Convert the index to a size_t and bounds-check it.
size_t index;
@ -4647,7 +4649,7 @@ ArrayType::Setter(JSContext* cx, HandleObject obj, HandleId idval, bool strict,
if (!ok && JSID_IS_STRING(idval) && !StringToInteger(cx, JSID_TO_STRING(idval), &dummy)) {
// String either isn't a number, or doesn't fit in size_t.
// Chances are it's a regular property lookup, so return.
return true;
return result.succeed();
}
if (!ok || index >= length) {
JS_ReportError(cx, "invalid index");
@ -4657,7 +4659,9 @@ ArrayType::Setter(JSContext* cx, HandleObject obj, HandleId idval, bool strict,
JSObject* baseType = GetBaseType(typeObj);
size_t elementSize = CType::GetSize(baseType);
char* data = static_cast<char*>(CData::GetData(obj)) + elementSize * index;
return ImplicitConvert(cx, vp, baseType, data, false, nullptr);
if (!ImplicitConvert(cx, vp, baseType, data, false, nullptr))
return false;
return result.succeed();
}
bool
@ -5290,7 +5294,8 @@ StructType::FieldGetter(JSContext* cx, HandleObject obj, HandleId idval, Mutable
}
bool
StructType::FieldSetter(JSContext* cx, HandleObject obj, HandleId idval, bool strict, MutableHandleValue vp)
StructType::FieldSetter(JSContext* cx, HandleObject obj, HandleId idval, MutableHandleValue vp,
ObjectOpResult &result)
{
if (!CData::IsCData(obj)) {
JS_ReportError(cx, "not a CData");
@ -5308,7 +5313,9 @@ StructType::FieldSetter(JSContext* cx, HandleObject obj, HandleId idval, bool st
return false;
char* data = static_cast<char*>(CData::GetData(obj)) + field->mOffset;
return ImplicitConvert(cx, vp, field->mType, data, false, nullptr);
if (!ImplicitConvert(cx, vp, field->mType, data, false, nullptr))
return false;
return result.succeed();
}
bool

View File

@ -110,7 +110,7 @@ check("o[- (o)]");
// A few one off tests
check_one("6", (function () { 6() }), " is not a function");
check_one("Array.prototype.reverse.call(...)", (function () { Array.prototype.reverse.call('123'); }), " is read-only");
check_one("0", (function () { Array.prototype.reverse.call('123'); }), " is read-only");
check_one(`(intermediate value)[Symbol.iterator](...).next(...).value`,
function () { var [{ x }] = [null, {}]; }, " is null");
check_one(`(intermediate value)[Symbol.iterator](...).next(...).value`,

View File

@ -8374,7 +8374,7 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_
MOZ_ASSERT(op == JSOP_SETPROP || op == JSOP_STRICTSETPROP);
RootedValue v(cx, rhs);
if (!SetProperty(cx, obj, obj, id, &v, op == JSOP_STRICTSETPROP))
if (!PutProperty(cx, obj, id, &v, op == JSOP_STRICTSETPROP))
return false;
}

View File

@ -1463,6 +1463,13 @@ GetPropertyIC::tryAttachTypedArrayLength(JSContext *cx, HandleScript outerScript
return linkAndAttachStub(cx, masm, attacher, ion, "typed array length");
}
static void
PushObjectOpResult(MacroAssembler &masm, uint32_t value = ObjectOpResult::Uninitialized)
{
static_assert(sizeof(ObjectOpResult) == sizeof(int32_t),
"ObjectOpResult size must match size reserved by masm.Push() here");
masm.Push(Imm32(value));
}
static bool
EmitCallProxyGet(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
@ -1507,6 +1514,9 @@ EmitCallProxyGet(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &at
masm.Push(object);
masm.movePtr(StackPointer, argProxyReg);
// Unused space, to keep the same stack layout as Proxy::set frames.
PushObjectOpResult(masm, 0);
masm.loadJSContext(argJSContextReg);
if (!masm.icBuildOOLFakeExitFrame(returnAddr, aic))
@ -2107,6 +2117,54 @@ IsCacheableSetPropCallPropertyOp(HandleObject obj, HandleObject holder, HandleSh
return true;
}
static bool
ReportStrictErrorOrWarning(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool strict,
JS::ObjectOpResult &result)
{
return result.reportStrictErrorOrWarning(cx, obj, id, strict);
}
template <class FrameLayout>
void
EmitObjectOpResultCheck(MacroAssembler &masm, Label *failure, bool strict,
Register scratchReg,
Register argJSContextReg,
Register argObjReg,
Register argIdReg,
Register argStrictReg,
Register argResultReg)
{
// if (!result) {
Label noStrictError;
masm.branch32(Assembler::Equal,
Address(StackPointer,
FrameLayout::offsetOfObjectOpResult()),
Imm32(ObjectOpResult::OkCode),
&noStrictError);
// if (!ReportStrictErrorOrWarning(cx, obj, id, strict, &result))
// goto failure;
masm.loadJSContext(argJSContextReg);
masm.computeEffectiveAddress(
Address(StackPointer, FrameLayout::offsetOfId()),
argIdReg);
masm.move32(Imm32(strict), argStrictReg);
masm.computeEffectiveAddress(
Address(StackPointer, FrameLayout::offsetOfObjectOpResult()),
argResultReg);
masm.setupUnalignedABICall(5, scratchReg);
masm.passABIArg(argJSContextReg);
masm.passABIArg(argObjReg);
masm.passABIArg(argIdReg);
masm.passABIArg(argStrictReg);
masm.passABIArg(argResultReg);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ReportStrictErrorOrWarning));
masm.branchIfFalseBool(ReturnReg, failure);
// }
masm.bind(&noStrictError);
}
static bool
EmitCallProxySet(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
HandleId propId, RegisterSet liveRegs, Register object,
@ -2114,18 +2172,23 @@ EmitCallProxySet(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &at
{
MacroAssembler::AfterICSaveLive aic = masm.icSaveLive(liveRegs);
// Remaining registers should be free, but we need to use |object| still
// so leave it alone.
// Remaining registers should be free, but we still need to use |object| so
// leave it alone.
//
// WARNING: We do not take() the register used by |value|, if any, so
// regSet is going to re-allocate it. Hence the emitted code must not touch
// any of the registers allocated from regSet until after the last use of
// |value|. (We can't afford to take it, either, because x86.)
RegisterSet regSet(RegisterSet::All());
regSet.take(AnyRegister(object));
// Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
// bool strict, MutableHandleValue vp)
// MutableHandleValue vp, ObjectOpResult &result)
Register argJSContextReg = regSet.takeGeneral();
Register argProxyReg = regSet.takeGeneral();
Register argIdReg = regSet.takeGeneral();
Register argVpReg = regSet.takeGeneral();
Register argStrictReg = regSet.takeGeneral();
Register argResultReg = regSet.takeGeneral();
Register scratch = regSet.takeGeneral();
@ -2145,8 +2208,11 @@ EmitCallProxySet(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &at
masm.Push(object);
masm.movePtr(StackPointer, argProxyReg);
// Allocate result out-param.
PushObjectOpResult(masm);
masm.movePtr(StackPointer, argResultReg);
masm.loadJSContext(argJSContextReg);
masm.move32(Imm32(strict? 1 : 0), argStrictReg);
if (!masm.icBuildOOLFakeExitFrame(returnAddr, aic))
return false;
@ -2158,13 +2224,19 @@ EmitCallProxySet(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &at
masm.passABIArg(argProxyReg);
masm.passABIArg(argProxyReg);
masm.passABIArg(argIdReg);
masm.passABIArg(argStrictReg);
masm.passABIArg(argVpReg);
masm.passABIArg(argResultReg);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, Proxy::set));
// Test for failure.
// Test for error.
masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
// Test for strict failure. We emit the check even in non-strict mode in
// order to pick up the warning if extraWarnings is enabled.
EmitObjectOpResultCheck<IonOOLProxyExitFrameLayout>(masm, masm.exceptionLabel(), strict,
scratch, argJSContextReg, argProxyReg,
argIdReg, argVpReg, argResultReg);
// masm.leaveExitFrame & pop locals
masm.adjustStack(IonOOLProxyExitFrameLayout::Size());
@ -2375,24 +2447,28 @@ GenerateCallSetter(JSContext *cx, IonScript *ion, MacroAssembler &masm,
Register argVpReg = regSet.takeGeneral();
Register argObjReg = regSet.takeGeneral();
Register argIdReg = regSet.takeGeneral();
Register argStrictReg = regSet.takeGeneral();
attacher.pushStubCodePointer(masm);
Register argResultReg = regSet.takeGeneral();
SetterOp target = shape->setterOp();
MOZ_ASSERT(target);
// JSSetterOp: bool fn(JSContext *cx, HandleObject obj,
// HandleId id, bool strict, MutableHandleValue vp);
// HandleId id, MutableHandleValue vp, ObjectOpResult &result);
// Push args on stack first so we can take pointers to make handles.
// First, allocate an ObjectOpResult on the stack. We push this before
// the stubCode pointer in order to match the layout of
// IonOOLSetterOpExitFrameLayout.
PushObjectOpResult(masm);
masm.movePtr(StackPointer, argResultReg);
attacher.pushStubCodePointer(masm);
// Push args on stack so we can take pointers to make handles.
if (value.constant())
masm.Push(value.value());
else
masm.Push(value.reg());
masm.movePtr(StackPointer, argVpReg);
masm.move32(Imm32(strict ? 1 : 0), argStrictReg);
// push canonical jsid from shape instead of propertyname.
masm.Push(shape->propid(), argIdReg);
masm.movePtr(StackPointer, argIdReg);
@ -2404,22 +2480,27 @@ GenerateCallSetter(JSContext *cx, IonScript *ion, MacroAssembler &masm,
if (!masm.icBuildOOLFakeExitFrame(returnAddr, aic))
return false;
masm.enterFakeExitFrame(IonOOLPropertyOpExitFrameLayout::Token());
masm.enterFakeExitFrame(IonOOLSetterOpExitFrameLayout::Token());
// Make the call.
masm.setupUnalignedABICall(5, scratchReg);
masm.passABIArg(argJSContextReg);
masm.passABIArg(argObjReg);
masm.passABIArg(argIdReg);
masm.passABIArg(argStrictReg);
masm.passABIArg(argVpReg);
masm.passABIArg(argResultReg);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, target));
// Test for failure.
// Test for error.
masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
// Test for failure.
EmitObjectOpResultCheck<IonOOLSetterOpExitFrameLayout>(masm, failure, strict, scratchReg,
argJSContextReg, argObjReg,
argIdReg, argVpReg, argResultReg);
// masm.leaveExitFrame & pop locals.
masm.adjustStack(IonOOLPropertyOpExitFrameLayout::Size());
masm.adjustStack(IonOOLSetterOpExitFrameLayout::Size());
} else {
MOZ_ASSERT(IsCacheableSetPropCallScripted(obj, holder, shape));

View File

@ -1310,9 +1310,16 @@ MarkJitExitFrame(JSTracer *trc, const JitFrameIterator &frame)
return;
}
if (frame.isExitFrameLayout<IonOOLPropertyOpExitFrameLayout>()) {
if (frame.isExitFrameLayout<IonOOLPropertyOpExitFrameLayout>() ||
frame.isExitFrameLayout<IonOOLSetterOpExitFrameLayout>())
{
// A SetterOp frame is a different size, but that's the only relevant
// difference between the two. The fields that need marking are all in
// the common base class.
IonOOLPropertyOpExitFrameLayout *oolgetter =
frame.exitFrame()->as<IonOOLPropertyOpExitFrameLayout>();
frame.isExitFrameLayout<IonOOLPropertyOpExitFrameLayout>()
? frame.exitFrame()->as<IonOOLPropertyOpExitFrameLayout>()
: frame.exitFrame()->as<IonOOLSetterOpExitFrameLayout>();
gc::MarkJitCodeRoot(trc, oolgetter->stubCode(), "ion-ool-property-op-code");
gc::MarkValueRoot(trc, oolgetter->vp(), "ion-ool-property-op-vp");
gc::MarkIdRoot(trc, oolgetter->id(), "ion-ool-property-op-id");

View File

@ -494,7 +494,8 @@ enum ExitFrameTokenValues
IonDOMMethodExitFrameLayoutToken = 0x3,
IonOOLNativeExitFrameLayoutToken = 0x4,
IonOOLPropertyOpExitFrameLayoutToken = 0x5,
IonOOLProxyExitFrameLayoutToken = 0x6,
IonOOLSetterOpExitFrameLayoutToken = 0x6,
IonOOLProxyExitFrameLayoutToken = 0x7,
ExitFrameLayoutBareToken = 0xFF
};
@ -627,7 +628,7 @@ class IonOOLNativeExitFrameLayout
class IonOOLPropertyOpExitFrameLayout
{
protected: // only to silence a clang warning about unused private fields
protected:
ExitFooterFrame footer_;
ExitFrameLayout exit_;
@ -652,6 +653,10 @@ class IonOOLPropertyOpExitFrameLayout
return sizeof(IonOOLPropertyOpExitFrameLayout);
}
static size_t offsetOfId() {
return offsetof(IonOOLPropertyOpExitFrameLayout, id_);
}
static size_t offsetOfResult() {
return offsetof(IonOOLPropertyOpExitFrameLayout, vp0_);
}
@ -670,16 +675,36 @@ class IonOOLPropertyOpExitFrameLayout
}
};
class IonOOLSetterOpExitFrameLayout : public IonOOLPropertyOpExitFrameLayout
{
protected: // only to silence a clang warning about unused private fields
JS::ObjectOpResult result_;
public:
static JitCode *Token() { return (JitCode *)IonOOLSetterOpExitFrameLayoutToken; }
static size_t offsetOfObjectOpResult() {
return offsetof(IonOOLSetterOpExitFrameLayout, result_);
}
static size_t Size() {
return sizeof(IonOOLSetterOpExitFrameLayout);
}
};
// Proxy::get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
// MutableHandleValue vp)
// Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
// bool strict, MutableHandleValue vp)
// MutableHandleValue vp, ObjectOpResult &result)
class IonOOLProxyExitFrameLayout
{
protected: // only to silence a clang warning about unused private fields
ExitFooterFrame footer_;
ExitFrameLayout exit_;
// result out-parameter (unused for Proxy::get)
JS::ObjectOpResult result_;
// The proxy object.
JSObject *proxy_;
@ -708,6 +733,14 @@ class IonOOLProxyExitFrameLayout
return offsetof(IonOOLProxyExitFrameLayout, vp0_);
}
static size_t offsetOfId() {
return offsetof(IonOOLProxyExitFrameLayout, id_);
}
static size_t offsetOfObjectOpResult() {
return offsetof(IonOOLProxyExitFrameLayout, result_);
}
inline JitCode **stubCode() {
return &stubCode_;
}

View File

@ -448,18 +448,24 @@ SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValu
return true;
}
ObjectOpResult result;
if (MOZ_LIKELY(!obj->getOps()->setProperty)) {
return NativeSetProperty(
cx, obj.as<NativeObject>(), obj.as<NativeObject>(), id,
(op == JSOP_SETNAME || op == JSOP_STRICTSETNAME ||
op == JSOP_SETGNAME || op == JSOP_STRICTSETGNAME)
? Unqualified
: Qualified,
&v,
strict);
if (!NativeSetProperty(
cx, obj.as<NativeObject>(), obj.as<NativeObject>(), id,
(op == JSOP_SETNAME || op == JSOP_STRICTSETNAME ||
op == JSOP_SETGNAME || op == JSOP_STRICTSETGNAME)
? Unqualified
: Qualified,
&v,
result))
{
return false;
}
} else {
if (!SetProperty(cx, obj, obj, id, &v, result))
return false;
}
return SetProperty(cx, obj, obj, id, &v, strict);
return result.checkStrictErrorOrWarning(cx, obj, id, strict);
}
bool

View File

@ -469,3 +469,6 @@ MSG_DEF(JSMSG_SYMBOL_TO_NUMBER, 0, JSEXN_TYPEERR, "can't convert symbol t
MSG_DEF(JSMSG_ATOMICS_BAD_ARRAY, 0, JSEXN_TYPEERR, "invalid array type for the operation")
MSG_DEF(JSMSG_ATOMICS_TOO_LONG, 0, JSEXN_RANGEERR, "timeout value too large")
MSG_DEF(JSMSG_ATOMICS_WAIT_NOT_ALLOWED, 0, JSEXN_ERR, "waiting is not allowed on this thread")
// XPConnect wrappers
MSG_DEF(JSMSG_CANT_SET_INTERPOSED, 1, JSEXN_TYPEERR, "unable to set interposed data property '{0}'")

View File

@ -45,11 +45,14 @@ BEGIN_TEST(testForwardSetProperty)
// Non-strict setter
CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, v3, true, setval));
ObjectOpResult result;
CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, setval, v3, result));
CHECK(result);
EXEC("assertEq(foundValue, obj3, 'wrong receiver passed to setter');");
CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, setval, true, setval));
CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, setval, setval, result));
CHECK(result);
EXEC("assertEq(typeof foundValue === 'object', true, \n"
" 'passing 42 as receiver to non-strict setter ' + \n"
@ -69,12 +72,13 @@ BEGIN_TEST(testForwardSetProperty)
"obj1;",
&v1);
CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, v3, true, setval));
CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, setval, v3, result));
CHECK(result);
EXEC("assertEq(foundValue, obj3, 'wrong receiver passed to strict setter');");
CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, setval, true, setval));
CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, setval, setval, result));
CHECK(result);
JS::RootedValue strictSetSupported(cx);
EVAL("var strictSetSupported = false; \n"

View File

@ -28,13 +28,13 @@ class CustomProxyHandler : public DirectProxyHandler {
}
bool set(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, bool strict, MutableHandleValue vp) const MOZ_OVERRIDE
HandleId id, MutableHandleValue vp, ObjectOpResult &result) const MOZ_OVERRIDE
{
Rooted<JSPropertyDescriptor> desc(cx);
if (!DirectProxyHandler::getPropertyDescriptor(cx, proxy, id, &desc))
return false;
return SetPropertyIgnoringNamedGetter(cx, this, proxy, receiver, id, &desc,
desc.object() == proxy, strict, vp);
desc.object() == proxy, vp, result);
}
private:

View File

@ -186,6 +186,12 @@ JS::ObjectOpResult::failGetterOnly()
return fail(JSMSG_GETTER_ONLY);
}
JS_PUBLIC_API(bool)
JS::ObjectOpResult::failCantSetInterposed()
{
return fail(JSMSG_CANT_SET_INTERPOSED);
}
JS_PUBLIC_API(int64_t)
JS_Now()
{
@ -1658,9 +1664,10 @@ JS_PropertyStub(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue
}
JS_PUBLIC_API(bool)
JS_StrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp)
JS_StrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp,
ObjectOpResult &result)
{
return true;
return result.succeed();
}
JS_PUBLIC_API(JSObject *)
@ -2806,25 +2813,25 @@ JS_SetPropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleValue v)
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj, id);
return SetProperty(cx, obj, obj, id, &value, false);
ObjectOpResult ignored;
return SetProperty(cx, obj, obj, id, &value, ignored);
}
JS_PUBLIC_API(bool)
JS_ForwardSetPropertyTo(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue onBehalfOf,
bool strict, JS::HandleValue v)
JS_ForwardSetPropertyTo(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
HandleValue receiver, ObjectOpResult &result)
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj, id);
assertSameCompartment(cx, onBehalfOf);
assertSameCompartment(cx, obj, id, receiver);
// XXX Bug 603201 will eliminate this ToObject.
RootedObject receiver(cx, ToObject(cx, onBehalfOf));
if (!receiver)
RootedObject receiverObj(cx, ToObject(cx, receiver));
if (!receiverObj)
return false;
RootedValue value(cx, v);
return SetProperty(cx, obj, receiver, id, &value, strict);
return SetProperty(cx, obj, receiverObj, id, &value, result);
}
static bool
@ -2834,7 +2841,8 @@ SetElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleValue v
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj, vp);
return SetElement(cx, obj, obj, index, vp, false);
ObjectOpResult ignored;
return SetElement(cx, obj, obj, index, vp, ignored);
}
JS_PUBLIC_API(bool)

View File

@ -1997,8 +1997,8 @@ JS_PropertyStub(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
JS::MutableHandleValue vp);
extern JS_PUBLIC_API(bool)
JS_StrictPropertyStub(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool strict,
JS::MutableHandleValue vp);
JS_StrictPropertyStub(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
JS::MutableHandleValue vp, JS::ObjectOpResult &result);
template<typename T>
struct JSConstScalarSpec {
@ -2841,8 +2841,8 @@ extern JS_PUBLIC_API(bool)
JS_SetPropertyById(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v);
extern JS_PUBLIC_API(bool)
JS_ForwardSetPropertyTo(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue onBehalfOf,
bool strict, JS::HandleValue vp);
JS_ForwardSetPropertyTo(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v,
JS::HandleValue receiver, JS::ObjectOpResult &result);
extern JS_PUBLIC_API(bool)
JS_DeleteProperty(JSContext *cx, JS::HandleObject obj, const char *name);

View File

@ -364,7 +364,7 @@ SetArrayElement(JSContext *cx, HandleObject obj, double index, HandleValue v)
return false;
RootedValue tmp(cx, v);
return SetProperty(cx, obj, obj, id, &tmp, true);
return SetProperty(cx, obj, obj, id, &tmp);
}
/*
@ -434,7 +434,7 @@ bool
js::SetLengthProperty(JSContext *cx, HandleObject obj, double length)
{
RootedValue v(cx, NumberValue(length));
return SetProperty(cx, obj, obj, cx->names().length, &v, true);
return SetProperty(cx, obj, obj, cx->names().length, &v);
}
/*
@ -460,7 +460,8 @@ array_length_getter(JSContext *cx, HandleObject obj_, HandleId id, MutableHandle
}
static bool
array_length_setter(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp)
array_length_setter(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp,
ObjectOpResult &result)
{
if (!obj->is<ArrayObject>()) {
// This array .length property was found on the prototype
@ -468,21 +469,14 @@ array_length_setter(JSContext *cx, HandleObject obj, HandleId id, bool strict, M
// we're here, do an impression of SetPropertyByDefining.
const Class *clasp = obj->getClass();
return DefineProperty(cx, obj, cx->names().length, vp,
clasp->getProperty, clasp->setProperty, JSPROP_ENUMERATE);
clasp->getProperty, clasp->setProperty, JSPROP_ENUMERATE, result);
}
Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
MOZ_ASSERT(arr->lengthIsWritable(),
"setter shouldn't be called if property is non-writable");
ObjectOpResult success;
if (!ArraySetLength(cx, arr, id, JSPROP_PERMANENT, vp, success))
return false;
if (strict && !success) {
success.reportError(cx, arr, id);
return false;
}
return true;
return ArraySetLength(cx, arr, id, JSPROP_PERMANENT, vp, result);
}
struct ReverseIndexComparator
@ -1277,7 +1271,7 @@ InitArrayElements(JSContext *cx, HandleObject obj, uint32_t start, uint32_t coun
value = *vector++;
indexv = DoubleValue(index);
if (!ValueToId<CanGC>(cx, indexv, &id) ||
!SetProperty(cx, obj, obj, id, &value, true))
!SetProperty(cx, obj, obj, id, &value))
{
return false;
}
@ -3074,8 +3068,7 @@ array_of(JSContext *cx, unsigned argc, Value *vp)
}
// Steps 9-10.
RootedValue v(cx, NumberValue(args.length()));
if (!SetProperty(cx, obj, obj, cx->names().length, &v, true))
if (!SetLengthProperty(cx, obj, args.length()))
return false;
// Step 11.

View File

@ -311,13 +311,13 @@ CallJSGetterOp(JSContext *cx, GetterOp op, HandleObject receiver, HandleId id,
}
MOZ_ALWAYS_INLINE bool
CallJSSetterOp(JSContext *cx, SetterOp op, HandleObject obj, HandleId id, bool strict,
MutableHandleValue vp)
CallJSSetterOp(JSContext *cx, SetterOp op, HandleObject obj, HandleId id, MutableHandleValue vp,
ObjectOpResult &result)
{
JS_CHECK_RECURSION(cx, return false);
assertSameCompartment(cx, obj, id, vp);
return op(cx, obj, id, strict, vp);
return op(cx, obj, id, vp, result);
}
static inline bool
@ -335,20 +335,22 @@ CallJSDeletePropertyOp(JSContext *cx, JSDeletePropertyOp op, HandleObject receiv
inline bool
CallSetter(JSContext *cx, HandleObject obj, HandleId id, SetterOp op, unsigned attrs,
bool strict, MutableHandleValue vp)
MutableHandleValue vp, ObjectOpResult &result)
{
if (attrs & JSPROP_SETTER) {
RootedValue opv(cx, CastAsObjectJsval(op));
return InvokeGetterOrSetter(cx, obj, opv, 1, vp.address(), vp);
if (!InvokeGetterOrSetter(cx, obj, opv, 1, vp.address(), vp))
return false;
return result.succeed();
}
if (attrs & JSPROP_GETTER)
return ReportGetterOnlyAssignment(cx, strict);
return result.fail(JSMSG_GETTER_ONLY);
if (!op)
return true;
return result.succeed();
return CallJSSetterOp(cx, op, obj, id, strict, vp);
return CallJSSetterOp(cx, op, obj, id, vp, result);
}
inline uintptr_t

View File

@ -370,7 +370,7 @@ proxy_GetProperty(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver
JS::MutableHandleValue vp);
extern JS_FRIEND_API(bool)
proxy_SetProperty(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, JS::HandleId id,
JS::MutableHandleValue bp, bool strict);
JS::MutableHandleValue bp, JS::ObjectOpResult &result);
extern JS_FRIEND_API(bool)
proxy_GetOwnPropertyDescriptor(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
JS::MutableHandle<JSPropertyDescriptor> desc);
@ -2640,7 +2640,8 @@ JS_FRIEND_API(bool)
SetPropertyIgnoringNamedGetter(JSContext *cx, const BaseProxyHandler *handler,
JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, JS::MutableHandle<JSPropertyDescriptor> desc,
bool descIsOwn, bool strict, JS::MutableHandleValue vp);
bool descIsOwn, JS::MutableHandleValue vp,
JS::ObjectOpResult &result);
JS_FRIEND_API(void)
ReportErrorWithId(JSContext *cx, const char *msg, JS::HandleId id);

View File

@ -1658,24 +1658,24 @@ js::CreateThisForFunction(JSContext *cx, HandleObject callee, NewObjectKind newK
/* static */ bool
JSObject::nonNativeSetProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
HandleId id, MutableHandleValue vp, bool strict)
HandleId id, MutableHandleValue vp, ObjectOpResult &result)
{
if (MOZ_UNLIKELY(obj->watched())) {
WatchpointMap *wpmap = cx->compartment()->watchpointMap;
if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, vp))
return false;
}
return obj->getOps()->setProperty(cx, obj, receiver, id, vp, strict);
return obj->getOps()->setProperty(cx, obj, receiver, id, vp, result);
}
/* static */ bool
JSObject::nonNativeSetElement(JSContext *cx, HandleObject obj, HandleObject receiver,
uint32_t index, MutableHandleValue vp, bool strict)
uint32_t index, MutableHandleValue vp, ObjectOpResult &result)
{
RootedId id(cx);
if (!IndexToId(cx, index, &id))
return false;
return nonNativeSetProperty(cx, obj, receiver, id, vp, strict);
return nonNativeSetProperty(cx, obj, receiver, id, vp, result);
}
JS_FRIEND_API(bool)
@ -3322,6 +3322,22 @@ js::DefineElement(ExclusiveContext *cx, HandleObject obj, uint32_t index, Handle
return DefineProperty(cx, obj, id, value, getter, setter, attrs);
}
bool
js::SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandlePropertyName name,
MutableHandleValue vp)
{
RootedId id(cx, NameToId(name));
return SetProperty(cx, obj, receiver, id, vp);
}
bool
js::PutProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, MutableHandleValue value,
bool strict)
{
RootedId id(cx, NameToId(name));
return PutProperty(cx, obj, id, value, strict);
}
/*** SpiderMonkey nonstandard internal methods ***************************************************/

View File

@ -486,10 +486,10 @@ class JSObject : public js::gc::Cell
static bool nonNativeSetProperty(JSContext *cx, js::HandleObject obj,
js::HandleObject receiver, js::HandleId id,
js::MutableHandleValue vp, bool strict);
js::MutableHandleValue vp, JS::ObjectOpResult &result);
static bool nonNativeSetElement(JSContext *cx, js::HandleObject obj,
js::HandleObject receiver, uint32_t index,
js::MutableHandleValue vp, bool strict);
js::MutableHandleValue vp, JS::ObjectOpResult &result);
static bool swap(JSContext *cx, JS::HandleObject a, JS::HandleObject b);
@ -870,19 +870,49 @@ GetElementNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index,
*/
inline bool
SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
MutableHandleValue vp, bool strict);
MutableHandleValue vp, ObjectOpResult &result);
inline bool
SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, PropertyName *name,
MutableHandleValue vp, bool strict)
MutableHandleValue vp, ObjectOpResult &result)
{
RootedId id(cx, NameToId(name));
return SetProperty(cx, obj, receiver, id, vp, strict);
return SetProperty(cx, obj, receiver, id, vp, result);
}
inline bool
SetElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index,
MutableHandleValue vp, bool strict);
MutableHandleValue vp, ObjectOpResult &result);
inline bool
SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
MutableHandleValue vp)
{
ObjectOpResult result;
return SetProperty(cx, obj, receiver, id, vp, result) &&
result.checkStrict(cx, receiver, id);
}
extern bool
SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandlePropertyName name,
MutableHandleValue vp);
/*
* ES6 draft rev 31 (15 Jan 2015) 7.3.3 Put (O, P, V, Throw), except that on
* success, the spec says this is supposed to return a boolean value, which we
* don't bother doing.
*/
inline bool
PutProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue value, bool strict)
{
ObjectOpResult result;
return SetProperty(cx, obj, obj, id, value, result) &&
result.checkStrictErrorOrWarning(cx, obj, id, strict);
}
extern bool
PutProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, MutableHandleValue value,
bool strict);
/*
* ES6 [[Delete]]. Equivalent to the JS code `delete obj[id]`.

View File

@ -742,7 +742,7 @@ NodeBuilder::newArray(NodeVector &elts, MutableHandleValue dst)
if (val.isMagic(JS_SERIALIZE_NO_NODE))
continue;
if (!SetElement(cx, array, array, i, &val, false))
if (!DefineElement(cx, array, i, val))
return false;
}

View File

@ -2168,7 +2168,7 @@ class MOZ_STACK_CLASS StringRegExpGuard
// Handle everything else generically (including throwing if .lastIndex is non-writable).
RootedValue zero(cx, Int32Value(0));
return SetProperty(cx, obj_, obj_, cx->names().lastIndex, &zero, true);
return SetProperty(cx, obj_, obj_, cx->names().lastIndex, &zero);
}
RegExpShared &regExp() { return *re_; }

View File

@ -135,8 +135,8 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper
virtual bool has(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool get(JSContext *cx, HandleObject wrapper, HandleObject receiver,
HandleId id, MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool set(JSContext *cx, HandleObject wrapper, HandleObject receiver,
HandleId id, bool strict, MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool set(JSContext *cx, HandleObject wrapper, HandleObject receiver, HandleId id,
MutableHandleValue vp, ObjectOpResult &result) const MOZ_OVERRIDE;
virtual bool call(JSContext *cx, HandleObject wrapper, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool construct(JSContext *cx, HandleObject wrapper, const CallArgs &args) const MOZ_OVERRIDE;

View File

@ -73,7 +73,7 @@ BaseProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
bool
BaseProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, bool strict, MutableHandleValue vp) const
HandleId id, MutableHandleValue vp, ObjectOpResult &result) const
{
assertEnteredPolicy(cx, proxy, id, SET);
@ -94,7 +94,7 @@ BaseProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
if (!GetPrototype(cx, proxy, &proto))
return false;
if (proto)
return SetProperty(cx, proto, receiver, id, vp, strict);
return SetProperty(cx, proto, receiver, id, vp, result);
// Change ownDesc to be a complete descriptor for a configurable,
// writable, enumerable data property. Then fall through to step 5.
@ -106,19 +106,14 @@ BaseProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
if (ownDesc.isDataDescriptor()) {
// Steps 5.a-b, adapted to our nonstandard implementation of ES6
// [[Set]] return values.
if (!ownDesc.isWritable()) {
if (strict)
return JSObject::reportReadOnly(cx, id, JSREPORT_ERROR);
if (cx->compartment()->options().extraWarnings(cx))
return JSObject::reportReadOnly(cx, id, JSREPORT_STRICT | JSREPORT_WARNING);
return true;
}
if (!ownDesc.isWritable())
return result.fail(JSMSG_READ_ONLY);
// Nonstandard SpiderMonkey special case: setter ops.
SetterOp setter = ownDesc.setter();
MOZ_ASSERT(setter != JS_StrictPropertyStub);
if (setter && setter != JS_StrictPropertyStub)
return CallSetter(cx, receiver, id, setter, ownDesc.attributes(), strict, vp);
return CallSetter(cx, receiver, id, setter, ownDesc.attributes(), vp, result);
// Steps 5.c-d. Adapt for SpiderMonkey by using HasOwnProperty instead
// of the standard [[GetOwnProperty]].
@ -137,8 +132,8 @@ BaseProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
const Class *clasp = receiver->getClass();
MOZ_ASSERT(clasp->getProperty != JS_PropertyStub);
MOZ_ASSERT(clasp->setProperty != JS_StrictPropertyStub);
return DefineProperty(cx, receiver, id, vp,
clasp->getProperty, clasp->setProperty, attrs);
return DefineProperty(cx, receiver, id, vp, clasp->getProperty, clasp->setProperty,
attrs, result);
}
// Step 6.
@ -147,16 +142,18 @@ BaseProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
if (ownDesc.hasSetterObject())
setter = ownDesc.setterObject();
if (!setter)
return ReportGetterOnlyAssignment(cx, strict);
return result.fail(JSMSG_GETTER_ONLY);
RootedValue setterValue(cx, ObjectValue(*setter));
return InvokeGetterOrSetter(cx, receiver, setterValue, 1, vp.address(), vp);
if (!InvokeGetterOrSetter(cx, receiver, setterValue, 1, vp.address(), vp))
return false;
return result.succeed();
}
bool
js::SetPropertyIgnoringNamedGetter(JSContext *cx, const BaseProxyHandler *handler,
HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandle<PropertyDescriptor> desc,
bool descIsOwn, bool strict, MutableHandleValue vp)
bool descIsOwn, MutableHandleValue vp, ObjectOpResult &result)
{
/* The control-flow here differs from ::get() because of the fall-through case below. */
MOZ_ASSERT_IF(descIsOwn, desc.object());
@ -165,38 +162,37 @@ js::SetPropertyIgnoringNamedGetter(JSContext *cx, const BaseProxyHandler *handle
MOZ_ASSERT(desc.setter() != JS_StrictPropertyStub);
// Check for read-only properties.
if (desc.isReadonly()) {
if (strict)
return Throw(cx, id, descIsOwn ? JSMSG_READ_ONLY : JSMSG_CANT_REDEFINE_PROP);
return true;
}
if (desc.isReadonly())
return result.fail(descIsOwn ? JSMSG_READ_ONLY : JSMSG_CANT_REDEFINE_PROP);
if (desc.hasSetterObject() || desc.setter()) {
if (!CallSetter(cx, receiver, id, desc.setter(), desc.attributes(), strict, vp))
if (!CallSetter(cx, receiver, id, desc.setter(), desc.attributes(), vp, result))
return false;
if (!proxy->is<ProxyObject>() || proxy->as<ProxyObject>().handler() != handler)
return true;
if (desc.isShared())
if (!result)
return true;
if (!proxy->is<ProxyObject>() ||
proxy->as<ProxyObject>().handler() != handler ||
desc.isShared())
{
return result.succeed();
}
}
desc.value().set(vp.get());
if (descIsOwn) {
MOZ_ASSERT(desc.object() == proxy);
ObjectOpResult result;
if (!handler->defineProperty(cx, proxy, id, desc, result))
return false;
return result.checkStrictErrorOrWarning(cx, proxy, id, strict);
return handler->defineProperty(cx, proxy, id, desc, result);
}
return DefineProperty(cx, receiver, id, desc.value(),
desc.getter(), desc.setter(), desc.attributes());
return DefineProperty(cx, receiver, id, desc.value(), desc.getter(), desc.setter(),
desc.attributes(), result);
}
desc.object().set(receiver);
desc.value().set(vp.get());
desc.setAttributes(JSPROP_ENUMERATE);
desc.setGetter(nullptr);
desc.setSetter(nullptr); // Pick up the class getter/setter.
return DefineProperty(cx, receiver, id, desc.value(), nullptr, nullptr, JSPROP_ENUMERATE);
return DefineProperty(cx, receiver, id, desc.value(), nullptr, nullptr, JSPROP_ENUMERATE,
result);
}
bool

View File

@ -169,13 +169,13 @@ CrossCompartmentWrapper::get(JSContext *cx, HandleObject wrapper, HandleObject r
bool
CrossCompartmentWrapper::set(JSContext *cx, HandleObject wrapper, HandleObject receiver,
HandleId id, bool strict, MutableHandleValue vp) const
HandleId id, MutableHandleValue vp, ObjectOpResult &result) const
{
RootedObject receiverCopy(cx, receiver);
PIERCE(cx, wrapper,
cx->compartment()->wrap(cx, &receiverCopy) &&
cx->compartment()->wrap(cx, vp),
Wrapper::set(cx, wrapper, receiverCopy, id, strict, vp),
Wrapper::set(cx, wrapper, receiverCopy, id, vp, result),
NOTHING);
}

View File

@ -223,11 +223,11 @@ DirectProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver
bool
DirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, bool strict, MutableHandleValue vp) const
HandleId id, MutableHandleValue vp, ObjectOpResult &result) const
{
assertEnteredPolicy(cx, proxy, id, SET);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return SetProperty(cx, target, receiver, id, vp, strict);
return SetProperty(cx, target, receiver, id, vp, result);
}
bool

View File

@ -304,20 +304,23 @@ Proxy::callProp(JSContext *cx, HandleObject proxy, HandleObject receiver, Handle
}
bool
Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, bool strict,
MutableHandleValue vp)
Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
MutableHandleValue vp, ObjectOpResult &result)
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::SET, true);
if (!policy.allowed())
return policy.returnValue();
if (!policy.allowed()) {
if (!policy.returnValue())
return false;
return result.succeed();
}
// Special case. See the comment on BaseProxyHandler::mHasPrototype.
if (handler->hasPrototype())
return handler->BaseProxyHandler::set(cx, proxy, receiver, id, strict, vp);
return handler->BaseProxyHandler::set(cx, proxy, receiver, id, vp, result);
return handler->set(cx, proxy, receiver, id, strict, vp);
return handler->set(cx, proxy, receiver, id, vp, result);
}
bool
@ -581,9 +584,9 @@ js::proxy_GetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, Ha
bool
js::proxy_SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
MutableHandleValue vp, bool strict)
MutableHandleValue vp, ObjectOpResult &result)
{
return Proxy::set(cx, obj, receiver, id, strict, vp);
return Proxy::set(cx, obj, receiver, id, vp, result);
}
bool

View File

@ -42,7 +42,7 @@ class Proxy
static bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
MutableHandleValue vp);
static bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
bool strict, MutableHandleValue vp);
MutableHandleValue vp, ObjectOpResult &result);
static bool call(JSContext *cx, HandleObject proxy, const CallArgs &args);
static bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args);

View File

@ -935,7 +935,7 @@ ScriptedDirectProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject
// ES6 (22 May, 2014) 9.5.9 Proxy.[[SetP]](P, V, Receiver)
bool
ScriptedDirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, bool strict, MutableHandleValue vp) const
HandleId id, MutableHandleValue vp, ObjectOpResult &result) const
{
// step 2
RootedObject handler(cx, GetDirectProxyHandlerObject(proxy));
@ -956,7 +956,7 @@ ScriptedDirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject
// step 7
if (trap.isUndefined())
return DirectProxyHandler::set(cx, proxy, receiver, id, strict, vp);
return DirectProxyHandler::set(cx, proxy, receiver, id, vp, result);
// step 8,10
RootedValue value(cx);
@ -972,7 +972,9 @@ ScriptedDirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject
if (!Invoke(cx, ObjectValue(*handler), trap, ArrayLength(argv), argv, &trapResult))
return false;
// step 9
// FIXME - bug 1132522: Step 9 is not implemented yet.
// if (!ToBoolean(trapResult))
// return result.fail(JSMSG_PROXY_SET_RETURNED_FALSE);
bool success = ToBoolean(trapResult);
if (success) {
@ -1001,8 +1003,9 @@ ScriptedDirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject
}
// step 11, 15
// XXX FIXME - This use of vp is wrong. Bug 1132522 can clean it up.
vp.setBoolean(success);
return true;
return result.succeed();
}

View File

@ -45,7 +45,7 @@ class ScriptedDirectProxyHandler : public DirectProxyHandler {
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
bool strict, MutableHandleValue vp) const MOZ_OVERRIDE;
MutableHandleValue vp, ObjectOpResult &result) const MOZ_OVERRIDE;
virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;

View File

@ -296,7 +296,7 @@ ScriptedIndirectProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObjec
bool
ScriptedIndirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, bool strict, MutableHandleValue vp) const
HandleId id, MutableHandleValue vp, ObjectOpResult &result) const
{
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
RootedValue idv(cx);
@ -310,13 +310,16 @@ ScriptedIndirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObjec
if (!GetDerivedTrap(cx, handler, cx->names().set, &fval))
return false;
if (!IsCallable(fval))
return derivedSet(cx, proxy, receiver, id, strict, vp);
return Trap(cx, handler, fval, 3, argv.begin(), &idv);
return derivedSet(cx, proxy, receiver, id, vp, result);
if (!Trap(cx, handler, fval, 3, argv.begin(), &idv))
return false;
return result.succeed();
}
bool
ScriptedIndirectProxyHandler::derivedSet(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, bool strict, MutableHandleValue vp) const
HandleId id, MutableHandleValue vp,
ObjectOpResult &result) const
{
// Find an own or inherited property. The code here is strange for maximum
// backward compatibility with earlier code written before ES6 and before
@ -330,8 +333,8 @@ ScriptedIndirectProxyHandler::derivedSet(JSContext *cx, HandleObject proxy, Hand
return false;
}
return SetPropertyIgnoringNamedGetter(cx, this, proxy, receiver, id, &desc, descIsOwn, strict,
vp);
return SetPropertyIgnoringNamedGetter(cx, this, proxy, receiver, id, &desc, descIsOwn, vp,
result);
}
bool

View File

@ -36,7 +36,7 @@ class ScriptedIndirectProxyHandler : public BaseProxyHandler
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
bool strict, MutableHandleValue vp) const MOZ_OVERRIDE;
MutableHandleValue vp, ObjectOpResult &result) const MOZ_OVERRIDE;
/* SpiderMonkey extensions. */
virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
@ -54,7 +54,7 @@ class ScriptedIndirectProxyHandler : public BaseProxyHandler
private:
bool derivedSet(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
bool strict, MutableHandleValue vp) const;
MutableHandleValue vp, ObjectOpResult &result) const;
};
/* Derived class to handle Proxy.createFunction() */

View File

@ -29,7 +29,7 @@ reportCompare(expect, actual, summary + ': join');
// reverse
value = '123';
expect = 'TypeError: Array.prototype.reverse.call(...) is read-only';
expect = 'TypeError: 0 is read-only';
try
{
actual = Array.prototype.reverse.call(value) + '';
@ -42,7 +42,7 @@ reportCompare(expect, actual, summary + ': reverse');
// sort
value = 'cba';
expect = 'TypeError: Array.prototype.sort.call(...) is read-only';
expect = 'TypeError: 0 is read-only';
try
{
actual = Array.prototype.sort.call(value) + '';
@ -100,7 +100,7 @@ reportCompare('abc', value, summary + ': pop');
// unshift
value = 'def';
expect = 'TypeError: Array.prototype.unshift.call(...) is read-only';
expect = 'TypeError: 0 is read-only';
try
{
actual = Array.prototype.unshift.call(value, 'a', 'b', 'c');
@ -114,7 +114,7 @@ reportCompare('def', value, summary + ': unshift');
// shift
value = 'abc';
expect = 'TypeError: Array.prototype.shift.call(...) is read-only';
expect = 'TypeError: 0 is read-only';
try
{
actual = Array.prototype.shift.call(value);
@ -128,7 +128,7 @@ reportCompare('abc', value, summary + ': shift');
// splice
value = 'abc';
expect = 'TypeError: Array.prototype.splice.call(...) is read-only';
expect = 'TypeError: 1 is read-only';
try
{
actual = Array.prototype.splice.call(value, 1, 1) + '';

View File

@ -317,10 +317,11 @@ ArgGetter(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
}
static bool
ArgSetter(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp)
ArgSetter(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp,
ObjectOpResult &result)
{
if (!obj->is<NormalArgumentsObject>())
return true;
return result.succeed();
Handle<NormalArgumentsObject*> argsobj = obj.as<NormalArgumentsObject>();
Rooted<PropertyDescriptor> desc(cx);
@ -339,7 +340,7 @@ ArgSetter(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHand
argsobj->setElement(cx, arg, vp);
if (arg < script->functionNonDelazifying()->nargs())
TypeScript::SetArgument(cx, script, arg, vp);
return true;
return result.succeed();
}
} else {
MOZ_ASSERT(JSID_IS_ATOM(id, cx->names().length) || JSID_IS_ATOM(id, cx->names().callee));
@ -354,7 +355,7 @@ ArgSetter(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHand
*/
bool succeeded;
return NativeDeleteProperty(cx, argsobj, id, &succeeded) &&
NativeDefineProperty(cx, argsobj, id, vp, nullptr, nullptr, attrs);
NativeDefineProperty(cx, argsobj, id, vp, nullptr, nullptr, attrs, result);
}
static bool
@ -438,10 +439,11 @@ StrictArgGetter(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue
}
static bool
StrictArgSetter(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp)
StrictArgSetter(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp,
ObjectOpResult &result)
{
if (!obj->is<StrictArgumentsObject>())
return true;
return result.succeed();
Handle<StrictArgumentsObject*> argsobj = obj.as<StrictArgumentsObject>();
Rooted<PropertyDescriptor> desc(cx);
@ -456,7 +458,7 @@ StrictArgSetter(JSContext *cx, HandleObject obj, HandleId id, bool strict, Mutab
unsigned arg = unsigned(JSID_TO_INT(id));
if (arg < argsobj->initialLength()) {
argsobj->setElement(cx, arg, vp);
return true;
return result.succeed();
}
} else {
MOZ_ASSERT(JSID_IS_ATOM(id, cx->names().length));
@ -469,7 +471,7 @@ StrictArgSetter(JSContext *cx, HandleObject obj, HandleId id, bool strict, Mutab
*/
bool succeeded;
return NativeDeleteProperty(cx, argsobj, id, &succeeded) &&
NativeDefineProperty(cx, argsobj, id, vp, nullptr, nullptr, attrs);
NativeDefineProperty(cx, argsobj, id, vp, nullptr, nullptr, attrs, result);
}
static bool

View File

@ -7517,7 +7517,7 @@ DebuggerEnv_setVariable(JSContext *cx, unsigned argc, Value *vp)
}
/* Just set the property. */
if (!SetProperty(cx, env, env, id, &v, true))
if (!SetProperty(cx, env, env, id, &v))
return false;
}

View File

@ -613,7 +613,10 @@ class GlobalObject : public NativeObject
#endif
RootedObject holder(cx, intrinsicsHolder());
RootedValue valCopy(cx, value);
return SetProperty(cx, holder, holder, name, &valCopy, false);
ObjectOpResult result;
bool ok = SetProperty(cx, holder, holder, name, &valCopy, result);
MOZ_ASSERT_IF(ok, result);
return ok;
}
bool getSelfHostedFunction(JSContext *cx, HandleAtom selfHostedName, HandleAtom name,

View File

@ -313,19 +313,20 @@ SetNameOperation(JSContext *cx, JSScript *script, jsbytecode *pc, HandleObject s
RootedPropertyName name(cx, script->getName(pc));
RootedValue valCopy(cx, val);
/*
* In strict-mode, we need to trigger an error when trying to assign to an
* undeclared global variable. To do this, we call NativeSetProperty
* directly and pass Unqualified.
*/
// In strict mode, assigning to an undeclared global variable is an
// error. To detect this, we call NativeSetProperty directly and pass
// Unqualified. It stores the error, if any, in |result|.
bool ok;
ObjectOpResult result;
RootedId id(cx, NameToId(name));
if (scope->isUnqualifiedVarObj()) {
MOZ_ASSERT(!scope->getOps()->setProperty);
RootedId id(cx, NameToId(name));
return NativeSetProperty(cx, scope.as<NativeObject>(), scope.as<NativeObject>(), id,
Unqualified, &valCopy, strict);
ok = NativeSetProperty(cx, scope.as<NativeObject>(), scope.as<NativeObject>(), id,
Unqualified, &valCopy, result);
} else {
ok = SetProperty(cx, scope, scope, id, &valCopy, result);
}
return SetProperty(cx, scope, scope, name, &valCopy, strict);
return ok && result.checkStrictErrorOrWarning(cx, scope, id, strict);
}
inline bool
@ -339,7 +340,7 @@ InitPropertyOperation(JSContext *cx, JSOp op, HandleObject obj, HandleId id, Han
MOZ_ASSERT(obj->as<UnboxedPlainObject>().layout().lookup(id));
RootedValue v(cx, rhs);
return SetProperty(cx, obj, obj, id, &v, false);
return PutProperty(cx, obj, id, &v, false);
}
inline bool

View File

@ -315,19 +315,19 @@ SetObjectProperty(JSContext *cx, JSOp op, HandleValue lval, HandleId id, Mutable
RootedObject obj(cx, &lval.toObject());
bool strict = op == JSOP_STRICTSETPROP;
ObjectOpResult result;
if (MOZ_LIKELY(!obj->getOps()->setProperty)) {
if (!NativeSetProperty(cx, obj.as<NativeObject>(), obj.as<NativeObject>(), id,
Qualified, rref, strict))
Qualified, rref, result))
{
return false;
}
} else {
if (!SetProperty(cx, obj, obj, id, rref, strict))
if (!SetProperty(cx, obj, obj, id, rref, result))
return false;
}
return true;
return result.checkStrictErrorOrWarning(cx, obj, id, op == JSOP_STRICTSETPROP);
}
static bool
@ -1390,7 +1390,7 @@ SetObjectElementOperation(JSContext *cx, Handle<JSObject*> obj, HandleId id, con
return false;
RootedValue tmp(cx, value);
return SetProperty(cx, obj, obj, id, &tmp, strict);
return PutProperty(cx, obj, id, &tmp, strict);
}
static MOZ_NEVER_INLINE bool
@ -3809,7 +3809,7 @@ js::DefFunOperation(JSContext *cx, HandleScript script, HandleObject scopeChain,
*/
/* Step 5f. */
return SetProperty(cx, parent, parent, name, &rval, script->strict());
return PutProperty(cx, parent, name, &rval, script->strict());
}
bool

View File

@ -1134,7 +1134,7 @@ UpdateShapeTypeAndValue(ExclusiveContext *cx, NativeObject *obj, Shape *shape, c
static bool
NativeSet(JSContext *cx, HandleNativeObject obj, HandleObject receiver,
HandleShape shape, bool strict, MutableHandleValue vp);
HandleShape shape, MutableHandleValue vp, ObjectOpResult &result);
static inline bool
DefinePropertyOrElement(ExclusiveContext *cx, HandleNativeObject obj, HandleId id,
@ -1226,10 +1226,7 @@ DefinePropertyOrElement(ExclusiveContext *cx, HandleNativeObject obj, HandleId i
if (!cx->shouldBeJSContext())
return false;
RootedValue nvalue(cx, value);
// FIXME: result should be passed to NativeSet.
if (!NativeSet(cx->asJSContext(), obj, obj, shape, false, &nvalue))
return false;
return NativeSet(cx->asJSContext(), obj, obj, shape, &nvalue, result);
}
return result.succeed();
@ -2007,7 +2004,7 @@ MaybeReportUndeclaredVarAssignment(JSContext *cx, JSString *propname)
*/
bool
js::SetPropertyByDefining(JSContext *cx, HandleObject obj, HandleObject receiver,
HandleId id, HandleValue v, bool strict, bool objHasOwn)
HandleId id, HandleValue v, bool objHasOwn, ObjectOpResult &result)
{
// Step 5.c-d: Test whether receiver has an existing own property
// receiver[id]. The spec calls [[GetOwnProperty]]; js::HasOwnProperty is
@ -2038,15 +2035,8 @@ js::SetPropertyByDefining(JSContext *cx, HandleObject obj, HandleObject receiver
bool extensible;
if (!IsExtensible(cx, receiver, &extensible))
return false;
if (!extensible) {
// Error in strict mode code, warn with extra warnings option,
// otherwise do nothing.
if (strict)
return receiver->reportNotExtensible(cx);
if (cx->compartment()->options().extraWarnings(cx))
return receiver->reportNotExtensible(cx, JSREPORT_STRICT | JSREPORT_WARNING);
return true;
}
if (!extensible)
return result.fail(JSMSG_OBJECT_NOT_EXTENSIBLE);
}
// Invalidate SpiderMonkey-specific caches or bail.
@ -2066,40 +2056,24 @@ js::SetPropertyByDefining(JSContext *cx, HandleObject obj, HandleObject receiver
MOZ_ASSERT(getter != JS_PropertyStub);
MOZ_ASSERT(setter != JS_StrictPropertyStub);
if (!receiver->is<NativeObject>())
return DefineProperty(cx, receiver, id, v, getter, setter, attrs);
return DefineProperty(cx, receiver, id, v, getter, setter, attrs, result);
Rooted<NativeObject*> nativeReceiver(cx, &receiver->as<NativeObject>());
ObjectOpResult success;
if (!DefinePropertyOrElement(cx, nativeReceiver, id, getter, setter, attrs, v, true, success))
return false;
return success.checkStrictErrorOrWarning(cx, receiver, id, strict);
return DefinePropertyOrElement(cx, nativeReceiver, id, getter, setter, attrs, v, true, result);
}
// When setting |id| for |receiver| and |obj| has no property for id, continue
// the search up the prototype chain.
bool
js::SetPropertyOnProto(JSContext *cx, HandleObject obj, HandleObject receiver,
HandleId id, MutableHandleValue vp, bool strict)
HandleId id, MutableHandleValue vp, ObjectOpResult &result)
{
MOZ_ASSERT(!obj->is<ProxyObject>());
RootedObject proto(cx, obj->getProto());
if (proto)
return SetProperty(cx, proto, receiver, id, vp, strict);
return SetPropertyByDefining(cx, obj, receiver, id, vp, strict, false);
}
bool
js::SetNonWritableProperty(JSContext *cx, HandleId id, bool strict)
{
// Setting a non-writable property is an error in strict mode code, a
// warning with the extra warnings option, and otherwise does nothing.
if (strict)
return JSObject::reportReadOnly(cx, id, JSREPORT_ERROR);
if (cx->compartment()->options().extraWarnings(cx))
return JSObject::reportReadOnly(cx, id, JSREPORT_STRICT | JSREPORT_WARNING);
return true;
return SetProperty(cx, proto, receiver, id, vp, result);
return SetPropertyByDefining(cx, obj, receiver, id, vp, false, result);
}
/*
@ -2113,7 +2087,7 @@ js::SetNonWritableProperty(JSContext *cx, HandleId id, bool strict)
*/
static bool
SetNonexistentProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiver, HandleId id,
QualifiedBool qualified, HandleValue v, bool strict)
QualifiedBool qualified, HandleValue v, ObjectOpResult &result)
{
// We should never add properties to lexical blocks.
MOZ_ASSERT(!receiver->is<BlockObject>());
@ -2123,7 +2097,7 @@ SetNonexistentProperty(JSContext *cx, HandleNativeObject obj, HandleObject recei
return false;
}
return SetPropertyByDefining(cx, obj, receiver, id, v, strict, false);
return SetPropertyByDefining(cx, obj, receiver, id, v, false, result);
}
/*
@ -2132,7 +2106,7 @@ SetNonexistentProperty(JSContext *cx, HandleNativeObject obj, HandleObject recei
*/
static bool
SetDenseOrTypedArrayElement(JSContext *cx, HandleNativeObject obj, uint32_t index,
MutableHandleValue vp, bool strict)
MutableHandleValue vp, ObjectOpResult &result)
{
if (IsAnyTypedArray(obj)) {
double d;
@ -2149,23 +2123,17 @@ SetDenseOrTypedArrayElement(JSContext *cx, HandleNativeObject obj, uint32_t inde
else
SharedTypedArrayObject::setElement(obj->as<SharedTypedArrayObject>(), index, d);
}
return true;
return result.succeed();
}
if (WouldDefinePastNonwritableLength(obj, index)) {
if (strict) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
return false;
}
return true;
}
if (WouldDefinePastNonwritableLength(obj, index))
return result.fail(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
if (!obj->maybeCopyElementsForWrite(cx))
return false;
obj->setDenseElementWithType(cx, index, vp);
return true;
return result.succeed();
}
/*
@ -2174,7 +2142,7 @@ SetDenseOrTypedArrayElement(JSContext *cx, HandleNativeObject obj, uint32_t inde
*/
static bool
NativeSet(JSContext *cx, HandleNativeObject obj, HandleObject receiver,
HandleShape shape, bool strict, MutableHandleValue vp)
HandleShape shape, MutableHandleValue vp, ObjectOpResult &result)
{
MOZ_ASSERT(obj->isNative());
@ -2186,7 +2154,7 @@ NativeSet(JSContext *cx, HandleNativeObject obj, HandleObject receiver,
// assignments to such properties as overwrites.
bool overwriting = !obj->is<GlobalObject>() || !obj->getSlot(shape->slot()).isUndefined();
obj->setSlotWithType(cx, shape, vp, overwriting);
return true;
return result.succeed();
}
}
@ -2198,13 +2166,13 @@ NativeSet(JSContext *cx, HandleNativeObject obj, HandleObject receiver,
* or throw if we're in strict mode.
*/
if (!shape->hasGetterValue() && shape->hasDefaultSetter())
return ReportGetterOnlyAssignment(cx, strict);
return result.fail(JSMSG_GETTER_ONLY);
}
RootedValue ovp(cx, vp);
uint32_t sample = cx->runtime()->propertyRemovals;
if (!shape->set(cx, obj, receiver, strict, vp))
if (!shape->set(cx, obj, receiver, vp, result))
return false;
/*
@ -2218,7 +2186,7 @@ NativeSet(JSContext *cx, HandleNativeObject obj, HandleObject receiver,
obj->setSlot(shape->slot(), vp);
}
return true;
return true; // result is populated by shape->set() above.
}
/*
@ -2230,38 +2198,30 @@ NativeSet(JSContext *cx, HandleNativeObject obj, HandleObject receiver,
*/
static bool
SetExistingProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiver, HandleId id,
HandleNativeObject pobj, HandleShape shape, MutableHandleValue vp, bool strict)
HandleNativeObject pobj, HandleShape shape, MutableHandleValue vp,
ObjectOpResult &result)
{
if (IsImplicitDenseOrTypedArrayElement(shape)) {
/* ES5 8.12.4 [[Put]] step 2, for a dense data property on pobj. */
if (pobj == receiver)
return SetDenseOrTypedArrayElement(cx, pobj, JSID_TO_INT(id), vp, strict);
return SetDenseOrTypedArrayElement(cx, pobj, JSID_TO_INT(id), vp, result);
} else {
/* ES5 8.12.4 [[Put]] step 2. */
if (shape->isAccessorDescriptor()) {
if (shape->hasDefaultSetter())
return ReportGetterOnlyAssignment(cx, strict);
return result.fail(JSMSG_GETTER_ONLY);
} else {
MOZ_ASSERT(shape->isDataDescriptor());
if (!shape->writable())
return SetNonWritableProperty(cx, id, strict);
return result.fail(JSMSG_READ_ONLY);
}
if (pobj == receiver) {
if (pobj->is<ArrayObject>() && id == NameToId(cx->names().length)) {
Rooted<ArrayObject*> arr(cx, &pobj->as<ArrayObject>());
ObjectOpResult success;
if (!ArraySetLength(cx, arr, id, shape->attributes(), vp, success))
return false;
if (strict && !success) {
if (cx->shouldBeJSContext())
success.reportError(cx->asJSContext(), arr, id);
return false;
}
return true;
return ArraySetLength(cx, arr, id, shape->attributes(), vp, result);
}
return NativeSet(cx, obj, receiver, shape, strict, vp);
return NativeSet(cx, obj, receiver, shape, vp, result);
}
// pobj[id] is not an own property of receiver. Call the setter or shadow it.
@ -2270,19 +2230,19 @@ SetExistingProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiver
{
// Weird special case: slotless property with default setter.
if (shape->hasDefaultSetter() && !shape->hasGetterValue())
return true;
return result.succeed();
return shape->set(cx, obj, receiver, strict, vp);
return shape->set(cx, obj, receiver, vp, result);
}
}
// Shadow pobj[id] by defining a new data property receiver[id].
return SetPropertyByDefining(cx, obj, receiver, id, vp, strict, obj == pobj);
return SetPropertyByDefining(cx, obj, receiver, id, vp, obj == pobj, result);
}
bool
js::NativeSetProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiver, HandleId id,
QualifiedBool qualified, MutableHandleValue vp, bool strict)
QualifiedBool qualified, MutableHandleValue vp, ObjectOpResult &result)
{
// Fire watchpoints, if any.
if (MOZ_UNLIKELY(obj->watched())) {
@ -2308,7 +2268,7 @@ js::NativeSetProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiv
if (shape) {
// Steps 5-6.
return SetExistingProperty(cx, obj, receiver, id, pobj, shape, vp, strict);
return SetExistingProperty(cx, obj, receiver, id, pobj, shape, vp, result);
}
// Steps 4.a-b. The check for 'done' on this next line is tricky.
@ -2322,7 +2282,7 @@ js::NativeSetProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiv
RootedObject proto(cx, done ? nullptr : pobj->getProto());
if (!proto) {
// Step 4.d.i (and step 5).
return SetNonexistentProperty(cx, obj, receiver, id, qualified, vp, strict);
return SetNonexistentProperty(cx, obj, receiver, id, qualified, vp, result);
}
// Step 4.c.i. If the prototype is also native, this step is a
@ -2339,10 +2299,10 @@ js::NativeSetProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiv
if (!HasProperty(cx, proto, id, &found))
return false;
if (!found)
return SetNonexistentProperty(cx, obj, receiver, id, qualified, vp, strict);
return SetNonexistentProperty(cx, obj, receiver, id, qualified, vp, result);
}
return SetProperty(cx, proto, receiver, id, vp, strict);
return SetProperty(cx, proto, receiver, id, vp, result);
}
pobj = &proto->as<NativeObject>();
}
@ -2350,12 +2310,12 @@ js::NativeSetProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiv
bool
js::NativeSetElement(JSContext *cx, HandleNativeObject obj, HandleObject receiver, uint32_t index,
MutableHandleValue vp, bool strict)
MutableHandleValue vp, ObjectOpResult &result)
{
RootedId id(cx);
if (!IndexToId(cx, index, &id))
return false;
return NativeSetProperty(cx, obj, receiver, id, Qualified, vp, strict);
return NativeSetProperty(cx, obj, receiver, id, Qualified, vp, result);
}
/*** [[Delete]] **********************************************************************************/

View File

@ -83,8 +83,7 @@ class ArrayObject;
*
* |id| must be "length", |attrs| are the attributes to be used for the newly-
* changed length property, |value| is the value for the new length, and
* |setterIsStrict| indicates whether invalid changes will cause a TypeError
* to be thrown.
* |result| receives an error code if the change is invalid.
*/
extern bool
ArraySetLength(JSContext *cx, Handle<ArrayObject*> obj, HandleId id,
@ -1299,16 +1298,12 @@ NativeGetElement(JSContext *cx, HandleNativeObject obj, uint32_t index, MutableH
}
bool
SetPropertyByDefining(JSContext *cx, HandleObject obj, HandleObject receiver,
HandleId id, HandleValue v, bool strict, bool objHasOwn);
SetPropertyByDefining(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
HandleValue v, bool objHasOwn, ObjectOpResult &result);
bool
SetPropertyOnProto(JSContext *cx, HandleObject obj, HandleObject receiver,
HandleId id, MutableHandleValue vp, bool strict);
// Report any error or warning when writing to a non-writable property.
bool
SetNonWritableProperty(JSContext *cx, HandleId id, bool strict);
SetPropertyOnProto(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
MutableHandleValue vp, ObjectOpResult &result);
/*
* Indicates whether an assignment operation is qualified (`x.y = 0`) or
@ -1324,11 +1319,11 @@ enum QualifiedBool {
extern bool
NativeSetProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiver, HandleId id,
QualifiedBool qualified, MutableHandleValue vp, bool strict);
QualifiedBool qualified, MutableHandleValue vp, ObjectOpResult &result);
extern bool
NativeSetElement(JSContext *cx, HandleNativeObject obj, HandleObject receiver, uint32_t index,
MutableHandleValue vp, bool strict);
MutableHandleValue vp, ObjectOpResult &result);
extern bool
NativeDeleteProperty(JSContext *cx, HandleNativeObject obj, HandleId id, bool *succeeded);
@ -1440,20 +1435,20 @@ js::GetPropertyNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, V
inline bool
js::SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
HandleId id, MutableHandleValue vp, bool strict)
HandleId id, MutableHandleValue vp, ObjectOpResult &result)
{
if (obj->getOps()->setProperty)
return JSObject::nonNativeSetProperty(cx, obj, receiver, id, vp, strict);
return NativeSetProperty(cx, obj.as<NativeObject>(), receiver, id, Qualified, vp, strict);
return JSObject::nonNativeSetProperty(cx, obj, receiver, id, vp, result);
return NativeSetProperty(cx, obj.as<NativeObject>(), receiver, id, Qualified, vp, result);
}
inline bool
js::SetElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index,
MutableHandleValue vp, bool strict)
MutableHandleValue vp, ObjectOpResult &result)
{
if (obj->getOps()->setProperty)
return JSObject::nonNativeSetElement(cx, obj, receiver, index, vp, strict);
return NativeSetElement(cx, obj.as<NativeObject>(), receiver, index, vp, strict);
return JSObject::nonNativeSetElement(cx, obj, receiver, index, vp, result);
return NativeSetElement(cx, obj.as<NativeObject>(), receiver, index, vp, result);
}
#endif /* vm_NativeObject_h */

View File

@ -298,7 +298,7 @@ CallObject::createHollowForDebug(JSContext *cx, HandleFunction callee)
RootedScript script(cx, callee->nonLazyScript());
for (BindingIter bi(script); !bi.done(); bi++) {
id = NameToId(bi->name());
if (!SetProperty(cx, callobj, callobj, id, &optimizedOut, true))
if (!SetProperty(cx, callobj, callobj, id, &optimizedOut))
return nullptr;
}
@ -495,13 +495,13 @@ with_GetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleI
static bool
with_SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
MutableHandleValue vp, bool strict)
MutableHandleValue vp, ObjectOpResult &result)
{
RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
RootedObject actualReceiver(cx, receiver);
if (receiver == obj)
actualReceiver = actual;
return SetProperty(cx, actual, actualReceiver, id, vp, strict);
return SetProperty(cx, actual, actualReceiver, id, vp, result);
}
static bool
@ -941,7 +941,7 @@ uninitialized_GetProperty(JSContext *cx, HandleObject obj, HandleObject receiver
static bool
uninitialized_SetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
MutableHandleValue vp, bool strict)
MutableHandleValue vp, ObjectOpResult &result)
{
ReportUninitializedLexicalId(cx, id);
return false;
@ -1603,8 +1603,8 @@ class DebugScopeProxy : public BaseProxyHandler
}
}
bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, bool strict,
MutableHandleValue vp) const MOZ_OVERRIDE
bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
MutableHandleValue vp, ObjectOpResult &result) const MOZ_OVERRIDE
{
Rooted<DebugScopeObject*> debugScope(cx, &proxy->as<DebugScopeObject>());
Rooted<ScopeObject*> scope(cx, &proxy->as<DebugScopeObject>().scope());
@ -1618,9 +1618,9 @@ class DebugScopeProxy : public BaseProxyHandler
switch (access) {
case ACCESS_UNALIASED:
return true;
return result.succeed();
case ACCESS_GENERIC:
return SetProperty(cx, scope, scope, id, vp, strict);
return SetProperty(cx, scope, scope, id, vp, result);
default:
MOZ_CRASH("bad AccessResult");
}

View File

@ -338,7 +338,8 @@ js::intrinsic_UnsafePutElements(JSContext *cx, unsigned argc, Value *vp)
MOZ_ASSERT_IF(arrobj->is<TypedObject>(), idx < uint32_t(arrobj->as<TypedObject>().length()));
RootedValue tmp(cx, args[elemi]);
// XXX: Always non-strict.
if (!SetElement(cx, arrobj, arrobj, idx, &tmp, false))
ObjectOpResult ignored;
if (!SetElement(cx, arrobj, arrobj, idx, &tmp, ignored))
return false;
} else {
MOZ_ASSERT(idx < arrobj->as<ArrayObject>().getDenseInitializedLength());

View File

@ -41,25 +41,27 @@ Shape::search(ExclusiveContext *cx, jsid id)
}
inline bool
Shape::set(JSContext* cx, HandleNativeObject obj, HandleObject receiver, bool strict,
MutableHandleValue vp)
Shape::set(JSContext* cx, HandleNativeObject obj, HandleObject receiver, MutableHandleValue vp,
ObjectOpResult &result)
{
MOZ_ASSERT_IF(hasDefaultSetter(), hasGetterValue());
MOZ_ASSERT(!obj->is<DynamicWithObject>()); // See bug 1128681.
if (attrs & JSPROP_SETTER) {
Value fval = setterValue();
return InvokeGetterOrSetter(cx, receiver, fval, 1, vp.address(), vp);
if (!InvokeGetterOrSetter(cx, receiver, fval, 1, vp.address(), vp))
return false;
return result.succeed();
}
if (attrs & JSPROP_GETTER)
return ReportGetterOnlyAssignment(cx, strict);
return result.fail(JSMSG_GETTER_ONLY);
if (!setterOp())
return true;
return result.succeed();
RootedId id(cx, propid());
return CallJSSetterOp(cx, setterOp(), obj, id, strict, vp);
return CallJSSetterOp(cx, setterOp(), obj, id, vp, result);
}
/* static */ inline Shape *

View File

@ -956,8 +956,8 @@ class Shape : public gc::TenuredCell
setter() == rawSetter;
}
bool set(JSContext* cx, HandleNativeObject obj, HandleObject receiver, bool strict,
MutableHandleValue vp);
bool set(JSContext* cx, HandleNativeObject obj, HandleObject receiver, MutableHandleValue vp,
ObjectOpResult &result);
BaseShape *base() const { return base_.get(); }

View File

@ -406,24 +406,24 @@ UnboxedPlainObject::obj_getProperty(JSContext *cx, HandleObject obj, HandleObjec
/* static */ bool
UnboxedPlainObject::obj_setProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
HandleId id, MutableHandleValue vp, bool strict)
HandleId id, MutableHandleValue vp, ObjectOpResult &result)
{
const UnboxedLayout &layout = obj->as<UnboxedPlainObject>().layout();
if (const UnboxedLayout::Property *property = layout.lookup(id)) {
if (obj == receiver) {
if (obj->as<UnboxedPlainObject>().setValue(cx, *property, vp))
return true;
return result.succeed();
if (!convertToNative(cx, obj))
return false;
return SetProperty(cx, obj, receiver, id, vp, strict);
return SetProperty(cx, obj, receiver, id, vp, result);
}
return SetPropertyByDefining(cx, obj, receiver, id, vp, strict, false);
return SetPropertyByDefining(cx, obj, receiver, id, vp, false, result);
}
return SetPropertyOnProto(cx, obj, receiver, id, vp, strict);
return SetPropertyOnProto(cx, obj, receiver, id, vp, result);
}
/* static */ bool

View File

@ -174,7 +174,7 @@ class UnboxedPlainObject : public JSObject
HandleId id, MutableHandleValue vp);
static bool obj_setProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
HandleId id, MutableHandleValue vp, bool strict);
HandleId id, MutableHandleValue vp, ObjectOpResult &result);
static bool obj_getOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
MutableHandle<JSPropertyDescriptor> desc);

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 = 241;
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 242;
static const uint32_t XDR_BYTECODE_VERSION =
uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
static_assert(JSErr_Limit == 375,
static_assert(JSErr_Limit == 376,
"GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or "
"removed MSG_DEFs from js.msg, you should increment "
"XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "

View File

@ -353,13 +353,14 @@ sandbox_convert(JSContext *cx, HandleObject obj, JSType type, MutableHandleValue
static bool
writeToProto_setProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
bool strict, JS::MutableHandleValue vp)
JS::MutableHandleValue vp, JS::ObjectOpResult &result)
{
RootedObject proto(cx);
if (!JS_GetPrototype(cx, obj, &proto))
return false;
return JS_SetPropertyById(cx, proto, id, vp);
RootedValue receiver(cx, ObjectValue(*proto));
return JS_ForwardSetPropertyTo(cx, proto, id, vp, receiver, result);
}
static bool
@ -734,10 +735,10 @@ bool
xpc::SandboxProxyHandler::set(JSContext *cx, JS::Handle<JSObject*> proxy,
JS::Handle<JSObject*> receiver,
JS::Handle<jsid> id,
bool strict,
JS::MutableHandle<Value> vp) const
JS::MutableHandle<Value> vp,
JS::ObjectOpResult &result) const
{
return BaseProxyHandler::set(cx, proxy, receiver, id, strict, vp);
return BaseProxyHandler::set(cx, proxy, receiver, id, vp, result);
}
bool

View File

@ -645,7 +645,8 @@ static const JSFunctionSpec glob_functions[] = {
};
static bool
env_setProperty(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp)
env_setProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp,
ObjectOpResult &result)
{
/* XXX porting may be easy, but these don't seem to supply setenv by default */
#if !defined SOLARIS
@ -695,7 +696,7 @@ env_setProperty(JSContext *cx, HandleObject obj, HandleId id, bool strict, Mutab
}
vp.set(STRING_TO_JSVAL(valstr));
#endif /* !defined SOLARIS */
return true;
return result.succeed();
}
static bool

View File

@ -427,9 +427,10 @@ XPC_WN_OnlyIWrite_AddPropertyStub(JSContext *cx, HandleObject obj, HandleId id,
}
static bool
XPC_WN_OnlyIWrite_SetPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict,
MutableHandleValue vp)
XPC_WN_OnlyIWrite_SetPropertyStub(JSContext *cx, HandleObject obj, HandleId id,
MutableHandleValue vp, ObjectOpResult &result)
{
result.succeed();
return XPC_WN_OnlyIWrite_AddPropertyStub(cx, obj, id, vp);
}
@ -448,10 +449,10 @@ XPC_WN_CantDeletePropertyStub(JSContext *cx, HandleObject obj, HandleId id,
}
static bool
XPC_WN_CannotModifyStrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict,
MutableHandleValue vp)
XPC_WN_CannotModifySetPropertyStub(JSContext *cx, HandleObject obj, HandleId id,
MutableHandleValue vp, ObjectOpResult &result)
{
return XPC_WN_CannotModifyPropertyStub(cx, obj, id, vp);
return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
}
static bool
@ -707,9 +708,10 @@ XPC_WN_MaybeResolvingPropertyStub(JSContext *cx, HandleObject obj, HandleId id,
}
static bool
XPC_WN_MaybeResolvingStrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict,
MutableHandleValue vp)
XPC_WN_MaybeResolvingSetPropertyStub(JSContext *cx, HandleObject obj, HandleId id,
MutableHandleValue vp, ObjectOpResult &result)
{
result.succeed();
return XPC_WN_MaybeResolvingPropertyStub(cx, obj, id, vp);
}
@ -747,6 +749,11 @@ XPC_WN_MaybeResolvingDeletePropertyStub(JSContext *cx, HandleObject obj, HandleI
return Throw(rv, cx); \
return retval;
#define POST_HELPER_STUB_WITH_OBJECTOPRESULT(failMethod) \
if (NS_FAILED(rv)) \
return Throw(rv, cx); \
return retval ? result.succeed() : result.failMethod();
static bool
XPC_WN_Helper_AddProperty(JSContext *cx, HandleObject obj, HandleId id,
MutableHandleValue vp)
@ -766,12 +773,12 @@ XPC_WN_Helper_GetProperty(JSContext *cx, HandleObject obj, HandleId id,
}
bool
XPC_WN_Helper_SetProperty(JSContext *cx, HandleObject obj, HandleId id, bool strict,
MutableHandleValue vp)
XPC_WN_Helper_SetProperty(JSContext *cx, HandleObject obj, HandleId id,
MutableHandleValue vp, ObjectOpResult &result)
{
PRE_HELPER_STUB
SetProperty(wrapper, cx, obj, id, vp.address(), &retval);
POST_HELPER_STUB
POST_HELPER_STUB_WITH_OBJECTOPRESULT(failReadOnly)
}
static bool
@ -1023,9 +1030,9 @@ XPCNativeScriptableShared::PopulateJSClass()
else if (mFlags.UseJSStubForSetProperty())
setProperty = nullptr;
else if (mFlags.AllowPropModsDuringResolve())
setProperty = XPC_WN_MaybeResolvingStrictPropertyStub;
setProperty = XPC_WN_MaybeResolvingSetPropertyStub;
else
setProperty = XPC_WN_CannotModifyStrictPropertyStub;
setProperty = XPC_WN_CannotModifySetPropertyStub;
mJSClass.base.setProperty = setProperty;
MOZ_ASSERT_IF(mFlags.WantEnumerate(), !mFlags.WantNewEnumerate());
@ -1355,9 +1362,10 @@ XPC_WN_OnlyIWrite_Proto_AddPropertyStub(JSContext *cx, HandleObject obj, HandleI
}
static bool
XPC_WN_OnlyIWrite_Proto_SetPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict,
MutableHandleValue vp)
XPC_WN_OnlyIWrite_Proto_SetPropertyStub(JSContext *cx, HandleObject obj, HandleId id,
MutableHandleValue vp, ObjectOpResult &result)
{
result.succeed();
return XPC_WN_OnlyIWrite_Proto_AddPropertyStub(cx, obj, id, vp);
}

View File

@ -120,14 +120,15 @@ AddonWrapper<Base>::get(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle
template<typename Base>
bool
AddonWrapper<Base>::set(JSContext *cx, JS::HandleObject wrapper, JS::HandleObject receiver,
JS::HandleId id, bool strict, JS::MutableHandleValue vp) const
JS::HandleId id, JS::MutableHandleValue vp,
JS::ObjectOpResult &result) const
{
Rooted<JSPropertyDescriptor> desc(cx);
if (!Interpose(cx, wrapper, nullptr, id, &desc))
return false;
if (!desc.object())
return Base::set(cx, wrapper, receiver, id, strict, vp);
return Base::set(cx, wrapper, receiver, id, vp, result);
if (desc.setter()) {
MOZ_ASSERT(desc.hasSetterObject());
@ -135,14 +136,12 @@ AddonWrapper<Base>::set(JSContext *cx, JS::HandleObject wrapper, JS::HandleObjec
JS::AutoValueVector args(cx);
args.append(vp);
RootedValue fval(cx, ObjectValue(*desc.setterObject()));
return JS_CallFunctionValue(cx, receiver, fval, args, vp);
} else {
if (!strict)
return true;
js::ReportErrorWithId(cx, "unable to set interposed data property %s", id);
return false;
if (!JS_CallFunctionValue(cx, receiver, fval, args, vp))
return false;
return result.succeed();
}
return result.failCantSetInterposed();
}
template<typename Base>

View File

@ -34,7 +34,8 @@ class AddonWrapper : public Base {
virtual bool get(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<JSObject*> receiver,
JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
virtual bool set(JSContext *cx, JS::HandleObject wrapper, JS::HandleObject receiver,
JS::HandleId id, bool strict, JS::MutableHandleValue vp) const MOZ_OVERRIDE;
JS::HandleId id, JS::MutableHandleValue vp,
JS::ObjectOpResult &result) const MOZ_OVERRIDE;
virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper,
JS::Handle<jsid> id,

View File

@ -32,11 +32,11 @@ ChromeObjectWrapper::defineProperty(JSContext *cx, HandleObject wrapper,
bool
ChromeObjectWrapper::set(JSContext *cx, HandleObject wrapper,
HandleObject receiver, HandleId id,
bool strict, MutableHandleValue vp) const
MutableHandleValue vp, ObjectOpResult &result) const
{
if (!AccessCheck::checkPassToPrivilegedCode(cx, wrapper, vp))
return false;
return ChromeObjectWrapperBase::set(cx, wrapper, receiver, id, strict, vp);
return ChromeObjectWrapperBase::set(cx, wrapper, receiver, id, vp, result);
}
}

View File

@ -33,7 +33,8 @@ class ChromeObjectWrapper : public ChromeObjectWrapperBase
JS::ObjectOpResult &result) const MOZ_OVERRIDE;
virtual bool set(JSContext *cx, JS::Handle<JSObject*> wrapper,
JS::Handle<JSObject*> receiver, JS::Handle<jsid> id,
bool strict, JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
JS::MutableHandle<JS::Value> vp,
JS::ObjectOpResult &result) const MOZ_OVERRIDE;
static const ChromeObjectWrapper singleton;
};

View File

@ -2059,13 +2059,13 @@ template <typename Base, typename Traits>
bool
XrayWrapper<Base, Traits>::set(JSContext *cx, HandleObject wrapper,
HandleObject receiver, HandleId id,
bool strict, MutableHandleValue vp) const
MutableHandleValue vp, ObjectOpResult &result) const
{
MOZ_ASSERT(!Traits::HasPrototype);
// Skip our Base if it isn't already BaseProxyHandler.
// NB: None of the functions we call are prepared for the receiver not
// being the wrapper, so ignore the receiver here.
return js::BaseProxyHandler::set(cx, wrapper, wrapper, id, strict, vp);
return js::BaseProxyHandler::set(cx, wrapper, wrapper, id, vp, result);
}
template <typename Base, typename Traits>

View File

@ -433,7 +433,8 @@ class XrayWrapper : public Base {
virtual bool get(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<JSObject*> receiver,
JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
virtual bool set(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<JSObject*> receiver,
JS::Handle<jsid> id, bool strict, JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp,
JS::ObjectOpResult &result) const MOZ_OVERRIDE;
virtual bool call(JSContext *cx, JS::Handle<JSObject*> wrapper,
const JS::CallArgs &args) const MOZ_OVERRIDE;
virtual bool construct(JSContext *cx, JS::Handle<JSObject*> wrapper,
@ -506,7 +507,8 @@ public:
virtual bool get(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<JSObject*> receiver,
JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
virtual bool set(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<JSObject*> receiver,
JS::Handle<jsid> id, bool strict, JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp,
JS::ObjectOpResult &result) const MOZ_OVERRIDE;
virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id,