diff --git a/mozjs-sys/Cargo.toml b/mozjs-sys/Cargo.toml index 194272b2d55..e2daa7a6ccf 100644 --- a/mozjs-sys/Cargo.toml +++ b/mozjs-sys/Cargo.toml @@ -2,7 +2,7 @@ name = "mozjs_sys" description = "System crate for the Mozilla SpiderMonkey JavaScript engine." repository.workspace = true -version = "0.140.5-1" +version = "0.140.5-2" authors = ["Mozilla", "The Servo Project Developers"] links = "mozjs" license.workspace = true diff --git a/mozjs-sys/etc/patches/0044-CurrentGlobalHandle.patch b/mozjs-sys/etc/patches/0044-CurrentGlobalHandle.patch new file mode 100644 index 00000000000..aaae4c0fe8d --- /dev/null +++ b/mozjs-sys/etc/patches/0044-CurrentGlobalHandle.patch @@ -0,0 +1,35 @@ +diff --git a/js/public/GlobalObject.h b/js/public/GlobalObject.h +index 22da1fc28..2d5562d33 100644 +--- a/js/public/GlobalObject.h ++++ b/js/public/GlobalObject.h +@@ -29,6 +29,12 @@ class JS_PUBLIC_API RealmOptions; + */ + extern JS_PUBLIC_API JSObject* CurrentGlobalOrNull(JSContext* cx); + ++/** ++ * Get the current realm's global. Returns nullptr if no realm has been ++ * entered. ++ */ ++extern JS_PUBLIC_API JSObject *const * CurrentGlobal(JSContext* cx); ++ + /** + * Get the global object associated with an object's realm. The object must not + * be a cross-compartment wrapper (because CCWs are shared by all realms in the +diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp +index 5a884a2a6..2d49fc416 100644 +--- a/js/src/jsapi.cpp ++++ b/js/src/jsapi.cpp +@@ -1187,6 +1187,13 @@ JS_PUBLIC_API JSObject* JS::CurrentGlobalOrNull(JSContext* cx) { + return cx->global(); + } + ++JS_PUBLIC_API JSObject *const * JS::CurrentGlobal(JSContext* cx) { ++ AssertHeapIsIdleOrIterating(); ++ CHECK_THREAD(cx); ++ MOZ_ASSERT(cx->realm()); ++ return reinterpret_cast(cx->global().address()); ++} ++ + JS_PUBLIC_API JSObject* JS::GetNonCCWObjectGlobal(JSObject* obj) { + AssertHeapIsIdleOrIterating(); + MOZ_DIAGNOSTIC_ASSERT(!IsCrossCompartmentWrapper(obj)); diff --git a/mozjs-sys/mozjs/js/public/GlobalObject.h b/mozjs-sys/mozjs/js/public/GlobalObject.h index 22da1fc28ba..2d5562d3332 100644 --- a/mozjs-sys/mozjs/js/public/GlobalObject.h +++ b/mozjs-sys/mozjs/js/public/GlobalObject.h @@ -29,6 +29,12 @@ class JS_PUBLIC_API RealmOptions; */ extern JS_PUBLIC_API JSObject* CurrentGlobalOrNull(JSContext* cx); +/** + * Get the current realm's global. Returns nullptr if no realm has been + * entered. + */ +extern JS_PUBLIC_API JSObject *const * CurrentGlobal(JSContext* cx); + /** * Get the global object associated with an object's realm. The object must not * be a cross-compartment wrapper (because CCWs are shared by all realms in the diff --git a/mozjs-sys/mozjs/js/src/jsapi.cpp b/mozjs-sys/mozjs/js/src/jsapi.cpp index 5a884a2a685..2d49fc416e1 100644 --- a/mozjs-sys/mozjs/js/src/jsapi.cpp +++ b/mozjs-sys/mozjs/js/src/jsapi.cpp @@ -1187,6 +1187,13 @@ JS_PUBLIC_API JSObject* JS::CurrentGlobalOrNull(JSContext* cx) { return cx->global(); } +JS_PUBLIC_API JSObject *const * JS::CurrentGlobal(JSContext* cx) { + AssertHeapIsIdleOrIterating(); + CHECK_THREAD(cx); + MOZ_ASSERT(cx->realm()); + return reinterpret_cast(cx->global().address()); +} + JS_PUBLIC_API JSObject* JS::GetNonCCWObjectGlobal(JSObject* obj) { AssertHeapIsIdleOrIterating(); MOZ_DIAGNOSTIC_ASSERT(!IsCrossCompartmentWrapper(obj)); diff --git a/mozjs/src/generate_wrappers.py b/mozjs/src/generate_wrappers.py index 54853827bcd..e41e0d7c5eb 100755 --- a/mozjs/src/generate_wrappers.py +++ b/mozjs/src/generate_wrappers.py @@ -124,7 +124,7 @@ def replace_in_line(fn: tuple[str, str | None]) -> str: .replace("*mut JSContext", "&mut JSContext") .replace("*const JSContext", "&JSContext") ) - if link_name in no_gc or "NewCompileOptions" in sig: + if link_name in no_gc or "NewCompileOptions" in sig or "CurrentGlobal" in sig: sig = sig.replace("&mut JSContext", "&JSContext") return sig diff --git a/mozjs/src/jsapi2_wrappers.in.rs b/mozjs/src/jsapi2_wrappers.in.rs index fa34cc51cbe..0a6c8185d2a 100644 --- a/mozjs/src/jsapi2_wrappers.in.rs +++ b/mozjs/src/jsapi2_wrappers.in.rs @@ -136,6 +136,7 @@ wrap!(jsapi: pub fn StealPendingExceptionStack(cx: &mut JSContext, exceptionStac wrap!(jsapi: pub fn SetPendingExceptionStack(cx: &JSContext, exceptionStack: *const ExceptionStack)); wrap!(jsapi: pub fn ExceptionStackOrNull(obj: HandleObject) -> *mut JSObject); wrap!(jsapi: pub fn CurrentGlobalOrNull(cx: &JSContext) -> *mut JSObject); +wrap!(jsapi: pub fn CurrentGlobal(cx: &JSContext) -> *const *mut JSObject); wrap!(jsapi: pub fn NewMapObject(cx: &mut JSContext) -> *mut JSObject); wrap!(jsapi: pub fn MapSize(cx: &JSContext, obj: HandleObject) -> u32); wrap!(jsapi: pub fn MapGet(cx: &mut JSContext, obj: HandleObject, key: HandleValue, rval: MutableHandleValue) -> bool); diff --git a/mozjs/src/realm.rs b/mozjs/src/realm.rs index 7932c390ef4..e4526144712 100644 --- a/mozjs/src/realm.rs +++ b/mozjs/src/realm.rs @@ -7,7 +7,7 @@ use crate::jsapi::{JSAutoRealm, JSObject}; use crate::context::JSContext; use crate::gc::Handle; -use crate::rust::wrappers2::{CurrentGlobalOrNull, GetCurrentRealmOrNull}; +use crate::rust::wrappers2::{CurrentGlobal, GetCurrentRealmOrNull}; /// Safe wrapper around [JSAutoRealm]. /// @@ -100,10 +100,51 @@ impl<'cx> AutoRealm<'cx> { CurrentRealm::assert(self) } - /// Obtain the handle to the global object of the current realm. + /// Obtain the handle to the global object of the this realm. + /// Because the handle is bounded with lifetime to realm, you cannot do this: + /// + /// ```compile_fail + /// use mozjs::context::JSContext; + /// use mozjs::jsapi::JSObject; + /// use mozjs::realm::AutoRealm; + /// use std::ptr::NonNull; + /// use mozjs::rust::Handle; + /// + /// fn g(realm: &'_ mut AutoRealm, global: Handle<'_, *mut JSObject>) { + /// } + /// + /// fn f(realm: &mut AutoRealm) { + /// let global = realm.global(); + /// g(realm, global); + /// } + /// ``` + /// + /// instead use [AutoRealm::global_and_reborrow]. pub fn global(&'_ self) -> Handle<'_, *mut JSObject> { // SAFETY: object is rooted by realm - unsafe { Handle::from_marked_location(CurrentGlobalOrNull(&*self) as _) } + unsafe { Handle::from_marked_location(CurrentGlobal(self)) } + } + + /// Obtain the handle to the global object of the this realm and reborrow the realm. + /// + /// ``` + /// use mozjs::context::JSContext; + /// use mozjs::jsapi::JSObject; + /// use mozjs::realm::AutoRealm; + /// use std::ptr::NonNull; + /// use mozjs::rust::Handle; + /// + /// fn g(realm: &'_ mut AutoRealm, global: Handle<'_, *mut JSObject>) { + /// } + /// + /// fn f(realm: &mut AutoRealm) { + /// let (global, realm) = realm.global_and_reborrow(); + /// g(realm, global); + /// } + /// ``` + pub fn global_and_reborrow(&'_ mut self) -> (Handle<'_, *mut JSObject>, &'_ mut Self) { + // SAFETY: This is ok because the handle will still be bound to original lifetime. + (unsafe { std::mem::transmute(self.global()) }, self) } /// Erase the lifetime of this [AutoRealm]. @@ -170,10 +211,51 @@ impl<'cx> CurrentRealm<'cx> { } } - /// Obtain the handle to the global object of the current realm. + /// Obtain the handle to the global object of the this realm. + /// Because the handle is bounded with lifetime to realm, you cannot do this: + /// + /// ```compile_fail + /// use mozjs::context::JSContext; + /// use mozjs::jsapi::JSObject; + /// use mozjs::realm::CurrentRealm; + /// use std::ptr::NonNull; + /// use mozjs::rust::Handle; + /// + /// fn g(realm: &'_ mut CurrentRealm, global: Handle<'_, *mut JSObject>) { + /// } + /// + /// fn f(realm: &mut CurrentRealm) { + /// let global = realm.global(); + /// g(realm, global); + /// } + /// ``` + /// + /// instead use [CurrentRealm::global_and_reborrow]. pub fn global(&'_ self) -> Handle<'_, *mut JSObject> { // SAFETY: object is rooted by realm - unsafe { Handle::from_marked_location(CurrentGlobalOrNull(&*self) as _) } + unsafe { Handle::from_marked_location(CurrentGlobal(self)) } + } + + /// Obtain the handle to the global object of this realm and reborrow the realm. + /// + /// ``` + /// use mozjs::context::JSContext; + /// use mozjs::jsapi::JSObject; + /// use mozjs::realm::CurrentRealm; + /// use std::ptr::NonNull; + /// use mozjs::rust::Handle; + /// + /// fn g(realm: &'_ mut CurrentRealm, global: Handle<'_, *mut JSObject>) { + /// } + /// + /// fn f(realm: &mut CurrentRealm) { + /// let (global, realm) = realm.global_and_reborrow(); + /// g(realm, global); + /// } + /// ``` + pub fn global_and_reborrow(&'_ mut self) -> (Handle<'_, *mut JSObject>, &'_ mut Self) { + // SAFETY: This is ok because the handle will still be bound to original lifetime. + (unsafe { std::mem::transmute(self.global()) }, self) } pub fn realm(&self) -> &NonNull { diff --git a/mozjs/tests/callback.rs b/mozjs/tests/callback.rs index 89f3be35f05..6422a624d46 100644 --- a/mozjs/tests/callback.rs +++ b/mozjs/tests/callback.rs @@ -38,16 +38,11 @@ fn callback() { &*c_option, )); let mut realm = AutoRealm::new_from_handle(context, global.handle()); - let context = &mut realm; + let (global_handle, realm) = realm.global_and_reborrow(); + let context = realm; - let function = JS_DefineFunction( - context, - global.handle().into(), - c"puts".as_ptr(), - Some(puts), - 1, - 0, - ); + let function = + JS_DefineFunction(context, global_handle, c"puts".as_ptr(), Some(puts), 1, 0); assert!(!function.is_null()); let javascript = "puts('Test Iñtërnâtiônàlizætiøn ┬─┬ノ( º _ ºノ) ');"; @@ -55,7 +50,7 @@ fn callback() { let options = CompileOptionsWrapper::new(&context, "test.js", 0); assert!(evaluate_script( context, - global.handle(), + global_handle, javascript, rval.handle_mut(), options