mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
Create two-phase initialization for generated JS engine bindings (#34366)
* script: Generate a runtime initialization for static JS binding information. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Replace dummy static initializers with OnceLock. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Fix clippy warnings. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Only initialize statics for DOM interfaces with interface objects. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Remove one unnecessary Box::leak usage. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * Tidy. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Hide thread-unsafe OnceLock usage inside of a wrapper type. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Mark ThreadUnsafeOnceLock::get unsafe. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * script: Simplify ThreadUnsafeOnceLock internals. Signed-off-by: Josh Matthews <josh@joshmatthews.net> --------- Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
parent
faefed9869
commit
3515b83a95
5 changed files with 296 additions and 108 deletions
|
@ -1644,7 +1644,7 @@ class PropertyDefiner:
|
||||||
assert len(array) != 0
|
assert len(array) != 0
|
||||||
specs = []
|
specs = []
|
||||||
prefableSpecs = []
|
prefableSpecs = []
|
||||||
prefableTemplate = ' Guard::new(%s, %s[%d])'
|
prefableTemplate = ' Guard::new(%s, (%s)[%d])'
|
||||||
origTemplate = specTemplate
|
origTemplate = specTemplate
|
||||||
if isinstance(specTemplate, str):
|
if isinstance(specTemplate, str):
|
||||||
specTemplate = lambda _: origTemplate # noqa
|
specTemplate = lambda _: origTemplate # noqa
|
||||||
|
@ -1654,22 +1654,29 @@ class PropertyDefiner:
|
||||||
if specTerminator:
|
if specTerminator:
|
||||||
currentSpecs.append(specTerminator)
|
currentSpecs.append(specTerminator)
|
||||||
joinedCurrentSpecs = ',\n'.join(currentSpecs)
|
joinedCurrentSpecs = ',\n'.join(currentSpecs)
|
||||||
specs.append(f"&[\n{joinedCurrentSpecs}]\n")
|
specs.append(f"&Box::leak(Box::new([\n{joinedCurrentSpecs}]))[..]\n")
|
||||||
conds = ','.join(cond) if isinstance(cond, list) else cond
|
conds = ','.join(cond) if isinstance(cond, list) else cond
|
||||||
prefableSpecs.append(
|
prefableSpecs.append(
|
||||||
prefableTemplate % (f"&[{conds}]", f"{name}_specs", len(specs) - 1)
|
prefableTemplate % (f"&[{conds}]", f"unsafe {{ {name}_specs.get() }}", len(specs) - 1)
|
||||||
)
|
)
|
||||||
|
|
||||||
joinedSpecs = ',\n'.join(specs)
|
joinedSpecs = ',\n'.join(specs)
|
||||||
specsArray = (f"const {name}_specs: &[&[{specType}]] = &[\n"
|
specsArray = f"static {name}_specs: ThreadUnsafeOnceLock<&[&[{specType}]]> = ThreadUnsafeOnceLock::new();\n"
|
||||||
f"{joinedSpecs}\n"
|
|
||||||
"];\n")
|
initSpecs = f"""
|
||||||
|
pub(crate) fn init_{name}_specs() {{
|
||||||
|
{name}_specs.set(Box::leak(Box::new([{joinedSpecs}])));
|
||||||
|
}}"""
|
||||||
|
|
||||||
joinedPrefableSpecs = ',\n'.join(prefableSpecs)
|
joinedPrefableSpecs = ',\n'.join(prefableSpecs)
|
||||||
prefArray = (f"const {name}: &[Guard<&[{specType}]>] = &[\n"
|
prefArray = f"static {name}: ThreadUnsafeOnceLock<&[Guard<&[{specType}]>]> = ThreadUnsafeOnceLock::new();\n"
|
||||||
f"{joinedPrefableSpecs}\n"
|
|
||||||
"];\n")
|
initPrefs = f"""
|
||||||
return f"{specsArray}{prefArray}"
|
pub(crate) fn init_{name}_prefs() {{
|
||||||
|
{name}.set(Box::leak(Box::new([{joinedPrefableSpecs}])));
|
||||||
|
}}"""
|
||||||
|
|
||||||
|
return f"{specsArray}{initSpecs}{prefArray}{initPrefs}"
|
||||||
|
|
||||||
def generateUnguardedArray(self, array, name, specTemplate, specTerminator,
|
def generateUnguardedArray(self, array, name, specTemplate, specTerminator,
|
||||||
specType, getCondition, getDataTuple):
|
specType, getCondition, getDataTuple):
|
||||||
|
@ -1692,12 +1699,12 @@ class PropertyDefiner:
|
||||||
specsArray.append(specTerminator)
|
specsArray.append(specTerminator)
|
||||||
|
|
||||||
joinedSpecs = ',\n'.join(specsArray)
|
joinedSpecs = ',\n'.join(specsArray)
|
||||||
return dedent(
|
initialSpecs = f"static {name}: ThreadUnsafeOnceLock<&[{specType}]> = ThreadUnsafeOnceLock::new();\n"
|
||||||
f"""
|
initSpecs = f"""
|
||||||
const {name}: &[{specType}] = &[
|
pub(crate) fn init_{name}() {{
|
||||||
{joinedSpecs}
|
{name}.set(Box::leak(Box::new([{joinedSpecs}])));
|
||||||
];
|
}}"""
|
||||||
""")
|
return dedent(f"{initialSpecs}{initSpecs}")
|
||||||
|
|
||||||
|
|
||||||
# The length of a method is the minimum of the lengths of the
|
# The length of a method is the minimum of the lengths of the
|
||||||
|
@ -1850,7 +1857,7 @@ class MethodDefiner(PropertyDefiner):
|
||||||
accessor = "None"
|
accessor = "None"
|
||||||
jitinfo = "ptr::null()"
|
jitinfo = "ptr::null()"
|
||||||
else:
|
else:
|
||||||
selfHostedName = "0 as *const libc::c_char"
|
selfHostedName = "ptr::null()"
|
||||||
if m.get("methodInfo", True):
|
if m.get("methodInfo", True):
|
||||||
if m.get("returnsPromise", False):
|
if m.get("returnsPromise", False):
|
||||||
exceptionToRejection = "true"
|
exceptionToRejection = "true"
|
||||||
|
@ -1861,11 +1868,12 @@ class MethodDefiner(PropertyDefiner):
|
||||||
# easy to tell whether the methodinfo is a JSJitInfo or
|
# easy to tell whether the methodinfo is a JSJitInfo or
|
||||||
# a JSTypedMethodJitInfo here. The compiler knows, though,
|
# a JSTypedMethodJitInfo here. The compiler knows, though,
|
||||||
# so let it do the work.
|
# so let it do the work.
|
||||||
jitinfo = f"&{identifier}_methodinfo as *const _ as *const JSJitInfo"
|
jitinfo = (f"unsafe {{ {identifier}_methodinfo.get() }}"
|
||||||
|
" as *const _ as *const JSJitInfo")
|
||||||
accessor = f"Some(generic_method::<{exceptionToRejection}>)"
|
accessor = f"Some(generic_method::<{exceptionToRejection}>)"
|
||||||
else:
|
else:
|
||||||
if m.get("returnsPromise", False):
|
if m.get("returnsPromise", False):
|
||||||
jitinfo = f"&{m.get('nativeName', m['name'])}_methodinfo"
|
jitinfo = f"unsafe {{ {m.get('nativeName', m['name'])}_methodinfo.get() }}"
|
||||||
accessor = "Some(generic_static_promise_method)"
|
accessor = "Some(generic_static_promise_method)"
|
||||||
else:
|
else:
|
||||||
jitinfo = "ptr::null()"
|
jitinfo = "ptr::null()"
|
||||||
|
@ -1956,11 +1964,11 @@ class AttrDefiner(PropertyDefiner):
|
||||||
attr = attr['attr']
|
attr = attr['attr']
|
||||||
|
|
||||||
if self.crossorigin and not attr.getExtendedAttribute("CrossOriginReadable"):
|
if self.crossorigin and not attr.getExtendedAttribute("CrossOriginReadable"):
|
||||||
return "JSNativeWrapper { op: None, info: 0 as *const JSJitInfo }"
|
return "JSNativeWrapper { op: None, info: ptr::null() }"
|
||||||
|
|
||||||
if self.static:
|
if self.static:
|
||||||
accessor = f'get_{self.descriptor.internalNameFor(attr.identifier.name)}'
|
accessor = f'get_{self.descriptor.internalNameFor(attr.identifier.name)}'
|
||||||
jitinfo = "0 as *const JSJitInfo"
|
jitinfo = "ptr::null()"
|
||||||
else:
|
else:
|
||||||
if attr.type.isPromise():
|
if attr.type.isPromise():
|
||||||
exceptionToRejection = "true"
|
exceptionToRejection = "true"
|
||||||
|
@ -1970,7 +1978,8 @@ class AttrDefiner(PropertyDefiner):
|
||||||
accessor = f"generic_lenient_getter::<{exceptionToRejection}>"
|
accessor = f"generic_lenient_getter::<{exceptionToRejection}>"
|
||||||
else:
|
else:
|
||||||
accessor = f"generic_getter::<{exceptionToRejection}>"
|
accessor = f"generic_getter::<{exceptionToRejection}>"
|
||||||
jitinfo = f"&{self.descriptor.internalNameFor(attr.identifier.name)}_getterinfo"
|
internalName = self.descriptor.internalNameFor(attr.identifier.name)
|
||||||
|
jitinfo = f"unsafe {{ {internalName}_getterinfo.get() }}"
|
||||||
|
|
||||||
return f"JSNativeWrapper {{ op: Some({accessor}), info: {jitinfo} }}"
|
return f"JSNativeWrapper {{ op: Some({accessor}), info: {jitinfo} }}"
|
||||||
|
|
||||||
|
@ -1981,17 +1990,18 @@ class AttrDefiner(PropertyDefiner):
|
||||||
or (attr.readonly
|
or (attr.readonly
|
||||||
and not attr.getExtendedAttribute("PutForwards")
|
and not attr.getExtendedAttribute("PutForwards")
|
||||||
and not attr.getExtendedAttribute("Replaceable"))):
|
and not attr.getExtendedAttribute("Replaceable"))):
|
||||||
return "JSNativeWrapper { op: None, info: 0 as *const JSJitInfo }"
|
return "JSNativeWrapper { op: None, info: ptr::null() }"
|
||||||
|
|
||||||
if self.static:
|
if self.static:
|
||||||
accessor = f'set_{self.descriptor.internalNameFor(attr.identifier.name)}'
|
accessor = f'set_{self.descriptor.internalNameFor(attr.identifier.name)}'
|
||||||
jitinfo = "0 as *const JSJitInfo"
|
jitinfo = "ptr::null()"
|
||||||
else:
|
else:
|
||||||
if attr.hasLegacyLenientThis():
|
if attr.hasLegacyLenientThis():
|
||||||
accessor = "generic_lenient_setter"
|
accessor = "generic_lenient_setter"
|
||||||
else:
|
else:
|
||||||
accessor = "generic_setter"
|
accessor = "generic_setter"
|
||||||
jitinfo = f"&{self.descriptor.internalNameFor(attr.identifier.name)}_setterinfo"
|
internalName = self.descriptor.internalNameFor(attr.identifier.name)
|
||||||
|
jitinfo = f"unsafe {{ {internalName}_setterinfo.get() }}"
|
||||||
|
|
||||||
return f"JSNativeWrapper {{ op: Some({accessor}), info: {jitinfo} }}"
|
return f"JSNativeWrapper {{ op: Some({accessor}), info: {jitinfo} }}"
|
||||||
|
|
||||||
|
@ -2345,7 +2355,7 @@ def DOMClass(descriptor):
|
||||||
# padding.
|
# padding.
|
||||||
protoList.extend(['PrototypeList::ID::Last'] * (descriptor.config.maxProtoChainLength - len(protoList)))
|
protoList.extend(['PrototypeList::ID::Last'] * (descriptor.config.maxProtoChainLength - len(protoList)))
|
||||||
prototypeChainString = ', '.join(protoList)
|
prototypeChainString = ', '.join(protoList)
|
||||||
mallocSizeOf = f'malloc_size_of_including_raw_self::<{descriptor.concreteType}>'
|
mallocSizeOf = f"malloc_size_of_including_raw_self::<{descriptor.concreteType}>"
|
||||||
if descriptor.isGlobal():
|
if descriptor.isGlobal():
|
||||||
globals_ = camel_to_upper_snake(descriptor.name)
|
globals_ = camel_to_upper_snake(descriptor.name)
|
||||||
else:
|
else:
|
||||||
|
@ -2393,32 +2403,41 @@ class CGDOMJSClass(CGThing):
|
||||||
elif self.descriptor.weakReferenceable:
|
elif self.descriptor.weakReferenceable:
|
||||||
args["slots"] = "2"
|
args["slots"] = "2"
|
||||||
return f"""
|
return f"""
|
||||||
static CLASS_OPS: JSClassOps = JSClassOps {{
|
static CLASS_OPS: ThreadUnsafeOnceLock<JSClassOps> = ThreadUnsafeOnceLock::new();
|
||||||
addProperty: None,
|
|
||||||
delProperty: None,
|
|
||||||
enumerate: None,
|
|
||||||
newEnumerate: {args['enumerateHook']},
|
|
||||||
resolve: {args['resolveHook']},
|
|
||||||
mayResolve: None,
|
|
||||||
finalize: Some({args['finalizeHook']}),
|
|
||||||
call: None,
|
|
||||||
construct: None,
|
|
||||||
trace: Some({args['traceHook']}),
|
|
||||||
}};
|
|
||||||
|
|
||||||
static Class: DOMJSClass = DOMJSClass {{
|
pub(crate) fn init_class_ops() {{
|
||||||
base: JSClass {{
|
CLASS_OPS.set(JSClassOps {{
|
||||||
name: {args['name']},
|
addProperty: None,
|
||||||
flags: JSCLASS_IS_DOMJSCLASS | {args['flags']} |
|
delProperty: None,
|
||||||
((({args['slots']}) & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT)
|
enumerate: None,
|
||||||
/* JSCLASS_HAS_RESERVED_SLOTS({args['slots']}) */,
|
newEnumerate: {args['enumerateHook']},
|
||||||
cOps: &CLASS_OPS,
|
resolve: {args['resolveHook']},
|
||||||
spec: ptr::null(),
|
mayResolve: None,
|
||||||
ext: ptr::null(),
|
finalize: Some({args['finalizeHook']}),
|
||||||
oOps: ptr::null(),
|
call: None,
|
||||||
}},
|
construct: None,
|
||||||
dom_class: {args['domClass']},
|
trace: Some({args['traceHook']}),
|
||||||
}};
|
}});
|
||||||
|
}}
|
||||||
|
|
||||||
|
static Class: ThreadUnsafeOnceLock<DOMJSClass> = ThreadUnsafeOnceLock::new();
|
||||||
|
|
||||||
|
pub(crate) fn init_domjs_class() {{
|
||||||
|
init_class_ops();
|
||||||
|
Class.set(DOMJSClass {{
|
||||||
|
base: JSClass {{
|
||||||
|
name: {args['name']},
|
||||||
|
flags: JSCLASS_IS_DOMJSCLASS | {args['flags']} |
|
||||||
|
((({args['slots']}) & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT)
|
||||||
|
/* JSCLASS_HAS_RESERVED_SLOTS({args['slots']}) */,
|
||||||
|
cOps: unsafe {{ CLASS_OPS.get() }},
|
||||||
|
spec: ptr::null(),
|
||||||
|
ext: ptr::null(),
|
||||||
|
oOps: ptr::null(),
|
||||||
|
}},
|
||||||
|
dom_class: {args['domClass']},
|
||||||
|
}});
|
||||||
|
}}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@ -2490,7 +2509,7 @@ static PrototypeClass: JSClass = JSClass {{
|
||||||
flags:
|
flags:
|
||||||
// JSCLASS_HAS_RESERVED_SLOTS()
|
// JSCLASS_HAS_RESERVED_SLOTS()
|
||||||
({slotCountStr} ) << JSCLASS_RESERVED_SLOTS_SHIFT,
|
({slotCountStr} ) << JSCLASS_RESERVED_SLOTS_SHIFT,
|
||||||
cOps: 0 as *const _,
|
cOps: ptr::null(),
|
||||||
spec: ptr::null(),
|
spec: ptr::null(),
|
||||||
ext: ptr::null(),
|
ext: ptr::null(),
|
||||||
oOps: ptr::null(),
|
oOps: ptr::null(),
|
||||||
|
@ -2523,8 +2542,10 @@ static NAMESPACE_OBJECT_CLASS: NamespaceObjectClass = unsafe {{
|
||||||
name = self.descriptor.interface.identifier.name
|
name = self.descriptor.interface.identifier.name
|
||||||
representation = f'b"function {name}() {{\\n [native code]\\n}}"'
|
representation = f'b"function {name}() {{\\n [native code]\\n}}"'
|
||||||
return f"""
|
return f"""
|
||||||
static INTERFACE_OBJECT_CLASS: NonCallbackInterfaceObjectClass =
|
static INTERFACE_OBJECT_CLASS: ThreadUnsafeOnceLock<NonCallbackInterfaceObjectClass> = ThreadUnsafeOnceLock::new();
|
||||||
NonCallbackInterfaceObjectClass::new(
|
|
||||||
|
pub(crate) fn init_interface_object() {{
|
||||||
|
INTERFACE_OBJECT_CLASS.set(NonCallbackInterfaceObjectClass::new(
|
||||||
{{
|
{{
|
||||||
// Intermediate `const` because as of nightly-2018-10-05,
|
// Intermediate `const` because as of nightly-2018-10-05,
|
||||||
// rustc is conservative in promotion to `'static` of the return values of `const fn`s:
|
// rustc is conservative in promotion to `'static` of the return values of `const fn`s:
|
||||||
|
@ -2535,7 +2556,9 @@ static INTERFACE_OBJECT_CLASS: NonCallbackInterfaceObjectClass =
|
||||||
}},
|
}},
|
||||||
{representation},
|
{representation},
|
||||||
PrototypeList::ID::{name},
|
PrototypeList::ID::{name},
|
||||||
{self.descriptor.prototypeDepth});
|
{self.descriptor.prototypeDepth},
|
||||||
|
));
|
||||||
|
}}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@ -2971,7 +2994,7 @@ def InitLegacyUnforgeablePropertiesOnHolder(descriptor, properties):
|
||||||
]
|
]
|
||||||
for template, array in unforgeableMembers:
|
for template, array in unforgeableMembers:
|
||||||
if array.length() > 0:
|
if array.length() > 0:
|
||||||
unforgeables.append(CGGeneric(template % array.variableName()))
|
unforgeables.append(CGGeneric(template % f"unsafe {{ {array.variableName()}.get() }}"))
|
||||||
return CGList(unforgeables, "\n")
|
return CGList(unforgeables, "\n")
|
||||||
|
|
||||||
|
|
||||||
|
@ -3072,7 +3095,7 @@ if let Some(given) = given_proto {
|
||||||
}
|
}
|
||||||
rooted!(in(*cx) let obj = JS_NewObjectWithGivenProto(
|
rooted!(in(*cx) let obj = JS_NewObjectWithGivenProto(
|
||||||
*cx,
|
*cx,
|
||||||
&Class.base,
|
&Class.get().base,
|
||||||
proto.handle(),
|
proto.handle(),
|
||||||
));
|
));
|
||||||
assert!(!obj.is_null());
|
assert!(!obj.is_null());
|
||||||
|
@ -3129,7 +3152,7 @@ class CGWrapGlobalMethod(CGAbstractMethod):
|
||||||
("define_guarded_methods", self.properties.methods),
|
("define_guarded_methods", self.properties.methods),
|
||||||
("define_guarded_constants", self.properties.consts)
|
("define_guarded_constants", self.properties.consts)
|
||||||
]
|
]
|
||||||
members = [f"{function}(cx, obj.handle(), {array.variableName()}, obj.handle());"
|
members = [f"{function}(cx, obj.handle(), {array.variableName()}.get(), obj.handle());"
|
||||||
for (function, array) in pairs if array.length() > 0]
|
for (function, array) in pairs if array.length() > 0]
|
||||||
membersStr = "\n".join(members)
|
membersStr = "\n".join(members)
|
||||||
|
|
||||||
|
@ -3140,7 +3163,7 @@ let origin = (*raw.as_ptr()).upcast::<GlobalScope>().origin();
|
||||||
rooted!(in(*cx) let mut obj = ptr::null_mut::<JSObject>());
|
rooted!(in(*cx) let mut obj = ptr::null_mut::<JSObject>());
|
||||||
create_global_object(
|
create_global_object(
|
||||||
cx,
|
cx,
|
||||||
&Class.base,
|
&Class.get().base,
|
||||||
raw.as_ptr() as *const libc::c_void,
|
raw.as_ptr() as *const libc::c_void,
|
||||||
_trace,
|
_trace,
|
||||||
obj.handle_mut(),
|
obj.handle_mut(),
|
||||||
|
@ -3189,7 +3212,7 @@ class CGIDLInterface(CGThing):
|
||||||
elif self.descriptor.proxy:
|
elif self.descriptor.proxy:
|
||||||
check = "ptr::eq(class, &Class)"
|
check = "ptr::eq(class, &Class)"
|
||||||
else:
|
else:
|
||||||
check = "ptr::eq(class, &Class.dom_class)"
|
check = "ptr::eq(class, unsafe { &Class.get().dom_class })"
|
||||||
return f"""
|
return f"""
|
||||||
impl IDLInterface for {name} {{
|
impl IDLInterface for {name} {{
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -3308,11 +3331,14 @@ class CGCrossOriginProperties(CGThing):
|
||||||
def define(self):
|
def define(self):
|
||||||
return f"{self.methods}{self.attributes}" + dedent(
|
return f"{self.methods}{self.attributes}" + dedent(
|
||||||
"""
|
"""
|
||||||
const CROSS_ORIGIN_PROPERTIES: proxyhandler::CrossOriginProperties =
|
static CROSS_ORIGIN_PROPERTIES: ThreadUnsafeOnceLock<CrossOriginProperties> = ThreadUnsafeOnceLock::new();
|
||||||
proxyhandler::CrossOriginProperties {
|
|
||||||
attributes: sCrossOriginAttributes,
|
pub(crate) fn init_cross_origin_properties() {
|
||||||
methods: sCrossOriginMethods,
|
CROSS_ORIGIN_PROPERTIES.set(CrossOriginProperties {
|
||||||
};
|
attributes: unsafe { sCrossOriginAttributes.get() },
|
||||||
|
methods: unsafe { sCrossOriginMethods.get() },
|
||||||
|
});
|
||||||
|
}
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -3387,11 +3413,11 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
||||||
else:
|
else:
|
||||||
proto = "JS_NewPlainObject(*cx)"
|
proto = "JS_NewPlainObject(*cx)"
|
||||||
if self.properties.static_methods.length():
|
if self.properties.static_methods.length():
|
||||||
methods = self.properties.static_methods.variableName()
|
methods = f"{self.properties.static_methods.variableName()}.get()"
|
||||||
else:
|
else:
|
||||||
methods = "&[]"
|
methods = "&[]"
|
||||||
if self.descriptor.interface.hasConstants():
|
if self.descriptor.interface.hasConstants():
|
||||||
constants = "sConstants"
|
constants = "sConstants.get()"
|
||||||
else:
|
else:
|
||||||
constants = "&[]"
|
constants = "&[]"
|
||||||
id = MakeNativeName(name)
|
id = MakeNativeName(name)
|
||||||
|
@ -3413,7 +3439,7 @@ assert!((*cache)[PrototypeList::Constructor::{id} as usize].is_null());
|
||||||
cName = str_to_cstr(name)
|
cName = str_to_cstr(name)
|
||||||
return CGGeneric(f"""
|
return CGGeneric(f"""
|
||||||
rooted!(in(*cx) let mut interface = ptr::null_mut::<JSObject>());
|
rooted!(in(*cx) let mut interface = ptr::null_mut::<JSObject>());
|
||||||
create_callback_interface_object(cx, global, sConstants, {cName}, interface.handle_mut());
|
create_callback_interface_object(cx, global, sConstants.get(), {cName}, interface.handle_mut());
|
||||||
assert!(!interface.is_null());
|
assert!(!interface.is_null());
|
||||||
assert!((*cache)[PrototypeList::Constructor::{name} as usize].is_null());
|
assert!((*cache)[PrototypeList::Constructor::{name} as usize].is_null());
|
||||||
(*cache)[PrototypeList::Constructor::{name} as usize] = interface.get();
|
(*cache)[PrototypeList::Constructor::{name} as usize] = interface.get();
|
||||||
|
@ -3456,7 +3482,7 @@ assert!(!prototype_proto.is_null());"""))
|
||||||
for arrayName in self.properties.arrayNames():
|
for arrayName in self.properties.arrayNames():
|
||||||
array = getattr(self.properties, arrayName)
|
array = getattr(self.properties, arrayName)
|
||||||
if array.length():
|
if array.length():
|
||||||
properties[arrayName] = array.variableName()
|
properties[arrayName] = f"{array.variableName()}.get()"
|
||||||
else:
|
else:
|
||||||
properties[arrayName] = "&[]"
|
properties[arrayName] = "&[]"
|
||||||
|
|
||||||
|
@ -3512,7 +3538,7 @@ rooted!(in(*cx) let mut interface = ptr::null_mut::<JSObject>());
|
||||||
create_noncallback_interface_object(cx,
|
create_noncallback_interface_object(cx,
|
||||||
global,
|
global,
|
||||||
interface_proto.handle(),
|
interface_proto.handle(),
|
||||||
&INTERFACE_OBJECT_CLASS,
|
INTERFACE_OBJECT_CLASS.get(),
|
||||||
{properties['static_methods']},
|
{properties['static_methods']},
|
||||||
{properties['static_attrs']},
|
{properties['static_attrs']},
|
||||||
{properties['consts']},
|
{properties['consts']},
|
||||||
|
@ -3614,7 +3640,7 @@ assert!((*cache)[PrototypeList::Constructor::{properties['id']} as usize].is_nul
|
||||||
holderClass = "ptr::null()"
|
holderClass = "ptr::null()"
|
||||||
holderProto = "HandleObject::null()"
|
holderProto = "HandleObject::null()"
|
||||||
else:
|
else:
|
||||||
holderClass = "&Class.base as *const JSClass"
|
holderClass = "&Class.get().base as *const JSClass"
|
||||||
holderProto = "prototype.handle()"
|
holderProto = "prototype.handle()"
|
||||||
code.append(CGGeneric(f"""
|
code.append(CGGeneric(f"""
|
||||||
rooted!(in(*cx) let mut unforgeable_holder = ptr::null_mut::<JSObject>());
|
rooted!(in(*cx) let mut unforgeable_holder = ptr::null_mut::<JSObject>());
|
||||||
|
@ -4482,7 +4508,7 @@ class CGMemberJITInfo(CGThing):
|
||||||
"""
|
"""
|
||||||
JSJitInfo {
|
JSJitInfo {
|
||||||
__bindgen_anon_1: JSJitInfo__bindgen_ty_1 {
|
__bindgen_anon_1: JSJitInfo__bindgen_ty_1 {
|
||||||
${opKind}: Some(${opName})
|
${opKind}: ${opValue}
|
||||||
},
|
},
|
||||||
__bindgen_anon_2: JSJitInfo__bindgen_ty_2 {
|
__bindgen_anon_2: JSJitInfo__bindgen_ty_2 {
|
||||||
protoID: PrototypeList::ID::${name} as u16,
|
protoID: PrototypeList::ID::${name} as u16,
|
||||||
|
@ -4505,7 +4531,7 @@ class CGMemberJITInfo(CGThing):
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
""",
|
""",
|
||||||
opName=opName,
|
opValue=f"Some({opName})",
|
||||||
name=self.descriptor.name,
|
name=self.descriptor.name,
|
||||||
depth=self.descriptor.interface.inheritanceDepth(),
|
depth=self.descriptor.interface.inheritanceDepth(),
|
||||||
opType=opType,
|
opType=opType,
|
||||||
|
@ -4531,17 +4557,26 @@ class CGMemberJITInfo(CGThing):
|
||||||
return fill(
|
return fill(
|
||||||
"""
|
"""
|
||||||
$*{argTypesDecl}
|
$*{argTypesDecl}
|
||||||
const ${infoName}: JSTypedMethodJitInfo = JSTypedMethodJitInfo {
|
static ${infoName}: ThreadUnsafeOnceLock<JSTypedMethodJitInfo> = ThreadUnsafeOnceLock::new();
|
||||||
base: ${jitInfo},
|
|
||||||
argTypes: &${argTypes} as *const _ as *const JSJitInfo_ArgType,
|
pub(crate) fn init_${infoName}() {
|
||||||
};
|
${infoName}.set(JSTypedMethodJitInfo {
|
||||||
|
base: ${jitInfoInit},
|
||||||
|
argTypes: &${argTypes} as *const _ as *const JSJitInfo_ArgType,
|
||||||
|
});
|
||||||
|
}
|
||||||
""",
|
""",
|
||||||
argTypesDecl=argTypesDecl,
|
argTypesDecl=argTypesDecl,
|
||||||
infoName=infoName,
|
infoName=infoName,
|
||||||
jitInfo=indent(jitInfoInitializer(True)),
|
jitInfoInit=indent(jitInfoInitializer(True)),
|
||||||
argTypes=argTypes)
|
argTypes=argTypes)
|
||||||
|
|
||||||
return f"\nconst {infoName}: JSJitInfo = {jitInfoInitializer(False)};\n"
|
return f"""
|
||||||
|
static {infoName}: ThreadUnsafeOnceLock<JSJitInfo> = ThreadUnsafeOnceLock::new();
|
||||||
|
|
||||||
|
pub(crate) fn init_{infoName}() {{
|
||||||
|
{infoName}.set({jitInfoInitializer(False)});
|
||||||
|
}}"""
|
||||||
|
|
||||||
def define(self):
|
def define(self):
|
||||||
if self.member.isAttr():
|
if self.member.isAttr():
|
||||||
|
@ -4815,30 +4850,34 @@ class CGStaticMethodJitinfo(CGGeneric):
|
||||||
CGGeneric.__init__(
|
CGGeneric.__init__(
|
||||||
self,
|
self,
|
||||||
f"""
|
f"""
|
||||||
const {method.identifier.name}_methodinfo: JSJitInfo = JSJitInfo {{
|
static {method.identifier.name}_methodinfo: ThreadUnsafeOnceLock<JSJitInfo> = ThreadUnsafeOnceLock::new();
|
||||||
__bindgen_anon_1: JSJitInfo__bindgen_ty_1 {{
|
|
||||||
staticMethod: Some({method.identifier.name})
|
pub(crate) fn init_{method.identifier.name}_methodinfo() {{
|
||||||
}},
|
{method.identifier.name}_methodinfo.set(JSJitInfo {{
|
||||||
__bindgen_anon_2: JSJitInfo__bindgen_ty_2 {{
|
__bindgen_anon_1: JSJitInfo__bindgen_ty_1 {{
|
||||||
protoID: PrototypeList::ID::Last as u16,
|
staticMethod: Some({method.identifier.name})
|
||||||
}},
|
}},
|
||||||
__bindgen_anon_3: JSJitInfo__bindgen_ty_3 {{ depth: 0 }},
|
__bindgen_anon_2: JSJitInfo__bindgen_ty_2 {{
|
||||||
_bitfield_align_1: [],
|
protoID: PrototypeList::ID::Last as u16,
|
||||||
_bitfield_1: __BindgenBitfieldUnit::new(
|
}},
|
||||||
new_jsjitinfo_bitfield_1!(
|
__bindgen_anon_3: JSJitInfo__bindgen_ty_3 {{ depth: 0 }},
|
||||||
JSJitInfo_OpType::StaticMethod as u8,
|
_bitfield_align_1: [],
|
||||||
JSJitInfo_AliasSet::AliasEverything as u8,
|
_bitfield_1: __BindgenBitfieldUnit::new(
|
||||||
JSValueType::JSVAL_TYPE_OBJECT as u8,
|
new_jsjitinfo_bitfield_1!(
|
||||||
false,
|
JSJitInfo_OpType::StaticMethod as u8,
|
||||||
false,
|
JSJitInfo_AliasSet::AliasEverything as u8,
|
||||||
false,
|
JSValueType::JSVAL_TYPE_OBJECT as u8,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
0,
|
false,
|
||||||
).to_ne_bytes()
|
false,
|
||||||
),
|
false,
|
||||||
}};
|
0,
|
||||||
|
).to_ne_bytes()
|
||||||
|
),
|
||||||
|
}});
|
||||||
|
}}
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -5790,7 +5829,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod):
|
||||||
"""
|
"""
|
||||||
if !proxyhandler::is_platform_object_same_origin(cx, proxy) {
|
if !proxyhandler::is_platform_object_same_origin(cx, proxy) {
|
||||||
if !proxyhandler::cross_origin_get_own_property_helper(
|
if !proxyhandler::cross_origin_get_own_property_helper(
|
||||||
cx, proxy, &CROSS_ORIGIN_PROPERTIES, id, desc, &mut *is_none
|
cx, proxy, CROSS_ORIGIN_PROPERTIES.get(), id, desc, &mut *is_none
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -6008,7 +6047,9 @@ class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod):
|
||||||
body += dedent(
|
body += dedent(
|
||||||
"""
|
"""
|
||||||
if !proxyhandler::is_platform_object_same_origin(cx, proxy) {
|
if !proxyhandler::is_platform_object_same_origin(cx, proxy) {
|
||||||
return proxyhandler::cross_origin_own_property_keys(cx, proxy, &CROSS_ORIGIN_PROPERTIES, props);
|
return proxyhandler::cross_origin_own_property_keys(
|
||||||
|
cx, proxy, CROSS_ORIGIN_PROPERTIES.get(), props
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safe to enter the Realm of proxy now.
|
// Safe to enter the Realm of proxy now.
|
||||||
|
@ -6130,7 +6171,9 @@ class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod):
|
||||||
indexed += dedent(
|
indexed += dedent(
|
||||||
"""
|
"""
|
||||||
if !proxyhandler::is_platform_object_same_origin(cx, proxy) {
|
if !proxyhandler::is_platform_object_same_origin(cx, proxy) {
|
||||||
return proxyhandler::cross_origin_has_own(cx, proxy, &CROSS_ORIGIN_PROPERTIES, id, bp);
|
return proxyhandler::cross_origin_has_own(
|
||||||
|
cx, proxy, CROSS_ORIGIN_PROPERTIES.get(), id, bp
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safe to enter the Realm of proxy now.
|
// Safe to enter the Realm of proxy now.
|
||||||
|
@ -6643,6 +6686,95 @@ class CGWeakReferenceableTrait(CGThing):
|
||||||
return self.code
|
return self.code
|
||||||
|
|
||||||
|
|
||||||
|
class CGInitStatics(CGThing):
|
||||||
|
def __init__(self, descriptor):
|
||||||
|
CGThing.__init__(self)
|
||||||
|
|
||||||
|
def internal(method):
|
||||||
|
return descriptor.internalNameFor(method.identifier.name)
|
||||||
|
|
||||||
|
properties = PropertyArrays(descriptor)
|
||||||
|
all_names = PropertyArrays.arrayNames()
|
||||||
|
arrays = [getattr(properties, name) for name in all_names]
|
||||||
|
nonempty = map(lambda x: x.variableName(), filter(lambda x: x.length() != 0, arrays))
|
||||||
|
specs = [[
|
||||||
|
f'init_{name}_specs();',
|
||||||
|
f'init_{name}_prefs();',
|
||||||
|
] for name in nonempty]
|
||||||
|
flat_specs = [x for xs in specs for x in xs]
|
||||||
|
specs = '\n'.join(flat_specs)
|
||||||
|
module = f"crate::dom::bindings::codegen::Bindings::{toBindingPath(descriptor)}"
|
||||||
|
relevantMethods = [
|
||||||
|
m for m in descriptor.interface.members if m.isMethod()
|
||||||
|
] if not descriptor.interface.isCallback() else []
|
||||||
|
allOperations = descriptor.operations.keys()
|
||||||
|
relevantOperations = list(map(lambda x: f"__{x.lower()}", filter(lambda o: o != "Stringifier", allOperations)))
|
||||||
|
relevantMethods = filter(
|
||||||
|
lambda m: internal(m) not in relevantOperations,
|
||||||
|
relevantMethods,
|
||||||
|
)
|
||||||
|
relevantMethods = filter(
|
||||||
|
lambda x: (
|
||||||
|
not x.isStatic()
|
||||||
|
or any([r.isPromise() for r, _ in x.signatures()])
|
||||||
|
),
|
||||||
|
relevantMethods
|
||||||
|
)
|
||||||
|
|
||||||
|
methods = [f'{module}::init_{internal(m)}_methodinfo();' for m in relevantMethods]
|
||||||
|
getters = [
|
||||||
|
f'init_{internal(m)}_getterinfo();'
|
||||||
|
for m in descriptor.interface.members if m.isAttr() and not m.isStatic()
|
||||||
|
]
|
||||||
|
setters = [
|
||||||
|
f'init_{internal(m)}_setterinfo();'
|
||||||
|
for m in descriptor.interface.members
|
||||||
|
if m.isAttr() and (
|
||||||
|
not m.readonly
|
||||||
|
or m.getExtendedAttribute("PutForwards")
|
||||||
|
or m.getExtendedAttribute("Replaceable")
|
||||||
|
) and not m.isStatic()
|
||||||
|
]
|
||||||
|
methods = '\n'.join(methods)
|
||||||
|
getters = '\n'.join(getters)
|
||||||
|
setters = '\n'.join(setters)
|
||||||
|
crossorigin = [
|
||||||
|
"init_sCrossOriginMethods();",
|
||||||
|
"init_sCrossOriginAttributes();",
|
||||||
|
"init_cross_origin_properties();"
|
||||||
|
] if descriptor.isMaybeCrossOriginObject() else []
|
||||||
|
crossorigin_joined = '\n'.join(crossorigin)
|
||||||
|
interface = (
|
||||||
|
"init_interface_object();"
|
||||||
|
if descriptor.interface.hasInterfaceObject()
|
||||||
|
and not descriptor.interface.isNamespace()
|
||||||
|
and not descriptor.interface.isCallback()
|
||||||
|
and not descriptor.interface.getExtendedAttribute("Inline")
|
||||||
|
else ""
|
||||||
|
)
|
||||||
|
nonproxy = (
|
||||||
|
"init_domjs_class();"
|
||||||
|
if not descriptor.proxy
|
||||||
|
and descriptor.concrete
|
||||||
|
else ""
|
||||||
|
)
|
||||||
|
|
||||||
|
self.code = f"""
|
||||||
|
pub(crate) fn init_statics() {{
|
||||||
|
{interface}
|
||||||
|
{nonproxy}
|
||||||
|
{methods}
|
||||||
|
{getters}
|
||||||
|
{setters}
|
||||||
|
{crossorigin_joined}
|
||||||
|
{specs}
|
||||||
|
}}
|
||||||
|
"""
|
||||||
|
|
||||||
|
def define(self):
|
||||||
|
return self.code
|
||||||
|
|
||||||
|
|
||||||
class CGDescriptor(CGThing):
|
class CGDescriptor(CGThing):
|
||||||
def __init__(self, descriptor, config, soleDescriptor):
|
def __init__(self, descriptor, config, soleDescriptor):
|
||||||
CGThing.__init__(self)
|
CGThing.__init__(self)
|
||||||
|
@ -6837,6 +6969,8 @@ class CGDescriptor(CGThing):
|
||||||
cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties, haveUnscopables,
|
cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties, haveUnscopables,
|
||||||
haveLegacyWindowAliases))
|
haveLegacyWindowAliases))
|
||||||
|
|
||||||
|
cgThings.append(CGInitStatics(descriptor))
|
||||||
|
|
||||||
cgThings = CGList(cgThings, '\n')
|
cgThings = CGList(cgThings, '\n')
|
||||||
|
|
||||||
# Add imports
|
# Add imports
|
||||||
|
@ -7205,6 +7339,23 @@ class CGDictionary(CGThing):
|
||||||
return deps
|
return deps
|
||||||
|
|
||||||
|
|
||||||
|
class CGInitAllStatics(CGAbstractMethod):
|
||||||
|
def __init__(self, config):
|
||||||
|
docs = "Initialize the static data used by the SpiderMonkey DOM bindings to implement JS interfaces."
|
||||||
|
descriptors = (config.getDescriptors(isCallback=False, register=True)
|
||||||
|
+ config.getDescriptors(isCallback=True, hasInterfaceObject=True, register=True))
|
||||||
|
CGAbstractMethod.__init__(self, None, 'InitAllStatics', 'void', [],
|
||||||
|
pub=True, docs=docs)
|
||||||
|
self.descriptors = descriptors
|
||||||
|
|
||||||
|
def definition_body(self):
|
||||||
|
return CGList([
|
||||||
|
CGGeneric(f" Bindings::{toBindingModuleFileFromDescriptor(desc)}::{toBindingNamespace(desc.name)}"
|
||||||
|
"::init_statics();")
|
||||||
|
for desc in self.descriptors
|
||||||
|
], "\n")
|
||||||
|
|
||||||
|
|
||||||
class CGRegisterProxyHandlersMethod(CGAbstractMethod):
|
class CGRegisterProxyHandlersMethod(CGAbstractMethod):
|
||||||
def __init__(self, descriptors):
|
def __init__(self, descriptors):
|
||||||
docs = "Create the global vtables used by the generated DOM bindings to implement JS proxies."
|
docs = "Create the global vtables used by the generated DOM bindings to implement JS proxies."
|
||||||
|
@ -7238,6 +7389,7 @@ class CGRegisterProxyHandlers(CGThing):
|
||||||
f"{body}}}\n"
|
f"{body}}}\n"
|
||||||
),
|
),
|
||||||
CGRegisterProxyHandlersMethod(descriptors),
|
CGRegisterProxyHandlersMethod(descriptors),
|
||||||
|
CGInitAllStatics(config),
|
||||||
], "\n")
|
], "\n")
|
||||||
|
|
||||||
def define(self):
|
def define(self):
|
||||||
|
|
|
@ -384,7 +384,7 @@ class Descriptor(DescriptorProvider):
|
||||||
filename = getIdlFileName(self.interface)
|
filename = getIdlFileName(self.interface)
|
||||||
# if interface name is not same as webidl file
|
# if interface name is not same as webidl file
|
||||||
# webidl is super module for interface
|
# webidl is super module for interface
|
||||||
if filename.lower() != self.interface.identifier.name.lower() and not self.interface.isIteratorInterface():
|
if filename.lower() != self.interface.identifier.name.lower():
|
||||||
return filename
|
return filename
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -34,11 +34,14 @@ pub mod base {
|
||||||
pub use crate::dom::bindings::error::Error::JSFailed;
|
pub use crate::dom::bindings::error::Error::JSFailed;
|
||||||
pub use crate::dom::bindings::error::{throw_dom_exception, Fallible};
|
pub use crate::dom::bindings::error::{throw_dom_exception, Fallible};
|
||||||
pub use crate::dom::bindings::num::Finite;
|
pub use crate::dom::bindings::num::Finite;
|
||||||
|
pub use crate::dom::bindings::proxyhandler::CrossOriginProperties;
|
||||||
pub use crate::dom::bindings::reflector::DomObject;
|
pub use crate::dom::bindings::reflector::DomObject;
|
||||||
pub use crate::dom::bindings::root::DomRoot;
|
pub use crate::dom::bindings::root::DomRoot;
|
||||||
pub use crate::dom::bindings::str::{ByteString, DOMString, USVString};
|
pub use crate::dom::bindings::str::{ByteString, DOMString, USVString};
|
||||||
pub use crate::dom::bindings::trace::RootedTraceableBox;
|
pub use crate::dom::bindings::trace::RootedTraceableBox;
|
||||||
pub use crate::dom::bindings::utils::{get_dictionary_property, set_dictionary_property};
|
pub use crate::dom::bindings::utils::{
|
||||||
|
get_dictionary_property, set_dictionary_property, ThreadUnsafeOnceLock,
|
||||||
|
};
|
||||||
pub use crate::dom::globalscope::GlobalScope;
|
pub use crate::dom::globalscope::GlobalScope;
|
||||||
pub use crate::script_runtime::JSContext as SafeJSContext;
|
pub use crate::script_runtime::JSContext as SafeJSContext;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::os::raw::{c_char, c_void};
|
use std::os::raw::{c_char, c_void};
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
|
use std::sync::OnceLock;
|
||||||
use std::{ptr, slice, str};
|
use std::{ptr, slice, str};
|
||||||
|
|
||||||
use js::conversions::ToJSValConvertible;
|
use js::conversions::ToJSValConvertible;
|
||||||
|
@ -48,6 +49,37 @@ use crate::dom::bindings::trace::trace_object;
|
||||||
use crate::dom::windowproxy::WindowProxyHandler;
|
use crate::dom::windowproxy::WindowProxyHandler;
|
||||||
use crate::script_runtime::JSContext as SafeJSContext;
|
use crate::script_runtime::JSContext as SafeJSContext;
|
||||||
|
|
||||||
|
/// A OnceLock wrapping a type that is not considered threadsafe by the Rust compiler, but
|
||||||
|
/// will be used in a threadsafe manner (it will not be mutated, after being initialized).
|
||||||
|
///
|
||||||
|
/// This is needed to allow using JS API types (which usually involve raw pointers) in static initializers,
|
||||||
|
/// when Servo guarantees through the use of OnceLock that only one thread will ever initialize
|
||||||
|
/// the value.
|
||||||
|
pub struct ThreadUnsafeOnceLock<T>(OnceLock<T>);
|
||||||
|
|
||||||
|
impl<T> ThreadUnsafeOnceLock<T> {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self(OnceLock::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize the value inside this lock. Panics if the lock has been previously initialized.
|
||||||
|
pub fn set(&self, val: T) {
|
||||||
|
assert!(self.0.set(val).is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a reference to the value inside this lock. Panics if the lock has not been initialized.
|
||||||
|
///
|
||||||
|
/// SAFETY:
|
||||||
|
/// The caller must ensure that it does not mutate value contained inside this lock
|
||||||
|
/// (using interior mutability).
|
||||||
|
pub unsafe fn get(&self) -> &T {
|
||||||
|
self.0.get().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T> Sync for ThreadUnsafeOnceLock<T> {}
|
||||||
|
unsafe impl<T> Send for ThreadUnsafeOnceLock<T> {}
|
||||||
|
|
||||||
#[derive(JSTraceable, MallocSizeOf)]
|
#[derive(JSTraceable, MallocSizeOf)]
|
||||||
/// Static data associated with a global object.
|
/// Static data associated with a global object.
|
||||||
pub struct GlobalStaticData {
|
pub struct GlobalStaticData {
|
||||||
|
|
|
@ -70,6 +70,7 @@ pub fn init() -> JSEngineSetup {
|
||||||
// Create the global vtables used by the (generated) DOM
|
// Create the global vtables used by the (generated) DOM
|
||||||
// bindings to implement JS proxies.
|
// bindings to implement JS proxies.
|
||||||
RegisterBindings::RegisterProxyHandlers();
|
RegisterBindings::RegisterProxyHandlers();
|
||||||
|
RegisterBindings::InitAllStatics();
|
||||||
|
|
||||||
js::glue::InitializeMemoryReporter(Some(is_dom_object));
|
js::glue::InitializeMemoryReporter(Some(is_dom_object));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue