Skip to content

Commit

Permalink
Rebase new error and complete updates/fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
nekevss committed Oct 20, 2022
1 parent 0243ca2 commit a1647d8
Show file tree
Hide file tree
Showing 17 changed files with 208 additions and 111 deletions.
11 changes: 7 additions & 4 deletions boa_engine/src/vm/opcode/binary_ops/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::{
error::JsNativeError,
vm::{opcode::Operation, ShouldExit},
Context, JsResult,
};
Expand Down Expand Up @@ -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)?;
Expand Down
41 changes: 33 additions & 8 deletions boa_engine/src/vm/opcode/call/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{
builtins::function::Function,
error::JsNativeError,
vm::{opcode::Operation, ShouldExit},
Context, JsResult, JsValue,
};
Expand All @@ -13,7 +14,9 @@ impl Operation for CallEval {

fn execute(context: &mut Context) -> JsResult<ShouldExit> {
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::<u32>();
let mut arguments = Vec::with_capacity(argument_count as usize);
Expand All @@ -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.
Expand Down Expand Up @@ -59,7 +66,9 @@ impl Operation for CallEvalSpread {

fn execute(context: &mut Context) -> JsResult<ShouldExit> {
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.
Expand All @@ -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.
Expand Down Expand Up @@ -111,7 +124,9 @@ impl Operation for Call {

fn execute(context: &mut Context) -> JsResult<ShouldExit> {
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::<u32>();
let mut arguments = Vec::with_capacity(argument_count as usize);
Expand All @@ -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)?;
Expand All @@ -144,7 +163,9 @@ impl Operation for CallSpread {

fn execute(context: &mut Context) -> JsResult<ShouldExit> {
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.
Expand All @@ -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)?;
Expand Down
9 changes: 7 additions & 2 deletions boa_engine/src/vm/opcode/delete/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::{
error::JsNativeError,
vm::{opcode::Operation, ShouldExit},
Context, JsResult, JsString,
};
Expand All @@ -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)
Expand All @@ -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)
Expand Down
64 changes: 29 additions & 35 deletions boa_engine/src/vm/opcode/environment/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{
environments::EnvironmentSlots,
error::JsNativeError,
vm::{code_block::initialize_instance_elements, opcode::Operation, ShouldExit},
Context, JsResult, JsValue,
};
Expand All @@ -14,15 +15,7 @@ impl Operation for This {
fn execute(context: &mut Context) -> JsResult<ShouldExit> {
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());
Expand All @@ -40,32 +33,21 @@ impl Operation for Super {
const INSTRUCTION: &'static str = "INST - Super";

fn execute(context: &mut Context) -> JsResult<ShouldExit> {
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 {
Expand Down Expand Up @@ -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)?;
Expand All @@ -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)
Expand Down Expand Up @@ -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)?;
Expand All @@ -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)
Expand Down Expand Up @@ -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)?;
Expand All @@ -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);
Expand Down
29 changes: 18 additions & 11 deletions boa_engine/src/vm/opcode/generator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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()?);
Expand Down Expand Up @@ -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 {
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down

0 comments on commit a1647d8

Please sign in to comment.