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.1 KiB96 linesraw
1use std::cell::RefCell;
2use std::collections::VecDeque;
3
4pub(crate) struct UncaughtException {
5    pub(crate) value: v8::Global<v8::Value>,
6    pub(crate) filename: String,
7    pub(crate) line: u32,
8    pub(crate) column: u32,
9}
10type ExceptionSlot = RefCell<VecDeque<UncaughtException>>;
11
12extern "C" fn uncaught_exception(message: v8::Local<v8::Message>, exception: v8::Local<v8::Value>) {
13    // V8 reports microtask exceptions to message listeners instead of the enclosing TryCatch.
14    // SAFETY: V8 invokes this listener with a valid message from the active isolate.
15    v8::callback_scope!(unsafe scope, message);
16    let exception = UncaughtException {
17        value: v8::Global::new(scope, exception),
18        filename: message
19            .get_script_resource_name(scope)
20            .map(|name| name.to_rust_string_lossy(scope))
21            .unwrap_or_default(),
22        line: message
23            .get_line_number(scope)
24            .unwrap_or_default()
25            .try_into()
26            .unwrap_or_default(),
27        column: message
28            .get_start_column()
29            .saturating_add(1)
30            .try_into()
31            .unwrap_or_default(),
32    };
33    scope
34        .get_slot::<ExceptionSlot>()
35        .unwrap()
36        .borrow_mut()
37        .push_back(exception);
38}
39
40pub(crate) fn clear(isolate: &mut v8::Isolate) {
41    isolate.remove_slot::<ExceptionSlot>();
42}
43
44pub(crate) fn external_references() -> Vec<v8::ExternalReference> {
45    vec![v8::ExternalReference {
46        pointer: uncaught_exception as *mut std::ffi::c_void,
47    }]
48}
49
50pub(crate) fn init(isolate: &mut v8::Isolate) {
51    isolate.set_slot::<ExceptionSlot>(RefCell::new(VecDeque::new()));
52}
53
54/// Message listeners belong to the isolate heap, and V8 serializes them into snapshots.
55pub(crate) fn add_listener(isolate: &mut v8::Isolate) {
56    isolate.add_message_listener(uncaught_exception);
57}
58
59pub(crate) fn enqueue<'s>(
60    scope: &mut v8::PinScope<'s, '_>,
61    args: v8::FunctionCallbackArguments<'s>,
62    _result: v8::ReturnValue,
63) {
64    let Ok(callback) = v8::Local::<v8::Function>::try_from(args.get(0)) else {
65        let message = v8::String::new(scope, "Expected a microtask callback").unwrap();
66        let error = v8::Exception::type_error(scope, message);
67        scope.throw_exception(error);
68        return;
69    };
70    scope.enqueue_microtask(callback);
71}
72
73pub(crate) fn process_exceptions(scope: &mut v8::PinScope) -> Option<v8::Global<v8::Value>> {
74    let mut fatal = None;
75    loop {
76        let exceptions =
77            std::mem::take(&mut *scope.get_slot::<ExceptionSlot>().unwrap().borrow_mut());
78        if exceptions.is_empty() {
79            return fatal;
80        }
81        for exception in exceptions {
82            let error = v8::Local::new(scope, &exception.value);
83            if !crate::reporting::report_exception_with_location(
84                scope,
85                error,
86                &exception.filename,
87                exception.line,
88                exception.column,
89            ) && fatal.is_none()
90            {
91                fatal = Some(v8::Global::new(scope, error));
92            }
93        }
94        crate::op::checkpoint(scope);
95    }
96}