feat(script): Implement [[Set]] for Location

This commit is contained in:
yvt 2021-07-17 13:31:39 +09:00
parent 80cda12a87
commit 4bc3453174
2 changed files with 123 additions and 3 deletions

View file

@ -3554,6 +3554,10 @@ class CGDefineProxyHandler(CGAbstractMethod):
# confused with ECMAScript's `[[SetImmutablePrototype]]`) always fails. # confused with ECMAScript's `[[SetImmutablePrototype]]`) always fails.
# This is the desired behavior, so we don't override it. # This is the desired behavior, so we don't override it.
customSet = 'None'
if self.descriptor.isMaybeCrossOriginObject():
customSet = 'Some(set)'
getOwnEnumerablePropertyKeys = "own_property_keys" getOwnEnumerablePropertyKeys = "own_property_keys"
if self.descriptor.interface.getExtendedAttribute("LegacyUnenumerableNamedProperties"): if self.descriptor.interface.getExtendedAttribute("LegacyUnenumerableNamedProperties"):
getOwnEnumerablePropertyKeys = "getOwnEnumerablePropertyKeys" getOwnEnumerablePropertyKeys = "getOwnEnumerablePropertyKeys"
@ -3564,6 +3568,7 @@ class CGDefineProxyHandler(CGAbstractMethod):
"getPrototypeIfOrdinary": customGetPrototypeIfOrdinary, "getPrototypeIfOrdinary": customGetPrototypeIfOrdinary,
"getPrototype": customGetPrototype, "getPrototype": customGetPrototype,
"setPrototype": customSetPrototype, "setPrototype": customSetPrototype,
"set": customSet,
"getOwnEnumerablePropertyKeys": getOwnEnumerablePropertyKeys, "getOwnEnumerablePropertyKeys": getOwnEnumerablePropertyKeys,
"trace": TRACE_HOOK_NAME, "trace": TRACE_HOOK_NAME,
"finalize": FINALIZE_HOOK_NAME, "finalize": FINALIZE_HOOK_NAME,
@ -3585,7 +3590,7 @@ let traps = ProxyTraps {
isExtensible: Some(proxyhandler::is_extensible), isExtensible: Some(proxyhandler::is_extensible),
has: None, has: None,
get: Some(get), get: Some(get),
set: None, set: %(set)s,
call: None, call: None,
construct: None, construct: None,
hasOwn: Some(hasOwn), hasOwn: Some(hasOwn),
@ -5951,12 +5956,61 @@ return true;""" % (maybeCrossOriginGet, getIndexedOrExpando, getNamed)
return CGGeneric(self.getBody()) return CGGeneric(self.getBody())
class CGDOMJSProxyHandler_set(CGAbstractExternMethod):
def __init__(self, descriptor):
args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', 'proxy'),
Argument('RawHandleId', 'id'), Argument('RawHandleValue', 'v'),
Argument('RawHandleValue', 'receiver'),
Argument('*mut ObjectOpResult', 'opresult')]
CGAbstractExternMethod.__init__(self, descriptor, "set", "bool", args)
self.descriptor = descriptor
def getBody(self):
descriptor = self.descriptor
# `CGDOMJSProxyHandler_set` doesn't support legacy platform objects'
# `[[Set]]` (https://heycam.github.io/webidl/#legacy-platform-object-set) yet.
#
assert descriptor.isMaybeCrossOriginObject()
assert not descriptor.operations['IndexedGetter']
assert not descriptor.operations['NamedGetter']
maybeCrossOriginSet = dedent(
"""
if !proxyhandler::is_platform_object_same_origin(cx, proxy) {
return proxyhandler::cross_origin_set(cx, proxy, id, v, receiver, opresult);
}
// Safe to enter the Realm of proxy now.
let _ac = JSAutoRealm::new(*cx, proxy.get());
""")
return dedent(
"""
let cx = SafeJSContext::from_ptr(cx);
%(maybeCrossOriginSet)s
// OrdinarySet
// <https://tc39.es/ecma262/#sec-ordinaryset>
rooted!(in(*cx) let mut own_desc = PropertyDescriptor::default());
if !getOwnPropertyDescriptor(*cx, proxy, id, own_desc.handle_mut().into()) {
return false;
}
js::jsapi::SetPropertyIgnoringNamedGetter(
*cx, proxy, id, v, receiver, own_desc.handle().into(), opresult)
""") % { "maybeCrossOriginSet": maybeCrossOriginSet }
def definition_body(self):
return CGGeneric(self.getBody())
class CGDOMJSProxyHandler_getPrototype(CGAbstractExternMethod): class CGDOMJSProxyHandler_getPrototype(CGAbstractExternMethod):
def __init__(self, descriptor): def __init__(self, descriptor):
args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', 'proxy'), args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', 'proxy'),
Argument('RawMutableHandleObject', 'proto')] Argument('RawMutableHandleObject', 'proto')]
CGAbstractExternMethod.__init__(self, descriptor, "getPrototype", "bool", args) CGAbstractExternMethod.__init__(self, descriptor, "getPrototype", "bool", args)
assert self.descriptor.isMaybeCrossOriginObject() assert descriptor.isMaybeCrossOriginObject()
self.descriptor = descriptor self.descriptor = descriptor
def getBody(self): def getBody(self):
@ -6636,7 +6690,7 @@ class CGDescriptor(CGThing):
if descriptor.isMaybeCrossOriginObject(): if descriptor.isMaybeCrossOriginObject():
cgThings.append(CGDOMJSProxyHandler_getPrototype(descriptor)) cgThings.append(CGDOMJSProxyHandler_getPrototype(descriptor))
# TODO: CGDOMJSProxyHandler_set(descriptor), cgThings.append(CGDOMJSProxyHandler_set(descriptor))
pass pass
# cgThings.append(CGDOMJSProxyHandler(descriptor)) # cgThings.append(CGDOMJSProxyHandler(descriptor))

View file

@ -436,12 +436,78 @@ pub unsafe fn cross_origin_get(
) )
} }
/// Implementation of [`CrossOriginSet`].
///
/// [`CrossOriginSet`]: https://html.spec.whatwg.org/multipage/#crossoriginset-(-o,-p,-v,-receiver-)
pub unsafe fn cross_origin_set(
cx: SafeJSContext,
proxy: RawHandleObject,
id: RawHandleId,
v: RawHandleValue,
receiver: RawHandleValue,
result: *mut ObjectOpResult,
) -> bool {
// > 1. Let desc be ? O.[[GetOwnProperty]](P).
rooted!(in(*cx) let mut descriptor = PropertyDescriptor::default());
if !InvokeGetOwnPropertyDescriptor(
GetProxyHandler(*proxy),
*cx,
proxy,
id,
descriptor.handle_mut().into(),
) {
return false;
}
// > 2. Assert: desc is not undefined.
assert!(
!descriptor.obj.is_null(),
"Callees should throw in all cases when they are not finding \
a property decriptor"
);
// > 3. If desc.[[Set]] is present and its value is not undefined,
// > then: [...]
rooted!(in(*cx) let mut setter = ptr::null_mut::<JSObject>());
get_setter_object(&descriptor, setter.handle_mut().into());
if setter.get().is_null() {
// > 4. Throw a "SecurityError" DOMException.
return report_cross_origin_denial(cx, id, "set");
}
rooted!(in(*cx) let mut setter_jsval = UndefinedValue());
setter.get().to_jsval(*cx, setter_jsval.handle_mut());
// > 3.1. Perform ? Call(setter, Receiver, «V»).
// >
// > 3.2. Return true.
rooted!(in(*cx) let mut ignored = UndefinedValue());
if !jsapi::Call(
*cx,
receiver,
setter_jsval.handle().into(),
&jsapi::HandleValueArray::from_rooted_slice(&[v.get()]),
ignored.handle_mut().into(),
) {
return false;
}
(*result).code_ = 0 /* OkCode */;
true
}
unsafe fn get_getter_object(d: &PropertyDescriptor, out: RawMutableHandleObject) { unsafe fn get_getter_object(d: &PropertyDescriptor, out: RawMutableHandleObject) {
if (d.attrs & jsapi::JSPROP_GETTER as u32) != 0 { if (d.attrs & jsapi::JSPROP_GETTER as u32) != 0 {
out.set(std::mem::transmute(d.getter)); out.set(std::mem::transmute(d.getter));
} }
} }
unsafe fn get_setter_object(d: &PropertyDescriptor, out: RawMutableHandleObject) {
if (d.attrs & jsapi::JSPROP_SETTER as u32) != 0 {
out.set(std::mem::transmute(d.setter));
}
}
/// <https://tc39.es/ecma262/#sec-isaccessordescriptor> /// <https://tc39.es/ecma262/#sec-isaccessordescriptor>
fn is_accessor_descriptor(d: &PropertyDescriptor) -> bool { fn is_accessor_descriptor(d: &PropertyDescriptor) -> bool {
d.attrs & (jsapi::JSPROP_GETTER as u32 | jsapi::JSPROP_SETTER as u32) != 0 d.attrs & (jsapi::JSPROP_GETTER as u32 | jsapi::JSPROP_SETTER as u32) != 0