#[repr(C)]
pub struct AutoSetAsyncStackForNewCalls { pub cx: *mut JSContext, pub oldAsyncStack: Rooted<*mut JSObject>, pub oldAsyncCause: *const i8, pub oldAsyncCallIsExplicit: bool, }
Expand description

Supply an alternative stack to incorporate into captured SavedFrame backtraces as the imputed caller of asynchronous JavaScript calls, like async function resumptions and DOM callbacks.

When one async function awaits the result of another, it’s natural to think of that as a sort of function call: just as execution resumes from an ordinary call expression when the callee returns, with the return value providing the value of the call expression, execution resumes from an ‘await’ expression after the awaited asynchronous function call returns, passing the return value along.

Call the two async functions in such a situation the ‘awaiter’ and the ‘awaitee’.

As an async function, the awaitee contains ‘await’ expressions of its own. Whenever it executes after its first ‘await’, there are never any actual frames on the JavaScript stack under it; its awaiter is certainly not there. An await expression’s continuation is invoked as a promise callback, and those are always called directly from the event loop in their own microtick. (Ignore unusual cases like nested event loops.)

But because await expressions bear such a strong resemblance to calls (and deliberately so!), it would be unhelpful for stacks captured within the awaitee to be empty; instead, they should present the awaiter as the caller.

The AutoSetAsyncStackForNewCalls RAII class supplies a SavedFrame stack to treat as the caller of any JavaScript invocations that occur within its lifetime. Any SavedFrame stack captured during such an invocation uses the SavedFrame passed to the constructor’s ‘stack’ parameter as the ‘asyncParent’ property of the SavedFrame for the invocation’s oldest frame. Its ‘parent’ property will be null, so stack-walking code can distinguish this awaiter/awaitee transition from an ordinary caller/callee transition.

The constructor’s ‘asyncCause’ parameter supplies a string explaining what sort of asynchronous call caused ‘stack’ to be spliced into the backtrace; for example, async function resumptions use the string “async”. This appears as the ‘asyncCause’ property of the ‘asyncParent’ SavedFrame.

Async callers are distinguished in the string form of a SavedFrame chain by including the ‘asyncCause’ string in the frame. It appears before the function name, with the two separated by a ‘*’.

Note that, as each compartment has its own set of SavedFrames, the ‘asyncParent’ may actually point to a copy of ‘stack’, rather than the exact SavedFrame object passed.

The youngest frame of ‘stack’ is not mutated to take the asyncCause string as its ‘asyncCause’ property; SavedFrame objects are immutable. Rather, a fresh clone of the frame is created with the needed ‘asyncCause’ property.

The ‘kind’ argument specifies how aggressively ‘stack’ supplants any JavaScript frames older than this AutoSetAsyncStackForNewCalls object. If ‘kind’ is ‘EXPLICIT’, then all captured SavedFrame chains take on ‘stack’ as their ‘asyncParent’ where the chain crosses this object’s scope. If ‘kind’ is ‘IMPLICIT’, then ‘stack’ is only included in captured chains if there are no other JavaScript frames on the stack — that is, only if the stack would otherwise end at that point.

AutoSetAsyncStackForNewCalls affects only SavedFrame chains; it does not affect Debugger.Frame or js::FrameIter. SavedFrame chains are used for Error.stack, allocation profiling, Promise debugging, and so on.

See also js/src/doc/SavedFrame/SavedFrame.md for documentation on async stack frames.

Fields§

§cx: *mut JSContext§oldAsyncStack: Rooted<*mut JSObject>§oldAsyncCause: *const i8§oldAsyncCallIsExplicit: bool

Auto Trait Implementations§

Blanket Implementations§

source§

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

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

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

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

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

source§

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

Mutably borrows from an owned value. 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 Twhere 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 Twhere U: Into<T>,

§

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 Twhere U: TryFrom<T>,

§

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.