static bool UnmappedArgSetter(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp, ObjectOpResult& result) { if (!obj->is<UnmappedArgumentsObject>()) return result.succeed(); Handle<UnmappedArgumentsObject*> argsobj = obj.as<UnmappedArgumentsObject>(); Rooted<PropertyDescriptor> desc(cx); if (!GetOwnPropertyDescriptor(cx, argsobj, id, &desc)) return false; MOZ_ASSERT(desc.object()); unsigned attrs = desc.attributes(); MOZ_ASSERT(!(attrs & JSPROP_READONLY)); attrs &= (JSPROP_ENUMERATE | JSPROP_PERMANENT); /* only valid attributes */ if (JSID_IS_INT(id)) { unsigned arg = unsigned(JSID_TO_INT(id)); if (arg < argsobj->initialLength()) { argsobj->setElement(cx, arg, vp); return result.succeed(); } } else { MOZ_ASSERT(JSID_IS_ATOM(id, cx->names().length)); } /* * For simplicity we use delete/define to replace the property with a * simple data property. Note that we rely on ArgumentsObject::obj_delProperty * to clear the corresponding reserved slot so the GC can collect its value. */ ObjectOpResult ignored; return NativeDeleteProperty(cx, argsobj, id, ignored) && NativeDefineProperty(cx, argsobj, id, vp, nullptr, nullptr, attrs, result); }
// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 9.5.10 Proxy.[[Delete]](P) bool ScriptedProxyHandler::delete_(JSContext* cx, HandleObject proxy, HandleId id, ObjectOpResult& result) const { // Steps 2-4. RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy)); if (!handler) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; } // Step 5. RootedObject target(cx, proxy->as<ProxyObject>().target()); MOZ_ASSERT(target); // Step 6. RootedValue trap(cx); if (!GetProxyTrap(cx, handler, cx->names().deleteProperty, &trap)) return false; // Step 7. if (trap.isUndefined()) return DeleteProperty(cx, target, id, result); // Step 8. bool booleanTrapResult; { RootedValue value(cx); if (!IdToStringOrSymbol(cx, id, &value)) return false; RootedValue targetVal(cx, ObjectValue(*target)); RootedValue trapResult(cx); if (!Call(cx, trap, handler, targetVal, value, &trapResult)) return false; booleanTrapResult = ToBoolean(trapResult); } // Step 9. if (!booleanTrapResult) return result.fail(JSMSG_PROXY_DELETE_RETURNED_FALSE); // Step 10. Rooted<PropertyDescriptor> desc(cx); if (!GetOwnPropertyDescriptor(cx, target, id, &desc)) return false; // Step 12. if (desc.object() && !desc.configurable()) { RootedValue v(cx, IdToValue(id)); ReportValueError(cx, JSMSG_CANT_DELETE, JSDVG_IGNORE_STACK, v, nullptr); return false; } // Steps 11,13. return result.succeed(); }
bool js::ProxySetProperty(JSContext* cx, HandleObject proxy, HandleId id, HandleValue val, bool strict) { ObjectOpResult result; RootedValue receiver(cx, ObjectValue(*proxy)); if (!Proxy::setInternal(cx, proxy, id, val, receiver, result)) return false; return result.checkStrictErrorOrWarning(cx, proxy, id, strict); }
bool WrapperOwner::ok(JSContext* cx, const ReturnStatus& status, ObjectOpResult& result) { if (status.type() == ReturnStatus::TReturnObjectOpResult) return result.fail(status.get_ReturnObjectOpResult().code()); if (!ok(cx, status)) return false; return result.succeed(); }
// ES6 draft rev 32 (2 Feb 2014) 9.5.10 Proxy.[[Delete]](P) bool ScriptedDirectProxyHandler::delete_(JSContext* cx, HandleObject proxy, HandleId id, ObjectOpResult& result) const { // step 2 RootedObject handler(cx, GetDirectProxyHandlerObject(proxy)); // step 3 if (!handler) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; } // steps 4-5 RootedObject target(cx, proxy->as<ProxyObject>().target()); // steps 6-7 RootedValue trap(cx); if (!GetProperty(cx, handler, handler, cx->names().deleteProperty, &trap)) return false; // step 8 if (trap.isUndefined()) return DeleteProperty(cx, target, id, result); // steps 9-10 RootedValue value(cx); if (!IdToStringOrSymbol(cx, id, &value)) return false; Value argv[] = { ObjectValue(*target), value }; RootedValue trapResult(cx); if (!Invoke(cx, ObjectValue(*handler), trap, ArrayLength(argv), argv, &trapResult)) return false; // step 11 if (!ToBoolean(trapResult)) return result.fail(JSMSG_PROXY_DELETE_RETURNED_FALSE); // steps 12-13 Rooted<PropertyDescriptor> desc(cx); if (!GetOwnPropertyDescriptor(cx, target, id, &desc)) return false; // step 14-15 if (desc.object() && !desc.configurable()) { RootedValue v(cx, IdToValue(id)); ReportValueError(cx, JSMSG_CANT_DELETE, JSDVG_IGNORE_STACK, v, nullptr); return false; } // step 16 return result.succeed(); }
bool ModuleNamespaceObject::ProxyHandler::delete_(JSContext* cx, HandleObject proxy, HandleId id, ObjectOpResult& result) const { Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>()); if (ns->bindings().has(id)) return result.failReadOnly(); return result.succeed(); }
// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 9.5.4 Proxy.[[PreventExtensions]]() bool ScriptedProxyHandler::preventExtensions(JSContext* cx, HandleObject proxy, ObjectOpResult& result) const { // Steps 1-3. RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy)); if (!handler) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; } // Step 4. RootedObject target(cx, proxy->as<ProxyObject>().target()); MOZ_ASSERT(target); // Step 5. RootedValue trap(cx); if (!GetProxyTrap(cx, handler, cx->names().preventExtensions, &trap)) return false; // Step 6. if (trap.isUndefined()) return PreventExtensions(cx, target, result); // Step 7. bool booleanTrapResult; { RootedValue arg(cx, ObjectValue(*target)); RootedValue trapResult(cx); if (!Call(cx, trap, handler, arg, &trapResult)) return false; booleanTrapResult = ToBoolean(trapResult); } // Step 8. if (booleanTrapResult) { // Step 8a. bool targetIsExtensible; if (!IsExtensible(cx, target, &targetIsExtensible)) return false; if (targetIsExtensible) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_REPORT_AS_NON_EXTENSIBLE); return false; } // Step 9. return result.succeed(); } // Also step 9. return result.fail(JSMSG_PROXY_PREVENTEXTENSIONS_RETURNED_FALSE); }
bool XPC_WN_MaybeResolvingSetPropertyStub(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp, ObjectOpResult& result) { result.succeed(); return XPC_WN_MaybeResolvingPropertyStub(cx, obj, id, vp); }
bool OpaqueCrossCompartmentWrapper::defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, Handle<JSPropertyDescriptor> desc, ObjectOpResult& result) const { return result.succeed(); }
bool ModuleNamespaceObject::ProxyHandler::preventExtensions(JSContext* cx, HandleObject proxy, ObjectOpResult& result) const { result.succeed(); return true; }
bool ModuleNamespaceObject::ProxyHandler::defineProperty(JSContext* cx, HandleObject proxy, HandleId id, Handle<PropertyDescriptor> desc, ObjectOpResult& result) const { return result.failReadOnly(); }
// ES6 draft rev 32 (2 Feb 2015) 9.5.4 Proxy.[[PreventExtensions]]() bool ScriptedDirectProxyHandler::preventExtensions(JSContext* cx, HandleObject proxy, ObjectOpResult& result) const { // Steps 1-3. RootedObject handler(cx, GetDirectProxyHandlerObject(proxy)); if (!handler) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; } // Step 4. RootedObject target(cx, proxy->as<ProxyObject>().target()); // Steps 5-6. RootedValue trap(cx); if (!GetProperty(cx, handler, handler, cx->names().preventExtensions, &trap)) return false; // Step 7. if (trap.isUndefined()) return PreventExtensions(cx, target, result); // Steps 8-9. Value argv[] = { ObjectValue(*target) }; RootedValue trapResult(cx); if (!Invoke(cx, ObjectValue(*handler), trap, ArrayLength(argv), argv, &trapResult)) return false; // Steps 10-11. if (ToBoolean(trapResult)) { bool extensible; if (!IsExtensible(cx, target, &extensible)) return false; if (extensible) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_REPORT_AS_NON_EXTENSIBLE); return false; } return result.succeed(); } return result.fail(JSMSG_PROXY_PREVENTEXTENSIONS_RETURNED_FALSE); }
static bool MappedArgSetter(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp, ObjectOpResult& result) { if (!obj->is<MappedArgumentsObject>()) return result.succeed(); Handle<MappedArgumentsObject*> argsobj = obj.as<MappedArgumentsObject>(); Rooted<PropertyDescriptor> desc(cx); if (!GetOwnPropertyDescriptor(cx, argsobj, id, &desc)) return false; MOZ_ASSERT(desc.object()); unsigned attrs = desc.attributes(); MOZ_ASSERT(!(attrs & JSPROP_READONLY)); attrs &= (JSPROP_ENUMERATE | JSPROP_PERMANENT); /* only valid attributes */ RootedFunction callee(cx, &argsobj->callee()); RootedScript script(cx, callee->getOrCreateScript(cx)); if (!script) return false; if (JSID_IS_INT(id)) { unsigned arg = unsigned(JSID_TO_INT(id)); if (arg < argsobj->initialLength() && !argsobj->isElementDeleted(arg)) { argsobj->setElement(cx, arg, vp); if (arg < script->functionNonDelazifying()->nargs()) TypeScript::SetArgument(cx, script, arg, vp); return result.succeed(); } } else { MOZ_ASSERT(JSID_IS_ATOM(id, cx->names().length) || JSID_IS_ATOM(id, cx->names().callee)); } /* * For simplicity we use delete/define to replace the property with a * simple data property. Note that we rely on ArgumentsObject::obj_delProperty * to clear the corresponding reserved slot so the GC can collect its value. * Note also that we must define the property instead of setting it in case * the user has changed the prototype to an object that has a setter for * this id. */ ObjectOpResult ignored; return NativeDeleteProperty(cx, argsobj, id, ignored) && NativeDefineProperty(cx, argsobj, id, vp, nullptr, nullptr, attrs, result); }
bool SecurityWrapper<Base>::preventExtensions(JSContext *cx, HandleObject wrapper, ObjectOpResult &result) const { // Just like BaseProxyHandler, SecurityWrappers claim by default to always // be extensible, so as not to leak information about the state of the // underlying wrapped thing. return result.fail(JSMSG_CANT_CHANGE_EXTENSIBILITY); }
bool RObjectState::recover(JSContext* cx, SnapshotIterator& iter) const { RootedObject object(cx, &iter.read().toObject()); RootedValue val(cx); if (object->is<UnboxedPlainObject>()) { const UnboxedLayout& layout = object->as<UnboxedPlainObject>().layout(); RootedId id(cx); RootedValue receiver(cx, ObjectValue(*object)); const UnboxedLayout::PropertyVector& properties = layout.properties(); for (size_t i = 0; i < properties.length(); i++) { val = iter.read(); // This is the default placeholder value of MObjectState, when no // properties are defined yet. if (val.isUndefined()) continue; id = NameToId(properties[i].name); ObjectOpResult result; // SetProperty can only fail due to OOM. if (!SetProperty(cx, object, id, val, receiver, result)) return false; if (!result) return result.reportError(cx, object, id); } } else { RootedNativeObject nativeObject(cx, &object->as<NativeObject>()); MOZ_ASSERT(nativeObject->slotSpan() == numSlots()); for (size_t i = 0; i < numSlots(); i++) { val = iter.read(); nativeObject->setSlot(i, val); } } val.setObject(*object); iter.storeInstructionResult(val); return true; }
static bool 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 JSString* valstr; JS::Rooted<JSString*> idstr(cx); int rv; RootedValue idval(cx); if (!JS_IdToValue(cx, id, &idval)) return false; idstr = ToString(cx, idval); valstr = ToString(cx, vp); if (!idstr || !valstr) return false; JSAutoByteString name(cx, idstr); if (!name) return false; JSAutoByteString value(cx, valstr); if (!value) return false; #if defined XP_WIN || defined HPUX || defined OSF1 || defined SCO { char* waste = JS_smprintf("%s=%s", name.ptr(), value.ptr()); if (!waste) { JS_ReportOutOfMemory(cx); return false; } rv = putenv(waste); #ifdef XP_WIN /* * HPUX9 at least still has the bad old non-copying putenv. * * Per mail from <*****@*****.**>, OSF1 also has a putenv * that will crash if you pass it an auto char array (so it must place * its argument directly in the char* environ[] array). */ free(waste); #endif } #else rv = setenv(name.ptr(), value.ptr(), 1); #endif if (rv < 0) { JS_ReportError(cx, "can't set envariable %s to %s", name.ptr(), value.ptr()); return false; } vp.setString(valstr); #endif /* !defined SOLARIS */ return result.succeed(); }
bool XPC_WN_MaybeResolvingDeletePropertyStub(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result) { XPCCallContext ccx(cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); if (ccx.GetResolvingWrapper() == wrapper) { return result.succeed(); } return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx); }
static bool args_delProperty(JSContext *cx, HandleObject obj, HandleId id, ObjectOpResult &result) { ArgumentsObject &argsobj = obj->as<ArgumentsObject>(); if (JSID_IS_INT(id)) { unsigned arg = unsigned(JSID_TO_INT(id)); if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) argsobj.markElementDeleted(arg); } else if (JSID_IS_ATOM(id, cx->names().length)) { argsobj.markLengthOverridden(); } else if (JSID_IS_ATOM(id, cx->names().callee)) { argsobj.as<NormalArgumentsObject>().clearCallee(); } return result.succeed(); }
bool SetProperty(JSContext* cx, HandleObject obj, HandlePropertyName name, HandleValue value, bool strict, jsbytecode* pc) { RootedId id(cx, NameToId(name)); JSOp op = JSOp(*pc); if (op == JSOP_SETALIASEDVAR) { // Aliased var assigns ignore readonly attributes on the property, as // required for initializing 'const' closure variables. Shape* shape = obj->as<NativeObject>().lookup(cx, name); MOZ_ASSERT(shape && shape->hasSlot()); obj->as<NativeObject>().setSlotWithType(cx, shape, value); return true; } RootedValue receiver(cx, ObjectValue(*obj)); ObjectOpResult result; if (MOZ_LIKELY(!obj->getOps()->setProperty)) { if (!NativeSetProperty( cx, obj.as<NativeObject>(), id, value, receiver, (op == JSOP_SETNAME || op == JSOP_STRICTSETNAME || op == JSOP_SETGNAME || op == JSOP_STRICTSETGNAME) ? Unqualified : Qualified, result)) { return false; } } else { if (!SetProperty(cx, obj, id, value, receiver, result)) return false; } return result.checkStrictErrorOrWarning(cx, obj, id, strict); }
bool Proxy::delete_(JSContext* cx, HandleObject proxy, HandleId id, ObjectOpResult& result) { if (!CheckRecursionLimit(cx)) return false; const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler(); AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::SET, true); if (!policy.allowed()) { bool ok = policy.returnValue(); if (ok) result.succeed(); return ok; } return proxy->as<ProxyObject>().handler()->delete_(cx, proxy, id, result); }
bool Proxy::defineProperty(JSContext* cx, HandleObject proxy, HandleId id, Handle<PropertyDescriptor> desc, ObjectOpResult& result) { if (!CheckRecursionLimit(cx)) return false; const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler(); AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::SET, true); if (!policy.allowed()) { if (!policy.returnValue()) return false; return result.succeed(); } return proxy->as<ProxyObject>().handler()->defineProperty(cx, proxy, id, desc, result); }
/* static */ bool ArgumentsObject::obj_delProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result) { ArgumentsObject& argsobj = obj->as<ArgumentsObject>(); if (JSID_IS_INT(id)) { unsigned arg = unsigned(JSID_TO_INT(id)); if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) { if (!argsobj.markElementDeleted(cx, arg)) return false; } } else if (JSID_IS_ATOM(id, cx->names().length)) { argsobj.markLengthOverridden(); } else if (JSID_IS_ATOM(id, cx->names().callee)) { argsobj.as<MappedArgumentsObject>().markCalleeOverridden(); } else if (JSID_IS_SYMBOL(id) && JSID_TO_SYMBOL(id) == cx->wellKnownSymbols().iterator) { argsobj.markIteratorOverridden(); } return result.succeed(); }
MOZ_ALWAYS_INLINE bool Proxy::setInternal(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, HandleValue receiver, ObjectOpResult& result) { MOZ_ASSERT_IF(receiver.isObject(), !IsWindow(&receiver.toObject())); if (!CheckRecursionLimit(cx)) return false; const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler(); AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::SET, true); if (!policy.allowed()) { if (!policy.returnValue()) return false; return result.succeed(); } // Special case. See the comment on BaseProxyHandler::mHasPrototype. if (handler->hasPrototype()) return handler->BaseProxyHandler::set(cx, proxy, id, v, receiver, result); return handler->set(cx, proxy, id, v, receiver, result); }
bool DOMProxyHandler::set(JSContext *cx, Handle<JSObject*> proxy, Handle<jsid> id, Handle<JS::Value> v, Handle<JS::Value> receiver, ObjectOpResult &result) const { MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy), "Should not have a XrayWrapper here"); bool done; if (!setCustom(cx, proxy, id, v, &done)) { return false; } if (done) { return result.succeed(); } // Make sure to ignore our named properties when checking for own // property descriptors for a set. JS::Rooted<PropertyDescriptor> ownDesc(cx); if (!getOwnPropDescriptor(cx, proxy, id, /* ignoreNamedProps = */ true, &ownDesc)) { return false; } return js::SetPropertyIgnoringNamedGetter(cx, proxy, id, v, receiver, ownDesc, result); }
bool js::SetPropertyIgnoringNamedGetter(JSContext* cx, HandleObject obj, HandleId id, HandleValue v, HandleValue receiver, Handle<PropertyDescriptor> ownDesc_, ObjectOpResult& result) { Rooted<PropertyDescriptor> ownDesc(cx, ownDesc_); // Step 4. if (!ownDesc.object()) { // The spec calls this variable "parent", but that word has weird // connotations in SpiderMonkey, so let's go with "proto". RootedObject proto(cx); if (!GetPrototype(cx, obj, &proto)) { return false; } if (proto) { return SetProperty(cx, proto, id, v, receiver, result); } // Step 4.d. ownDesc.setDataDescriptor(UndefinedHandleValue, JSPROP_ENUMERATE); } // Step 5. if (ownDesc.isDataDescriptor()) { // Steps 5.a-b. if (!ownDesc.writable()) { return result.fail(JSMSG_READ_ONLY); } if (!receiver.isObject()) { return result.fail(JSMSG_SET_NON_OBJECT_RECEIVER); } RootedObject receiverObj(cx, &receiver.toObject()); // Nonstandard SpiderMonkey special case: setter ops. if (SetterOp setter = ownDesc.setter()) { return CallJSSetterOp(cx, setter, receiverObj, id, v, result); } // Steps 5.c-d. Rooted<PropertyDescriptor> existingDescriptor(cx); if (!GetOwnPropertyDescriptor(cx, receiverObj, id, &existingDescriptor)) { return false; } // Step 5.e. if (existingDescriptor.object()) { // Step 5.e.i. if (existingDescriptor.isAccessorDescriptor()) { return result.fail(JSMSG_OVERWRITING_ACCESSOR); } // Step 5.e.ii. if (!existingDescriptor.writable()) { return result.fail(JSMSG_READ_ONLY); } } // Steps 5.e.iii-iv. and 5.f.i. unsigned attrs = existingDescriptor.object() ? JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_READONLY | JSPROP_IGNORE_PERMANENT : JSPROP_ENUMERATE; return DefineDataProperty(cx, receiverObj, id, v, attrs, result); } // Step 6. MOZ_ASSERT(ownDesc.isAccessorDescriptor()); RootedObject setter(cx); if (ownDesc.hasSetterObject()) { setter = ownDesc.setterObject(); } if (!setter) { return result.fail(JSMSG_GETTER_ONLY); } RootedValue setterValue(cx, ObjectValue(*setter)); if (!CallSetter(cx, receiver, setterValue, v)) { return false; } return result.succeed(); }
bool OpaqueCrossCompartmentWrapper::preventExtensions(JSContext* cx, HandleObject wrapper, ObjectOpResult& result) const { return result.failCantPreventExtensions(); }
bool OpaqueCrossCompartmentWrapper::setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, ObjectOpResult& result) const { return result.succeed(); }
bool OpaqueCrossCompartmentWrapper::delete_(JSContext* cx, HandleObject wrapper, HandleId id, ObjectOpResult& result) const { return result.succeed(); }
// ES6 draft rev 31 (15 Jan 2015) 9.5.6 Proxy.[[DefineOwnProperty]](P, Desc) bool ScriptedDirectProxyHandler::defineProperty(JSContext* cx, HandleObject proxy, HandleId id, Handle<PropertyDescriptor> desc, ObjectOpResult& result) const { // steps 2-4 RootedObject handler(cx, GetDirectProxyHandlerObject(proxy)); if (!handler) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; } // step 5 RootedObject target(cx, proxy->as<ProxyObject>().target()); // steps 6-7 RootedValue trap(cx); if (!GetProperty(cx, handler, handler, cx->names().defineProperty, &trap)) return false; // step 8 if (trap.isUndefined()) return DefineProperty(cx, target, id, desc, result); // step 9 RootedValue descObj(cx); if (!FromPropertyDescriptorToObject(cx, desc, &descObj)) return false; // steps 10-11 RootedValue propKey(cx); if (!IdToStringOrSymbol(cx, id, &propKey)) return false; Value argv[] = { ObjectValue(*target), propKey, descObj }; RootedValue trapResult(cx); if (!Invoke(cx, ObjectValue(*handler), trap, ArrayLength(argv), argv, &trapResult)) return false; // step 12 if (!ToBoolean(trapResult)) return result.fail(JSMSG_PROXY_DEFINE_RETURNED_FALSE); // step 13-14 Rooted<PropertyDescriptor> targetDesc(cx); if (!GetOwnPropertyDescriptor(cx, target, id, &targetDesc)) return false; // step 15-16 bool extensibleTarget; if (!IsExtensible(cx, target, &extensibleTarget)) return false; // step 17-18 bool settingConfigFalse = desc.hasConfigurable() && !desc.configurable(); if (!targetDesc.object()) { // step 19.a if (!extensibleTarget) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_DEFINE_NEW); return false; } // step 19.b if (settingConfigFalse) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_DEFINE_NE_AS_NC); return false; } } else { // step 20 bool valid; if (!ValidatePropertyDescriptor(cx, extensibleTarget, desc, targetDesc, &valid)) return false; if (!valid || (settingConfigFalse && targetDesc.configurable())) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_DEFINE_INVALID); return false; } } // step 21 return result.succeed(); }
// ES6 draft rev 32 (2015 Feb 2) 9.5.9 Proxy.[[Set]](P, V, Receiver) bool ScriptedDirectProxyHandler::set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, HandleValue receiver, ObjectOpResult& result) const { // step 2-3 (Steps 1 and 4 are irrelevant assertions.) RootedObject handler(cx, GetDirectProxyHandlerObject(proxy)); if (!handler) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; } // step 5-7 RootedObject target(cx, proxy->as<ProxyObject>().target()); RootedValue trap(cx); if (!GetProperty(cx, handler, handler, cx->names().set, &trap)) return false; // step 8 if (trap.isUndefined()) return SetProperty(cx, target, id, v, receiver, result); // step 9-10 RootedValue value(cx); if (!IdToStringOrSymbol(cx, id, &value)) return false; Value argv[] = { ObjectOrNullValue(target), value, v.get(), receiver.get() }; RootedValue trapResult(cx); if (!Invoke(cx, ObjectValue(*handler), trap, ArrayLength(argv), argv, &trapResult)) return false; // step 11 if (!ToBoolean(trapResult)) return result.fail(JSMSG_PROXY_SET_RETURNED_FALSE); // step 12-13 Rooted<PropertyDescriptor> desc(cx); if (!GetOwnPropertyDescriptor(cx, target, id, &desc)) return false; // step 14 if (desc.object()) { if (desc.isDataDescriptor() && !desc.configurable() && !desc.writable()) { bool same; if (!SameValue(cx, v, desc.value(), &same)) return false; if (!same) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_SET_NW_NC); return false; } } if (desc.isAccessorDescriptor() && !desc.configurable() && desc.setterObject() == nullptr) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_SET_WO_SETTER); return false; } } // step 15 return result.succeed(); }