Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/src/context/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions core/src/value/atom/predefined.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -839,6 +842,7 @@ mod test {
PredefinedAtom::TypeError,
PredefinedAtom::URIError,
PredefinedAtom::InternalError,
PredefinedAtom::DOMException,
PredefinedAtom::SymbolAsyncIterator,
PredefinedAtom::SymbolIterator,
PredefinedAtom::SymbolMatch,
Expand Down
101 changes: 48 additions & 53 deletions core/src/value/exception.rs
Original file line number Diff line number Diff line change
@@ -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};

Expand Down Expand Up @@ -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::<u8>()
.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> {
Expand Down Expand Up @@ -109,58 +127,34 @@ 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::<u8>().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
}

/// 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::<u8>().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
}

/// 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::<u8>().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);
}
Expand All @@ -169,38 +163,39 @@ 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::<u8>().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
}

/// 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::<u8>().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);
}
Expand Down
2 changes: 1 addition & 1 deletion sys/quickjs
Loading