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 that takes &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. For cases where notion of no GC but no actual context is needed, we have &NoGC token.

use std::marker::PhantomData;
use mozjs::context::*;

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: &'a NoGC) -> 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 &JSContext or &NoGC is alive, because they require such functions accept &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) -> 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

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
}

Trait Implementations§

Source§

impl Deref for JSContext

Source§

fn deref<'cx>(&'cx self) -> &'cx Self::Target

Deref &JSContext into &NoGC so that one can pass &JSContext to functions that require &NoGC.

Source§

type Target = NoGC

The resulting type after dereferencing.

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<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
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