Skip to content

Commit 3289877

Browse files
committed
Add JSContext wrapper for bindings with fewer raw pointers.
Signed-off-by: Josh Matthews <[email protected]>
1 parent 87cabf4 commit 3289877

25 files changed

+235
-190
lines changed

mozjs/examples/eval.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ use mozjs::rust::{JSEngine, RealmOptions, Runtime};
2323

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

4243
/*
4344
* Some example source in a string. This is equivalent to JS_EvaluateScript in C++.

mozjs/examples/minimal.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ fn run(rt: Runtime) {
4040
// This demonstrates the way Rust uses the C++ garbage collector: using the rooted! macro to
4141
// indicate when the GC can collect them.
4242
let options = RealmOptions::default();
43-
rooted!(in(cx) let _global = unsafe {
44-
JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
43+
rooted!(in(*cx) let _global = unsafe {
44+
JS_NewGlobalObject(*cx, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
4545
OnNewGlobalHookOption::FireOnNewGlobalHook,
4646
&*options)
4747
});

mozjs/examples/wasm.rs

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -47,34 +47,35 @@ unsafe extern "C" fn bar(_cx: *mut JSContext, argc: u32, vp: *mut Value) -> bool
4747

4848
fn run(rt: Runtime) {
4949
let options = RealmOptions::default();
50-
rooted!(in(rt.cx()) let global = unsafe {
51-
JS_NewGlobalObject(rt.cx(), &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
50+
let cx = rt.cx();
51+
rooted!(in(*cx) let global = unsafe {
52+
JS_NewGlobalObject(*cx, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
5253
OnNewGlobalHookOption::FireOnNewGlobalHook,
5354
&*options)
5455
});
55-
let _ac = JSAutoRealm::new(rt.cx(), global.get());
56+
let _ac = JSAutoRealm::new(*cx, global.get());
5657

5758
// Get WebAssembly.Module and WebAssembly.Instance constructors.
58-
rooted!(in(rt.cx()) let mut wasm = UndefinedValue());
59-
rooted!(in(rt.cx()) let mut wasm_module = UndefinedValue());
60-
rooted!(in(rt.cx()) let mut wasm_instance = UndefinedValue());
59+
rooted!(in(*cx) let mut wasm = UndefinedValue());
60+
rooted!(in(*cx) let mut wasm_module = UndefinedValue());
61+
rooted!(in(*cx) let mut wasm_instance = UndefinedValue());
6162

6263
unsafe {
6364
assert!(JS_GetProperty(
64-
rt.cx(),
65+
*cx,
6566
global.handle(),
6667
c"WebAssembly".as_ptr(),
6768
&mut wasm.handle_mut()
6869
));
69-
rooted!(in(rt.cx()) let mut wasm_obj = wasm.to_object());
70+
rooted!(in(*cx) let mut wasm_obj = wasm.to_object());
7071
assert!(JS_GetProperty(
71-
rt.cx(),
72+
*cx,
7273
wasm_obj.handle(),
7374
c"Module".as_ptr(),
7475
&mut wasm_module.handle_mut()
7576
));
7677
assert!(JS_GetProperty(
77-
rt.cx(),
78+
*cx,
7879
wasm_obj.handle(),
7980
c"Instance".as_ptr(),
8081
&mut wasm_instance.handle_mut()
@@ -84,85 +85,85 @@ fn run(rt: Runtime) {
8485
assert!(HI_WASM.0.as_ptr() as usize % 8 == 0);
8586

8687
// Construct Wasm module from bytes.
87-
rooted!(in(rt.cx()) let mut module = null_mut::<JSObject>());
88+
rooted!(in(*cx) let mut module = null_mut::<JSObject>());
8889
{
8990
let array_buffer = JS::NewArrayBufferWithUserOwnedContents(
90-
rt.cx(),
91+
*cx,
9192
HI_WASM.0.len(),
9293
HI_WASM.0.as_ptr() as _,
9394
);
9495
assert!(!array_buffer.is_null());
9596

96-
rooted!(in(rt.cx()) let val = ObjectValue(array_buffer));
97+
rooted!(in(*cx) let val = ObjectValue(array_buffer));
9798
let args = HandleValueArray::from(val.handle().into_handle());
9899

99100
assert!(Construct1(
100-
rt.cx(),
101+
*cx,
101102
wasm_module.handle(),
102103
&args,
103104
&mut module.handle_mut()
104105
))
105106
}
106107

107108
// Construct Wasm module instance with required imports.
108-
rooted!(in(rt.cx()) let mut instance = null_mut::<JSObject>());
109+
rooted!(in(*cx) let mut instance = null_mut::<JSObject>());
109110
{
110111
// Build "env" imports object.
111-
rooted!(in(rt.cx()) let mut env_import_obj = JS_NewPlainObject(rt.cx()));
112+
rooted!(in(*cx) let mut env_import_obj = JS_NewPlainObject(*cx));
112113
assert!(!env_import_obj.is_null());
113114
let function = JS_DefineFunction(
114-
rt.cx(),
115+
*cx,
115116
env_import_obj.handle().into(),
116117
c"bar".as_ptr(),
117118
Some(bar),
118119
1,
119120
0,
120121
);
121122
assert!(!function.is_null());
122-
rooted!(in(rt.cx()) let mut env_import = ObjectValue(env_import_obj.get()));
123+
rooted!(in(*cx) let mut env_import = ObjectValue(env_import_obj.get()));
123124
// Build imports bag.
124-
rooted!(in(rt.cx()) let mut imports = JS_NewPlainObject(rt.cx()));
125+
rooted!(in(*cx) let mut imports = JS_NewPlainObject(*cx));
125126
assert!(!imports.is_null());
126127
assert!(JS_SetProperty(
127-
rt.cx(),
128+
*cx,
128129
imports.handle(),
129130
c"env".as_ptr(),
130131
env_import.handle()
131132
));
132133

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

135136
assert!(Construct1(
136-
rt.cx(),
137+
*cx,
137138
wasm_instance.handle(),
138139
&HandleValueArray::from(&args),
139140
&mut instance.handle_mut()
140141
));
141142
}
142143

143144
// Find `foo` method in exports.
144-
rooted!(in(rt.cx()) let mut exports = UndefinedValue());
145+
rooted!(in(*cx) let mut exports = UndefinedValue());
145146

146147
assert!(JS_GetProperty(
147-
rt.cx(),
148+
*cx,
148149
instance.handle(),
149150
c"exports".as_ptr(),
150151
&mut exports.handle_mut()
151152
));
152153

153-
rooted!(in(rt.cx()) let mut exports_obj = exports.to_object());
154-
rooted!(in(rt.cx()) let mut foo = UndefinedValue());
154+
rooted!(in(*cx) let mut exports_obj = exports.to_object());
155+
rooted!(in(*cx) let mut foo = UndefinedValue());
155156
assert!(JS_GetProperty(
156-
rt.cx(),
157+
*cx,
157158
exports_obj.handle(),
158159
c"foo".as_ptr(),
159160
&mut foo.handle_mut()
160161
));
161162

162163
// call foo and get its result
163-
rooted!(in(rt.cx()) let mut rval = UndefinedValue());
164+
rooted!(in(*cx) let mut rval = UndefinedValue());
164165
assert!(Call(
165-
rt.cx(),
166+
*cx,
166167
JS::UndefinedHandleValue,
167168
foo.handle().into(),
168169
&HandleValueArray::empty(),

mozjs/src/context.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
3+
* You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
use std::marker::PhantomData;
6+
use std::ops::Deref;
7+
8+
/// A wrapper for raw JSContext pointers that are strongly associated with
9+
/// the [Runtime] type.
10+
#[derive(Copy, Clone)]
11+
pub struct JSContext<'a> {
12+
pub(crate) raw: *mut crate::jsapi::JSContext,
13+
pub(crate) anchor: PhantomData<&'a ()>,
14+
}
15+
16+
impl<'a> JSContext<'a> {
17+
/// Wrap an existing raw JSContext pointer.
18+
///
19+
/// SAFETY:
20+
/// - cx must point to non-null, valid JSContext object.
21+
/// - the resulting lifetime must not exceed the actual lifetime of the
22+
/// associated JS runtime.
23+
pub unsafe fn from_ptr(cx: *mut crate::jsapi::JSContext) -> JSContext<'a> {
24+
JSContext {
25+
raw: cx,
26+
anchor: PhantomData,
27+
}
28+
}
29+
}
30+
31+
impl<'a> Deref for JSContext<'a> {
32+
type Target = *mut crate::jsapi::JSContext;
33+
34+
fn deref(&self) -> &Self::Target {
35+
&self.raw
36+
}
37+
}

mozjs/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ pub mod jsapi {
4646
pub mod rust;
4747

4848
mod consts;
49+
pub mod context;
4950
pub mod conversions;
5051
pub mod error;
5152
pub mod gc;

mozjs/src/rust.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -392,8 +392,11 @@ impl Runtime {
392392
}
393393

394394
/// Returns the `JSContext` object.
395-
pub fn cx(&self) -> *mut JSContext {
396-
self.cx
395+
pub fn cx<'a>(&self) -> crate::context::JSContext<'a> {
396+
crate::context::JSContext {
397+
raw: self.cx,
398+
anchor: std::marker::PhantomData,
399+
}
397400
}
398401

399402
pub fn evaluate_script(
@@ -409,12 +412,13 @@ impl Runtime {
409412
filename, script
410413
);
411414

412-
let _ac = JSAutoRealm::new(self.cx(), glob.get());
413-
let options = unsafe { CompileOptionsWrapper::new(self.cx(), filename, line_num) };
415+
let cx = self.cx();
416+
let _ac = JSAutoRealm::new(*cx, glob.get());
417+
let options = unsafe { CompileOptionsWrapper::new(*cx, filename, line_num) };
414418

415419
unsafe {
416420
let mut source = transform_str_to_source_text(&script);
417-
if !Evaluate2(self.cx(), options.ptr, &mut source, rval.into()) {
421+
if !Evaluate2(*cx, options.ptr, &mut source, rval.into()) {
418422
debug!("...err!");
419423
maybe_resume_unwind();
420424
Err(())

mozjs/tests/callback.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,23 @@ fn callback() {
2020
let context = runtime.cx();
2121
#[cfg(feature = "debugmozjs")]
2222
unsafe {
23-
mozjs::jsapi::SetGCZeal(context, 2, 1);
23+
mozjs::jsapi::SetGCZeal(*context, 2, 1);
2424
}
2525
let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
2626
let c_option = RealmOptions::default();
2727

2828
unsafe {
29-
rooted!(in(context) let global = JS_NewGlobalObject(
30-
context,
29+
rooted!(in(*context) let global = JS_NewGlobalObject(
30+
*context,
3131
&SIMPLE_GLOBAL_CLASS,
3232
ptr::null_mut(),
3333
h_option,
3434
&*c_option,
3535
));
36-
let _ac = JSAutoRealm::new(context, global.get());
36+
let _ac = JSAutoRealm::new(*context, global.get());
3737

3838
let function = JS_DefineFunction(
39-
context,
39+
*context,
4040
global.handle().into(),
4141
c"puts".as_ptr(),
4242
Some(puts),
@@ -46,7 +46,7 @@ fn callback() {
4646
assert!(!function.is_null());
4747

4848
let javascript = "puts('Test Iñtërnâtiônàlizætiøn ┬─┬ノ( º _ ºノ) ');";
49-
rooted!(in(context) let mut rval = UndefinedValue());
49+
rooted!(in(*context) let mut rval = UndefinedValue());
5050
assert!(runtime
5151
.evaluate_script(global.handle(), javascript, "test.js", 0, rval.handle_mut())
5252
.is_ok());

mozjs/tests/capture_stack.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,23 +36,23 @@ fn capture_stack() {
3636
let context = runtime.cx();
3737
#[cfg(feature = "debugmozjs")]
3838
unsafe {
39-
mozjs::jsapi::SetGCZeal(context, 2, 1);
39+
mozjs::jsapi::SetGCZeal(*context, 2, 1);
4040
}
4141
let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
4242
let c_option = RealmOptions::default();
4343

4444
unsafe {
45-
rooted!(in(context) let global = JS_NewGlobalObject(
46-
context,
45+
rooted!(in(*context) let global = JS_NewGlobalObject(
46+
*context,
4747
&SIMPLE_GLOBAL_CLASS,
4848
ptr::null_mut(),
4949
h_option,
5050
&*c_option,
5151
));
52-
let _ac = JSAutoRealm::new(context, global.get());
52+
let _ac = JSAutoRealm::new(*context, global.get());
5353

5454
let function = JS_DefineFunction(
55-
context,
55+
*context,
5656
global.handle().into(),
5757
c"print_stack".as_ptr(),
5858
Some(print_stack),
@@ -71,7 +71,7 @@ fn capture_stack() {
7171
7272
foo(\"arg1-value\");
7373
";
74-
rooted!(in(context) let mut rval = UndefinedValue());
74+
rooted!(in(*context) let mut rval = UndefinedValue());
7575
assert!(runtime
7676
.evaluate_script(global.handle(), javascript, "test.js", 0, rval.handle_mut())
7777
.is_ok());

mozjs/tests/custom_auto_rooter.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ fn virtual_trace_called() {
3535
let context = runtime.cx();
3636

3737
let mut rooter = CustomAutoRooter::new(TraceCheck::new());
38-
let guard = rooter.root(context);
38+
let guard = rooter.root(*context);
3939

4040
unsafe {
41-
JS_GC(context, GCReason::API);
41+
JS_GC(*context, GCReason::API);
4242
}
4343

4444
assert!(guard.trace_was_called.get());

mozjs/tests/custom_auto_rooter_macro.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ fn custom_auto_rooter_macro() {
3232
let runtime = Runtime::new(engine.handle());
3333
let context = runtime.cx();
3434

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

3737
unsafe {
38-
JS_GC(context, GCReason::API);
38+
JS_GC(*context, GCReason::API);
3939
}
4040

4141
vec.iter()

0 commit comments

Comments
 (0)