Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add JSContext wrapper for bindings with fewer raw pointers. #554

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions mozjs/examples/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ use mozjs::rust::{JSEngine, RealmOptions, Runtime};

fn run(rt: Runtime) {
let options = RealmOptions::default();
rooted!(in(rt.cx()) let global = unsafe {
JS_NewGlobalObject(rt.cx(), &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
let cx = rt.cx();
rooted!(in(*cx) let global = unsafe {
JS_NewGlobalObject(*cx, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
OnNewGlobalHookOption::FireOnNewGlobalHook,
&*options)
});
Expand All @@ -37,7 +38,7 @@ fn run(rt: Runtime) {
* The return value comes back here. If it could be a GC thing, you must add it to the
* GC's "root set" with the rooted! macro.
*/
rooted!(in(rt.cx()) let mut rval = UndefinedValue());
rooted!(in(*cx) let mut rval = UndefinedValue());

/*
* Some example source in a string. This is equivalent to JS_EvaluateScript in C++.
Expand Down
4 changes: 2 additions & 2 deletions mozjs/examples/minimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ fn run(rt: Runtime) {
// This demonstrates the way Rust uses the C++ garbage collector: using the rooted! macro to
// indicate when the GC can collect them.
let options = RealmOptions::default();
rooted!(in(cx) let _global = unsafe {
JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
rooted!(in(*cx) let _global = unsafe {
JS_NewGlobalObject(*cx, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
OnNewGlobalHookOption::FireOnNewGlobalHook,
&*options)
});
Expand Down
59 changes: 30 additions & 29 deletions mozjs/examples/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,34 +47,35 @@ unsafe extern "C" fn bar(_cx: *mut JSContext, argc: u32, vp: *mut Value) -> bool

fn run(rt: Runtime) {
let options = RealmOptions::default();
rooted!(in(rt.cx()) let global = unsafe {
JS_NewGlobalObject(rt.cx(), &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
let cx = rt.cx();
rooted!(in(*cx) let global = unsafe {
JS_NewGlobalObject(*cx, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
OnNewGlobalHookOption::FireOnNewGlobalHook,
&*options)
});
let _ac = JSAutoRealm::new(rt.cx(), global.get());
let _ac = JSAutoRealm::new(*cx, global.get());

// Get WebAssembly.Module and WebAssembly.Instance constructors.
rooted!(in(rt.cx()) let mut wasm = UndefinedValue());
rooted!(in(rt.cx()) let mut wasm_module = UndefinedValue());
rooted!(in(rt.cx()) let mut wasm_instance = UndefinedValue());
rooted!(in(*cx) let mut wasm = UndefinedValue());
rooted!(in(*cx) let mut wasm_module = UndefinedValue());
rooted!(in(*cx) let mut wasm_instance = UndefinedValue());

unsafe {
assert!(JS_GetProperty(
rt.cx(),
*cx,
global.handle(),
c"WebAssembly".as_ptr(),
&mut wasm.handle_mut()
));
rooted!(in(rt.cx()) let mut wasm_obj = wasm.to_object());
rooted!(in(*cx) let mut wasm_obj = wasm.to_object());
assert!(JS_GetProperty(
rt.cx(),
*cx,
wasm_obj.handle(),
c"Module".as_ptr(),
&mut wasm_module.handle_mut()
));
assert!(JS_GetProperty(
rt.cx(),
*cx,
wasm_obj.handle(),
c"Instance".as_ptr(),
&mut wasm_instance.handle_mut()
Expand All @@ -84,85 +85,85 @@ fn run(rt: Runtime) {
assert!(HI_WASM.0.as_ptr() as usize % 8 == 0);

// Construct Wasm module from bytes.
rooted!(in(rt.cx()) let mut module = null_mut::<JSObject>());
rooted!(in(*cx) let mut module = null_mut::<JSObject>());
{
let array_buffer = JS::NewArrayBufferWithUserOwnedContents(
rt.cx(),
*cx,
HI_WASM.0.len(),
HI_WASM.0.as_ptr() as _,
);
assert!(!array_buffer.is_null());

rooted!(in(rt.cx()) let val = ObjectValue(array_buffer));
rooted!(in(*cx) let val = ObjectValue(array_buffer));
let args = HandleValueArray::from(val.handle().into_handle());

assert!(Construct1(
rt.cx(),
*cx,
wasm_module.handle(),
&args,
&mut module.handle_mut()
))
}

// Construct Wasm module instance with required imports.
rooted!(in(rt.cx()) let mut instance = null_mut::<JSObject>());
rooted!(in(*cx) let mut instance = null_mut::<JSObject>());
{
// Build "env" imports object.
rooted!(in(rt.cx()) let mut env_import_obj = JS_NewPlainObject(rt.cx()));
rooted!(in(*cx) let mut env_import_obj = JS_NewPlainObject(*cx));
assert!(!env_import_obj.is_null());
let function = JS_DefineFunction(
rt.cx(),
*cx,
env_import_obj.handle().into(),
c"bar".as_ptr(),
Some(bar),
1,
0,
);
assert!(!function.is_null());
rooted!(in(rt.cx()) let mut env_import = ObjectValue(env_import_obj.get()));
rooted!(in(*cx) let mut env_import = ObjectValue(env_import_obj.get()));
// Build imports bag.
rooted!(in(rt.cx()) let mut imports = JS_NewPlainObject(rt.cx()));
rooted!(in(*cx) let mut imports = JS_NewPlainObject(*cx));
assert!(!imports.is_null());
assert!(JS_SetProperty(
rt.cx(),
*cx,
imports.handle(),
c"env".as_ptr(),
env_import.handle()
));

rooted!(in(rt.cx()) let mut args = ValueArray::new([ObjectValue(module.get()), ObjectValue(imports.get())]));
rooted!(in(*cx) let mut args = ValueArray::new([ObjectValue(module.get()), ObjectValue(imports.get())]));

assert!(Construct1(
rt.cx(),
*cx,
wasm_instance.handle(),
&HandleValueArray::from(&args),
&mut instance.handle_mut()
));
}

// Find `foo` method in exports.
rooted!(in(rt.cx()) let mut exports = UndefinedValue());
rooted!(in(*cx) let mut exports = UndefinedValue());

assert!(JS_GetProperty(
rt.cx(),
*cx,
instance.handle(),
c"exports".as_ptr(),
&mut exports.handle_mut()
));

rooted!(in(rt.cx()) let mut exports_obj = exports.to_object());
rooted!(in(rt.cx()) let mut foo = UndefinedValue());
rooted!(in(*cx) let mut exports_obj = exports.to_object());
rooted!(in(*cx) let mut foo = UndefinedValue());
assert!(JS_GetProperty(
rt.cx(),
*cx,
exports_obj.handle(),
c"foo".as_ptr(),
&mut foo.handle_mut()
));

// call foo and get its result
rooted!(in(rt.cx()) let mut rval = UndefinedValue());
rooted!(in(*cx) let mut rval = UndefinedValue());
assert!(Call(
rt.cx(),
*cx,
JS::UndefinedHandleValue,
foo.handle().into(),
&HandleValueArray::empty(),
Expand Down
1 change: 1 addition & 0 deletions mozjs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub mod jsapi {
pub mod rust;

mod consts;
pub mod context;
pub mod conversions;
pub mod error;
pub mod gc;
Expand Down
14 changes: 9 additions & 5 deletions mozjs/src/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,8 +392,11 @@ impl Runtime {
}

/// Returns the `JSContext` object.
pub fn cx(&self) -> *mut JSContext {
self.cx
pub fn cx<'a>(&self) -> crate::context::JSContext<'a> {
crate::context::JSContext {
raw: self.cx,
anchor: std::marker::PhantomData,
}
}

pub fn evaluate_script(
Expand All @@ -409,12 +412,13 @@ impl Runtime {
filename, script
);

let _ac = JSAutoRealm::new(self.cx(), glob.get());
let options = unsafe { CompileOptionsWrapper::new(self.cx(), filename, line_num) };
let cx = self.cx();
let _ac = JSAutoRealm::new(*cx, glob.get());
let options = unsafe { CompileOptionsWrapper::new(*cx, filename, line_num) };

unsafe {
let mut source = transform_str_to_source_text(&script);
if !Evaluate2(self.cx(), options.ptr, &mut source, rval.into()) {
if !Evaluate2(*cx, options.ptr, &mut source, rval.into()) {
debug!("...err!");
maybe_resume_unwind();
Err(())
Expand Down
12 changes: 6 additions & 6 deletions mozjs/tests/callback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,23 @@ fn callback() {
let context = runtime.cx();
#[cfg(feature = "debugmozjs")]
unsafe {
mozjs::jsapi::SetGCZeal(context, 2, 1);
mozjs::jsapi::SetGCZeal(*context, 2, 1);
}
let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
let c_option = RealmOptions::default();

unsafe {
rooted!(in(context) let global = JS_NewGlobalObject(
context,
rooted!(in(*context) let global = JS_NewGlobalObject(
*context,
&SIMPLE_GLOBAL_CLASS,
ptr::null_mut(),
h_option,
&*c_option,
));
let _ac = JSAutoRealm::new(context, global.get());
let _ac = JSAutoRealm::new(*context, global.get());

let function = JS_DefineFunction(
context,
*context,
global.handle().into(),
c"puts".as_ptr(),
Some(puts),
Expand All @@ -46,7 +46,7 @@ fn callback() {
assert!(!function.is_null());

let javascript = "puts('Test Iñtërnâtiônàlizætiøn ┬─┬ノ( º _ ºノ) ');";
rooted!(in(context) let mut rval = UndefinedValue());
rooted!(in(*context) let mut rval = UndefinedValue());
assert!(runtime
.evaluate_script(global.handle(), javascript, "test.js", 0, rval.handle_mut())
.is_ok());
Expand Down
12 changes: 6 additions & 6 deletions mozjs/tests/capture_stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,23 @@ fn capture_stack() {
let context = runtime.cx();
#[cfg(feature = "debugmozjs")]
unsafe {
mozjs::jsapi::SetGCZeal(context, 2, 1);
mozjs::jsapi::SetGCZeal(*context, 2, 1);
}
let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
let c_option = RealmOptions::default();

unsafe {
rooted!(in(context) let global = JS_NewGlobalObject(
context,
rooted!(in(*context) let global = JS_NewGlobalObject(
*context,
&SIMPLE_GLOBAL_CLASS,
ptr::null_mut(),
h_option,
&*c_option,
));
let _ac = JSAutoRealm::new(context, global.get());
let _ac = JSAutoRealm::new(*context, global.get());

let function = JS_DefineFunction(
context,
*context,
global.handle().into(),
c"print_stack".as_ptr(),
Some(print_stack),
Expand All @@ -71,7 +71,7 @@ fn capture_stack() {

foo(\"arg1-value\");
";
rooted!(in(context) let mut rval = UndefinedValue());
rooted!(in(*context) let mut rval = UndefinedValue());
assert!(runtime
.evaluate_script(global.handle(), javascript, "test.js", 0, rval.handle_mut())
.is_ok());
Expand Down
4 changes: 2 additions & 2 deletions mozjs/tests/custom_auto_rooter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ fn virtual_trace_called() {
let context = runtime.cx();

let mut rooter = CustomAutoRooter::new(TraceCheck::new());
let guard = rooter.root(context);
let guard = rooter.root(*context);

unsafe {
JS_GC(context, GCReason::API);
JS_GC(*context, GCReason::API);
}

assert!(guard.trace_was_called.get());
Expand Down
4 changes: 2 additions & 2 deletions mozjs/tests/custom_auto_rooter_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ fn custom_auto_rooter_macro() {
let runtime = Runtime::new(engine.handle());
let context = runtime.cx();

auto_root!(in(context) let vec = vec![TraceCheck::new(), TraceCheck::new()]);
auto_root!(in(*context) let vec = vec![TraceCheck::new(), TraceCheck::new()]);

unsafe {
JS_GC(context, GCReason::API);
JS_GC(*context, GCReason::API);
}

vec.iter()
Expand Down
18 changes: 9 additions & 9 deletions mozjs/tests/enforce_range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,18 @@ impl SM {
let cx = rt.cx();
#[cfg(feature = "debugmozjs")]
unsafe {
mozjs::jsapi::SetGCZeal(cx, 2, 1);
mozjs::jsapi::SetGCZeal(*cx, 2, 1);
}
let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
let c_option = RealmOptions::default();
rooted!(in(cx) let global = unsafe {JS_NewGlobalObject(
cx,
rooted!(in(*cx) let global = unsafe {JS_NewGlobalObject(
*cx,
&SIMPLE_GLOBAL_CLASS,
ptr::null_mut(),
h_option,
&*c_option,
)});
let _ac = JSAutoRealm::new(cx, global.get());
let _ac = JSAutoRealm::new(*cx, global.get());
Self {
_engine: engine,
rt,
Expand All @@ -52,7 +52,7 @@ impl SM {
js: &str,
) -> Result<T, ()> {
let cx = self.rt.cx();
rooted!(in(cx) let mut rval = UndefinedValue());
rooted!(in(*cx) let mut rval = UndefinedValue());
unsafe {
self.rt
.evaluate_script(
Expand All @@ -63,17 +63,17 @@ impl SM {
rval.handle_mut(),
)
.unwrap();
assert!(!JS_IsExceptionPending(cx));
assert!(!JS_IsExceptionPending(*cx));
match <T as FromJSValConvertible>::from_jsval(
cx,
*cx,
rval.handle(),
ConversionBehavior::EnforceRange,
) {
Ok(ConversionResult::Success(t)) => Ok(t),
Ok(ConversionResult::Failure(e)) => panic!("{e}"),
Err(()) => {
assert!(JS_IsExceptionPending(cx));
JS_ClearPendingException(cx);
assert!(JS_IsExceptionPending(*cx));
JS_ClearPendingException(*cx);
Err(())
}
}
Expand Down
Loading
Loading