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:
Josh Matthews 2024-12-06 02:34:24 -05:00 committed by GitHub
parent faefed9869
commit 3515b83a95
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 296 additions and 108 deletions

View file

@ -7,6 +7,7 @@
use std::ffi::CString;
use std::os::raw::{c_char, c_void};
use std::ptr::NonNull;
use std::sync::OnceLock;
use std::{ptr, slice, str};
use js::conversions::ToJSValConvertible;
@ -48,6 +49,37 @@ use crate::dom::bindings::trace::trace_object;
use crate::dom::windowproxy::WindowProxyHandler;
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)]
/// Static data associated with a global object.
pub struct GlobalStaticData {