bindings: Convert certain Exceptions into Promise rejections (#32923)

* Impl promise exception to rejection for methods

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>

* Impl promise exception to rejection for getters

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>

* Impl promise exception to rejection for static methods

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>

* Add tests for exception to rejection

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>

* Expectations

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>

---------

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
This commit is contained in:
Samson 2024-08-03 14:58:37 +02:00 committed by GitHub
parent fd83281657
commit f3bec0aed3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 291 additions and 20 deletions

View file

@ -6,6 +6,7 @@
use std::ffi::CString;
use std::os::raw::{c_char, c_void};
use std::ptr::NonNull;
use std::{ptr, slice, str};
use js::conversions::ToJSValConvertible;
@ -14,17 +15,19 @@ use js::glue::{
UnwrapObjectDynamic, UnwrapObjectStatic, RUST_FUNCTION_VALUE_TO_JITINFO,
};
use js::jsapi::{
AtomToLinearString, CallArgs, DOMCallbacks, GetLinearStringCharAt, GetLinearStringLength,
GetNonCCWObjectGlobal, HandleId as RawHandleId, HandleObject as RawHandleObject, Heap, JSAtom,
JSContext, JSJitInfo, JSObject, JSTracer, JS_DeprecatedStringHasLatin1Chars,
JS_EnumerateStandardClasses, JS_FreezeObject, JS_GetLatin1StringCharsAndLength,
JS_IsExceptionPending, JS_IsGlobalObject, JS_ResolveStandardClass,
MutableHandleIdVector as RawMutableHandleIdVector, ObjectOpResult, StringIsArrayIndex,
AtomToLinearString, CallArgs, DOMCallbacks, ExceptionStackBehavior, GetLinearStringCharAt,
GetLinearStringLength, GetNonCCWObjectGlobal, HandleId as RawHandleId,
HandleObject as RawHandleObject, Heap, JSAtom, JSContext, JSJitInfo, JSObject, JSTracer,
JS_ClearPendingException, JS_DeprecatedStringHasLatin1Chars, JS_EnumerateStandardClasses,
JS_FreezeObject, JS_GetLatin1StringCharsAndLength, JS_IsExceptionPending, JS_IsGlobalObject,
JS_ResolveStandardClass, MutableHandleIdVector as RawMutableHandleIdVector,
MutableHandleValue as RawMutableHandleValue, ObjectOpResult, StringIsArrayIndex,
};
use js::jsval::{JSVal, UndefinedValue};
use js::rust::wrappers::{
JS_DeletePropertyById, JS_ForwardGetPropertyTo, JS_GetProperty, JS_GetPrototype,
JS_HasProperty, JS_HasPropertyById, JS_SetProperty,
CallOriginalPromiseReject, JS_DeletePropertyById, JS_ForwardGetPropertyTo,
JS_GetPendingException, JS_GetProperty, JS_GetPrototype, JS_HasProperty, JS_HasPropertyById,
JS_SetPendingException, JS_SetProperty,
};
use js::rust::{
get_object_class, is_dom_class, GCMethods, Handle, HandleId, HandleObject, HandleValue,
@ -617,3 +620,41 @@ impl AsCCharPtrPtr for [u8] {
pub unsafe fn callargs_is_constructing(args: &CallArgs) -> bool {
(*args.argv_.offset(-1)).is_magic()
}
/// https://searchfox.org/mozilla-central/rev/7279a1df13a819be254fd4649e07c4ff93e4bd45/dom/bindings/BindingUtils.cpp#3300
pub unsafe extern "C" fn generic_static_promise_method(
cx: *mut JSContext,
argc: libc::c_uint,
vp: *mut JSVal,
) -> bool {
let args = CallArgs::from_vp(vp, argc);
let info = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));
assert!(!info.is_null());
// TODO: we need safe wrappers for this in mozjs!
//assert_eq!((*info)._bitfield_1, JSJitInfo_OpType::StaticMethod as u8)
let static_fn = (*info).__bindgen_anon_1.staticMethod.unwrap();
if static_fn(cx, argc, vp) {
return true;
}
exception_to_promise(cx, args.rval())
}
/// Coverts exception to promise rejection
///
/// https://searchfox.org/mozilla-central/rev/b220e40ff2ee3d10ce68e07d8a8a577d5558e2a2/dom/bindings/BindingUtils.cpp#3315
pub unsafe fn exception_to_promise(cx: *mut JSContext, rval: RawMutableHandleValue) -> bool {
rooted!(in(cx) let mut exception = UndefinedValue());
if !JS_GetPendingException(cx, exception.handle_mut()) {
return false;
}
JS_ClearPendingException(cx);
if let Some(promise) = NonNull::new(CallOriginalPromiseReject(cx, exception.handle())) {
promise.to_jsval(cx, MutableHandleValue::from_raw(rval));
true
} else {
// We just give up. Put the exception back.
JS_SetPendingException(cx, exception.handle(), ExceptionStackBehavior::Capture);
false
}
}