use std::pin::pin; struct Formatter(v8::Global); #[cfg(not(target_os = "windows"))] #[repr(C)] struct CallbackResult(*const v8::Value); #[cfg(not(target_os = "windows"))] type Callback = unsafe extern "C" fn( v8::Local, v8::Local, v8::Local, ) -> CallbackResult; #[cfg(target_os = "windows")] type Callback = unsafe extern "C" fn( *mut *const v8::Value, v8::Local, v8::Local, v8::Local, ) -> *mut *const v8::Value; unsafe extern "C" { fn v8__Isolate__SetPrepareStackTraceCallback( isolate: v8::UnsafeRawIsolatePtr, callback: Option, ); } /// Restores V8's own formatting until another context installs a formatter. pub(crate) fn clear(isolate: &mut v8::Isolate) { // SAFETY: isolate is live, and a null callback disables custom formatting. unsafe { v8__Isolate__SetPrepareStackTraceCallback(isolate.as_raw_isolate_ptr(), None); } isolate.remove_slot::(); } pub(crate) fn init(scope: &mut v8::PinScope, formatter: v8::Local) { scope.set_slot(Formatter(v8::Global::new(scope, formatter))); // rusty_v8's safe adapter cannot return an empty MaybeLocal on exceptions, // causing V8 to cache undefined. Mirror its ABI until it supports Option. // SAFETY: scope provides a live isolate, and callback matches the platform-specific // PrepareStackTraceCallback ABI, including its pointer-sized MaybeLocal result. unsafe { v8__Isolate__SetPrepareStackTraceCallback(scope.as_raw_isolate_ptr(), Some(callback)); } } fn format<'s>( context: v8::Local<'s, v8::Context>, error: v8::Local<'s, v8::Value>, frames: v8::Local<'s, v8::Array>, ) -> *const v8::Value { // SAFETY: These handles and the entered isolate/context are supplied by V8 itself. let scope = pin!(unsafe { v8::CallbackScope::new(context) }); let scope = scope.init(); let formatter = scope.get_slot::().unwrap().0.clone(); let formatter = v8::Local::new(&scope, formatter); let receiver = v8::undefined(&scope).into(); formatter .call(&scope, receiver, &[error, frames.into()]) .map_or(std::ptr::null(), |value| &*value as *const _) } #[cfg(not(target_os = "windows"))] unsafe extern "C" fn callback( context: v8::Local, error: v8::Local, frames: v8::Local, ) -> CallbackResult { CallbackResult(format(context, error, frames)) } #[cfg(target_os = "windows")] unsafe extern "C" fn callback( result: *mut *const v8::Value, context: v8::Local, error: v8::Local, frames: v8::Local, ) -> *mut *const v8::Value { // SAFETY: V8 supplies storage for its MaybeLocal return value on Windows. // It is non-null, aligned, and writable for one pointer until the callback returns. unsafe { result.write(format(context, error, frames)); } result }