char/avril

(wip) why'd you have to go and make things so complicaaaaated?

git clone https://git.t4t.associates/char/avril

Charlotte Somsnapshot: capture and restore extension layouts in one artifactd71572b

main
3.0 KiB89 linesraw
1use std::pin::pin;
2
3struct Formatter(v8::Global<v8::Function>);
4
5#[cfg(not(target_os = "windows"))]
6#[repr(C)]
7struct CallbackResult(*const v8::Value);
8
9#[cfg(not(target_os = "windows"))]
10type Callback = unsafe extern "C" fn(
11    v8::Local<v8::Context>,
12    v8::Local<v8::Value>,
13    v8::Local<v8::Array>,
14) -> CallbackResult;
15
16#[cfg(target_os = "windows")]
17type Callback = unsafe extern "C" fn(
18    *mut *const v8::Value,
19    v8::Local<v8::Context>,
20    v8::Local<v8::Value>,
21    v8::Local<v8::Array>,
22) -> *mut *const v8::Value;
23
24unsafe extern "C" {
25    fn v8__Isolate__SetPrepareStackTraceCallback(
26        isolate: v8::UnsafeRawIsolatePtr,
27        callback: Option<Callback>,
28    );
29}
30
31/// Restores V8's own formatting until another context installs a formatter.
32pub(crate) fn clear(isolate: &mut v8::Isolate) {
33    // SAFETY: isolate is live, and a null callback disables custom formatting.
34    unsafe {
35        v8__Isolate__SetPrepareStackTraceCallback(isolate.as_raw_isolate_ptr(), None);
36    }
37    isolate.remove_slot::<Formatter>();
38}
39
40pub(crate) fn init(scope: &mut v8::PinScope, formatter: v8::Local<v8::Function>) {
41    scope.set_slot(Formatter(v8::Global::new(scope, formatter)));
42    // rusty_v8's safe adapter cannot return an empty MaybeLocal on exceptions,
43    // causing V8 to cache undefined. Mirror its ABI until it supports Option<Local>.
44    // SAFETY: scope provides a live isolate, and callback matches the platform-specific
45    // PrepareStackTraceCallback ABI, including its pointer-sized MaybeLocal result.
46    unsafe {
47        v8__Isolate__SetPrepareStackTraceCallback(scope.as_raw_isolate_ptr(), Some(callback));
48    }
49}
50
51fn format<'s>(
52    context: v8::Local<'s, v8::Context>,
53    error: v8::Local<'s, v8::Value>,
54    frames: v8::Local<'s, v8::Array>,
55) -> *const v8::Value {
56    // SAFETY: These handles and the entered isolate/context are supplied by V8 itself.
57    let scope = pin!(unsafe { v8::CallbackScope::new(context) });
58    let scope = scope.init();
59    let formatter = scope.get_slot::<Formatter>().unwrap().0.clone();
60    let formatter = v8::Local::new(&scope, formatter);
61    let receiver = v8::undefined(&scope).into();
62    formatter
63        .call(&scope, receiver, &[error, frames.into()])
64        .map_or(std::ptr::null(), |value| &*value as *const _)
65}
66
67#[cfg(not(target_os = "windows"))]
68unsafe extern "C" fn callback(
69    context: v8::Local<v8::Context>,
70    error: v8::Local<v8::Value>,
71    frames: v8::Local<v8::Array>,
72) -> CallbackResult {
73    CallbackResult(format(context, error, frames))
74}
75
76#[cfg(target_os = "windows")]
77unsafe extern "C" fn callback(
78    result: *mut *const v8::Value,
79    context: v8::Local<v8::Context>,
80    error: v8::Local<v8::Value>,
81    frames: v8::Local<v8::Array>,
82) -> *mut *const v8::Value {
83    // SAFETY: V8 supplies storage for its MaybeLocal return value on Windows.
84    // It is non-null, aligned, and writable for one pointer until the callback returns.
85    unsafe {
86        result.write(format(context, error, frames));
87    }
88    result
89}