diff --git a/core/src/context/builder.rs b/core/src/context/builder.rs index e6b1d24a7..bd9a02624 100644 --- a/core/src/context/builder.rs +++ b/core/src/context/builder.rs @@ -77,6 +77,8 @@ pub mod intrinsic { Performance JS_AddPerformance, /// Add WeakRef support WeakRef JS_AddIntrinsicWeakRef, + /// Add DOMException support + DOMException JS_AddIntrinsicDOMException, } /// Add none intrinsics diff --git a/core/src/value/atom/predefined.rs b/core/src/value/atom/predefined.rs index 7b67c4081..526a60806 100644 --- a/core/src/value/atom/predefined.rs +++ b/core/src/value/atom/predefined.rs @@ -389,6 +389,8 @@ pub enum PredefinedAtom { URIError = qjs::JS_ATOM_URIError as u32, /// "InternalError" InternalError = qjs::JS_ATOM_InternalError as u32, + /// "DOMException" + DOMException = qjs::JS_ATOM_DOMException as u32, /// "Symbol.asyncIterator" SymbolAsyncIterator = qjs::JS_ATOM_Symbol_asyncIterator as u32, /// "Symbol.iterator" @@ -626,6 +628,7 @@ impl PredefinedAtom { PredefinedAtom::TypeError => "TypeError", PredefinedAtom::URIError => "URIError", PredefinedAtom::InternalError => "InternalError", + PredefinedAtom::DOMException => "DOMException", PredefinedAtom::SymbolAsyncIterator => "Symbol.asyncIterator", PredefinedAtom::SymbolIterator => "Symbol.iterator", PredefinedAtom::SymbolMatch => "Symbol.match", @@ -839,6 +842,7 @@ mod test { PredefinedAtom::TypeError, PredefinedAtom::URIError, PredefinedAtom::InternalError, + PredefinedAtom::DOMException, PredefinedAtom::SymbolAsyncIterator, PredefinedAtom::SymbolIterator, PredefinedAtom::SymbolMatch, diff --git a/core/src/value/exception.rs b/core/src/value/exception.rs index d208ea32e..f83119b42 100644 --- a/core/src/value/exception.rs +++ b/core/src/value/exception.rs @@ -1,5 +1,5 @@ use alloc::string::String; -use core::{error::Error as ErrorTrait, ffi::CStr, fmt}; +use core::{error::Error as ErrorTrait, ffi::CStr, fmt, mem::MaybeUninit}; use crate::{atom::PredefinedAtom, convert::Coerced, qjs, Ctx, Error, Object, Result, Value}; @@ -35,6 +35,24 @@ fn truncate_str(mut max: usize, bytes: &[u8]) -> &[u8] { &bytes[..max] } +// generate C string inline. +// QuickJS implementation doesn't allow error strings longer then 256 anyway +// so truncating here is fine. +#[inline] +fn stack_cstr(str: &str) -> MaybeUninit<[u8; 256]> { + let mut buffer = MaybeUninit::<[u8; 256]>::uninit(); + let bytes = truncate_str(255, str.as_bytes()); + unsafe { + core::ptr::copy_nonoverlapping(bytes.as_ptr(), buffer.as_mut_ptr().cast(), bytes.len()); + buffer + .as_mut_ptr() + .cast::() + .add(bytes.len()) + .write(b'\0'); + } + buffer +} + impl<'js> Exception<'js> { /// Turns the exception into the underlying object. pub fn into_object(self) -> Object<'js> { @@ -109,19 +127,10 @@ impl<'js> Exception<'js> { /// Throws a new syntax error. pub fn throw_syntax(ctx: &Ctx<'js>, message: &str) -> Error { - // generate C string inline. - // QuickJS implementation doesn't allow error strings longer then 256 anyway so truncating - // here is fine. - let mut buffer = core::mem::MaybeUninit::<[u8; 256]>::uninit(); - let str = truncate_str(255, message.as_bytes()); + let buffer = stack_cstr(message); unsafe { - core::ptr::copy_nonoverlapping(message.as_ptr(), buffer.as_mut_ptr().cast(), str.len()); - buffer.as_mut_ptr().cast::().add(str.len()).write(b'\0'); - let res = qjs::JS_ThrowSyntaxError( - ctx.as_ptr(), - ERROR_FORMAT_STR.as_ptr(), - buffer.as_ptr().cast::<*mut u8>(), - ); + let res = + qjs::JS_ThrowSyntaxError(ctx.as_ptr(), ERROR_FORMAT_STR.as_ptr(), buffer.as_ptr()); debug_assert_eq!(qjs::JS_VALUE_GET_NORM_TAG(res), qjs::JS_TAG_EXCEPTION); } Error::Exception @@ -129,19 +138,10 @@ impl<'js> Exception<'js> { /// Throws a new type error. pub fn throw_type(ctx: &Ctx<'js>, message: &str) -> Error { - // generate C string inline. - // QuickJS implementation doesn't allow error strings longer then 256 anyway so truncating - // here is fine. - let mut buffer = core::mem::MaybeUninit::<[u8; 256]>::uninit(); - let str = truncate_str(255, message.as_bytes()); + let buffer = stack_cstr(message); unsafe { - core::ptr::copy_nonoverlapping(message.as_ptr(), buffer.as_mut_ptr().cast(), str.len()); - buffer.as_mut_ptr().cast::().add(str.len()).write(b'\0'); - let res = qjs::JS_ThrowTypeError( - ctx.as_ptr(), - ERROR_FORMAT_STR.as_ptr(), - buffer.as_ptr().cast::<*mut u8>(), - ); + let res = + qjs::JS_ThrowTypeError(ctx.as_ptr(), ERROR_FORMAT_STR.as_ptr(), buffer.as_ptr()); debug_assert_eq!(qjs::JS_VALUE_GET_NORM_TAG(res), qjs::JS_TAG_EXCEPTION); } Error::Exception @@ -149,18 +149,12 @@ impl<'js> Exception<'js> { /// Throws a new reference error. pub fn throw_reference(ctx: &Ctx<'js>, message: &str) -> Error { - // generate C string inline. - // QuickJS implementation doesn't allow error strings longer then 256 anyway so truncating - // here is fine. - let mut buffer = core::mem::MaybeUninit::<[u8; 256]>::uninit(); - let str = truncate_str(255, message.as_bytes()); + let buffer = stack_cstr(message); unsafe { - core::ptr::copy_nonoverlapping(message.as_ptr(), buffer.as_mut_ptr().cast(), str.len()); - buffer.as_mut_ptr().cast::().add(str.len()).write(b'\0'); let res = qjs::JS_ThrowReferenceError( ctx.as_ptr(), ERROR_FORMAT_STR.as_ptr(), - buffer.as_ptr().cast::<*mut u8>(), + buffer.as_ptr(), ); debug_assert_eq!(qjs::JS_VALUE_GET_NORM_TAG(res), qjs::JS_TAG_EXCEPTION); } @@ -169,19 +163,10 @@ impl<'js> Exception<'js> { /// Throws a new range error. pub fn throw_range(ctx: &Ctx<'js>, message: &str) -> Error { - // generate C string inline. - // QuickJS implementation doesn't allow error strings longer then 256 anyway so truncating - // here is fine. - let mut buffer = core::mem::MaybeUninit::<[u8; 256]>::uninit(); - let str = truncate_str(255, message.as_bytes()); + let buffer = stack_cstr(message); unsafe { - core::ptr::copy_nonoverlapping(message.as_ptr(), buffer.as_mut_ptr().cast(), str.len()); - buffer.as_mut_ptr().cast::().add(str.len()).write(b'\0'); - let res = qjs::JS_ThrowRangeError( - ctx.as_ptr(), - ERROR_FORMAT_STR.as_ptr(), - buffer.as_ptr().cast::<*mut u8>(), - ); + let res = + qjs::JS_ThrowRangeError(ctx.as_ptr(), ERROR_FORMAT_STR.as_ptr(), buffer.as_ptr()); debug_assert_eq!(qjs::JS_VALUE_GET_NORM_TAG(res), qjs::JS_TAG_EXCEPTION); } Error::Exception @@ -189,18 +174,28 @@ impl<'js> Exception<'js> { /// Throws a new internal error. pub fn throw_internal(ctx: &Ctx<'js>, message: &str) -> Error { - // generate C string inline. - // QuickJS implementation doesn't allow error strings longer then 256 anyway so truncating - // here is fine. - let mut buffer = core::mem::MaybeUninit::<[u8; 256]>::uninit(); - let str = truncate_str(255, message.as_bytes()); + let buffer = stack_cstr(message); unsafe { - core::ptr::copy_nonoverlapping(message.as_ptr(), buffer.as_mut_ptr().cast(), str.len()); - buffer.as_mut_ptr().cast::().add(str.len()).write(b'\0'); let res = qjs::JS_ThrowInternalError( ctx.as_ptr(), ERROR_FORMAT_STR.as_ptr(), - buffer.as_ptr().cast::<*mut u8>(), + buffer.as_ptr(), + ); + debug_assert_eq!(qjs::JS_VALUE_GET_NORM_TAG(res), qjs::JS_TAG_EXCEPTION); + } + Error::Exception + } + + /// Throws a new DOMException + pub fn throw_dom(ctx: &Ctx<'js>, name: &str, message: &str) -> Error { + let name = stack_cstr(name); + let message = stack_cstr(message); + unsafe { + let res = qjs::JS_ThrowDOMException( + ctx.as_ptr(), + name.as_ptr().cast(), + ERROR_FORMAT_STR.as_ptr(), + message.as_ptr(), ); debug_assert_eq!(qjs::JS_VALUE_GET_NORM_TAG(res), qjs::JS_TAG_EXCEPTION); } diff --git a/sys/quickjs b/sys/quickjs index 07214197c..632601d68 160000 --- a/sys/quickjs +++ b/sys/quickjs @@ -1 +1 @@ -Subproject commit 07214197c24bb60066a0378ebd7690041f86e361 +Subproject commit 632601d68fed1a4e43d8d8857450484cbb84fd97