script_bindings/
constructor.rs1use std::ffi::CStr;
6use std::ptr;
7
8use js::gc::RootedGuard;
9use js::jsapi::{CallArgs, JSFunctionSpec, JSObject, JSPropertySpec};
10use js::rooted;
11use js::rust::HandleObject;
12use js::rust::wrappers2::{GetRealmObjectPrototype, JS_NewPlainObject};
13
14use crate::DomTypes;
15use crate::codegen::PrototypeList::{self};
16use crate::constant::ConstantSpec;
17use crate::error::throw_constructor_without_new;
18use crate::guard::Guard;
19use crate::interface::{create_callback_interface_object, get_desired_proto};
20use crate::js::rust::GCMethods;
21use crate::namespace::{NamespaceObjectClass, create_namespace_object};
22use crate::utils::ProtoOrIfaceArray;
23
24pub(crate) unsafe fn call_default_constructor<D: crate::DomTypes>(
25 cx: &mut js::context::JSContext,
26 args: &CallArgs,
27 global: &D::GlobalScope,
28 proto_id: PrototypeList::ID,
29 ctor_name: &str,
30 creator: unsafe fn(&mut js::context::JSContext, HandleObject, *mut ProtoOrIfaceArray),
31 constructor: impl FnOnce(
32 &mut js::context::JSContext,
33 &CallArgs,
34 &D::GlobalScope,
35 HandleObject,
36 ) -> bool,
37) -> bool {
38 if !args.is_constructing() {
39 throw_constructor_without_new(cx.into(), ctor_name);
40 return false;
41 }
42
43 rooted!(&in(cx) let mut desired_proto = ptr::null_mut::<JSObject>());
44 let proto_result = get_desired_proto(cx, args, proto_id, creator, desired_proto.handle_mut());
45 if proto_result.is_err() {
46 return false;
47 }
48
49 constructor(cx, args, global, desired_proto.handle())
50}
51
52unsafe fn post_barrier(
54 constructor: PrototypeList::Constructor,
55 cache: *mut ProtoOrIfaceArray,
56 object: RootedGuard<'_, *mut JSObject>,
57) {
58 unsafe {
59 assert!((*cache)[constructor as usize].is_null());
60 (*cache)[constructor as usize] = object.get();
61 <*mut JSObject>::post_barrier(
62 (*cache).as_mut_ptr().offset(constructor as isize),
63 ptr::null_mut(),
64 object.get(),
65 );
66 }
67}
68
69pub(crate) struct NamespaceInit {
70 pub(crate) is_proto_hack: bool,
71 pub(crate) static_methods: &'static [Guard<&'static [JSFunctionSpec]>],
72 pub(crate) namespace_object_class: &'static NamespaceObjectClass,
73 pub(crate) constructor_name: PrototypeList::Constructor,
74 pub(crate) constants: &'static [Guard<&'static [ConstantSpec]>],
75 pub(crate) attributes: &'static [Guard<&'static [JSPropertySpec]>],
76 pub(crate) name: &'static CStr,
77}
78
79pub(crate) struct CallbackInit {
80 pub(crate) constants: &'static [Guard<&'static [ConstantSpec]>],
81 pub(crate) constructor_name: PrototypeList::Constructor,
82 pub(crate) name: &'static CStr,
83}
84
85pub(crate) unsafe fn create_namespace_interface_objects<D: DomTypes>(
87 cx: &mut js::context::JSContext,
88 init: NamespaceInit,
89 global: HandleObject,
90 cache: *mut ProtoOrIfaceArray,
91) {
92 rooted!(&in(cx) let mut proto: *mut JSObject = std::ptr::null_mut());
93 unsafe {
94 if init.is_proto_hack {
95 proto.set(GetRealmObjectPrototype(cx))
96 } else {
97 proto.set(JS_NewPlainObject(cx))
98 };
99 }
100
101 assert!(!proto.is_null());
102 rooted!(&in(cx) let mut namespace = ptr::null_mut::<JSObject>());
103 create_namespace_object::<D>(
104 cx,
105 global,
106 proto.handle(),
107 init.namespace_object_class,
108 init.static_methods,
109 init.attributes,
110 init.constants,
111 init.name,
112 namespace.handle_mut(),
113 );
114 assert!(!namespace.is_null());
115
116 unsafe {
117 post_barrier(init.constructor_name, cache, namespace);
118 }
119}
120
121pub(crate) unsafe fn create_callback_interface_objects<D: DomTypes>(
123 cx: &mut js::context::JSContext,
124 init: CallbackInit,
125 global: HandleObject,
126 cache: *mut ProtoOrIfaceArray,
127) {
128 rooted!(&in(cx) let mut interface = ptr::null_mut::<JSObject>());
129 create_callback_interface_object::<D>(
130 cx,
131 global,
132 init.constants,
133 init.name,
134 interface.handle_mut(),
135 );
136 unsafe {
137 post_barrier(init.constructor_name, cache, interface);
138 }
139}