JSContext

Struct JSContext 

Source
pub struct JSContext {
    pub(crate) ptr: NonNull<RawJSContext>,
}
Expand description

A wrapper for raw JSContext pointers that are strongly associated with the [Runtime] type.

This type is fundamental for safe SpiderMonkey usage. Each (SpiderMonkey) function which takes &mut JSContext as argument can trigger GC. SpiderMonkey functions require take &JSContext are guaranteed to not trigger GC. We must not hold any unrooted or borrowed data while calling any functions that can trigger GC. That can causes panics or UB. Such types are derived from NoGC token which can be though of &JSContext, so they are bounded to JSContext.

use std::marker::PhantomData;
use mozjs::context::*;
use mozjs::jsapi::JSContext as RawJSContext;

struct ShouldNotBeHoldAcrossGC<'a>(PhantomData<&'a ()>);

impl<'a> Drop for ShouldNotBeHoldAcrossGC<'a> {
    fn drop(&mut self) {}
}

fn something_that_should_not_hold_across_gc<'a>(_no_gc: &NoGC<'a>) -> ShouldNotBeHoldAcrossGC<'a> {
    ShouldNotBeHoldAcrossGC(PhantomData)
}

fn SM_function_that_can_trigger_gc(_cx: *mut RawJSContext) {}

// this lives in mozjs
fn safe_wrapper_to_SM_function_that_can_trigger_gc(cx: &mut JSContext) {
    unsafe { SM_function_that_can_trigger_gc(cx.raw_cx()) }
}

fn can_cause_gc(cx: &mut JSContext) {
    safe_wrapper_to_SM_function_that_can_trigger_gc(cx);
    {
        let t = something_that_should_not_hold_across_gc(&cx.no_gc());
        // do something with it
    } // t get dropped
    safe_wrapper_to_SM_function_that_can_trigger_gc(cx); // we can call GC again
}

One cannot call any GC function, while any NoGC token is alive, because NoGC token borrows JSContext (&JSContext) and thus prevents calling any function that triggers GC, because they require exclusive access to JSContext (&mut JSContext).

use std::marker::PhantomData;
use mozjs::context::*;
use mozjs::jsapi::JSContext as RawJSContext;

struct ShouldNotBeHoldAcrossGC<'a>(PhantomData<&'a ()>);

impl<'a> Drop for ShouldNotBeHoldAcrossGC<'a> {
    fn drop(&mut self) {} // make type not trivial, or else compiler can shorten it's lifetime
}

fn something_that_should_not_hold_across_gc<'a>(_no_gc: &'a NoGC<'a>) -> ShouldNotBeHoldAcrossGC<'a> {
    ShouldNotBeHoldAcrossGC(PhantomData)
}

fn safe_wrapper_to_SM_function_that_can_trigger_gc(_cx: &mut JSContext) {
}

fn can_cause_gc(cx: &mut JSContext) {
    safe_wrapper_to_SM_function_that_can_trigger_gc(cx);
    let t = something_that_should_not_hold_across_gc(&cx.no_gc());
    // this will create compile error, because we cannot hold NoGc across C triggering function.
    // more specifically we cannot borrow `JSContext` as mutable because it is also borrowed as immutable (NoGC).
    safe_wrapper_to_SM_function_that_can_trigger_gc(cx);
}

§WIP

This model is still being incrementally introduced, so there are currently some escape hatches.

Fields§

§ptr: NonNull<RawJSContext>

Implementations§

Source§

impl JSContext

Source

pub unsafe fn from_ptr(cx: NonNull<RawJSContext>) -> JSContext

Wrap an existing RawJSContext pointer.

SAFETY:

  • cx must be valid RawJSContext object.
  • only one JSContext can be alive and it should not outlive [Runtime]. This in turn means that JSContext always needs to be passed down as an argument, but for the SpiderMonkey callbacks which provide RawJSContext it’s safe to construct one from provided RawJSContext.
Source

pub fn no_gc<'cx>(&'cx self) -> &'cx NoGC<'cx>

Returns NoGC token bounded to this JSContext. No function that accepts &mut JSContext (read: triggers GC) can be called while this is alive.

Source

pub unsafe fn raw_cx(&mut self) -> *mut RawJSContext

Obtain RawJSContext mutable pointer.

§Safety

No NoGC tokens should be constructed while returned pointer is available to user. In practices this means that one should use the result as direct argument to SpiderMonkey function and not store it in variable.

use mozjs::context::*;
use mozjs::jsapi::JSContext as RawJSContext;

fn SM_function_that_can_trigger_gc(_cx: *mut RawJSContext) {}

fn can_trigger_gc(cx: &mut JSContext) {
    unsafe { SM_function_that_can_trigger_gc(cx.raw_cx()) } // returned pointer is immediately used
    cx.no_gc(); // this is ok because no outstanding raw pointer is alive
}
Source

pub unsafe fn raw_cx_no_gc(&self) -> *mut RawJSContext

Obtain RawJSContext mutable pointer, that will not be used for GC.

§Safety

No &mut calls should be done on JSContext while returned pointer is available. In practices this means that one should use the result as direct argument to SpiderMonkey function and not store it in variable.

use mozjs::context::*;
use mozjs::jsapi::JSContext as RawJSContext;

fn SM_function_that_cannot_trigger_gc(_cx: *mut RawJSContext) {}

fn f(cx: &mut JSContext) {
    unsafe { SM_function_that_cannot_trigger_gc(cx.raw_cx_no_gc()) } // returned pointer is immediately used
}

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> Filterable for T

Source§

fn filterable( self, filter_name: &'static str, ) -> RequestFilterDataProvider<T, fn(DataRequest<'_>) -> bool>

Creates a filterable data provider with the given name for debugging. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> MaybeSendSync for T