Use dynamic dispatch in mozjs::panic::wrap_panic

Pick up https://github.com/servo/rust-mozjs/pull/512

Fixes https://github.com/servo/servo/issues/26585

This diff is best viewed with "ignore whitespace changes", because of indentation change.
This commit is contained in:
Simon Sapin 2020-05-25 20:29:18 +02:00
parent 6114b75403
commit d103e06ba9
3 changed files with 105 additions and 102 deletions

2
Cargo.lock generated
View file

@ -3572,7 +3572,7 @@ dependencies = [
[[package]] [[package]]
name = "mozjs" name = "mozjs"
version = "0.13.0" version = "0.13.0"
source = "git+https://github.com/servo/rust-mozjs#11cabdef2cbf0884a2cc33e3c73719646bd31ce5" source = "git+https://github.com/servo/rust-mozjs#dbb9bee06e0b0168ccae0619c5077e302669d2fb"
dependencies = [ dependencies = [
"cc", "cc",
"lazy_static", "lazy_static",

View file

@ -2573,9 +2573,19 @@ class CGAbstractMethod(CGThing):
body = self.definition_body() body = self.definition_body()
if self.catchPanic: if self.catchPanic:
body = CGWrapper(CGIndenter(body), if self.returnType == "void":
pre="return wrap_panic(panic::AssertUnwindSafe(|| {\n", pre = "wrap_panic(&mut || {\n"
post=("""\n}), %s);""" % ("()" if self.returnType == "void" else "false"))) post = "\n})"
else:
pre = (
"let mut result = false;\n"
"wrap_panic(&mut || result = (|| {\n"
)
post = (
"\n})());\n"
"return result"
)
body = CGWrapper(CGIndenter(body), pre=pre, post=post)
return CGWrapper(CGIndenter(body), return CGWrapper(CGIndenter(body),
pre=self.definition_prologue(), pre=self.definition_prologue(),

View file

@ -81,7 +81,6 @@ use std::io::{stdout, Write};
use std::ops::Deref; use std::ops::Deref;
use std::os; use std::os;
use std::os::raw::c_void; use std::os::raw::c_void;
use std::panic::AssertUnwindSafe;
use std::ptr; use std::ptr;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Mutex; use std::sync::Mutex;
@ -169,29 +168,27 @@ pub trait ScriptPort {
#[allow(unsafe_code)] #[allow(unsafe_code)]
unsafe extern "C" fn get_incumbent_global(_: *const c_void, _: *mut RawJSContext) -> *mut JSObject { unsafe extern "C" fn get_incumbent_global(_: *const c_void, _: *mut RawJSContext) -> *mut JSObject {
wrap_panic( let mut result = ptr::null_mut();
AssertUnwindSafe(|| { wrap_panic(&mut || {
let incumbent_global = GlobalScope::incumbent(); let incumbent_global = GlobalScope::incumbent();
assert!(incumbent_global.is_some()); assert!(incumbent_global.is_some());
incumbent_global result = incumbent_global
.map(|g| g.reflector().get_jsobject().get()) .map(|g| g.reflector().get_jsobject().get())
.unwrap_or(ptr::null_mut()) .unwrap_or(ptr::null_mut())
}), });
ptr::null_mut(), result
)
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
unsafe extern "C" fn empty(extra: *const c_void) -> bool { unsafe extern "C" fn empty(extra: *const c_void) -> bool {
wrap_panic( let mut result = false;
AssertUnwindSafe(|| { wrap_panic(&mut || {
let microtask_queue = &*(extra as *const MicrotaskQueue); let microtask_queue = &*(extra as *const MicrotaskQueue);
microtask_queue.empty() result = microtask_queue.empty()
}), });
false, result
)
} }
/// SM callback for promise job resolution. Adds a promise callback to the current /// SM callback for promise job resolution. Adds a promise callback to the current
@ -206,30 +203,29 @@ unsafe extern "C" fn enqueue_promise_job(
incumbent_global: HandleObject, incumbent_global: HandleObject,
) -> bool { ) -> bool {
let cx = JSContext::from_ptr(cx); let cx = JSContext::from_ptr(cx);
wrap_panic( let mut result = false;
AssertUnwindSafe(|| { wrap_panic(&mut || {
let microtask_queue = &*(extra as *const MicrotaskQueue); let microtask_queue = &*(extra as *const MicrotaskQueue);
let global = GlobalScope::from_object(incumbent_global.get()); let global = GlobalScope::from_object(incumbent_global.get());
let pipeline = global.pipeline_id(); let pipeline = global.pipeline_id();
let interaction = if promise.get().is_null() { let interaction = if promise.get().is_null() {
PromiseUserInputEventHandlingState::DontCare PromiseUserInputEventHandlingState::DontCare
} else { } else {
GetPromiseUserInputEventHandlingState(promise) GetPromiseUserInputEventHandlingState(promise)
}; };
let is_user_interacting = let is_user_interacting =
interaction == PromiseUserInputEventHandlingState::HadUserInteractionAtCreation; interaction == PromiseUserInputEventHandlingState::HadUserInteractionAtCreation;
microtask_queue.enqueue( microtask_queue.enqueue(
Microtask::Promise(EnqueuedPromiseCallback { Microtask::Promise(EnqueuedPromiseCallback {
callback: PromiseJobCallback::new(cx, job.get()), callback: PromiseJobCallback::new(cx, job.get()),
pipeline, pipeline,
is_user_interacting, is_user_interacting,
}), }),
cx, cx,
); );
true result = true
}), });
false, result
)
} }
#[allow(unsafe_code, unrooted_must_root)] #[allow(unsafe_code, unrooted_must_root)]
@ -248,69 +244,66 @@ unsafe extern "C" fn promise_rejection_tracker(
let in_realm_proof = AlreadyInRealm::assert_for_cx(cx); let in_realm_proof = AlreadyInRealm::assert_for_cx(cx);
let global = GlobalScope::from_context(*cx, InRealm::Already(&in_realm_proof)); let global = GlobalScope::from_context(*cx, InRealm::Already(&in_realm_proof));
wrap_panic( wrap_panic(&mut || {
AssertUnwindSafe(|| { match state {
match state { // Step 4.
// Step 4. PromiseRejectionHandlingState::Unhandled => {
PromiseRejectionHandlingState::Unhandled => { global.add_uncaught_rejection(promise);
global.add_uncaught_rejection(promise); },
}, // Step 5.
// Step 5. PromiseRejectionHandlingState::Handled => {
PromiseRejectionHandlingState::Handled => { // Step 5-1.
// Step 5-1. if global
if global .get_uncaught_rejections()
.get_uncaught_rejections() .borrow()
.borrow() .contains(&Heap::boxed(promise.get()))
.contains(&Heap::boxed(promise.get())) {
{ global.remove_uncaught_rejection(promise);
global.remove_uncaught_rejection(promise); return;
return; }
}
// Step 5-2. // Step 5-2.
if !global if !global
.get_consumed_rejections() .get_consumed_rejections()
.borrow() .borrow()
.contains(&Heap::boxed(promise.get())) .contains(&Heap::boxed(promise.get()))
{ {
return; return;
} }
// Step 5-3. // Step 5-3.
global.remove_consumed_rejection(promise); global.remove_consumed_rejection(promise);
let target = Trusted::new(global.upcast::<EventTarget>()); let target = Trusted::new(global.upcast::<EventTarget>());
let promise = Promise::new_with_js_promise(Handle::from_raw(promise), cx); let promise = Promise::new_with_js_promise(Handle::from_raw(promise), cx);
let trusted_promise = TrustedPromise::new(promise.clone()); let trusted_promise = TrustedPromise::new(promise.clone());
// Step 5-4. // Step 5-4.
global.dom_manipulation_task_source().queue( global.dom_manipulation_task_source().queue(
task!(rejection_handled_event: move || { task!(rejection_handled_event: move || {
let target = target.root(); let target = target.root();
let cx = target.global().get_cx(); let cx = target.global().get_cx();
let root_promise = trusted_promise.root(); let root_promise = trusted_promise.root();
rooted!(in(*cx) let mut reason = UndefinedValue()); rooted!(in(*cx) let mut reason = UndefinedValue());
JS_GetPromiseResult(root_promise.reflector().get_jsobject(), reason.handle_mut()); JS_GetPromiseResult(root_promise.reflector().get_jsobject(), reason.handle_mut());
let event = PromiseRejectionEvent::new( let event = PromiseRejectionEvent::new(
&target.global(), &target.global(),
atom!("rejectionhandled"), atom!("rejectionhandled"),
EventBubbles::DoesNotBubble, EventBubbles::DoesNotBubble,
EventCancelable::Cancelable, EventCancelable::Cancelable,
root_promise, root_promise,
reason.handle() reason.handle()
); );
event.upcast::<Event>().fire(&target); event.upcast::<Event>().fire(&target);
}), }),
global.upcast(), global.upcast(),
).unwrap(); ).unwrap();
}, },
}; };
}), })
(),
);
} }
#[allow(unsafe_code, unrooted_must_root)] #[allow(unsafe_code, unrooted_must_root)]