From a1647d8b7e7df83b38c8080a1e7750bb3e9c754b Mon Sep 17 00:00:00 2001 From: nekevss Date: Wed, 19 Oct 2022 20:03:35 -0400 Subject: [PATCH] Rebase new error and complete updates/fixes --- boa_engine/src/vm/opcode/binary_ops/mod.rs | 11 ++-- boa_engine/src/vm/opcode/call/mod.rs | 41 +++++++++--- boa_engine/src/vm/opcode/delete/mod.rs | 9 ++- boa_engine/src/vm/opcode/environment/mod.rs | 64 +++++++++---------- boa_engine/src/vm/opcode/generator/mod.rs | 29 +++++---- boa_engine/src/vm/opcode/get/name.rs | 22 ++++--- boa_engine/src/vm/opcode/get/private.rs | 14 ++-- .../src/vm/opcode/iteration/for_await.rs | 9 ++- boa_engine/src/vm/opcode/iteration/for_in.rs | 3 +- boa_engine/src/vm/opcode/new/mod.rs | 21 ++++-- boa_engine/src/vm/opcode/promise/mod.rs | 4 +- boa_engine/src/vm/opcode/push/class/mod.rs | 9 ++- boa_engine/src/vm/opcode/require/mod.rs | 2 +- boa_engine/src/vm/opcode/set/name.rs | 35 ++++++---- boa_engine/src/vm/opcode/set/private.rs | 33 +++++++--- boa_engine/src/vm/opcode/throw/mod.rs | 4 +- boa_engine/src/vm/opcode/value/mod.rs | 9 ++- 17 files changed, 208 insertions(+), 111 deletions(-) diff --git a/boa_engine/src/vm/opcode/binary_ops/mod.rs b/boa_engine/src/vm/opcode/binary_ops/mod.rs index 181b3e9c55b..704f6562bc5 100644 --- a/boa_engine/src/vm/opcode/binary_ops/mod.rs +++ b/boa_engine/src/vm/opcode/binary_ops/mod.rs @@ -1,4 +1,5 @@ use crate::{ + error::JsNativeError, vm::{opcode::Operation, ShouldExit}, Context, JsResult, }; @@ -67,10 +68,12 @@ impl Operation for In { let lhs = context.vm.pop(); if !rhs.is_object() { - return context.throw_type_error(format!( - "right-hand side of 'in' should be an object, got {}", - rhs.type_of().to_std_string_escaped() - )); + return Err(JsNativeError::typ() + .with_message(format!( + "right-hand side of 'in' should be an object, got {}", + rhs.type_of().to_std_string_escaped() + )) + .into()); } let key = lhs.to_property_key(context)?; let value = context.has_property(&rhs, &key)?; diff --git a/boa_engine/src/vm/opcode/call/mod.rs b/boa_engine/src/vm/opcode/call/mod.rs index 4cf3eb26834..e76e9258a02 100644 --- a/boa_engine/src/vm/opcode/call/mod.rs +++ b/boa_engine/src/vm/opcode/call/mod.rs @@ -1,5 +1,6 @@ use crate::{ builtins::function::Function, + error::JsNativeError, vm::{opcode::Operation, ShouldExit}, Context, JsResult, JsValue, }; @@ -13,7 +14,9 @@ impl Operation for CallEval { fn execute(context: &mut Context) -> JsResult { if context.vm.stack_size_limit <= context.vm.stack.len() { - return context.throw_range_error("Maximum call stack size exceeded"); + return Err(JsNativeError::range() + .with_message("Maximum call stack size exceeded") + .into()); } let argument_count = context.vm.read::(); let mut arguments = Vec::with_capacity(argument_count as usize); @@ -27,7 +30,11 @@ impl Operation for CallEval { let object = match func { JsValue::Object(ref object) if object.is_callable() => object.clone(), - _ => return context.throw_type_error("not a callable function"), + _ => { + return Err(JsNativeError::typ() + .with_message("not a callable function") + .into()) + } }; // A native function with the name "eval" implies, that is this the built-in eval function. @@ -59,7 +66,9 @@ impl Operation for CallEvalSpread { fn execute(context: &mut Context) -> JsResult { if context.vm.stack_size_limit <= context.vm.stack.len() { - return context.throw_range_error("Maximum call stack size exceeded"); + return Err(JsNativeError::range() + .with_message("Maximum call stack size exceeded") + .into()); } // Get the arguments that are stored as an array object on the stack. @@ -79,7 +88,11 @@ impl Operation for CallEvalSpread { let object = match func { JsValue::Object(ref object) if object.is_callable() => object.clone(), - _ => return context.throw_type_error("not a callable function"), + _ => { + return Err(JsNativeError::typ() + .with_message("not a callable function") + .into()) + } }; // A native function with the name "eval" implies, that is this the built-in eval function. @@ -111,7 +124,9 @@ impl Operation for Call { fn execute(context: &mut Context) -> JsResult { if context.vm.stack_size_limit <= context.vm.stack.len() { - return context.throw_range_error("Maximum call stack size exceeded"); + return Err(JsNativeError::range() + .with_message("Maximum call stack size exceeded") + .into()); } let argument_count = context.vm.read::(); let mut arguments = Vec::with_capacity(argument_count as usize); @@ -125,7 +140,11 @@ impl Operation for Call { let object = match func { JsValue::Object(ref object) if object.is_callable() => object.clone(), - _ => return context.throw_type_error("not a callable function"), + _ => { + return Err(JsNativeError::typ() + .with_message("not a callable function") + .into()) + } }; let result = object.__call__(&this, &arguments, context)?; @@ -144,7 +163,9 @@ impl Operation for CallSpread { fn execute(context: &mut Context) -> JsResult { if context.vm.stack_size_limit <= context.vm.stack.len() { - return context.throw_range_error("Maximum call stack size exceeded"); + return Err(JsNativeError::range() + .with_message("Maximum call stack size exceeded") + .into()); } // Get the arguments that are stored as an array object on the stack. @@ -164,7 +185,11 @@ impl Operation for CallSpread { let object = match func { JsValue::Object(ref object) if object.is_callable() => object.clone(), - _ => return context.throw_type_error("not a callable function"), + _ => { + return Err(JsNativeError::typ() + .with_message("not a callable function") + .into()) + } }; let result = object.__call__(&this, &arguments, context)?; diff --git a/boa_engine/src/vm/opcode/delete/mod.rs b/boa_engine/src/vm/opcode/delete/mod.rs index 267d362c235..1f64759e2fc 100644 --- a/boa_engine/src/vm/opcode/delete/mod.rs +++ b/boa_engine/src/vm/opcode/delete/mod.rs @@ -1,4 +1,5 @@ use crate::{ + error::JsNativeError, vm::{opcode::Operation, ShouldExit}, Context, JsResult, JsString, }; @@ -21,7 +22,9 @@ impl Operation for DeletePropertyByName { let object = context.vm.pop(); let result = object.to_object(context)?.__delete__(&key, context)?; if !result && context.vm.frame().code.strict { - return Err(context.construct_type_error("Cannot delete property")); + return Err(JsNativeError::typ() + .with_message("Cannot delete property") + .into()); } context.vm.push(result); Ok(ShouldExit::False) @@ -42,7 +45,9 @@ impl Operation for DeletePropertyByValue { .to_object(context)? .__delete__(&key.to_property_key(context)?, context)?; if !result && context.vm.frame().code.strict { - return Err(context.construct_type_error("Cannot delete property")); + return Err(JsNativeError::typ() + .with_message("Cannot delete property") + .into()); } context.vm.push(result); Ok(ShouldExit::False) diff --git a/boa_engine/src/vm/opcode/environment/mod.rs b/boa_engine/src/vm/opcode/environment/mod.rs index cf6f01d68eb..4e6ddc29cb1 100644 --- a/boa_engine/src/vm/opcode/environment/mod.rs +++ b/boa_engine/src/vm/opcode/environment/mod.rs @@ -1,5 +1,6 @@ use crate::{ environments::EnvironmentSlots, + error::JsNativeError, vm::{code_block::initialize_instance_elements, opcode::Operation, ShouldExit}, Context, JsResult, JsValue, }; @@ -14,15 +15,7 @@ impl Operation for This { fn execute(context: &mut Context) -> JsResult { let env = context.realm.environments.get_this_environment(); match env { - EnvironmentSlots::Function(env) => { - let env_b = env.borrow(); - if let Some(this) = env_b.get_this_binding() { - context.vm.push(this); - } else { - drop(env_b); - return context.throw_reference_error("Must call super constructor in derived class before accessing 'this' or returning from derived constructor"); - } - } + EnvironmentSlots::Function(env) => context.vm.push(env.borrow().get_this_binding()?), EnvironmentSlots::Global => { let this = context.realm.global_object(); context.vm.push(this.clone()); @@ -40,32 +33,21 @@ impl Operation for Super { const INSTRUCTION: &'static str = "INST - Super"; fn execute(context: &mut Context) -> JsResult { - let env = context - .realm - .environments - .get_this_environment() - .as_function_slots() - .expect("super access must be in a function environment"); - - let home = if env.borrow().get_this_binding().is_some() { + let home = { + let env = context + .realm + .environments + .get_this_environment() + .as_function_slots() + .expect("super access must be in a function environment"); let env = env.borrow(); + let this = env.get_this_binding()?; let function_object = env.function_object().borrow(); let function = function_object .as_function() .expect("must be function object"); - let mut home_object = function.get_home_object().cloned(); - - if home_object.is_none() { - home_object = env - .get_this_binding() - .expect("can not get `this` object") - .as_object() - .cloned(); - } - home_object - } else { - return context.throw_range_error("Must call super constructor in derived class before accessing 'this' or returning from derived constructor"); + function.get_home_object().or(this.as_object()).cloned() }; if let Some(home) = home { @@ -117,7 +99,9 @@ impl Operation for SuperCall { .expect("function object must have prototype"); if !super_constructor.is_constructor() { - return context.throw_type_error("super constructor object must be constructor"); + return Err(JsNativeError::typ() + .with_message("super constructor object must be constructor") + .into()); } let result = super_constructor.__construct__(&arguments, &new_target, context)?; @@ -132,7 +116,9 @@ impl Operation for SuperCall { .expect("super call must be in function environment"); if !this_env.borrow_mut().bind_this_value(&result) { - return context.throw_reference_error("this already initialized"); + return Err(JsNativeError::reference() + .with_message("this already initialized") + .into()); } context.vm.push(result); Ok(ShouldExit::False) @@ -180,7 +166,9 @@ impl Operation for SuperCallSpread { .expect("function object must have prototype"); if !super_constructor.is_constructor() { - return context.throw_type_error("super constructor object must be constructor"); + return Err(JsNativeError::typ() + .with_message("super constructor object must be constructor") + .into()); } let result = super_constructor.__construct__(&arguments, &new_target, context)?; @@ -195,7 +183,9 @@ impl Operation for SuperCallSpread { .expect("super call must be in function environment"); if !this_env.borrow_mut().bind_this_value(&result) { - return context.throw_reference_error("this already initialized"); + return Err(JsNativeError::reference() + .with_message("this already initialized") + .into()); } context.vm.push(result); Ok(ShouldExit::False) @@ -238,7 +228,9 @@ impl Operation for SuperCallDerived { .expect("function object must have prototype"); if !super_constructor.is_constructor() { - return context.throw_type_error("super constructor object must be constructor"); + return Err(JsNativeError::typ() + .with_message("super constructor object must be constructor") + .into()); } let result = super_constructor.__construct__(&arguments, &new_target, context)?; @@ -252,7 +244,9 @@ impl Operation for SuperCallDerived { .as_function_slots() .expect("super call must be in function environment"); if !this_env.borrow_mut().bind_this_value(&result) { - return context.throw_reference_error("this already initialized"); + return Err(JsNativeError::reference() + .with_message("this already initialized") + .into()); } context.vm.push(result); diff --git a/boa_engine/src/vm/opcode/generator/mod.rs b/boa_engine/src/vm/opcode/generator/mod.rs index 7d9c56e1365..fd9a13468fe 100644 --- a/boa_engine/src/vm/opcode/generator/mod.rs +++ b/boa_engine/src/vm/opcode/generator/mod.rs @@ -3,12 +3,13 @@ use crate::{ async_generator::{AsyncGenerator, AsyncGeneratorState}, iterable::IteratorRecord, }, + error::JsNativeError, vm::{ call_frame::{FinallyReturn, GeneratorResumeKind}, opcode::Operation, ShouldExit, }, - Context, JsResult, JsValue, + Context, JsError, JsResult, JsValue, }; pub(crate) mod yield_stm; @@ -26,7 +27,7 @@ impl Operation for GeneratorNext { GeneratorResumeKind::Normal => Ok(ShouldExit::False), GeneratorResumeKind::Throw => { let received = context.vm.pop(); - Err(received) + Err(JsError::from_opaque(received)) } GeneratorResumeKind::Return => { let mut finally_left = false; @@ -63,7 +64,7 @@ impl Operation for AsyncGeneratorNext { let value = context.vm.pop(); if context.vm.frame().generator_resume_kind == GeneratorResumeKind::Throw { - return Err(value); + return Err(JsError::from_opaque(value)); } let completion = Ok(value); @@ -91,9 +92,11 @@ impl Operation for AsyncGeneratorNext { if let Some(next) = gen.queue.front() { let (completion, r#return) = &next.completion; if *r#return { - match completion { - Ok(value) | Err(value) => context.vm.push(value), - } + let value = match completion { + Ok(value) => value.clone(), + Err(e) => e.clone().to_opaque(context), + }; + context.vm.push(value); context.vm.push(true); } else { context.vm.push(completion.clone()?); @@ -133,7 +136,7 @@ impl Operation for GeneratorNextDelegate { GeneratorResumeKind::Normal => { let result = context.call(&next_method, &iterator.clone().into(), &[received])?; let result_object = result.as_object().ok_or_else(|| { - context.construct_type_error("generator next method returned non-object") + JsNativeError::typ().with_message("generator next method returned non-object") })?; let done = result_object.get("done", context)?.to_boolean(); if done { @@ -154,7 +157,8 @@ impl Operation for GeneratorNextDelegate { if let Some(throw) = throw { let result = throw.call(&iterator.clone().into(), &[received], context)?; let result_object = result.as_object().ok_or_else(|| { - context.construct_type_error("generator throw method returned non-object") + JsNativeError::typ() + .with_message("generator throw method returned non-object") })?; let done = result_object.get("done", context)?.to_boolean(); if done { @@ -173,15 +177,18 @@ impl Operation for GeneratorNextDelegate { context.vm.frame_mut().pc = done_address as usize; let iterator_record = IteratorRecord::new(iterator.clone(), next_method, done); iterator_record.close(Ok(JsValue::Undefined), context)?; - let error = context.construct_type_error("iterator does not have a throw method"); - Err(error) + + Err(JsNativeError::typ() + .with_message("iterator does not have a throw method") + .into()) } GeneratorResumeKind::Return => { let r#return = iterator.get_method("return", context)?; if let Some(r#return) = r#return { let result = r#return.call(&iterator.clone().into(), &[received], context)?; let result_object = result.as_object().ok_or_else(|| { - context.construct_type_error("generator return method returned non-object") + JsNativeError::typ() + .with_message("generator return method returned non-object") })?; let done = result_object.get("done", context)?.to_boolean(); if done { diff --git a/boa_engine/src/vm/opcode/get/name.rs b/boa_engine/src/vm/opcode/get/name.rs index 86f326edf73..aeae0d2470c 100644 --- a/boa_engine/src/vm/opcode/get/name.rs +++ b/boa_engine/src/vm/opcode/get/name.rs @@ -1,4 +1,5 @@ use crate::{ + error::JsNativeError, property::DescriptorKind, vm::{opcode::Operation, ShouldExit}, Context, JsResult, JsString, JsValue, @@ -38,17 +39,18 @@ impl Operation for GetName { context.call(&get, &context.global_object().clone().into(), &[])? } _ => { - return context.throw_reference_error(format!( - "{} is not defined", - key.to_std_string_escaped() - )) + return Err(JsNativeError::reference() + .with_message(format!( + "{} is not defined", + key.to_std_string_escaped() + )) + .into()) } }, _ => { - return context.throw_reference_error(format!( - "{} is not defined", - key.to_std_string_escaped() - )) + return Err(JsNativeError::reference() + .with_message(format!("{} is not defined", key.to_std_string_escaped())) + .into()) } } } @@ -63,7 +65,9 @@ impl Operation for GetName { .interner() .resolve_expect(binding_locator.name().sym()) .to_string(); - return context.throw_reference_error(format!("{name} is not initialized")); + return Err(JsNativeError::reference() + .with_message(format!("{name} is not initialized")) + .into()); }; context.vm.push(value); diff --git a/boa_engine/src/vm/opcode/get/private.rs b/boa_engine/src/vm/opcode/get/private.rs index b5a10e865f6..a39f255fd99 100644 --- a/boa_engine/src/vm/opcode/get/private.rs +++ b/boa_engine/src/vm/opcode/get/private.rs @@ -1,4 +1,5 @@ use crate::{ + error::JsNativeError, object::PrivateElement, vm::{opcode::Operation, ShouldExit}, Context, JsResult, @@ -29,15 +30,20 @@ impl Operation for GetPrivateField { context.vm.push(value); } PrivateElement::Accessor { .. } => { - return context - .throw_type_error("private property was defined without a getter"); + return Err(JsNativeError::typ() + .with_message("private property was defined without a getter") + .into()); } } } else { - return context.throw_type_error("private property does not exist"); + return Err(JsNativeError::typ() + .with_message("private property does not exist") + .into()); } } else { - return context.throw_type_error("cannot read private property from non-object"); + return Err(JsNativeError::typ() + .with_message("cannot read private property from non-object") + .into()); } Ok(ShouldExit::False) } diff --git a/boa_engine/src/vm/opcode/iteration/for_await.rs b/boa_engine/src/vm/opcode/iteration/for_await.rs index 9cdb112d12f..ca7ec103721 100644 --- a/boa_engine/src/vm/opcode/iteration/for_await.rs +++ b/boa_engine/src/vm/opcode/iteration/for_await.rs @@ -1,5 +1,6 @@ use crate::{ builtins::iterable::IteratorResult, + error::JsNativeError, vm::{opcode::Operation, ShouldExit}, Context, JsResult, }; @@ -21,7 +22,9 @@ impl Operation for ForAwaitOfLoopIterate { let next_method_object = if let Some(object) = next_method.as_callable() { object } else { - return context.throw_type_error("iterable next method not a function"); + return Err(JsNativeError::typ() + .with_message("iterable next method not a function") + .into()); }; let iterator = context.vm.pop(); let next_result = next_method_object.call(&iterator, &[], context)?; @@ -46,7 +49,9 @@ impl Operation for ForAwaitOfLoopNext { let next_result = if let Some(next_result) = next_result.as_object() { IteratorResult::new(next_result.clone()) } else { - return context.throw_type_error("next value should be an object"); + return Err(JsNativeError::typ() + .with_message("next value should be an object") + .into()); }; if next_result.complete(context)? { diff --git a/boa_engine/src/vm/opcode/iteration/for_in.rs b/boa_engine/src/vm/opcode/iteration/for_in.rs index d5d0d53df36..ec3bd144dcb 100644 --- a/boa_engine/src/vm/opcode/iteration/for_in.rs +++ b/boa_engine/src/vm/opcode/iteration/for_in.rs @@ -1,5 +1,6 @@ use crate::{ builtins::{iterable::IteratorRecord, ForInIterator}, + error::JsNativeError, property::PropertyDescriptor, vm::{opcode::Operation, ShouldExit}, Context, JsResult, JsValue, @@ -28,7 +29,7 @@ impl Operation for ForInLoopInitIterator { .as_ref() .map(PropertyDescriptor::expect_value) .cloned() - .ok_or_else(|| context.construct_type_error("Could not find property `next`"))?; + .ok_or_else(|| JsNativeError::typ().with_message("Could not find property `next`"))?; context.vm.push(iterator); context.vm.push(next_method); diff --git a/boa_engine/src/vm/opcode/new/mod.rs b/boa_engine/src/vm/opcode/new/mod.rs index 2d081b5e4df..4134954d105 100644 --- a/boa_engine/src/vm/opcode/new/mod.rs +++ b/boa_engine/src/vm/opcode/new/mod.rs @@ -1,4 +1,5 @@ use crate::{ + error::JsNativeError, vm::{opcode::Operation, ShouldExit}, Context, JsResult, }; @@ -12,7 +13,9 @@ impl Operation for New { fn execute(context: &mut Context) -> JsResult { if context.vm.stack_size_limit <= context.vm.stack.len() { - return context.throw_range_error("Maximum call stack size exceeded"); + return Err(JsNativeError::range() + .with_message("Maximum call stack size exceeded") + .into()); } let argument_count = context.vm.read::(); let mut arguments = Vec::with_capacity(argument_count as usize); @@ -24,7 +27,11 @@ impl Operation for New { let result = func .as_constructor() - .ok_or_else(|| context.construct_type_error("not a constructor")) + .ok_or_else(|| { + JsNativeError::typ() + .with_message("not a constructor") + .into() + }) .and_then(|cons| cons.__construct__(&arguments, cons, context))?; context.vm.push(result); @@ -41,7 +48,9 @@ impl Operation for NewSpread { fn execute(context: &mut Context) -> JsResult { if context.vm.stack_size_limit <= context.vm.stack.len() { - return context.throw_range_error("Maximum call stack size exceeded"); + return Err(JsNativeError::range() + .with_message("Maximum call stack size exceeded") + .into()); } // Get the arguments that are stored as an array object on the stack. let arguments_array = context.vm.pop(); @@ -59,7 +68,11 @@ impl Operation for NewSpread { let result = func .as_constructor() - .ok_or_else(|| context.construct_type_error("not a constructor")) + .ok_or_else(|| { + JsNativeError::typ() + .with_message("not a constructor") + .into() + }) .and_then(|cons| cons.__construct__(&arguments, cons, context))?; context.vm.push(result); diff --git a/boa_engine/src/vm/opcode/promise/mod.rs b/boa_engine/src/vm/opcode/promise/mod.rs index 544740e0189..c7e563fc262 100644 --- a/boa_engine/src/vm/opcode/promise/mod.rs +++ b/boa_engine/src/vm/opcode/promise/mod.rs @@ -1,6 +1,6 @@ use crate::{ vm::{opcode::Operation, FinallyReturn, ShouldExit}, - Context, JsResult, + Context, JsError, JsResult, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -43,7 +43,7 @@ impl Operation for FinallyEnd { Ok(ShouldExit::False) } FinallyReturn::Ok => Ok(ShouldExit::True), - FinallyReturn::Err => Err(context.vm.pop()), + FinallyReturn::Err => Err(JsError::from_opaque(context.vm.pop())), } } } diff --git a/boa_engine/src/vm/opcode/push/class/mod.rs b/boa_engine/src/vm/opcode/push/class/mod.rs index b790660095e..450bf77c9ec 100644 --- a/boa_engine/src/vm/opcode/push/class/mod.rs +++ b/boa_engine/src/vm/opcode/push/class/mod.rs @@ -1,5 +1,6 @@ use crate::{ builtins::function::{ConstructorKind, Function}, + error::JsNativeError, vm::{opcode::Operation, ShouldExit}, Context, JsResult, JsValue, }; @@ -23,7 +24,9 @@ impl Operation for PushClassPrototype { if let Some(superclass) = superclass.as_constructor() { let proto = superclass.get("prototype", context)?; if !proto.is_object() && !proto.is_null() { - return context.throw_type_error("superclass prototype must be an object or null"); + return Err(JsNativeError::typ() + .with_message("superclass prototype must be an object or null") + .into()); } let class = context.vm.pop(); @@ -50,7 +53,9 @@ impl Operation for PushClassPrototype { context.vm.push(JsValue::Null); Ok(ShouldExit::False) } else { - context.throw_type_error("superclass must be a constructor") + Err(JsNativeError::typ() + .with_message("superclass must be a constructor") + .into()) } } } diff --git a/boa_engine/src/vm/opcode/require/mod.rs b/boa_engine/src/vm/opcode/require/mod.rs index 13692d8cb11..07362bec716 100644 --- a/boa_engine/src/vm/opcode/require/mod.rs +++ b/boa_engine/src/vm/opcode/require/mod.rs @@ -12,7 +12,7 @@ impl Operation for RequireObjectCoercible { fn execute(context: &mut Context) -> JsResult { let value = context.vm.pop(); - let value = value.require_object_coercible(context)?; + let value = value.require_object_coercible()?; context.vm.push(value); Ok(ShouldExit::False) } diff --git a/boa_engine/src/vm/opcode/set/name.rs b/boa_engine/src/vm/opcode/set/name.rs index 25accacc4ad..8c096245488 100644 --- a/boa_engine/src/vm/opcode/set/name.rs +++ b/boa_engine/src/vm/opcode/set/name.rs @@ -1,4 +1,5 @@ use crate::{ + error::JsNativeError, vm::{opcode::Operation, ShouldExit}, Context, JsResult, JsString, }; @@ -29,10 +30,12 @@ impl Operation for SetName { let exists = context.global_bindings_mut().contains_key(&key); if !exists && context.vm.frame().code.strict { - return context.throw_reference_error(format!( - "assignment to undeclared variable {}", - key.to_std_string_escaped() - )); + return Err(JsNativeError::reference() + .with_message(format!( + "assignment to undeclared variable {}", + key.to_std_string_escaped() + )) + .into()); } let success = crate::object::internal_methods::global::global_set_no_receiver( @@ -42,10 +45,12 @@ impl Operation for SetName { )?; if !success && context.vm.frame().code.strict { - return context.throw_type_error(format!( - "cannot set non-writable property: {}", - key.to_std_string_escaped() - )); + return Err(JsNativeError::typ() + .with_message(format!( + "cannot set non-writable property: {}", + key.to_std_string_escaped() + )) + .into()); } } } else if !context.realm.environments.put_value_if_initialized( @@ -54,12 +59,14 @@ impl Operation for SetName { binding_locator.name(), value, ) { - context.throw_reference_error(format!( - "cannot access '{}' before initialization", - context - .interner() - .resolve_expect(binding_locator.name().sym()) - ))?; + return Err(JsNativeError::reference() + .with_message(format!( + "cannot access '{}' before initialization", + context + .interner() + .resolve_expect(binding_locator.name().sym()) + )) + .into()); } Ok(ShouldExit::False) } diff --git a/boa_engine/src/vm/opcode/set/private.rs b/boa_engine/src/vm/opcode/set/private.rs index 22c3241903d..75267cbb819 100644 --- a/boa_engine/src/vm/opcode/set/private.rs +++ b/boa_engine/src/vm/opcode/set/private.rs @@ -1,4 +1,5 @@ use crate::{ + error::JsNativeError, object::PrivateElement, vm::{opcode::Operation, ShouldExit}, Context, JsResult, @@ -23,7 +24,9 @@ impl Operation for AssignPrivateField { object_borrow_mut.set_private_element(name.sym(), PrivateElement::Field(value)); } Some(PrivateElement::Method(_)) => { - return context.throw_type_error("private method is not writable"); + return Err(JsNativeError::typ() + .with_message("private method is not writable") + .into()); } Some(PrivateElement::Accessor { setter: Some(setter), @@ -34,14 +37,20 @@ impl Operation for AssignPrivateField { setter.call(&object.clone().into(), &[value], context)?; } None => { - return context.throw_type_error("private field not defined"); + return Err(JsNativeError::typ() + .with_message("private field not defined") + .into()); } _ => { - return context.throw_type_error("private field defined without a setter"); + return Err(JsNativeError::typ() + .with_message("private field defined without a setter") + .into()); } } } else { - return context.throw_type_error("cannot set private property on non-object"); + return Err(JsNativeError::typ() + .with_message("cannot set private property on non-object") + .into()); } Ok(ShouldExit::False) } @@ -73,7 +82,9 @@ impl Operation for SetPrivateField { object_borrow_mut.set_private_element(name.sym(), PrivateElement::Field(value)); } } else { - return context.throw_type_error("cannot set private property on non-object"); + return Err(JsNativeError::typ() + .with_message("cannot set private property on non-object") + .into()); } Ok(ShouldExit::False) } @@ -97,7 +108,9 @@ impl Operation for SetPrivateMethod { object_borrow_mut .set_private_element(name.sym(), PrivateElement::Method(value.clone())); } else { - return context.throw_type_error("cannot set private setter on non-object"); + return Err(JsNativeError::typ() + .with_message("cannot set private setter on non-object") + .into()); } Ok(ShouldExit::False) } @@ -120,7 +133,9 @@ impl Operation for SetPrivateSetter { let mut object_borrow_mut = object.borrow_mut(); object_borrow_mut.set_private_element_setter(name.sym(), value.clone()); } else { - return context.throw_type_error("cannot set private setter on non-object"); + return Err(JsNativeError::typ() + .with_message("cannot set private setter on non-object") + .into()); } Ok(ShouldExit::False) } @@ -143,7 +158,9 @@ impl Operation for SetPrivateGetter { let mut object_borrow_mut = object.borrow_mut(); object_borrow_mut.set_private_element_getter(name.sym(), value.clone()); } else { - return context.throw_type_error("cannot set private getter on non-object"); + return Err(JsNativeError::typ() + .with_message("cannot set private getter on non-object") + .into()); } Ok(ShouldExit::False) } diff --git a/boa_engine/src/vm/opcode/throw/mod.rs b/boa_engine/src/vm/opcode/throw/mod.rs index 5ab7cf4ef99..1d46ae04216 100644 --- a/boa_engine/src/vm/opcode/throw/mod.rs +++ b/boa_engine/src/vm/opcode/throw/mod.rs @@ -1,6 +1,6 @@ use crate::{ vm::{opcode::Operation, ShouldExit}, - Context, JsResult, + Context, JsError, JsResult, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -12,6 +12,6 @@ impl Operation for Throw { fn execute(context: &mut Context) -> JsResult { let value = context.vm.pop(); - Err(value) + Err(JsError::from_opaque(value)) } } diff --git a/boa_engine/src/vm/opcode/value/mod.rs b/boa_engine/src/vm/opcode/value/mod.rs index c439aee4076..876e5ff6d42 100644 --- a/boa_engine/src/vm/opcode/value/mod.rs +++ b/boa_engine/src/vm/opcode/value/mod.rs @@ -1,4 +1,5 @@ use crate::{ + error::JsNativeError, vm::{opcode::Operation, ShouldExit}, Context, JsResult, }; @@ -13,10 +14,14 @@ impl Operation for ValueNotNullOrUndefined { fn execute(context: &mut Context) -> JsResult { let value = context.vm.pop(); if value.is_null() { - return context.throw_type_error("Cannot destructure 'null' value"); + return Err(JsNativeError::typ() + .with_message("Cannot destructure 'null' value") + .into()); } if value.is_undefined() { - return context.throw_type_error("Cannot destructure 'undefined' value"); + return Err(JsNativeError::typ() + .with_message("Cannot destructure 'undefined' value") + .into()); } context.vm.push(value); Ok(ShouldExit::False)