// 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 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(); }
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); }
// 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(); }
// 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); }
// 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); }
// 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(); }
// 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(); }
// 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(); }
// 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(); }