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); }
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; }
// 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(); }
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 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); }
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); }
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 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 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); }
// 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 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 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(); }
// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 9.5.9 Proxy.[[Set]](P, V, Receiver) bool ScriptedProxyHandler::set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, HandleValue receiver, 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().set, &trap)) return false; // Step 7. if (trap.isUndefined()) return SetProperty(cx, target, id, v, receiver, result); // Step 8. RootedValue value(cx); if (!IdToStringOrSymbol(cx, id, &value)) return false; RootedValue trapResult(cx); { FixedInvokeArgs<4> args(cx); args[0].setObject(*target); args[1].set(value); args[2].set(v); args[3].set(receiver); RootedValue thisv(cx, ObjectValue(*handler)); if (!Call(cx, trap, thisv, args, &trapResult)) return false; } // Step 9. if (!ToBoolean(trapResult)) return result.fail(JSMSG_PROXY_SET_RETURNED_FALSE); // Step 10. Rooted<PropertyDescriptor> desc(cx); if (!GetOwnPropertyDescriptor(cx, target, id, &desc)) return false; // Step 11. if (desc.object()) { // Step 11a. if (desc.isDataDescriptor() && !desc.configurable() && !desc.writable()) { bool same; if (!SameValue(cx, v, desc.value(), &same)) return false; if (!same) return js::Throw(cx, id, JSMSG_CANT_SET_NW_NC); } // Step 11b. if (desc.isAccessorDescriptor() && !desc.configurable() && desc.setterObject() == nullptr) return js::Throw(cx, id, JSMSG_CANT_SET_WO_SETTER); } // Step 12. 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(); }
// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 9.5.2 Proxy.[[SetPrototypeOf]]. bool ScriptedProxyHandler::setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, ObjectOpResult& result) const { // Steps 1-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().setPrototypeOf, &trap)) return false; // Step 7. if (trap.isUndefined()) return SetPrototype(cx, target, proto, result); // Step 8. bool booleanTrapResult; { FixedInvokeArgs<2> args(cx); args[0].setObject(*target); args[1].setObjectOrNull(proto); RootedValue hval(cx, ObjectValue(*handler)); if (!js::Call(cx, trap, hval, args, &hval)) return false; booleanTrapResult = ToBoolean(hval); } // Step 9. if (!booleanTrapResult) return result.fail(JSMSG_PROXY_SETPROTOTYPEOF_RETURNED_FALSE); // Step 10. bool extensibleTarget; if (!IsExtensible(cx, target, &extensibleTarget)) return false; // Step 11. if (extensibleTarget) return result.succeed(); // Step 12. RootedObject targetProto(cx); if (!GetPrototype(cx, target, &targetProto)) return false; // Step 13. if (proto != targetProto) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCONSISTENT_SETPROTOTYPEOF_TRAP); return false; } // Step 14. 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(); }
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(); }
// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 9.5.6 Proxy.[[DefineOwnProperty]](P, Desc) bool ScriptedProxyHandler::defineProperty(JSContext* cx, HandleObject proxy, HandleId id, Handle<PropertyDescriptor> desc, 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().defineProperty, &trap)) return false; // Step 7. if (trap.isUndefined()) return DefineProperty(cx, target, id, desc, result); // Step 8. RootedValue descObj(cx); if (!FromPropertyDescriptorToObject(cx, desc, &descObj)) return false; // Step 9. RootedValue propKey(cx); if (!IdToStringOrSymbol(cx, id, &propKey)) return false; RootedValue trapResult(cx); { FixedInvokeArgs<3> args(cx); args[0].setObject(*target); args[1].set(propKey); args[2].set(descObj); RootedValue thisv(cx, ObjectValue(*handler)); if (!Call(cx, trap, thisv, args, &trapResult)) return false; } // Step 10. if (!ToBoolean(trapResult)) return result.fail(JSMSG_PROXY_DEFINE_RETURNED_FALSE); // Step 11. Rooted<PropertyDescriptor> targetDesc(cx); if (!GetOwnPropertyDescriptor(cx, target, id, &targetDesc)) return false; // Step 12. bool extensibleTarget; if (!IsExtensible(cx, target, &extensibleTarget)) return false; // Steps 13-14. bool settingConfigFalse = desc.hasConfigurable() && !desc.configurable(); // Steps 15-16. if (!targetDesc.object()) { // Step 15a. if (!extensibleTarget) return js::Throw(cx, id, JSMSG_CANT_DEFINE_NEW); // Step 15b. if (settingConfigFalse) return js::Throw(cx, id, JSMSG_CANT_DEFINE_NE_AS_NC); } else { // Step 16a. const char* errorDetails = nullptr; if (!IsCompatiblePropertyDescriptor(cx, extensibleTarget, desc, targetDesc, &errorDetails)) return false; if (errorDetails) return js::Throw(cx, id, JSMSG_CANT_DEFINE_INVALID, errorDetails); // Step 16b. if (settingConfigFalse && targetDesc.configurable()) { static const char* DETAILS_CANT_REPORT_C_AS_NC = "proxy can't define an existing configurable property as non-configurable"; return js::Throw(cx, id, JSMSG_CANT_DEFINE_INVALID, DETAILS_CANT_REPORT_C_AS_NC); } } // Step 17. return result.succeed(); }
// ES 2017 draft 9.4.4.2 /* static */ bool MappedArgumentsObject::obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, Handle<PropertyDescriptor> desc, ObjectOpResult& result) { // Step 1. Rooted<MappedArgumentsObject*> argsobj(cx, &obj->as<MappedArgumentsObject>()); // Steps 2-3. bool isMapped = false; if (JSID_IS_INT(id)) { unsigned arg = unsigned(JSID_TO_INT(id)); isMapped = arg < argsobj->initialLength() && !argsobj->isElementDeleted(arg); } // Step 4. Rooted<PropertyDescriptor> newArgDesc(cx, desc); // Step 5. if (!desc.isAccessorDescriptor() && isMapped) { // Step 5.a. if (desc.hasWritable() && !desc.writable()) { if (!desc.hasValue()) { RootedValue v(cx, argsobj->element(JSID_TO_INT(id))); newArgDesc.setValue(v); } newArgDesc.setGetter(nullptr); newArgDesc.setSetter(nullptr); } else { // In this case the live mapping is supposed to keep working, // we have to pass along the Getter/Setter otherwise they are // overwritten. newArgDesc.setGetter(MappedArgGetter); newArgDesc.setSetter(MappedArgSetter); newArgDesc.value().setUndefined(); newArgDesc.attributesRef() |= JSPROP_IGNORE_VALUE; } } // Step 6. NativeDefineProperty will lookup [[Value]] for us. if (!NativeDefineProperty(cx, obj.as<NativeObject>(), id, newArgDesc, result)) return false; // Step 7. if (!result.ok()) return true; // Step 8. if (isMapped) { unsigned arg = unsigned(JSID_TO_INT(id)); if (desc.isAccessorDescriptor()) { if (!argsobj->markElementDeleted(cx, arg)) return false; } else { if (desc.hasValue()) { RootedFunction callee(cx, &argsobj->callee()); RootedScript script(cx, JSFunction::getOrCreateScript(cx, callee)); if (!script) return false; argsobj->setElement(cx, arg, desc.value()); if (arg < script->functionNonDelazifying()->nargs()) TypeScript::SetArgument(cx, script, arg, desc.value()); } if (desc.hasWritable() && !desc.writable()) { if (!argsobj->markElementDeleted(cx, arg)) return false; } } } // Step 9. return result.succeed(); }