From 6711953620dae7e1bb962762945e04d023a1caea Mon Sep 17 00:00:00 2001 From: KAUSTUBHOG Date: Sat, 14 Mar 2026 01:54:52 +0530 Subject: [PATCH] fix(builtins/typed_array,iterable,generator,error,bigint,eval): convert panics to EngineError::Panic using js_expect Part of #3241. It changes the following: core/engine/src/builtins/typed_array/builtin.rs: converted 30 panics core/engine/src/builtins/typed_array/object.rs: converted 3 panics core/engine/src/builtins/iterable/async_from_sync_iterator.rs: converted 8 panics core/engine/src/builtins/generator/mod.rs: converted 3 panics core/engine/src/builtins/error/aggregate.rs: converted 1 panic core/engine/src/builtins/bigint/mod.rs: converted 1 panic core/engine/src/builtins/eval/mod.rs: converted 1 panic --- core/engine/src/builtins/bigint/mod.rs | 9 +- core/engine/src/builtins/error/aggregate.rs | 4 +- core/engine/src/builtins/eval/mod.rs | 4 +- core/engine/src/builtins/generator/mod.rs | 26 ++++-- .../iterable/async_from_sync_iterator.rs | 18 ++-- core/engine/src/builtins/json/mod.rs | 4 +- core/engine/src/builtins/promise/mod.rs | 8 +- .../src/builtins/typed_array/builtin.rs | 88 ++++++++++--------- .../engine/src/builtins/typed_array/object.rs | 38 ++++---- core/engine/src/object/builtins/jspromise.rs | 4 +- core/engine/src/vm/opcode/await/mod.rs | 4 +- 11 files changed, 113 insertions(+), 94 deletions(-) diff --git a/core/engine/src/builtins/bigint/mod.rs b/core/engine/src/builtins/bigint/mod.rs index 96ba6db92af..d7f557d06fc 100644 --- a/core/engine/src/builtins/bigint/mod.rs +++ b/core/engine/src/builtins/bigint/mod.rs @@ -13,7 +13,7 @@ //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt use crate::{ - Context, JsArgs, JsBigInt, JsResult, JsString, JsValue, + Context, JsArgs, JsBigInt, JsExpect, JsResult, JsString, JsValue, builtins::BuiltInObject, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, error::JsNativeError, @@ -122,7 +122,12 @@ impl BigInt { } // 2. Return the BigInt value that represents โ„(number). - Ok(JsBigInt::from(number.to_bigint().expect("This conversion must be safe")).into()) + Ok(JsBigInt::from( + number + .to_bigint() + .js_expect("This conversion must be safe")?, + ) + .into()) } /// The abstract operation `thisBigIntValue` takes argument value. diff --git a/core/engine/src/builtins/error/aggregate.rs b/core/engine/src/builtins/error/aggregate.rs index a0fa11e524f..186f6aede5a 100644 --- a/core/engine/src/builtins/error/aggregate.rs +++ b/core/engine/src/builtins/error/aggregate.rs @@ -8,7 +8,7 @@ //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError use crate::{ - Context, JsArgs, JsResult, JsString, JsValue, + Context, JsArgs, JsExpect, JsResult, JsString, JsValue, builtins::{ Array, BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject, iterable::IteratorHint, @@ -128,7 +128,7 @@ impl BuiltInConstructor for AggregateError { .build(), context, ) - .expect("should not fail according to spec"); + .js_expect("should not fail according to spec")?; // 5. Return O. Ok(o.into()) diff --git a/core/engine/src/builtins/eval/mod.rs b/core/engine/src/builtins/eval/mod.rs index 07f32265398..f8fc8f458f0 100644 --- a/core/engine/src/builtins/eval/mod.rs +++ b/core/engine/src/builtins/eval/mod.rs @@ -10,7 +10,7 @@ //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval use crate::{ - Context, JsArgs, JsResult, JsString, JsValue, SpannedSourceText, + Context, JsArgs, JsExpect, JsResult, JsString, JsValue, SpannedSourceText, builtins::{BuiltInObject, function::OrdinaryFunction}, bytecompiler::{ByteCompiler, prepare_eval_declaration_instantiation}, context::intrinsics::Intrinsics, @@ -152,7 +152,7 @@ impl Eval { .slots() .function_object() .downcast_ref::() - .expect("must be function object"); + .js_expect("must be function object")?; // ii. Set inFunction to true. let mut flags = Flags::IN_FUNCTION; diff --git a/core/engine/src/builtins/generator/mod.rs b/core/engine/src/builtins/generator/mod.rs index 6b010d42c09..74ad7a0feec 100644 --- a/core/engine/src/builtins/generator/mod.rs +++ b/core/engine/src/builtins/generator/mod.rs @@ -10,10 +10,11 @@ //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator use crate::{ - Context, JsArgs, JsData, JsError, JsResult, JsString, + Context, JsArgs, JsData, JsError, JsExpect, JsResult, JsString, builtins::iterable::create_iter_result_object, context::intrinsics::Intrinsics, error::JsNativeError, + error::PanicError, js_string, object::{CONSTRUCTOR, JsObject}, property::Attribute, @@ -101,7 +102,9 @@ impl GeneratorContext { context: &mut Context, ) -> CompletionRecord { std::mem::swap(&mut context.vm.stack, &mut self.stack); - let frame = self.call_frame.take().expect("should have a call frame"); + let Some(frame) = self.call_frame.take() else { + return CompletionRecord::Throw(PanicError::new("should have a call frame").into()); + }; let fp = frame.fp; let rp = frame.rp; context.vm.push_frame(frame); @@ -125,16 +128,21 @@ impl GeneratorContext { } /// Returns the async generator object, if the function that this [`GeneratorContext`] is from an async generator, [`None`] otherwise. - pub(crate) fn async_generator_object(&self) -> Option { - let frame = self.call_frame.as_ref()?; + pub(crate) fn async_generator_object(&self) -> JsResult> { + let Some(frame) = self.call_frame.as_ref() else { + return Ok(None); + }; + if !frame.code_block().is_async_generator() { - return None; + return Ok(None); } - self.stack + let val = self + .stack .get_register(frame, CallFrame::ASYNC_GENERATOR_OBJECT_REGISTER_INDEX) - .expect("registers must have an async generator object") - .as_object() + .js_expect("registers must have an async generator object")?; + + Ok(val.as_object()) } } @@ -306,7 +314,7 @@ impl Generator { let mut r#gen = generator_obj .downcast_mut::() - .expect("already checked this object type"); + .js_expect("already checked this object type")?; // 8. Push genContext onto the execution context stack; genContext is now the running execution context. // 9. Resume the suspended evaluation of genContext using NormalCompletion(value) as the result of the operation that suspended it. Let result be the value returned by the resumed computation. diff --git a/core/engine/src/builtins/iterable/async_from_sync_iterator.rs b/core/engine/src/builtins/iterable/async_from_sync_iterator.rs index f7719ded246..56b198e80e3 100644 --- a/core/engine/src/builtins/iterable/async_from_sync_iterator.rs +++ b/core/engine/src/builtins/iterable/async_from_sync_iterator.rs @@ -1,5 +1,5 @@ use crate::{ - Context, JsArgs, JsData, JsError, JsNativeError, JsResult, JsValue, + Context, JsArgs, JsData, JsError, JsExpect, JsNativeError, JsResult, JsValue, builtins::{ BuiltInBuilder, IntrinsicObject, Promise, iterable::{IteratorRecord, IteratorResult, create_iter_result_object}, @@ -99,7 +99,7 @@ impl AsyncFromSyncIterator { let mut sync_iterator_record = object .as_ref() .and_then(JsObject::downcast_ref::) - .expect("async from sync iterator prototype must be object") + .js_expect("async from sync iterator prototype must be object")? .sync_iterator_record .clone(); @@ -108,7 +108,7 @@ impl AsyncFromSyncIterator { &context.intrinsics().constructors().promise().constructor(), context, ) - .expect("cannot fail with promise constructor"); + .js_expect("cannot fail with promise constructor")?; // 5. If value is present, then // a. Let result be Completion(IteratorNext(syncIteratorRecord, value)). @@ -143,7 +143,7 @@ impl AsyncFromSyncIterator { let sync_iterator_record = object .as_ref() .and_then(JsObject::downcast_ref::) - .expect("async from sync iterator prototype must be object") + .js_expect("async from sync iterator prototype must be object")? .sync_iterator_record .clone(); // 5. Let syncIterator be syncIteratorRecord.[[Iterator]]. @@ -154,7 +154,7 @@ impl AsyncFromSyncIterator { &context.intrinsics().constructors().promise().constructor(), context, ) - .expect("cannot fail with promise constructor"); + .js_expect("cannot fail with promise constructor")?; // 6. Let return be Completion(GetMethod(syncIterator, "return")). let r#return = sync_iterator.get_method(js_string!("return"), context); @@ -173,7 +173,7 @@ impl AsyncFromSyncIterator { promise_capability .resolve() .call(&JsValue::undefined(), &[iter_result], context) - .expect("cannot fail according to spec"); + .js_expect("cannot fail according to spec")?; // c. Return promiseCapability.[[Promise]]. return Ok(promise_capability.promise().clone().into()); @@ -225,7 +225,7 @@ impl AsyncFromSyncIterator { let sync_iterator_record = object .as_ref() .and_then(JsObject::downcast_ref::) - .expect("async from sync iterator prototype must be object") + .js_expect("async from sync iterator prototype must be object")? .sync_iterator_record .clone(); // 5. Let syncIterator be syncIteratorRecord.[[Iterator]]. @@ -236,7 +236,7 @@ impl AsyncFromSyncIterator { &context.intrinsics().constructors().promise().constructor(), context, ) - .expect("cannot fail with promise constructor"); + .js_expect("cannot fail with promise constructor")?; // 6. Let throw be Completion(GetMethod(syncIterator, "throw")). let throw = sync_iterator.get_method(js_string!("throw"), context); @@ -267,7 +267,7 @@ impl AsyncFromSyncIterator { .into()], context, ) - .expect("cannot fail according to spec"); + .js_expect("cannot fail according to spec")?; // h. Return promiseCapability.[[Promise]]. return Ok(promise_capability.promise().clone().into()); diff --git a/core/engine/src/builtins/json/mod.rs b/core/engine/src/builtins/json/mod.rs index 5d6969eefaf..c3692eed980 100644 --- a/core/engine/src/builtins/json/mod.rs +++ b/core/engine/src/builtins/json/mod.rs @@ -563,11 +563,11 @@ impl Json { // 5. Perform ! CreateDataPropertyOrThrow(obj, "rawJSON", jsonString). obj.create_data_property_or_throw(js_string!("rawJSON"), json_string, context) - .expect("CreateDataPropertyOrThrow should never throw here"); + .js_expect("CreateDataPropertyOrThrow should never throw here")?; // 6. Perform ! SetIntegrityLevel(obj, frozen). obj.set_integrity_level(IntegrityLevel::Frozen, context) - .expect("SetIntegrityLevel should never throw here"); + .js_expect("SetIntegrityLevel should never throw here")?; // 7. Return obj. Ok(obj.into()) diff --git a/core/engine/src/builtins/promise/mod.rs b/core/engine/src/builtins/promise/mod.rs index 2d1f8f17c3e..e8d09fc3514 100644 --- a/core/engine/src/builtins/promise/mod.rs +++ b/core/engine/src/builtins/promise/mod.rs @@ -1298,10 +1298,10 @@ impl Promise { js_string!("fulfilled"), context, ) - .expect("cannot fail per spec"); + .js_expect("cannot fail per spec")?; // c. Perform ! CreateDataPropertyOrThrow(obj, "value", x). obj.create_data_property_or_throw(js_string!("value"), x, context) - .expect("cannot fail per spec"); + .js_expect("cannot fail per spec")?; // d. Set values[index] to obj. captures.values.borrow_mut()[captures.index] = obj.into(); } @@ -1374,10 +1374,10 @@ impl Promise { js_string!("rejected"), context, ) - .expect("cannot fail per spec"); + .js_expect("cannot fail per spec")?; // 5. Perform ! CreateDataPropertyOrThrow(obj, "reason", x). obj.create_data_property_or_throw(js_string!("reason"), x, context) - .expect("cannot fail per spec"); + .js_expect("cannot fail per spec")?; // 6. Set values[index] to obj. captures.values.borrow_mut()[captures.index] = obj.into(); diff --git a/core/engine/src/builtins/typed_array/builtin.rs b/core/engine/src/builtins/typed_array/builtin.rs index 391ca0f3f32..598211dced0 100644 --- a/core/engine/src/builtins/typed_array/builtin.rs +++ b/core/engine/src/builtins/typed_array/builtin.rs @@ -10,7 +10,7 @@ use super::{ ContentType, TypedArray, TypedArrayKind, TypedArrayMarker, object::typed_array_set_element, }; use crate::{ - Context, JsArgs, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, + Context, JsArgs, JsExpect, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, builtins::{ Array, BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject, array::{ArrayIterator, Direction, find_via_predicate}, @@ -264,7 +264,7 @@ impl BuiltinTypedArray { // 8. Let arrayLike be ! ToObject(source). let array_like = source .to_object(context) - .expect("ToObject cannot fail here"); + .js_expect("ToObject cannot fail here")?; // 9. Let len be ? LengthOfArrayLike(arrayLike). let len = array_like.length_of_array_like(context)?; @@ -395,7 +395,9 @@ impl BuiltinTypedArray { } // 8. Return ! Get(O, ! ToString(๐”ฝ(k))). - Ok(o.upcast().get(k, context).expect("Get cannot fail here")) + Ok(o.upcast() + .get(k, context) + .js_expect("Get cannot fail here")?) } /// `get %TypedArray%.prototype.buffer` @@ -769,7 +771,7 @@ impl BuiltinTypedArray { // a. Let Pk be ! ToString(๐”ฝ(k)). // b. Perform ! Set(O, Pk, value, true). ta.set(k, value.clone(), true, context) - .expect("Set cannot fail here"); + .js_expect("Set cannot fail here")?; // c. Set k to k + 1. } @@ -820,7 +822,7 @@ impl BuiltinTypedArray { for k in 0..len { // a. Let Pk be ! ToString(๐”ฝ(k)). // b. Let kValue be ! Get(O, Pk). - let k_value = ta.get(k, context).expect("Get cannot fail here"); + let k_value = ta.get(k, context).js_expect("Get cannot fail here")?; // c. Let selected be ! ToBoolean(? Call(callbackfn, thisArg, ยซ kValue, ๐”ฝ(k), O ยป)).# let selected = callback_fn @@ -849,7 +851,7 @@ impl BuiltinTypedArray { for (n, e) in kept.iter().enumerate() { // a. Perform ! Set(A, ! ToString(๐”ฝ(n)), e, true). a.set(n, e.clone(), true, context) - .expect("Set cannot fail here"); + .js_expect("Set cannot fail here")?; // b. Set n to n + 1. } @@ -1036,7 +1038,7 @@ impl BuiltinTypedArray { for k in 0..len { // a. Let Pk be ! ToString(๐”ฝ(k)). // b. Let kValue be ! Get(O, Pk). - let k_value = ta.get(k, context).expect("Get cannot fail here"); + let k_value = ta.get(k, context).js_expect("Get cannot fail here")?; // c. Perform ? Call(callbackfn, thisArg, ยซ kValue, ๐”ฝ(k), O ยป). callback_fn.call( @@ -1100,7 +1102,7 @@ impl BuiltinTypedArray { let ta = ta.upcast(); for k in k..len { // a. Let elementK be ! Get(O, ! ToString(๐”ฝ(k))). - let element_k = ta.get(k, context).expect("Get cannot fail here"); + let element_k = ta.get(k, context).js_expect("Get cannot fail here")?; // b. If SameValueZero(searchElement, elementK) is true, return true. if JsValue::same_value_zero(args.get_or_undefined(0), &element_k) { @@ -1168,7 +1170,7 @@ impl BuiltinTypedArray { // b.i. Let elementK be ! Get(O, ! ToString(๐”ฝ(k))). // ii. Let same be IsStrictlyEqual(searchElement, elementK). // iii. If same is true, return ๐”ฝ(k). - if let Some(element_k) = ta.try_get(k, context).expect("Get cannot fail here") + if let Some(element_k) = ta.try_get(k, context).js_expect("Get cannot fail here")? && args.get_or_undefined(0).strict_equals(&element_k) { return Ok(k.into()); @@ -1221,7 +1223,7 @@ impl BuiltinTypedArray { } // b. Let element be ! Get(O, ! ToString(๐”ฝ(k))). - let element = ta.get(k, context).expect("Get cannot fail here"); + let element = ta.get(k, context).js_expect("Get cannot fail here")?; // c. If element is undefined, let next be the empty String; otherwise, let next be ! ToString(element). // d. Set R to the string-concatenation of R and next. @@ -1303,7 +1305,7 @@ impl BuiltinTypedArray { // b.i. Let elementK be ! Get(O, ! ToString(๐”ฝ(k))). // ii. Let same be IsStrictlyEqual(searchElement, elementK). // iii. If same is true, return ๐”ฝ(k). - if let Some(element_k) = ta.try_get(k, context).expect("Get cannot fail here") + if let Some(element_k) = ta.try_get(k, context).js_expect("Get cannot fail here")? && args.get_or_undefined(0).strict_equals(&element_k) { return Ok(k.into()); @@ -1391,7 +1393,7 @@ impl BuiltinTypedArray { for k in 0..len { // a. Let Pk be ! ToString(๐”ฝ(k)). // b. Let kValue be ! Get(O, Pk). - let k_value = ta.get(k, context).expect("Get cannot fail here"); + let k_value = ta.get(k, context).js_expect("Get cannot fail here")?; // c. Let mappedValue be ? Call(callbackfn, thisArg, ยซ kValue, ๐”ฝ(k), O ยป). let mapped_value = callback_fn.call( @@ -1460,14 +1462,14 @@ impl BuiltinTypedArray { // b. Set accumulator to ! Get(O, Pk). // c. Set k to k + 1. k += 1; - ta.get(0, context).expect("Get cannot fail here") + ta.get(0, context).js_expect("Get cannot fail here")? }; // 10. Repeat, while k < len, for k in k..len { // a. Let Pk be ! ToString(๐”ฝ(k)). // b. Let kValue be ! Get(O, Pk). - let k_value = ta.get(k, context).expect("Get cannot fail here"); + let k_value = ta.get(k, context).js_expect("Get cannot fail here")?; // c. Set accumulator to ? Call(callbackfn, undefined, ยซ accumulator, kValue, ๐”ฝ(k), O ยป). accumulator = callback_fn.call( @@ -1530,7 +1532,7 @@ impl BuiltinTypedArray { } else { // a. Let Pk be ! ToString(๐”ฝ(k)). // b. Set accumulator to ! Get(O, Pk). - let accumulator = ta.get(len - 1, context).expect("Get cannot fail here"); + let accumulator = ta.get(len - 1, context).js_expect("Get cannot fail here")?; // c. Set k to k - 1. (accumulator, len - 1) @@ -1540,7 +1542,7 @@ impl BuiltinTypedArray { for k in (0..k).rev() { // a. Let Pk be ! ToString(๐”ฝ(k)). // b. Let kValue be ! Get(O, Pk). - let k_value = ta.get(k, context).expect("Get cannot fail here"); + let k_value = ta.get(k, context).js_expect("Get cannot fail here")?; // c. Set accumulator to ? Call(callbackfn, undefined, ยซ accumulator, kValue, ๐”ฝ(k), O ยป). accumulator = callback_fn.call( @@ -1590,16 +1592,16 @@ impl BuiltinTypedArray { // b. Let upperP be ! ToString(๐”ฝ(upper)). // c. Let lowerP be ! ToString(๐”ฝ(lower)). // d. Let lowerValue be ! Get(O, lowerP). - let lower_value = ta.get(lower, context).expect("Get cannot fail here"); + let lower_value = ta.get(lower, context).js_expect("Get cannot fail here")?; // e. Let upperValue be ! Get(O, upperP). - let upper_value = ta.get(upper, context).expect("Get cannot fail here"); + let upper_value = ta.get(upper, context).js_expect("Get cannot fail here")?; // f. Perform ! Set(O, lowerP, upperValue, true). ta.set(lower, upper_value, true, context) - .expect("Set cannot fail here"); + .js_expect("Set cannot fail here")?; // g. Perform ! Set(O, upperP, lowerValue, true). ta.set(upper, lower_value, true, context) - .expect("Set cannot fail here"); + .js_expect("Set cannot fail here")?; // h. Set lower to lower + 1. lower += 1; @@ -1637,11 +1639,11 @@ impl BuiltinTypedArray { // c. Let fromValue be ! Get(O, from). let value = ta .get(len - k - 1, context) - .expect("cannot fail per the spec"); + .js_expect("cannot fail per the spec")?; // d. Perform ! Set(A, Pk, fromValue, true). new_array .set(k, value, true, context) - .expect("cannot fail per the spec"); + .js_expect("cannot fail per the spec")?; // e. Set k to k + 1. } @@ -1819,7 +1821,7 @@ impl BuiltinTypedArray { let slice = src_buf_obj.as_buffer(); let slice = slice .bytes_with_len(src_buf_len) - .expect("Already checked for detached buffer"); + .js_expect("Already checked for detached buffer")?; // b. Set srcBuffer to ? CloneArrayBuffer(srcBuffer, srcByteOffset, srcByteLength, %ArrayBuffer%). // c. NOTE: %ArrayBuffer% is used to clone srcBuffer because is it known to not have any observable side-effects. @@ -1846,12 +1848,12 @@ impl BuiltinTypedArray { let src_buffer = src_buf_obj.as_buffer(); let src_buffer = src_buffer .bytes_with_len(src_buf_len) - .expect("Already checked for detached buffer"); + .js_expect("Already checked for detached buffer")?; let mut target_buffer = target_buf_obj.as_buffer_mut(); let mut target_buffer = target_buffer .bytes_with_len(target_buf_len) - .expect("Already checked for detached buffer"); + .js_expect("Already checked for detached buffer")?; // 24. If srcType is the same as targetType, then if src_type == target_type { @@ -1901,7 +1903,7 @@ impl BuiltinTypedArray { let value = target_type .get_element(&value, context) - .expect("value can only be f64 or BigInt"); + .js_expect("value can only be f64 or BigInt")?; // ii. Perform SetValueInBuffer(targetBuffer, targetByteIndex, targetType, value, true, Unordered). // SAFETY: previous checks preserve the validity of the indices. @@ -2097,12 +2099,12 @@ impl BuiltinTypedArray { for (n, k) in (start_index..end_index).enumerate() { // 1. Let Pk be ! ToString(๐”ฝ(k)). // 2. Let kValue be ! Get(O, Pk). - let k_value = src.get(k, context).expect("Get cannot fail here"); + let k_value = src.get(k, context).js_expect("Get cannot fail here")?; // 3. Perform ! Set(A, ! ToString(๐”ฝ(n)), kValue, true). target .set(n, k_value, true, context) - .expect("Set cannot fail here"); + .js_expect("Set cannot fail here")?; // 4. Set k to k + 1. // 5. Set n to n + 1. @@ -2150,7 +2152,7 @@ impl BuiltinTypedArray { let mut src_buf_borrow = src_borrow.data().viewed_array_buffer().as_buffer_mut(); let mut src_buf = src_buf_borrow .bytes_with_len(src_buf_len) - .expect("already checked that the buffer is not detached"); + .js_expect("already checked that the buffer is not detached")?; #[cfg(debug_assertions)] { @@ -2171,7 +2173,7 @@ impl BuiltinTypedArray { let mut target_buf = target_borrow.data().viewed_array_buffer().as_buffer_mut(); let mut target_buf = target_buf .bytes(Ordering::SeqCst) - .expect("newly created array cannot be detached"); + .js_expect("newly created array cannot be detached")?; #[cfg(debug_assertions)] { @@ -2233,7 +2235,7 @@ impl BuiltinTypedArray { for k in 0..len { // a. Let Pk be ! ToString(๐”ฝ(k)). // b. Let kValue be ! Get(O, Pk). - let k_value = ta.get(k, context).expect("Get cannot fail here"); + let k_value = ta.get(k, context).js_expect("Get cannot fail here")?; // c. Let testResult be ! ToBoolean(? Call(callbackfn, thisArg, ยซ kValue, ๐”ฝ(k), O ยป)). // d. If testResult is true, return true. @@ -2299,7 +2301,7 @@ impl BuiltinTypedArray { for (j, item) in sorted.into_iter().enumerate() { // a. Perform ! Set(obj, ! ToString(๐”ฝ(j)), sortedList[j], true). ta.set(j, item, true, context) - .expect("cannot fail per spec"); + .js_expect("cannot fail per spec")?; // b. Set j to j + 1. } @@ -2356,7 +2358,7 @@ impl BuiltinTypedArray { // a. Perform ! Set(A, ! ToString(๐”ฝ(j)), sortedList[j], true). new_array .set(j, item, true, context) - .expect("cannot fail per spec"); + .js_expect("cannot fail per spec")?; // b. Set j to j + 1. } @@ -2630,12 +2632,12 @@ impl BuiltinTypedArray { numeric_value.clone() } else { // c. Else, let fromValue be ! Get(O, Pk). - ta.get(k, context).expect("cannot fail per the spec") + ta.get(k, context).js_expect("cannot fail per the spec")? }; // d. Perform ! Set(A, Pk, fromValue, true). new_array .set(k, value, true, context) - .expect("cannot fail per the spec"); + .js_expect("cannot fail per the spec")?; // e. Set k to k + 1. } @@ -2928,7 +2930,7 @@ impl BuiltinTypedArray { let mut data = SliceRefMut::Slice( data.data_mut() .bytes_mut() - .expect("a new buffer cannot be detached"), + .js_expect("a new buffer cannot be detached")?, ); // b. If srcArray.[[ContentType]] is not O.[[ContentType]], throw a TypeError exception. @@ -2966,7 +2968,7 @@ impl BuiltinTypedArray { // TODO: cast between types instead of converting to `JsValue`. let value = element_type .get_element(&value, context) - .expect("value must be bigint or float"); + .js_expect("value must be bigint or float")?; // ii. Perform SetValueInBuffer(data, targetByteIndex, elementType, value, true, unordered). // SAFETY: The newly created buffer has at least `element_size * element_length` @@ -3261,10 +3263,10 @@ fn compare_typed_array_elements( /// - [ECMAScript reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-isvalidintegerindex -pub(crate) fn is_valid_integer_index(obj: &JsObject, index: f64) -> bool { - let inner = obj.downcast_ref::().expect( - "integer indexed exotic method should only be callable from integer indexed objects", - ); +pub(crate) fn is_valid_integer_index(obj: &JsObject, index: f64) -> JsResult { + let inner = obj.downcast_ref::().js_expect( + "integer indexed exotic method should only be callable from TypedArray objects", + )?; let buf = inner.viewed_array_buffer(); let buf = buf.as_buffer(); @@ -3273,8 +3275,8 @@ pub(crate) fn is_valid_integer_index(obj: &JsObject, index: f64) -> bool { // 4. Let taRecord be MakeTypedArrayWithBufferWitnessRecord(O, unordered). // 5. NOTE: Bounds checking is not a synchronizing operation when O's backing buffer is a growable SharedArrayBuffer. let Some(buf_len) = buf.bytes(Ordering::Relaxed).map(|s| s.len()) else { - return false; + return Ok(false); }; - inner.validate_index(index, buf_len).is_some() + Ok(inner.validate_index(index, buf_len).is_some()) } diff --git a/core/engine/src/builtins/typed_array/object.rs b/core/engine/src/builtins/typed_array/object.rs index 9298d167923..500071e8be2 100644 --- a/core/engine/src/builtins/typed_array/object.rs +++ b/core/engine/src/builtins/typed_array/object.rs @@ -3,7 +3,7 @@ use std::sync::atomic::Ordering; use crate::{ - Context, JsNativeError, JsResult, JsString, JsValue, + Context, JsExpect, JsNativeError, JsResult, JsString, JsValue, builtins::array_buffer::BufferObject, object::{ JsData, JsObject, @@ -293,7 +293,7 @@ pub(crate) fn typed_array_exotic_prevent_extensions( let is_fixed_length = { let ta = obj .downcast_ref::() - .expect("must be a TypedArray"); + .js_expect("must be a TypedArray")?; ta.viewed_array_buffer().as_buffer().is_fixed_len() }; @@ -355,7 +355,7 @@ pub(crate) fn typed_array_exotic_get_own_property( // 1.b. If numericIndex is not undefined, then if let Some(numeric_index) = p { // i. Let value be IntegerIndexedElementGet(O, numericIndex). - let value = typed_array_get_element(obj, numeric_index); + let value = typed_array_get_element(obj, numeric_index)?; // ii. If value is undefined, return undefined. // iii. Return the PropertyDescriptor { [[Value]]: value, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true }. @@ -396,7 +396,7 @@ pub(crate) fn typed_array_exotic_has_property( // 1. If P is a String, then // 1.b. If numericIndex is not undefined, return IsValidIntegerIndex(O, numericIndex). if let Some(numeric_index) = p { - return Ok(is_valid_integer_index(obj, numeric_index)); + return is_valid_integer_index(obj, numeric_index); } // 2. Return ? OrdinaryHasProperty(O, P). @@ -428,7 +428,7 @@ pub(crate) fn typed_array_exotic_define_own_property( // 1.b. If numericIndex is not undefined, then if let Some(numeric_index) = p { // i. If IsValidIntegerIndex(O, numericIndex) is false, return false. - if !is_valid_integer_index(obj, numeric_index) { + if !is_valid_integer_index(obj, numeric_index)? { return Ok(false); } @@ -494,7 +494,7 @@ pub(crate) fn typed_array_exotic_try_get( // 1.b. If numericIndex is not undefined, then if let Some(numeric_index) = p { // i. Return IntegerIndexedElementGet(O, numericIndex). - return Ok(typed_array_get_element(obj, numeric_index)); + return typed_array_get_element(obj, numeric_index); } // 2. Return ? OrdinaryGet(O, P, Receiver). @@ -526,7 +526,7 @@ pub(crate) fn typed_array_exotic_get( // 1.b. If numericIndex is not undefined, then if let Some(numeric_index) = p { // i. Return IntegerIndexedElementGet(O, numericIndex). - return Ok(typed_array_get_element(obj, numeric_index).unwrap_or_default()); + return Ok(typed_array_get_element(obj, numeric_index)?.unwrap_or_default()); } // 2. Return ? OrdinaryGet(O, P, Receiver). @@ -568,7 +568,7 @@ pub(crate) fn typed_array_exotic_set( } // ii. If IsValidIntegerIndex(O, numericIndex) is false, return true. - if !is_valid_integer_index(obj, numeric_index) { + if !is_valid_integer_index(obj, numeric_index)? { return Ok(true); } } @@ -601,7 +601,7 @@ pub(crate) fn typed_array_exotic_delete( // 1.b. If numericIndex is not undefined, then if let Some(numeric_index) = p { // i. If IsValidIntegerIndex(O, numericIndex) is false, return true; else return false. - return Ok(!is_valid_integer_index(obj, numeric_index)); + return Ok(!is_valid_integer_index(obj, numeric_index)?); } // 2. Return ! OrdinaryDelete(O, P). @@ -621,7 +621,7 @@ pub(crate) fn typed_array_exotic_own_property_keys( ) -> JsResult> { let inner = obj .downcast_ref::() - .expect("TypedArray exotic method should only be callable from TypedArray objects"); + .js_expect("TypedArray exotic method should only be callable from TypedArray objects")?; // 1. Let taRecord be MakeTypedArrayWithBufferWitnessRecord(O, seq-cst). // 2. Let keys be a new empty List. @@ -659,17 +659,21 @@ pub(crate) fn typed_array_exotic_own_property_keys( /// - [ECMAScript reference][spec] /// /// [spec]: https://tc39.es/ecma262/sec-typedarraygetelement -fn typed_array_get_element(obj: &JsObject, index: f64) -> Option { +fn typed_array_get_element(obj: &JsObject, index: f64) -> JsResult> { let inner = obj .downcast_ref::() - .expect("Must be an TypedArray object"); + .js_expect("typed_array_get_element should only be called on TypedArray objects")?; let buffer = inner.viewed_array_buffer(); let buffer = buffer.as_buffer(); // 1. If IsValidIntegerIndex(O, index) is false, return undefined. - let buffer = buffer.bytes(Ordering::Relaxed)?; + let Some(buffer) = buffer.bytes(Ordering::Relaxed) else { + return Ok(None); + }; - let index = inner.validate_index(index, buffer.len())?; + let Some(index) = inner.validate_index(index, buffer.len()) else { + return Ok(None); + }; // 2. Let offset be O.[[ByteOffset]]. let offset = inner.byte_offset(); @@ -692,7 +696,7 @@ fn typed_array_get_element(obj: &JsObject, index: f64) -> Option { .get_value(elem_type, Ordering::Relaxed) }; - Some(value.into()) + Ok(Some(value.into())) } /// Abstract operation `TypedArraySetElement ( O, index, value )`. @@ -710,8 +714,8 @@ pub(crate) fn typed_array_set_element( let obj = obj .clone() .downcast::() - .expect("function can only be called for typed array objects"); - + .ok() + .js_expect("function can only be called for typed array objects")?; // b. Let arrayTypeName be the String value of O.[[TypedArrayName]]. // e. Let elementType be the Element Type value in Table 73 for arrayTypeName. let elem_type = obj.borrow().data().kind(); diff --git a/core/engine/src/object/builtins/jspromise.rs b/core/engine/src/object/builtins/jspromise.rs index dd7870c1dce..f291ac62c4b 100644 --- a/core/engine/src/object/builtins/jspromise.rs +++ b/core/engine/src/object/builtins/jspromise.rs @@ -1248,7 +1248,7 @@ impl JsPromise { let mut r#gen = captures.1.take().js_expect("should only run once")?; // NOTE: We need to get the object before resuming, since it could clear the stack. - let async_generator = r#gen.async_generator_object(); + let async_generator = r#gen.async_generator_object()?; std::mem::swap(&mut context.vm.stack, &mut r#gen.stack); let frame = r#gen @@ -1310,7 +1310,7 @@ impl JsPromise { let mut r#gen = captures.1.take().js_expect("should only run once")?; // NOTE: We need to get the object before resuming, since it could clear the stack. - let async_generator = r#gen.async_generator_object(); + let async_generator = r#gen.async_generator_object()?; std::mem::swap(&mut context.vm.stack, &mut r#gen.stack); let frame = r#gen diff --git a/core/engine/src/vm/opcode/await/mod.rs b/core/engine/src/vm/opcode/await/mod.rs index ecc3ee63bcd..2dce3496414 100644 --- a/core/engine/src/vm/opcode/await/mod.rs +++ b/core/engine/src/vm/opcode/await/mod.rs @@ -64,7 +64,7 @@ impl Await { let mut r#gen = captures.take().expect("should only run once"); // NOTE: We need to get the object before resuming, since it could clear the stack. - let async_generator = r#gen.async_generator_object(); + let async_generator = r#gen.async_generator_object()?; r#gen.resume( Some(args.get_or_undefined(0).clone()), @@ -105,7 +105,7 @@ impl Await { let mut r#gen = captures.take().expect("should only run once"); // NOTE: We need to get the object before resuming, since it could clear the stack. - let async_generator = r#gen.async_generator_object(); + let async_generator = r#gen.async_generator_object()?; r#gen.resume( Some(args.get_or_undefined(0).clone()),