refactor CGClassConstructHook to use handwritten constructors (#33614)

* extract generated class constructor hook into handwritten functions

Signed-off-by: Gae24 <96017547+Gae24@users.noreply.github.com>

* downcast to window only when it's actually used

Signed-off-by: Gae24 <96017547+Gae24@users.noreply.github.com>

* simplify downcast

Signed-off-by: Gae24 <96017547+Gae24@users.noreply.github.com>

* rename htmlconstructor to constructor, include call_default_constructor in it

Signed-off-by: Gae24 <96017547+Gae24@users.noreply.github.com>

---------

Signed-off-by: Gae24 <96017547+Gae24@users.noreply.github.com>
This commit is contained in:
Gae24 2024-10-09 14:33:44 +02:00 committed by GitHub
parent 3eee02869a
commit 5ba8054b69
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 65 additions and 40 deletions

View file

@ -6228,17 +6228,12 @@ class CGClassConstructHook(CGAbstractExternMethod):
preamble = """let cx = SafeJSContext::from_ptr(cx);
let args = CallArgs::from_vp(vp, argc);
let global = GlobalScope::from_object(JS_CALLEE(*cx, vp).to_object());
"""
if len(self.exposureSet) == 1:
preamble += f"""
let global = DomRoot::downcast::<dom::types::{list(self.exposureSet)[0]}>(global).unwrap();
"""
if self.constructor.isHTMLConstructor():
signatures = self.constructor.signatures()
assert len(signatures) == 1
constructorCall = CGGeneric(
f"""
dom::bindings::htmlconstructor::call_html_constructor::<dom::types::{self.descriptor.name}>(
constructorCall = f"""
call_html_constructor::<dom::types::{self.descriptor.name}>(
cx,
&args,
&global,
@ -6246,34 +6241,39 @@ let global = DomRoot::downcast::<dom::types::{list(self.exposureSet)[0]}>(global
CreateInterfaceObjects,
)
"""
)
else:
ctorName = GetConstructorNameForReporting(self.descriptor, self.constructor)
preamble += f"""
if !args.is_constructing() {{
throw_constructor_without_new(*cx, "{ctorName}");
return false;
}}
rooted!(in(*cx) let mut desired_proto = ptr::null_mut::<JSObject>());
let proto_result = get_desired_proto(
cx,
&args,
PrototypeList::ID::{MakeNativeName(self.descriptor.name)},
CreateInterfaceObjects,
desired_proto.handle_mut(),
);
assert!(proto_result.is_ok());
if proto_result.is_err() {{
return false;
}}
"""
name = self.constructor.identifier.name
nativeName = MakeNativeName(self.descriptor.binaryNameFor(name))
args = ["&global", "Some(desired_proto.handle())", "CanGc::note()"]
constructorCall = CGMethodCall(args, nativeName, True,
self.descriptor, self.constructor)
return CGList([CGGeneric(preamble), constructorCall])
if len(self.exposureSet) == 1:
args = [
f"global.downcast::<dom::types::{list(self.exposureSet)[0]}>().unwrap()",
"Some(desired_proto.handle())",
"CanGc::note()"
]
else:
args = [
"&global",
"Some(desired_proto.handle())",
"CanGc::note()"
]
constructor = CGMethodCall(args, nativeName, True, self.descriptor, self.constructor)
constructorCall = f"""
call_default_constructor(
cx,
&args,
global,
PrototypeList::ID::{MakeNativeName(self.descriptor.name)},
\"{ctorName}\",
CreateInterfaceObjects,
|cx, args, global, desired_proto| {{
{constructor.define()}
}}
)
"""
return CGList([CGGeneric(preamble), CGGeneric(constructorCall)])
class CGClassFinalizeHook(CGAbstractClassHook):

View file

@ -7,6 +7,7 @@ use std::ptr;
use html5ever::interface::QualName;
use html5ever::{local_name, namespace_url, ns, LocalName};
use js::conversions::ToJSValConvertible;
use js::gc::RootedGuard;
use js::glue::{UnwrapObjectDynamic, UnwrapObjectStatic};
use js::jsapi::{CallArgs, CurrentGlobalOrNull, JSAutoRealm, JSObject};
use js::rust::wrappers::{JS_SetPrototype, JS_WrapObject};
@ -40,7 +41,7 @@ use crate::dom::bindings::codegen::Bindings::{
};
use crate::dom::bindings::codegen::PrototypeList;
use crate::dom::bindings::conversions::DerivedFrom;
use crate::dom::bindings::error::{throw_dom_exception, Error};
use crate::dom::bindings::error::{throw_constructor_without_new, throw_dom_exception, Error};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::interface::get_desired_proto;
use crate::dom::bindings::reflector::DomObject;
@ -57,14 +58,14 @@ use crate::script_thread::ScriptThread;
// https://html.spec.whatwg.org/multipage/#htmlconstructor
unsafe fn html_constructor(
cx: JSContext,
window: &Window,
global: &GlobalScope,
call_args: &CallArgs,
check_type: fn(&Element) -> bool,
proto_id: PrototypeList::ID,
creator: unsafe fn(SafeJSContext, HandleObject, *mut ProtoOrIfaceArray),
) -> Result<(), ()> {
let window = global.downcast::<Window>().unwrap();
let document = window.Document();
let global = window.upcast::<GlobalScope>();
// Step 1
let registry = window.CustomElements();
@ -377,10 +378,10 @@ pub fn push_new_element_queue() {
ScriptThread::push_new_element_queue();
}
pub(crate) unsafe fn call_html_constructor<T: DerivedFrom<Element> + DomObject>(
pub unsafe fn call_html_constructor<T: DerivedFrom<Element> + DomObject>(
cx: JSContext,
args: &CallArgs,
global: &Window,
global: &GlobalScope,
proto_id: PrototypeList::ID,
creator: unsafe fn(SafeJSContext, HandleObject, *mut ProtoOrIfaceArray),
) -> bool {
@ -398,3 +399,26 @@ pub(crate) unsafe fn call_html_constructor<T: DerivedFrom<Element> + DomObject>(
)
.is_ok()
}
pub unsafe fn call_default_constructor(
cx: JSContext,
args: &CallArgs,
global: DomRoot<GlobalScope>,
proto_id: PrototypeList::ID,
ctor_name: &str,
creator: unsafe fn(JSContext, HandleObject, *mut ProtoOrIfaceArray),
constructor: impl FnOnce(JSContext, &CallArgs, &GlobalScope, RootedGuard<*mut JSObject>) -> bool,
) -> bool {
if !args.is_constructing() {
throw_constructor_without_new(*cx, ctor_name);
return false;
}
rooted!(in(*cx) let mut desired_proto = ptr::null_mut::<JSObject>());
let proto_result = get_desired_proto(cx, args, proto_id, creator, desired_proto.handle_mut());
if proto_result.is_err() {
return false;
}
constructor(cx, args, &global, desired_proto)
}

View file

@ -103,6 +103,10 @@ pub mod module {
pub use crate::dom::bindings::codegen::Bindings::EventTargetBinding::EventTarget_Binding;
pub use crate::dom::bindings::codegen::{InterfaceObjectMap, PrototypeList, RegisterBindings};
pub use crate::dom::bindings::constant::{ConstantSpec, ConstantVal};
pub use crate::dom::bindings::constructor::{
call_default_constructor, call_html_constructor, pop_current_element_queue,
push_new_element_queue,
};
pub use crate::dom::bindings::conversions::{
is_array_like, jsid_to_string, native_from_handlevalue, native_from_object_static,
IDLInterface, StringificationBehavior, ToJSValConvertible, DOM_OBJECT_SLOT,
@ -112,9 +116,6 @@ pub mod module {
finalize_common, finalize_global, finalize_weak_referenceable,
};
pub use crate::dom::bindings::guard::{Condition, Guard};
pub use crate::dom::bindings::htmlconstructor::{
pop_current_element_queue, push_new_element_queue,
};
pub use crate::dom::bindings::inheritance::Castable;
pub use crate::dom::bindings::interface::{
create_callback_interface_object, create_global_object, create_interface_prototype_object,

View file

@ -138,11 +138,11 @@ pub mod buffer_source;
pub mod callback;
pub mod cell;
pub mod constant;
pub mod constructor;
pub mod conversions;
pub mod error;
pub mod finalize;
pub mod guard;
pub mod htmlconstructor;
pub mod import;
pub mod inheritance;
pub mod interface;