From 816acecb1a4628da4e44c01efca47259862de377 Mon Sep 17 00:00:00 2001 From: nekevss Date: Sat, 8 Oct 2022 15:03:47 -0400 Subject: [PATCH 01/12] Initial work on concept --- boa_engine/src/vm/mod.rs | 187 +++--------------- boa_engine/src/vm/opcode/dup/mod.rs | 19 ++ .../src/vm/{opcode.rs => opcode/mod.rs} | 163 ++++++++------- boa_engine/src/vm/opcode/pop/if_thrown.rs | 21 ++ boa_engine/src/vm/opcode/pop/mod.rs | 21 ++ .../src/vm/opcode/push/class_prototype.rs | 50 +++++ boa_engine/src/vm/opcode/push/literal.rs | 19 ++ boa_engine/src/vm/opcode/push/mod.rs | 68 +++++++ boa_engine/src/vm/opcode/push/numbers.rs | 55 ++++++ boa_engine/src/vm/opcode/push/object.rs | 17 ++ .../src/vm/opcode/set/class_prototype.rs | 65 ++++++ boa_engine/src/vm/opcode/set/home_object.rs | 31 +++ boa_engine/src/vm/opcode/set/mod.rs | 6 + boa_engine/src/vm/opcode/swap/mod.rs | 21 ++ 14 files changed, 518 insertions(+), 225 deletions(-) create mode 100644 boa_engine/src/vm/opcode/dup/mod.rs rename boa_engine/src/vm/{opcode.rs => opcode/mod.rs} (91%) create mode 100644 boa_engine/src/vm/opcode/pop/if_thrown.rs create mode 100644 boa_engine/src/vm/opcode/pop/mod.rs create mode 100644 boa_engine/src/vm/opcode/push/class_prototype.rs create mode 100644 boa_engine/src/vm/opcode/push/literal.rs create mode 100644 boa_engine/src/vm/opcode/push/mod.rs create mode 100644 boa_engine/src/vm/opcode/push/numbers.rs create mode 100644 boa_engine/src/vm/opcode/push/object.rs create mode 100644 boa_engine/src/vm/opcode/set/class_prototype.rs create mode 100644 boa_engine/src/vm/opcode/set/home_object.rs create mode 100644 boa_engine/src/vm/opcode/set/mod.rs create mode 100644 boa_engine/src/vm/opcode/swap/mod.rs diff --git a/boa_engine/src/vm/mod.rs b/boa_engine/src/vm/mod.rs index 1fe3d507824..273ac22290c 100644 --- a/boa_engine/src/vm/mod.rs +++ b/boa_engine/src/vm/mod.rs @@ -28,6 +28,8 @@ mod call_frame; mod code_block; mod opcode; +use opcode::*; + pub use {call_frame::CallFrame, code_block::CodeBlock, opcode::Opcode}; pub(crate) use { @@ -145,163 +147,30 @@ impl Context { let _timer = Profiler::global().start_event(opcode.as_instruction_str(), "vm"); - match opcode { - Opcode::Nop => {} - Opcode::Pop => { - let _val = self.vm.pop(); - } - Opcode::PopIfThrown => { - let frame = self.vm.frame_mut(); - if frame.thrown { - frame.thrown = false; - self.vm.pop(); - } - } - Opcode::Dup => { - let value = self.vm.pop(); - self.vm.push(value.clone()); - self.vm.push(value); - } - Opcode::Swap => { - let first = self.vm.pop(); - let second = self.vm.pop(); - - self.vm.push(first); - self.vm.push(second); - } - Opcode::PushUndefined => self.vm.push(JsValue::undefined()), - Opcode::PushNull => self.vm.push(JsValue::null()), - Opcode::PushTrue => self.vm.push(true), - Opcode::PushFalse => self.vm.push(false), - Opcode::PushZero => self.vm.push(0), - Opcode::PushOne => self.vm.push(1), - Opcode::PushInt8 => { - let value = self.vm.read::(); - self.vm.push(i32::from(value)); - } - Opcode::PushInt16 => { - let value = self.vm.read::(); - self.vm.push(i32::from(value)); - } - Opcode::PushInt32 => { - let value = self.vm.read::(); - self.vm.push(value); - } - Opcode::PushRational => { - let value = self.vm.read::(); - self.vm.push(value); - } - Opcode::PushNaN => self.vm.push(JsValue::nan()), - Opcode::PushPositiveInfinity => self.vm.push(JsValue::positive_infinity()), - Opcode::PushNegativeInfinity => self.vm.push(JsValue::negative_infinity()), - Opcode::PushLiteral => { - let index = self.vm.read::() as usize; - let value = self.vm.frame().code.literals[index].clone(); - self.vm.push(value); - } - Opcode::PushEmptyObject => self.vm.push(self.construct_object()), - Opcode::PushClassPrototype => { - let superclass = self.vm.pop(); - - if let Some(superclass) = superclass.as_constructor() { - let proto = superclass.get("prototype", self)?; - if !proto.is_object() && !proto.is_null() { - return Err(JsNativeError::typ() - .with_message("superclass prototype must be an object or null") - .into()); - } - - let class = self.vm.pop(); - { - let class_object = class.as_object().expect("class must be object"); - class_object.set_prototype(Some(superclass.clone())); - - let mut class_object_mut = class_object.borrow_mut(); - let class_function = class_object_mut - .as_function_mut() - .expect("class must be function object"); - if let Function::Ordinary { - constructor_kind, .. - } = class_function - { - *constructor_kind = ConstructorKind::Derived; - } - } - - self.vm.push(class); - self.vm.push(proto); - } else if superclass.is_null() { - self.vm.push(JsValue::Null); - } else { - return Err(JsNativeError::typ() - .with_message("superclass must be a constructor") - .into()); - } - } - Opcode::SetClassPrototype => { - let prototype_value = self.vm.pop(); - let prototype = match &prototype_value { - JsValue::Object(proto) => Some(proto.clone()), - JsValue::Null => None, - JsValue::Undefined => { - Some(self.intrinsics().constructors().object().prototype.clone()) - } - _ => unreachable!(), - }; - - let proto = JsObject::from_proto_and_data(prototype, ObjectData::ordinary()); - let class = self.vm.pop(); - - { - let class_object = class.as_object().expect("class must be object"); - class_object - .define_property_or_throw( - "prototype", - PropertyDescriptorBuilder::new() - .value(proto.clone()) - .writable(false) - .enumerable(false) - .configurable(false), - self, - ) - .expect("cannot fail per spec"); - let mut class_object_mut = class_object.borrow_mut(); - let class_function = class_object_mut - .as_function_mut() - .expect("class must be function object"); - class_function.set_home_object(proto.clone()); - } - - proto - .__define_own_property__( - "constructor".into(), - PropertyDescriptorBuilder::new() - .value(class) - .writable(true) - .enumerable(false) - .configurable(true) - .build(), - self, - ) - .expect("cannot fail per spec"); - - self.vm.push(proto); - } - Opcode::SetHomeObject => { - let function = self.vm.pop(); - let function_object = function.as_object().expect("must be object"); - let home = self.vm.pop(); - let home_object = home.as_object().expect("must be object"); - - function_object - .borrow_mut() - .as_function_mut() - .expect("must be function object") - .set_home_object(home_object.clone()); - - self.vm.push(home); - self.vm.push(function); - } + let result = match opcode { + Opcode::Nop => {ShouldExit::False} + Opcode::Pop(op) => Pop::execute(self)?, + Opcode::PopIfThrown(op) => PopIfThrown::execute(self)?, + Opcode::Dup(op) => Dup::execute(self)?, + Opcode::Swap(op) => Swap::execute(self)?, + Opcode::PushUndefined(op) => PushUndefined::execute(self)?, + Opcode::PushNull(op) => PushNull::execute(self)?, + Opcode::PushTrue(op) => PushTrue::execute(self)?, + Opcode::PushFalse(op) => PushFalse::execute(self)?, + Opcode::PushZero(op) => PushZero::execute(self)?, + Opcode::PushOne(op) => PushOne::execute(self)?, + Opcode::PushInt8(op) => PushInt8::execute(self)?, + Opcode::PushInt16(op) => PushInt16::execute(self)?, + Opcode::PushInt32(op) => PushInt32::execute(self)?, + Opcode::PushRational(op) => PushRational::execute(self)?, + Opcode::PushNaN(op) => PushNaN::execute(self)?, + Opcode::PushPositiveInfinity(op) => PushPositiveInfinity::execute(self)?, + Opcode::PushNegativeInfinity(op) => PushNegativeInfinity::execute(self)?, + Opcode::PushLiteral(op) => PushLiteral::execute(self)?, + Opcode::PushEmptyObject(op) => PushEmptyObject::execute(self)?, + Opcode::PushClassPrototype(op) => PushClassPrototype::execute(self)?, + Opcode::SetClassPrototype(op) => SetClassPrototype::execute(self)?, + Opcode::SetHomeObject(op) => SetHomeObject::execute(self)?, Opcode::PushNewArray => { let array = Array::array_create(0, None, self) .expect("Array creation with 0 length should never fail"); @@ -2645,9 +2514,9 @@ impl Context { self.vm.push(JsValue::undefined()); } } - } + }; - Ok(ShouldExit::False) + Ok(result) } pub(crate) fn run(&mut self) -> JsResult<(JsValue, ReturnType)> { diff --git a/boa_engine/src/vm/opcode/dup/mod.rs b/boa_engine/src/vm/opcode/dup/mod.rs new file mode 100644 index 00000000000..7095d20f1d4 --- /dev/null +++ b/boa_engine/src/vm/opcode/dup/mod.rs @@ -0,0 +1,19 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Dup; + +impl Operation for Dup { + const NAME: &'static str = "Dup"; + const INSTRUCTION: &'static str = "INST - Dup"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + context.vm.push(value.clone()); + context.vm.push(value); + Ok(ShouldExit::False) + } +} \ No newline at end of file diff --git a/boa_engine/src/vm/opcode.rs b/boa_engine/src/vm/opcode/mod.rs similarity index 91% rename from boa_engine/src/vm/opcode.rs rename to boa_engine/src/vm/opcode/mod.rs index ee5982b8965..4a498f57aba 100644 --- a/boa_engine/src/vm/opcode.rs +++ b/boa_engine/src/vm/opcode/mod.rs @@ -1,4 +1,35 @@ /// The opcodes of the vm. +use crate::{ + vm::ShouldExit, + Context,JsResult +}; + +// Operation modules +pub(crate) mod pop; +pub(crate) mod dup; +pub(crate) mod swap; +pub(crate) mod push; +pub(crate) mod set; + +// Operation structs +pub(crate) use pop::{Pop, PopIfThrown}; +pub(crate) use dup::Dup; +pub(crate) use swap::Swap; +pub(crate) use push::{ + PushUndefined, PushNull, PushTrue, PushFalse, + PushZero, PushOne, PushInt8, PushInt16, PushInt32, + PushRational, PushNaN, PushPositiveInfinity, PushNegativeInfinity, + PushLiteral, PushEmptyObject, PushClassPrototype +}; +pub(crate) use set::{SetClassPrototype, SetHomeObject}; + +pub(crate) trait Operation { + const NAME: &'static str; + const INSTRUCTION: &'static str; + + fn execute(context: &mut Context) -> JsResult; +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[repr(u8)] pub enum Opcode { @@ -7,119 +38,119 @@ pub enum Opcode { /// Operands: /// /// Stack: value **=>** - Pop, + Pop(Pop), /// Pop the top value from the stack if the last try block has thrown a value. /// /// Operands: /// /// Stack: value **=>** - PopIfThrown, + PopIfThrown(PopIfThrown), /// Push a copy of the top value on the stack. /// /// Operands: /// /// Stack: value **=>** value, value - Dup, + Dup(Dup), /// Swap the top two values on the stack. /// /// Operands: /// /// Stack: second, first **=>** first, second - Swap, + Swap(Swap), /// Push integer `0` on the stack. /// /// Operands: /// /// Stack: **=>** `0` - PushZero, + PushZero(PushZero), /// Push integer `1` on the stack. /// /// Operands: /// /// Stack: **=>** `1` - PushOne, + PushOne(PushZero), /// Push `i8` value on the stack. /// /// Operands: value: `i8` /// /// Stack: **=>** value - PushInt8, + PushInt8(PushInt8), /// Push i16 value on the stack. /// /// Operands: value: `i16` /// /// Stack: **=>** value - PushInt16, + PushInt16(PushInt16), /// Push i32 value on the stack. /// /// Operands: value: `i32` /// /// Stack: **=>** value - PushInt32, + PushInt32(PushInt32), /// Push `f64` value on the stack. /// /// Operands: value: `f64` /// /// Stack: **=>** value - PushRational, + PushRational(PushRational), /// Push `NaN` integer on the stack. /// /// Operands: /// /// Stack: **=>** `NaN` - PushNaN, + PushNaN(PushNaN), /// Push `Infinity` value on the stack. /// /// Operands: /// /// Stack: **=>** `Infinity` - PushPositiveInfinity, + PushPositiveInfinity(PushPositiveInfinity), /// Push `-Infinity` value on the stack. /// /// Operands: /// /// Stack: **=>** `-Infinity` - PushNegativeInfinity, + PushNegativeInfinity(PushNegativeInfinity), /// Push `null` value on the stack. /// /// Operands: /// /// Stack: **=>** `null` - PushNull, + PushNull(PushNull), /// Push `true` value on the stack. /// /// Operands: /// /// Stack: **=>** `true` - PushTrue, + PushTrue(PushTrue), /// Push `false` value on the stack. /// /// Operands: /// /// Stack: **=>** `false` - PushFalse, + PushFalse(PushFalse), /// Push `undefined` value on the stack. /// /// Operands: /// /// Stack: **=>** `undefined` - PushUndefined, + PushUndefined(PushUndefined), /// Push literal value on the stack. /// @@ -129,35 +160,35 @@ pub enum Opcode { /// Operands: index: `u32` /// /// Stack: **=>** (`literals[index]`) - PushLiteral, + PushLiteral(PushLiteral), /// Push empty object `{}` value on the stack. /// /// Operands: /// /// Stack: **=>** `{}` - PushEmptyObject, + PushEmptyObject(PushEmptyObject), /// Get the prototype of a superclass and push it on the stack. /// /// Operands: /// /// Stack: class, superclass **=>** class, superclass.prototype - PushClassPrototype, + PushClassPrototype(PushClassPrototype), /// Set the prototype of a class object. /// /// Operands: /// /// Stack: class, prototype **=>** class.prototype - SetClassPrototype, + SetClassPrototype(SetClassPrototype), /// Set home object internal slot of a function object. /// /// Operands: /// /// Stack: home, function **=>** home, function - SetHomeObject, + SetHomeObject(SetHomeObject), /// Push an empty array value on the stack. /// @@ -1212,28 +1243,28 @@ impl Opcode { pub fn as_str(self) -> &'static str { match self { - Self::Pop => "Pop", - Self::PopIfThrown => "PopIfThrown", - Self::Dup => "Dup", - Self::Swap => "Swap", - Self::PushZero => "PushZero", - Self::PushOne => "PushOne", - Self::PushInt8 => "PushInt8", - Self::PushInt16 => "PushInt16", - Self::PushInt32 => "PushInt32", - Self::PushRational => "PushRational", - Self::PushNaN => "PushNaN", - Self::PushPositiveInfinity => "PushPositiveInfinity", - Self::PushNegativeInfinity => "PushNegativeInfinity", - Self::PushNull => "PushNull", - Self::PushTrue => "PushTrue", - Self::PushFalse => "PushFalse", - Self::PushUndefined => "PushUndefined", - Self::PushLiteral => "PushLiteral", - Self::PushEmptyObject => "PushEmptyObject", - Self::PushClassPrototype => "PushClassPrototype", - Self::SetClassPrototype => "SetClassPrototype", - Self::SetHomeObject => "SetHomeObject", + Self::Pop(op) => Pop::NAME, + Self::PopIfThrown(op) => PopIfThrown::NAME, + Self::Dup(op) => Dup::NAME, + Self::Swap(op) => Swap::NAME, + Self::PushZero(op) => PushZero::NAME, + Self::PushOne(op) => PushOne::NAME, + Self::PushInt8(op) => PushInt8::NAME, + Self::PushInt16(op) => PushInt16::NAME, + Self::PushInt32(op) => PushInt32::NAME, + Self::PushRational(op) => PushRational::NAME, + Self::PushNaN(op) => PushNaN::NAME, + Self::PushPositiveInfinity(op) => PushPositiveInfinity::NAME, + Self::PushNegativeInfinity(op) => PushNegativeInfinity::NAME, + Self::PushNull(op) => PushNull::NAME, + Self::PushTrue(op) => PushTrue::NAME, + Self::PushFalse(op) => PushFalse::NAME, + Self::PushUndefined(op) => PushUndefined::NAME, + Self::PushLiteral(op) => PushLiteral::NAME, + Self::PushEmptyObject(op) => PushEmptyObject::NAME, + Self::PushClassPrototype(op) => PushClassPrototype::NAME, + Self::SetClassPrototype(op) => SetClassPrototype::NAME, + Self::SetHomeObject(op) => SetHomeObject::NAME, Self::PushNewArray => "PushNewArray", Self::PushValueToArray => "PushValueToArray", Self::PushElisionToArray => "PushElisionToArray", @@ -1380,25 +1411,25 @@ impl Opcode { /// Name of the profiler event for this opcode pub fn as_instruction_str(self) -> &'static str { match self { - Self::Pop => "INST - Pop", - Self::PopIfThrown => "INST - PopIfThrown", - Self::Dup => "INST - Dup", - Self::Swap => "INST - Swap", - Self::PushZero => "INST - PushZero", - Self::PushOne => "INST - PushOne", - Self::PushInt8 => "INST - PushInt8", - Self::PushInt16 => "INST - PushInt16", - Self::PushInt32 => "INST - PushInt32", - Self::PushRational => "INST - PushRational", - Self::PushNaN => "INST - PushNaN", - Self::PushPositiveInfinity => "INST - PushPositiveInfinity", - Self::PushNegativeInfinity => "INST - PushNegativeInfinity", - Self::PushNull => "INST - PushNull", - Self::PushTrue => "INST - PushTrue", - Self::PushFalse => "INST - PushFalse", - Self::PushUndefined => "INST - PushUndefined", - Self::PushLiteral => "INST - PushLiteral", - Self::PushEmptyObject => "INST - PushEmptyObject", + Self::Pop(op) => Pop::INSTRUCTION, + Self::PopIfThrown(op) => PopIfThrown::INSTRUCTION, + Self::Dup(op) => Dup::INSTRUCTION, + Self::Swap(op) => Swap::INSTRUCTION, + Self::PushZero(op) => PushZero::INSTRUCTION, + Self::PushOne(op) => PushOne::INSTRUCTION, + Self::PushInt8(op) => PushInt8::INSTRUCTION, + Self::PushInt16(op) => PushInt16::INSTRUCTION, + Self::PushInt32(op) => PushInt32::INSTRUCTION, + Self::PushRational(op) => PushRational::INSTRUCTION, + Self::PushNaN(op) => PushNaN::INSTRUCTION, + Self::PushPositiveInfinity(op) => PushPositiveInfinity::INSTRUCTION, + Self::PushNegativeInfinity(op) => PushNegativeInfinity::INSTRUCTION, + Self::PushNull(op) => PushNull::INSTRUCTION, + Self::PushTrue(op) => PushTrue::INSTRUCTION, + Self::PushFalse(op) => PushFalse::INSTRUCTION, + Self::PushUndefined(op) => PushUndefined::INSTRUCTION, + Self::PushLiteral(op) => PushLiteral::INSTRUCTION, + Self::PushEmptyObject(op) => PushEmptyObject::INSTRUCTION, Self::PushNewArray => "INST - PushNewArray", Self::PushValueToArray => "INST - PushValueToArray", Self::PushElisionToArray => "INST - PushElisionToArray", @@ -1521,9 +1552,9 @@ impl Opcode { Self::Await => "INST - Await", Self::GeneratorNextDelegate => "INST - GeneratorNextDelegate", Self::Nop => "INST - Nop", - Self::PushClassPrototype => "INST - PushClassPrototype", - Self::SetClassPrototype => "INST - SetClassPrototype", - Self::SetHomeObject => "INST - SetHomeObject", + Self::PushClassPrototype(op) => PushClassPrototype::INSTRUCTION, + Self::SetClassPrototype(op) => SetClassPrototype::INSTRUCTION, + Self::SetHomeObject(op) => SetHomeObject::INSTRUCTION, Self::DefineClassMethodByName => "INST - DefineClassMethodByName", Self::DefineClassMethodByValue => "INST - DefineClassMethodByValue", Self::DefineClassGetterByName => "INST - DefineClassGetterByName", diff --git a/boa_engine/src/vm/opcode/pop/if_thrown.rs b/boa_engine/src/vm/opcode/pop/if_thrown.rs new file mode 100644 index 00000000000..7dade24dc1e --- /dev/null +++ b/boa_engine/src/vm/opcode/pop/if_thrown.rs @@ -0,0 +1,21 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PopIfThrown; + +impl Operation for PopIfThrown { + const NAME: &'static str = "PopIfThrown"; + const INSTRUCTION: &'static str = "INST - PopIfThrown"; + + fn execute(context: &mut Context) -> JsResult { + let frame = context.vm.frame_mut(); + if frame.thrown { + frame.thrown = false; + context.vm.pop(); + } + Ok(ShouldExit::False) + } +} \ No newline at end of file diff --git a/boa_engine/src/vm/opcode/pop/mod.rs b/boa_engine/src/vm/opcode/pop/mod.rs new file mode 100644 index 00000000000..c33cda75817 --- /dev/null +++ b/boa_engine/src/vm/opcode/pop/mod.rs @@ -0,0 +1,21 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult +}; + +pub(crate) mod if_thrown; + +pub(crate) use if_thrown::PopIfThrown; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Pop; + +impl Operation for Pop { + const NAME: &'static str = "Pop"; + const INSTRUCTION: &'static str = "INST - Pop"; + + fn execute(context: &mut Context) -> JsResult { + let _val = context.vm.pop(); + Ok(ShouldExit::False) + } +} \ No newline at end of file diff --git a/boa_engine/src/vm/opcode/push/class_prototype.rs b/boa_engine/src/vm/opcode/push/class_prototype.rs new file mode 100644 index 00000000000..0901e58ec40 --- /dev/null +++ b/boa_engine/src/vm/opcode/push/class_prototype.rs @@ -0,0 +1,50 @@ +use crate::{ + vm::{ShouldExit, opcode::Operation}, + builtins::function::{Function, ConstructorKind}, + Context, JsValue, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PushClassPrototype; + +impl Operation for PushClassPrototype { + const NAME: &'static str = "PushClassPrototype"; + const INSTRUCTION: &'static str = "INST - PushClassPrototype"; + + fn execute(context: &mut Context) -> JsResult { + let superclass = context.vm.pop(); + + 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"); + } + + let class = context.vm.pop(); + { + let class_object = class.as_object().expect("class must be object"); + class_object.set_prototype(Some(superclass.clone())); + + let mut class_object_mut = class_object.borrow_mut(); + let class_function = class_object_mut + .as_function_mut() + .expect("class must be function object"); + if let Function::Ordinary { + constructor_kind, .. + } = class_function + { + *constructor_kind = ConstructorKind::Derived; + } + } + + context.vm.push(class); + context.vm.push(proto); + Ok(ShouldExit::False) + } else if superclass.is_null() { + context.vm.push(JsValue::Null); + Ok(ShouldExit::False) + } else { + return context.throw_type_error("superclass must be a constructor"); + } + } +} \ No newline at end of file diff --git a/boa_engine/src/vm/opcode/push/literal.rs b/boa_engine/src/vm/opcode/push/literal.rs new file mode 100644 index 00000000000..d0b809d492e --- /dev/null +++ b/boa_engine/src/vm/opcode/push/literal.rs @@ -0,0 +1,19 @@ +use crate::{ + vm::{ShouldExit, opcode::Operation}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PushLiteral; + +impl Operation for PushLiteral { + const NAME: &'static str = "PushLiteral"; + const INSTRUCTION: &'static str = "INST - PushLiteral"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::() as usize; + let value = context.vm.frame().code.literals[index].clone(); + context.vm.push(value); + Ok(ShouldExit::False) + } +} \ No newline at end of file diff --git a/boa_engine/src/vm/opcode/push/mod.rs b/boa_engine/src/vm/opcode/push/mod.rs new file mode 100644 index 00000000000..81b27c7011a --- /dev/null +++ b/boa_engine/src/vm/opcode/push/mod.rs @@ -0,0 +1,68 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsValue, +}; + +pub(crate) mod numbers; +pub(crate) mod literal; +pub(crate) mod class_prototype; +pub(crate) mod object; + +pub(crate) use numbers::*; +pub(crate) use literal::*; +pub(crate) use class_prototype::*; +pub(crate) use object::*; + + +macro_rules! implement_push_generics { + ($name:ident, $push_value:expr) => { + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub(crate) struct $name; + + impl Operation for $name { + const NAME: &'static str = stringify!($name); + const INSTRUCTION: &'static str = stringify!("INST - " + $name); + + fn execute(context: &mut Context) -> JsResult { + context.vm.push($push_value); + Ok(ShouldExit::False) + } + } + } +} + +implement_push_generics!( + PushUndefined, {JsValue::undefined()} +); + +implement_push_generics!( + PushNull, {JsValue::null()} +); + +implement_push_generics!( + PushTrue, true +); + +implement_push_generics!( + PushFalse, false +); + +implement_push_generics!( + PushZero, 0 +); + +implement_push_generics!( + PushOne, 1 +); + +implement_push_generics!( + PushNaN, JsValue::nan() +); + +implement_push_generics!( + PushPositiveInfinity, JsValue::positive_infinity() +); + +implement_push_generics!( + PushNegativeInfinity, JsValue::negative_infinity() +); \ No newline at end of file diff --git a/boa_engine/src/vm/opcode/push/numbers.rs b/boa_engine/src/vm/opcode/push/numbers.rs new file mode 100644 index 00000000000..1500cbea027 --- /dev/null +++ b/boa_engine/src/vm/opcode/push/numbers.rs @@ -0,0 +1,55 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult +}; + +macro_rules! implement_push_numbers_with_conversion { + ($name:ident, $num_type:ty) => { + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub(crate) struct $name; + + impl Operation for $name { + const NAME: &'static str = stringify!($name); + const INSTRUCTION: &'static str = stringify!("INST - " + $name); + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.read::<$num_type>(); + context.vm.push(i32::from(value)); + Ok(ShouldExit::False) + } + } + } +} + +macro_rules! implement_push_numbers_no_conversion { + ($name:ident, $num_type:ty) => { + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub(crate) struct $name; + + impl Operation for $name { + const NAME: &'static str = stringify!($name); + const INSTRUCTION: &'static str = stringify!("INST - " + $name); + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.read::<$num_type>(); + context.vm.push(value); + Ok(ShouldExit::False) + } + } + } +} +implement_push_numbers_with_conversion! ( + PushInt8, i8 +); + +implement_push_numbers_with_conversion!( + PushInt16, i16 +); + +implement_push_numbers_no_conversion!( + PushInt32, i32 +); + +implement_push_numbers_no_conversion!( + PushRational, f64 +); diff --git a/boa_engine/src/vm/opcode/push/object.rs b/boa_engine/src/vm/opcode/push/object.rs new file mode 100644 index 00000000000..857e1d52735 --- /dev/null +++ b/boa_engine/src/vm/opcode/push/object.rs @@ -0,0 +1,17 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PushEmptyObject; + +impl Operation for PushEmptyObject { + const NAME: &'static str = "PushEmptyObject"; + const INSTRUCTION: &'static str = "INST - PushEmptyObject"; + + fn execute(context: &mut Context) -> JsResult { + context.vm.push(context.construct_object()); + Ok(ShouldExit::False) + } +} \ No newline at end of file diff --git a/boa_engine/src/vm/opcode/set/class_prototype.rs b/boa_engine/src/vm/opcode/set/class_prototype.rs new file mode 100644 index 00000000000..00167f1b18e --- /dev/null +++ b/boa_engine/src/vm/opcode/set/class_prototype.rs @@ -0,0 +1,65 @@ +use crate::{ + object::{JsObject, ObjectData}, + property::PropertyDescriptorBuilder, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsValue +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct SetClassPrototype; + +impl Operation for SetClassPrototype { + const NAME: &'static str = "SetClassPrototype"; + const INSTRUCTION: &'static str = "INST - SetClassPrototype"; + + fn execute(context: &mut Context) -> JsResult { + let prototype_value = context.vm.pop(); + let prototype = match &prototype_value { + JsValue::Object(proto) => Some(proto.clone()), + JsValue::Null => None, + JsValue::Undefined => { + Some(context.intrinsics().constructors().object().prototype.clone()) + } + _ => unreachable!(), + }; + + let proto = JsObject::from_proto_and_data(prototype, ObjectData::ordinary()); + let class = context.vm.pop(); + + { + let class_object = class.as_object().expect("class must be object"); + class_object + .define_property_or_throw( + "prototype", + PropertyDescriptorBuilder::new() + .value(proto.clone()) + .writable(false) + .enumerable(false) + .configurable(false), + context, + ) + .expect("cannot fail per spec"); + let mut class_object_mut = class_object.borrow_mut(); + let class_function = class_object_mut + .as_function_mut() + .expect("class must be function object"); + class_function.set_home_object(proto.clone()); + } + + proto + .__define_own_property__( + "constructor".into(), + PropertyDescriptorBuilder::new() + .value(class) + .writable(true) + .enumerable(false) + .configurable(true) + .build(), + context, + ) + .expect("cannot fail per spec"); + + context.vm.push(proto); + Ok(ShouldExit::False) + } +} \ No newline at end of file diff --git a/boa_engine/src/vm/opcode/set/home_object.rs b/boa_engine/src/vm/opcode/set/home_object.rs new file mode 100644 index 00000000000..7c59766db37 --- /dev/null +++ b/boa_engine/src/vm/opcode/set/home_object.rs @@ -0,0 +1,31 @@ +use crate::{ + object::{JsObject, ObjectData}, + property::PropertyDescriptorBuilder, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsValue +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct SetHomeObject; + +impl Operation for SetHomeObject { + const NAME: &'static str = "SetHomeObject"; + const INSTRUCTION: &'static str = "INST - SetHomeObject"; + + fn execute(context: &mut Context) -> JsResult { + let function = context.vm.pop(); + let function_object = function.as_object().expect("must be object"); + let home = context.vm.pop(); + let home_object = home.as_object().expect("must be object"); + + function_object + .borrow_mut() + .as_function_mut() + .expect("must be function object") + .set_home_object(home_object.clone()); + + context.vm.push(home); + context.vm.push(function); + Ok(ShouldExit::False) + } +} \ No newline at end of file diff --git a/boa_engine/src/vm/opcode/set/mod.rs b/boa_engine/src/vm/opcode/set/mod.rs new file mode 100644 index 00000000000..f72f12e773d --- /dev/null +++ b/boa_engine/src/vm/opcode/set/mod.rs @@ -0,0 +1,6 @@ + +pub mod class_prototype; +pub mod home_object; + +pub use class_prototype::*; +pub use home_object::*; \ No newline at end of file diff --git a/boa_engine/src/vm/opcode/swap/mod.rs b/boa_engine/src/vm/opcode/swap/mod.rs new file mode 100644 index 00000000000..8c08fec1ad3 --- /dev/null +++ b/boa_engine/src/vm/opcode/swap/mod.rs @@ -0,0 +1,21 @@ +use crate::{ + vm::{ShouldExit, opcode::Operation}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Swap; + +impl Operation for Swap { + const NAME: &'static str = "Swap"; + const INSTRUCTION: &'static str = "INST - Swap"; + + fn execute(context: &mut Context) -> JsResult { + let first = context.vm.pop(); + let second = context.vm.pop(); + + context.vm.push(first); + context.vm.push(second); + Ok(ShouldExit::False) + } +} \ No newline at end of file From af83e2fe0bf0ce18897bf601af941570878711eb Mon Sep 17 00:00:00 2001 From: nekevss Date: Sun, 9 Oct 2022 00:36:04 -0400 Subject: [PATCH 02/12] Complete initial breakup of opcode --- boa_engine/src/vm/code_block.rs | 328 +-- boa_engine/src/vm/mod.rs | 2495 +---------------- boa_engine/src/vm/opcode/await_stm/mod.rs | 115 + boa_engine/src/vm/opcode/call/mod.rs | 175 ++ boa_engine/src/vm/opcode/concat/mod.rs | 25 + boa_engine/src/vm/opcode/conversion/mod.rs | 33 + boa_engine/src/vm/opcode/copy/mod.rs | 38 + boa_engine/src/vm/opcode/define/class.rs | 240 ++ boa_engine/src/vm/opcode/define/mod.rs | 123 + .../src/vm/opcode/define/own_property.rs | 68 + boa_engine/src/vm/opcode/delete/mod.rs | 46 + boa_engine/src/vm/opcode/dup/mod.rs | 4 +- boa_engine/src/vm/opcode/environment/mod.rs | 261 ++ boa_engine/src/vm/opcode/general/jump.rs | 52 + boa_engine/src/vm/opcode/general/logical.rs | 72 + boa_engine/src/vm/opcode/general/mod.rs | 307 ++ boa_engine/src/vm/opcode/generator/mod.rs | 215 ++ boa_engine/src/vm/opcode/get/function.rs | 36 + boa_engine/src/vm/opcode/get/generator.rs | 36 + boa_engine/src/vm/opcode/get/mod.rs | 11 + boa_engine/src/vm/opcode/get/name.rs | 111 + boa_engine/src/vm/opcode/get/private.rs | 44 + boa_engine/src/vm/opcode/get/property.rs | 80 + .../src/vm/opcode/iteration/for_await.rs | 65 + boa_engine/src/vm/opcode/iteration/for_in.rs | 77 + boa_engine/src/vm/opcode/iteration/init.rs | 39 + .../src/vm/opcode/iteration/iterator.rs | 97 + boa_engine/src/vm/opcode/iteration/mod.rs | 74 + boa_engine/src/vm/opcode/mod.rs | 914 +++--- boa_engine/src/vm/opcode/new/mod.rs | 68 + boa_engine/src/vm/opcode/pop/if_thrown.rs | 4 +- boa_engine/src/vm/opcode/pop/mod.rs | 45 +- boa_engine/src/vm/opcode/promise/mod.rs | 72 + boa_engine/src/vm/opcode/push/array.rs | 90 + boa_engine/src/vm/opcode/push/class.rs | 207 ++ .../src/vm/opcode/push/class_prototype.rs | 50 - boa_engine/src/vm/opcode/push/environment.rs | 48 + boa_engine/src/vm/opcode/push/literal.rs | 4 +- boa_engine/src/vm/opcode/push/mod.rs | 53 +- boa_engine/src/vm/opcode/push/new_target.rs | 30 + boa_engine/src/vm/opcode/push/numbers.rs | 22 +- boa_engine/src/vm/opcode/push/object.rs | 4 +- boa_engine/src/vm/opcode/require/mod.rs | 19 + .../src/vm/opcode/rest_parameter/mod.rs | 54 + boa_engine/src/vm/opcode/return_stm/mod.rs | 48 + .../src/vm/opcode/set/class_prototype.rs | 15 +- boa_engine/src/vm/opcode/set/home_object.rs | 4 +- boa_engine/src/vm/opcode/set/mod.rs | 15 +- boa_engine/src/vm/opcode/set/name.rs | 60 + boa_engine/src/vm/opcode/set/private.rs | 149 + boa_engine/src/vm/opcode/set/property.rs | 184 ++ boa_engine/src/vm/opcode/swap/mod.rs | 4 +- boa_engine/src/vm/opcode/switch/mod.rs | 40 + boa_engine/src/vm/opcode/throw/mod.rs | 17 + boa_engine/src/vm/opcode/try_catch/mod.rs | 144 + boa_engine/src/vm/opcode/value/mod.rs | 24 + 56 files changed, 4575 insertions(+), 3080 deletions(-) create mode 100644 boa_engine/src/vm/opcode/await_stm/mod.rs create mode 100644 boa_engine/src/vm/opcode/call/mod.rs create mode 100644 boa_engine/src/vm/opcode/concat/mod.rs create mode 100644 boa_engine/src/vm/opcode/conversion/mod.rs create mode 100644 boa_engine/src/vm/opcode/copy/mod.rs create mode 100644 boa_engine/src/vm/opcode/define/class.rs create mode 100644 boa_engine/src/vm/opcode/define/mod.rs create mode 100644 boa_engine/src/vm/opcode/define/own_property.rs create mode 100644 boa_engine/src/vm/opcode/delete/mod.rs create mode 100644 boa_engine/src/vm/opcode/environment/mod.rs create mode 100644 boa_engine/src/vm/opcode/general/jump.rs create mode 100644 boa_engine/src/vm/opcode/general/logical.rs create mode 100644 boa_engine/src/vm/opcode/general/mod.rs create mode 100644 boa_engine/src/vm/opcode/generator/mod.rs create mode 100644 boa_engine/src/vm/opcode/get/function.rs create mode 100644 boa_engine/src/vm/opcode/get/generator.rs create mode 100644 boa_engine/src/vm/opcode/get/mod.rs create mode 100644 boa_engine/src/vm/opcode/get/name.rs create mode 100644 boa_engine/src/vm/opcode/get/private.rs create mode 100644 boa_engine/src/vm/opcode/get/property.rs create mode 100644 boa_engine/src/vm/opcode/iteration/for_await.rs create mode 100644 boa_engine/src/vm/opcode/iteration/for_in.rs create mode 100644 boa_engine/src/vm/opcode/iteration/init.rs create mode 100644 boa_engine/src/vm/opcode/iteration/iterator.rs create mode 100644 boa_engine/src/vm/opcode/iteration/mod.rs create mode 100644 boa_engine/src/vm/opcode/new/mod.rs create mode 100644 boa_engine/src/vm/opcode/promise/mod.rs create mode 100644 boa_engine/src/vm/opcode/push/array.rs create mode 100644 boa_engine/src/vm/opcode/push/class.rs delete mode 100644 boa_engine/src/vm/opcode/push/class_prototype.rs create mode 100644 boa_engine/src/vm/opcode/push/environment.rs create mode 100644 boa_engine/src/vm/opcode/push/new_target.rs create mode 100644 boa_engine/src/vm/opcode/require/mod.rs create mode 100644 boa_engine/src/vm/opcode/rest_parameter/mod.rs create mode 100644 boa_engine/src/vm/opcode/return_stm/mod.rs create mode 100644 boa_engine/src/vm/opcode/set/name.rs create mode 100644 boa_engine/src/vm/opcode/set/private.rs create mode 100644 boa_engine/src/vm/opcode/set/property.rs create mode 100644 boa_engine/src/vm/opcode/switch/mod.rs create mode 100644 boa_engine/src/vm/opcode/throw/mod.rs create mode 100644 boa_engine/src/vm/opcode/try_catch/mod.rs create mode 100644 boa_engine/src/vm/opcode/value/mod.rs diff --git a/boa_engine/src/vm/code_block.rs b/boa_engine/src/vm/code_block.rs index 3e63f15226d..204eb376c3e 100644 --- a/boa_engine/src/vm/code_block.rs +++ b/boa_engine/src/vm/code_block.rs @@ -165,68 +165,68 @@ impl CodeBlock { /// Modifies the `pc` to point to the next instruction. /// /// Returns an empty `String` if no operands are present. - pub(crate) fn instruction_operands(&self, pc: &mut usize, interner: &Interner) -> String { + pub(crate) fn instruction_erands(&self, pc: &mut usize, interner: &Interner) -> String { let opcode: Opcode = self.code[*pc].try_into().expect("invalid opcode"); *pc += size_of::(); match opcode { - Opcode::PushInt8 => { + Opcode::PushInt8(_) => { let result = self.read::(*pc).to_string(); *pc += size_of::(); result } - Opcode::PushInt16 => { + Opcode::PushInt16(_) => { let result = self.read::(*pc).to_string(); *pc += size_of::(); result } - Opcode::PushInt32 => { + Opcode::PushInt32(_) => { let result = self.read::(*pc).to_string(); *pc += size_of::(); result } - Opcode::PushRational => { + Opcode::PushRational(_) => { let operand = self.read::(*pc); *pc += size_of::(); ryu_js::Buffer::new().format(operand).to_string() } - Opcode::PushLiteral - | Opcode::Jump - | Opcode::JumpIfFalse - | Opcode::JumpIfNotUndefined - | Opcode::CatchStart - | Opcode::FinallySetJump - | Opcode::Case - | Opcode::Default - | Opcode::LogicalAnd - | Opcode::LogicalOr - | Opcode::Coalesce - | Opcode::CallEval - | Opcode::Call - | Opcode::New - | Opcode::SuperCall - | Opcode::ForInLoopInitIterator - | Opcode::ForInLoopNext - | Opcode::ForAwaitOfLoopNext - | Opcode::ConcatToString - | Opcode::GeneratorNextDelegate => { + Opcode::PushLiteral(_) + | Opcode::Jump(_) + | Opcode::JumpIfFalse(_) + | Opcode::JumpIfNotUndefined(_) + | Opcode::CatchStart(_) + | Opcode::FinallySetJump(_) + | Opcode::Case(_) + | Opcode::Default(_) + | Opcode::LogicalAnd(_) + | Opcode::LogicalOr(_) + | Opcode::Coalesce(_) + | Opcode::CallEval(_) + | Opcode::Call(_) + | Opcode::New(_) + | Opcode::SuperCall(_) + | Opcode::ForInLoopInitIterator(_) + | Opcode::ForInLoopNext(_) + | Opcode::ForAwaitOfLoopNext(_) + | Opcode::ConcatToString(_) + | Opcode::GeneratorNextDelegate(_) => { let result = self.read::(*pc).to_string(); *pc += size_of::(); result } - Opcode::TryStart - | Opcode::PushDeclarativeEnvironment - | Opcode::PushFunctionEnvironment - | Opcode::CopyDataProperties => { + Opcode::TryStart(_) + | Opcode::PushDeclarativeEnvironment(_) + | Opcode::PushFunctionEnvironment(_) + | Opcode::CopyDataProperties(_) => { let operand1 = self.read::(*pc); *pc += size_of::(); let operand2 = self.read::(*pc); *pc += size_of::(); format!("{operand1}, {operand2}") } - Opcode::GetFunction - | Opcode::GetFunctionAsync - | Opcode::GetGenerator - | Opcode::GetGeneratorAsync => { + Opcode::GetFunction(_) + | Opcode::GetFunctionAsync(_) + | Opcode::GetGenerator(_) + | Opcode::GetGeneratorAsync(_) => { let operand = self.read::(*pc); *pc += size_of::(); format!( @@ -235,15 +235,15 @@ impl CodeBlock { self.functions[operand as usize].length ) } - Opcode::DefInitArg - | Opcode::DefVar - | Opcode::DefInitVar - | Opcode::DefLet - | Opcode::DefInitLet - | Opcode::DefInitConst - | Opcode::GetName - | Opcode::GetNameOrUndefined - | Opcode::SetName => { + Opcode::DefInitArg(_) + | Opcode::DefVar(_) + | Opcode::DefInitVar(_) + | Opcode::DefLet(_) + | Opcode::DefInitLet(_) + | Opcode::DefInitConst(_) + | Opcode::GetName(_) + | Opcode::GetNameOrUndefined(_) + | Opcode::SetName(_) => { let operand = self.read::(*pc); *pc += size_of::(); format!( @@ -252,25 +252,25 @@ impl CodeBlock { interner.resolve_expect(self.bindings[operand as usize].name().sym()), ) } - Opcode::GetPropertyByName - | Opcode::SetPropertyByName - | Opcode::DefineOwnPropertyByName - | Opcode::DefineClassMethodByName - | Opcode::SetPropertyGetterByName - | Opcode::DefineClassGetterByName - | Opcode::SetPropertySetterByName - | Opcode::DefineClassSetterByName - | Opcode::AssignPrivateField - | Opcode::SetPrivateField - | Opcode::SetPrivateMethod - | Opcode::SetPrivateSetter - | Opcode::SetPrivateGetter - | Opcode::GetPrivateField - | Opcode::DeletePropertyByName - | Opcode::PushClassFieldPrivate - | Opcode::PushClassPrivateGetter - | Opcode::PushClassPrivateSetter - | Opcode::PushClassPrivateMethod => { + Opcode::GetPropertyByName(_) + | Opcode::SetPropertyByName(_) + | Opcode::DefineOwnPropertyByName(_) + | Opcode::DefineClassMethodByName(_) + | Opcode::SetPropertyGetterByName(_) + | Opcode::DefineClassGetterByName(_) + | Opcode::SetPropertySetterByName(_) + | Opcode::DefineClassSetterByName(_) + | Opcode::AssignPrivateField(_) + | Opcode::SetPrivateField(_) + | Opcode::SetPrivateMethod(_) + | Opcode::SetPrivateSetter(_) + | Opcode::SetPrivateGetter(_) + | Opcode::GetPrivateField(_) + | Opcode::DeletePropertyByName(_) + | Opcode::PushClassFieldPrivate(_) + | Opcode::PushClassPrivateGetter(_) + | Opcode::PushClassPrivateSetter(_) + | Opcode::PushClassPrivateMethod(_) => { let operand = self.read::(*pc); *pc += size_of::(); format!( @@ -278,108 +278,108 @@ impl CodeBlock { interner.resolve_expect(self.names[operand as usize].sym()), ) } - Opcode::Pop - | Opcode::PopIfThrown - | Opcode::Dup - | Opcode::Swap - | Opcode::PushZero - | Opcode::PushOne - | Opcode::PushNaN - | Opcode::PushPositiveInfinity - | Opcode::PushNegativeInfinity - | Opcode::PushNull - | Opcode::PushTrue - | Opcode::PushFalse - | Opcode::PushUndefined - | Opcode::PushEmptyObject - | Opcode::PushClassPrototype - | Opcode::SetClassPrototype - | Opcode::SetHomeObject - | Opcode::Add - | Opcode::Sub - | Opcode::Div - | Opcode::Mul - | Opcode::Mod - | Opcode::Pow - | Opcode::ShiftRight - | Opcode::ShiftLeft - | Opcode::UnsignedShiftRight - | Opcode::BitOr - | Opcode::BitAnd - | Opcode::BitXor - | Opcode::BitNot - | Opcode::In - | Opcode::Eq - | Opcode::StrictEq - | Opcode::NotEq - | Opcode::StrictNotEq - | Opcode::GreaterThan - | Opcode::GreaterThanOrEq - | Opcode::LessThan - | Opcode::LessThanOrEq - | Opcode::InstanceOf - | Opcode::TypeOf - | Opcode::Void - | Opcode::LogicalNot - | Opcode::Pos - | Opcode::Neg - | Opcode::Inc - | Opcode::IncPost - | Opcode::Dec - | Opcode::DecPost - | Opcode::GetPropertyByValue - | Opcode::GetPropertyByValuePush - | Opcode::SetPropertyByValue - | Opcode::DefineOwnPropertyByValue - | Opcode::DefineClassMethodByValue - | Opcode::SetPropertyGetterByValue - | Opcode::DefineClassGetterByValue - | Opcode::SetPropertySetterByValue - | Opcode::DefineClassSetterByValue - | Opcode::DeletePropertyByValue - | Opcode::ToPropertyKey - | Opcode::ToBoolean - | Opcode::Throw - | Opcode::TryEnd - | Opcode::CatchEnd - | Opcode::CatchEnd2 - | Opcode::FinallyStart - | Opcode::FinallyEnd - | Opcode::This - | Opcode::Super - | Opcode::Return - | Opcode::PopEnvironment - | Opcode::LoopStart - | Opcode::LoopContinue - | Opcode::LoopEnd - | Opcode::InitIterator - | Opcode::InitIteratorAsync - | Opcode::IteratorNext - | Opcode::IteratorClose - | Opcode::IteratorToArray - | Opcode::RequireObjectCoercible - | Opcode::ValueNotNullOrUndefined - | Opcode::RestParameterInit - | Opcode::RestParameterPop - | Opcode::PushValueToArray - | Opcode::PushElisionToArray - | Opcode::PushIteratorToArray - | Opcode::PushNewArray - | Opcode::PopOnReturnAdd - | Opcode::PopOnReturnSub - | Opcode::Yield - | Opcode::GeneratorNext - | Opcode::AsyncGeneratorNext - | Opcode::PushClassField - | Opcode::SuperCallDerived - | Opcode::Await - | Opcode::PushNewTarget - | Opcode::CallEvalSpread - | Opcode::CallSpread - | Opcode::NewSpread - | Opcode::SuperCallSpread - | Opcode::ForAwaitOfLoopIterate - | Opcode::Nop => String::new(), + Opcode::Pop(_) + | Opcode::PopIfThrown(_) + | Opcode::Dup(_) + | Opcode::Swap(_) + | Opcode::PushZero(_) + | Opcode::PushOne(_) + | Opcode::PushNaN(_) + | Opcode::PushPositiveInfinity(_) + | Opcode::PushNegativeInfinity(_) + | Opcode::PushNull(_) + | Opcode::PushTrue(_) + | Opcode::PushFalse(_) + | Opcode::PushUndefined(_) + | Opcode::PushEmptyObject(_) + | Opcode::PushClassPrototype(_) + | Opcode::SetClassPrototype(_) + | Opcode::SetHomeObject(_) + | Opcode::Add(_) + | Opcode::Sub(_) + | Opcode::Div(_) + | Opcode::Mul(_) + | Opcode::Mod(_) + | Opcode::Pow(_) + | Opcode::ShiftRight(_) + | Opcode::ShiftLeft(_) + | Opcode::UnsignedShiftRight(_) + | Opcode::BitOr(_) + | Opcode::BitAnd(_) + | Opcode::BitXor(_) + | Opcode::BitNot(_) + | Opcode::In(_) + | Opcode::Eq(_) + | Opcode::StrictEq(_) + | Opcode::NotEq(_) + | Opcode::StrictNotEq(_) + | Opcode::GreaterThan(_) + | Opcode::GreaterThanOrEq(_) + | Opcode::LessThan(_) + | Opcode::LessThanOrEq(_) + | Opcode::InstanceOf(_) + | Opcode::TypeOf(_) + | Opcode::Void(_) + | Opcode::LogicalNot(_) + | Opcode::Pos(_) + | Opcode::Neg(_) + | Opcode::Inc(_) + | Opcode::IncPost(_) + | Opcode::Dec(_) + | Opcode::DecPost(_) + | Opcode::GetPropertyByValue(_) + | Opcode::GetPropertyByValuePush(_) + | Opcode::SetPropertyByValue(_) + | Opcode::DefineOwnPropertyByValue(_) + | Opcode::DefineClassMethodByValue(_) + | Opcode::SetPropertyGetterByValue(_) + | Opcode::DefineClassGetterByValue(_) + | Opcode::SetPropertySetterByValue(_) + | Opcode::DefineClassSetterByValue(_) + | Opcode::DeletePropertyByValue(_) + | Opcode::ToPropertyKey(_) + | Opcode::ToBoolean(_) + | Opcode::Throw(_) + | Opcode::TryEnd(_) + | Opcode::CatchEnd(_) + | Opcode::CatchEnd2(_) + | Opcode::FinallyStart(_) + | Opcode::FinallyEnd(_) + | Opcode::This(_) + | Opcode::Super(_) + | Opcode::Return(_) + | Opcode::PopEnvironment(_) + | Opcode::LoopStart(_) + | Opcode::LoopContinue(_) + | Opcode::LoopEnd(_) + | Opcode::InitIterator(_) + | Opcode::InitIteratorAsync(_) + | Opcode::IteratorNext(_) + | Opcode::IteratorClose(_) + | Opcode::IteratorToArray(_) + | Opcode::RequireObjectCoercible(_) + | Opcode::ValueNotNullOrUndefined(_) + | Opcode::RestParameterInit(_) + | Opcode::RestParameterPop(_) + | Opcode::PushValueToArray(_) + | Opcode::PushElisionToArray(_) + | Opcode::PushIteratorToArray(_) + | Opcode::PushNewArray(_) + | Opcode::PopOnReturnAdd(_) + | Opcode::PopOnReturnSub(_) + | Opcode::Yield(_) + | Opcode::GeneratorNext(_) + | Opcode::AsyncGeneratorNext(_) + | Opcode::PushClassField(_) + | Opcode::SuperCallDerived(_) + | Opcode::Await(_) + | Opcode::PushNewTarget(_) + | Opcode::CallEvalSpread(_) + | Opcode::CallSpread(_) + | Opcode::NewSpread(_) + | Opcode::SuperCallSpread(_) + | Opcode::ForAwaitOfLoopIterate(_) + | Opcode::Nop(_) => String::new(), } } } @@ -404,7 +404,7 @@ impl ToInternedString for CodeBlock { let opcode: Opcode = self.code[pc].try_into().expect("invalid opcode"); let opcode = opcode.as_str(); let previous_pc = pc; - let operands = self.instruction_operands(&mut pc, interner); + let operands = self.instruction_erands(&mut pc, interner); f.push_str(&format!( "{previous_pc:06} {count:04} {opcode:<27}{operands}\n", )); diff --git a/boa_engine/src/vm/mod.rs b/boa_engine/src/vm/mod.rs index 273ac22290c..0a35e98ff2e 100644 --- a/boa_engine/src/vm/mod.rs +++ b/boa_engine/src/vm/mod.rs @@ -22,7 +22,7 @@ use crate::{ }; use boa_interner::ToInternedString; use boa_profiler::Profiler; -use std::{convert::TryInto, mem::size_of, ops::Neg, time::Instant}; +use std::{convert::TryInto, mem::size_of, time::Instant}; mod call_frame; mod code_block; @@ -127,15 +127,6 @@ pub(crate) enum ReturnType { impl Context { fn execute_instruction(&mut self) -> JsResult { - macro_rules! bin_op { - ($op:ident) => {{ - let rhs = self.vm.pop(); - let lhs = self.vm.pop(); - let value = lhs.$op(&rhs, self)?; - self.vm.push(value) - }}; - } - let opcode: Opcode = { let _timer = Profiler::global().start_event("Opcode retrieval", "vm"); let opcode = self.vm.frame().code.code[self.vm.frame().pc] @@ -148,7 +139,7 @@ impl Context { let _timer = Profiler::global().start_event(opcode.as_instruction_str(), "vm"); let result = match opcode { - Opcode::Nop => {ShouldExit::False} + Opcode::Nop(op) => Nop::execute(self)?, Opcode::Pop(op) => Pop::execute(self)?, Opcode::PopIfThrown(op) => PopIfThrown::execute(self)?, Opcode::Dup(op) => Dup::execute(self)?, @@ -171,2349 +162,145 @@ impl Context { Opcode::PushClassPrototype(op) => PushClassPrototype::execute(self)?, Opcode::SetClassPrototype(op) => SetClassPrototype::execute(self)?, Opcode::SetHomeObject(op) => SetHomeObject::execute(self)?, - Opcode::PushNewArray => { - let array = Array::array_create(0, None, self) - .expect("Array creation with 0 length should never fail"); - self.vm.push(array); - } - Opcode::PushValueToArray => { - let value = self.vm.pop(); - let array = self.vm.pop(); - let o = array.as_object().expect("should be an object"); - let len = o - .length_of_array_like(self) - .expect("should have 'length' property"); - o.create_data_property_or_throw(len, value, self) - .expect("should be able to create new data property"); - self.vm.push(array); - } - Opcode::PushElisionToArray => { - let array = self.vm.pop(); - let o = array.as_object().expect("should always be an object"); - - let len = o - .length_of_array_like(self) - .expect("arrays should always have a 'length' property"); - - o.set("length", len + 1, true, self)?; - self.vm.push(array); - } - Opcode::PushIteratorToArray => { - let done = self - .vm - .pop() - .as_boolean() - .expect("iterator [[Done]] was not a boolean"); - let next_method = self.vm.pop(); - let iterator = self.vm.pop(); - let iterator = iterator.as_object().expect("iterator was not an object"); - let array = self.vm.pop(); - - let iterator = IteratorRecord::new(iterator.clone(), next_method, done); - while let Some(next) = iterator.step(self)? { - Array::push(&array, &[next.value(self)?], self)?; - } - - self.vm.push(array); - } - Opcode::Add => bin_op!(add), - Opcode::Sub => bin_op!(sub), - Opcode::Mul => bin_op!(mul), - Opcode::Div => bin_op!(div), - Opcode::Pow => bin_op!(pow), - Opcode::Mod => bin_op!(rem), - Opcode::BitAnd => bin_op!(bitand), - Opcode::BitOr => bin_op!(bitor), - Opcode::BitXor => bin_op!(bitxor), - Opcode::ShiftLeft => bin_op!(shl), - Opcode::ShiftRight => bin_op!(shr), - Opcode::UnsignedShiftRight => bin_op!(ushr), - Opcode::Eq => { - let rhs = self.vm.pop(); - let lhs = self.vm.pop(); - let value = lhs.equals(&rhs, self)?; - self.vm.push(value); - } - Opcode::NotEq => { - let rhs = self.vm.pop(); - let lhs = self.vm.pop(); - let value = !lhs.equals(&rhs, self)?; - self.vm.push(value); - } - Opcode::StrictEq => { - let rhs = self.vm.pop(); - let lhs = self.vm.pop(); - self.vm.push(lhs.strict_equals(&rhs)); - } - Opcode::StrictNotEq => { - let rhs = self.vm.pop(); - let lhs = self.vm.pop(); - self.vm.push(!lhs.strict_equals(&rhs)); - } - Opcode::GreaterThan => bin_op!(gt), - Opcode::GreaterThanOrEq => bin_op!(ge), - Opcode::LessThan => bin_op!(lt), - Opcode::LessThanOrEq => bin_op!(le), - Opcode::In => { - let rhs = self.vm.pop(); - let lhs = self.vm.pop(); - - if !rhs.is_object() { - 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(self)?; - let value = self.has_property(&rhs, &key)?; - self.vm.push(value); - } - Opcode::InstanceOf => { - let target = self.vm.pop(); - let v = self.vm.pop(); - let value = v.instance_of(&target, self)?; - - self.vm.push(value); - } - Opcode::Void => { - let _old = self.vm.pop(); - self.vm.push(JsValue::undefined()); - } - Opcode::TypeOf => { - let value = self.vm.pop(); - self.vm.push(value.type_of()); - } - Opcode::Pos => { - let value = self.vm.pop(); - let value = value.to_number(self)?; - self.vm.push(value); - } - Opcode::Neg => { - let value = self.vm.pop(); - match value.to_numeric(self)? { - Numeric::Number(number) => self.vm.push(number.neg()), - Numeric::BigInt(bigint) => self.vm.push(JsBigInt::neg(&bigint)), - } - } - Opcode::Inc => { - let value = self.vm.pop(); - match value.to_numeric(self)? { - Numeric::Number(number) => self.vm.push(number + 1f64), - Numeric::BigInt(bigint) => { - self.vm.push(JsBigInt::add(&bigint, &JsBigInt::one())); - } - } - } - Opcode::IncPost => { - let value = self.vm.pop(); - let value = value.to_numeric(self)?; - self.vm.push(value.clone()); - match value { - Numeric::Number(number) => self.vm.push(number + 1f64), - Numeric::BigInt(bigint) => { - self.vm.push(JsBigInt::add(&bigint, &JsBigInt::one())); - } - } - } - Opcode::Dec => { - let value = self.vm.pop(); - match value.to_numeric(self)? { - Numeric::Number(number) => self.vm.push(number - 1f64), - Numeric::BigInt(bigint) => { - self.vm.push(JsBigInt::sub(&bigint, &JsBigInt::one())); - } - } - } - Opcode::DecPost => { - let value = self.vm.pop(); - let value = value.to_numeric(self)?; - self.vm.push(value.clone()); - match value { - Numeric::Number(number) => self.vm.push(number - 1f64), - Numeric::BigInt(bigint) => { - self.vm.push(JsBigInt::sub(&bigint, &JsBigInt::one())); - } - } - } - Opcode::LogicalNot => { - let value = self.vm.pop(); - self.vm.push(!value.to_boolean()); - } - Opcode::BitNot => { - let value = self.vm.pop(); - match value.to_numeric(self)? { - Numeric::Number(number) => self.vm.push(Number::not(number)), - Numeric::BigInt(bigint) => self.vm.push(JsBigInt::not(&bigint)), - } - } - Opcode::DefVar => { - let index = self.vm.read::(); - let binding_locator = self.vm.frame().code.bindings[index as usize]; - - if binding_locator.is_global() { - let key = self - .interner() - .resolve_expect(binding_locator.name().sym()) - .into_common(false); - self.global_bindings_mut().entry(key).or_insert( - PropertyDescriptor::builder() - .value(JsValue::Undefined) - .writable(true) - .enumerable(true) - .configurable(true) - .build(), - ); - } else { - self.realm.environments.put_value_if_uninitialized( - binding_locator.environment_index(), - binding_locator.binding_index(), - JsValue::Undefined, - ); - } - } - Opcode::DefInitVar => { - let index = self.vm.read::(); - let value = self.vm.pop(); - let binding_locator = self.vm.frame().code.bindings[index as usize]; - binding_locator.throw_mutate_immutable(self)?; - - if binding_locator.is_global() { - let key = self - .interner() - .resolve_expect(binding_locator.name().sym()) - .into_common::(false) - .into(); - crate::object::internal_methods::global::global_set_no_receiver( - &key, value, self, - )?; - } else { - self.realm.environments.put_value( - binding_locator.environment_index(), - binding_locator.binding_index(), - value, - ); - } - } - Opcode::DefLet => { - let index = self.vm.read::(); - let binding_locator = self.vm.frame().code.bindings[index as usize]; - self.realm.environments.put_value( - binding_locator.environment_index(), - binding_locator.binding_index(), - JsValue::Undefined, - ); - } - Opcode::DefInitLet | Opcode::DefInitConst | Opcode::DefInitArg => { - let index = self.vm.read::(); - let value = self.vm.pop(); - let binding_locator = self.vm.frame().code.bindings[index as usize]; - self.realm.environments.put_value( - binding_locator.environment_index(), - binding_locator.binding_index(), - value, - ); - } - Opcode::GetName => { - let index = self.vm.read::(); - let binding_locator = self.vm.frame().code.bindings[index as usize]; - binding_locator.throw_mutate_immutable(self)?; - - let value = if binding_locator.is_global() { - if let Some(value) = self - .realm - .environments - .get_value_global_poisoned(binding_locator.name()) - { - value - } else { - let key: JsString = self - .interner() - .resolve_expect(binding_locator.name().sym()) - .into_common(false); - match self.global_bindings_mut().get(&key) { - Some(desc) => match desc.kind() { - DescriptorKind::Data { - value: Some(value), .. - } => value.clone(), - DescriptorKind::Accessor { get: Some(get), .. } - if !get.is_undefined() => - { - let get = get.clone(); - self.call(&get, &self.global_object().clone().into(), &[])? - } - _ => { - return Err(JsNativeError::reference() - .with_message(format!( - "{} is not defined", - key.to_std_string_escaped() - )) - .into()) - } - }, - _ => { - return Err(JsNativeError::reference() - .with_message(format!( - "{} is not defined", - key.to_std_string_escaped() - )) - .into()) - } - } - } - } else if let Some(value) = self.realm.environments.get_value_optional( - binding_locator.environment_index(), - binding_locator.binding_index(), - binding_locator.name(), - ) { - value - } else { - let name = self - .interner() - .resolve_expect(binding_locator.name().sym()) - .to_string(); - return Err(JsNativeError::reference() - .with_message(format!("{name} is not initialized")) - .into()); - }; - - self.vm.push(value); - } - Opcode::GetNameOrUndefined => { - let index = self.vm.read::(); - let binding_locator = self.vm.frame().code.bindings[index as usize]; - binding_locator.throw_mutate_immutable(self)?; - let value = if binding_locator.is_global() { - if let Some(value) = self - .realm - .environments - .get_value_global_poisoned(binding_locator.name()) - { - value - } else { - let key: JsString = self - .interner() - .resolve_expect(binding_locator.name().sym()) - .into_common(false); - match self.global_bindings_mut().get(&key) { - Some(desc) => match desc.kind() { - DescriptorKind::Data { - value: Some(value), .. - } => value.clone(), - DescriptorKind::Accessor { get: Some(get), .. } - if !get.is_undefined() => - { - let get = get.clone(); - self.call(&get, &self.global_object().clone().into(), &[])? - } - _ => JsValue::undefined(), - }, - _ => JsValue::undefined(), - } - } - } else if let Some(value) = self.realm.environments.get_value_optional( - binding_locator.environment_index(), - binding_locator.binding_index(), - binding_locator.name(), - ) { - value - } else { - JsValue::undefined() - }; - - self.vm.push(value); - } - Opcode::SetName => { - let index = self.vm.read::(); - let binding_locator = self.vm.frame().code.bindings[index as usize]; - let value = self.vm.pop(); - binding_locator.throw_mutate_immutable(self)?; - - if binding_locator.is_global() { - if !self - .realm - .environments - .put_value_global_poisoned(binding_locator.name(), &value) - { - let key: JsString = self - .interner() - .resolve_expect(binding_locator.name().sym()) - .into_common(false); - let exists = self.global_bindings_mut().contains_key(&key); - - if !exists && self.vm.frame().code.strict { - 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( - &key.clone().into(), - value, - self, - )?; - - if !success && self.vm.frame().code.strict { - return Err(JsNativeError::typ() - .with_message(format!( - "cannot set non-writable property: {}", - key.to_std_string_escaped() - )) - .into()); - } - } - } else if !self.realm.environments.put_value_if_initialized( - binding_locator.environment_index(), - binding_locator.binding_index(), - binding_locator.name(), - value, - ) { - return Err(JsNativeError::reference() - .with_message(format!( - "cannot access '{}' before initialization", - self.interner().resolve_expect(binding_locator.name().sym()) - )) - .into()); - } - } - Opcode::Jump => { - let address = self.vm.read::(); - self.vm.frame_mut().pc = address as usize; - } - Opcode::JumpIfFalse => { - let address = self.vm.read::(); - if !self.vm.pop().to_boolean() { - self.vm.frame_mut().pc = address as usize; - } - } - Opcode::JumpIfNotUndefined => { - let address = self.vm.read::(); - let value = self.vm.pop(); - if !value.is_undefined() { - self.vm.frame_mut().pc = address as usize; - self.vm.push(value); - } - } - Opcode::LogicalAnd => { - let exit = self.vm.read::(); - let lhs = self.vm.pop(); - if !lhs.to_boolean() { - self.vm.frame_mut().pc = exit as usize; - self.vm.push(lhs); - } - } - Opcode::LogicalOr => { - let exit = self.vm.read::(); - let lhs = self.vm.pop(); - if lhs.to_boolean() { - self.vm.frame_mut().pc = exit as usize; - self.vm.push(lhs); - } - } - Opcode::Coalesce => { - let exit = self.vm.read::(); - let lhs = self.vm.pop(); - if !lhs.is_null_or_undefined() { - self.vm.frame_mut().pc = exit as usize; - self.vm.push(lhs); - } - } - Opcode::ToBoolean => { - let value = self.vm.pop(); - self.vm.push(value.to_boolean()); - } - Opcode::GetPropertyByName => { - let index = self.vm.read::(); - - let value = self.vm.pop(); - let object = if let Some(object) = value.as_object() { - object.clone() - } else { - value.to_object(self)? - }; - - let name = self.vm.frame().code.names[index as usize]; - let name: PropertyKey = self - .interner() - .resolve_expect(name.sym()) - .into_common::(false) - .into(); - let result = object.get(name, self)?; - - self.vm.push(result); - } - Opcode::GetPropertyByValue => { - let object = self.vm.pop(); - let key = self.vm.pop(); - let object = if let Some(object) = object.as_object() { - object.clone() - } else { - object.to_object(self)? - }; - - let key = key.to_property_key(self)?; - let value = object.get(key, self)?; - - self.vm.push(value); - } - Opcode::GetPropertyByValuePush => { - let object = self.vm.pop(); - let key = self.vm.pop(); - let object = if let Some(object) = object.as_object() { - object.clone() - } else { - object.to_object(self)? - }; - - let property_key = key.to_property_key(self)?; - let value = object.get(property_key, self)?; - - self.vm.push(key); - self.vm.push(value); - } - Opcode::SetPropertyByName => { - let index = self.vm.read::(); - - let object = self.vm.pop(); - let value = self.vm.pop(); - let object = if let Some(object) = object.as_object() { - object.clone() - } else { - object.to_object(self)? - }; - - let name = self.vm.frame().code.names[index as usize]; - let name: PropertyKey = self - .interner() - .resolve_expect(name.sym()) - .into_common::(false) - .into(); - - object.set(name, value, self.vm.frame().code.strict, self)?; - } - Opcode::DefineOwnPropertyByName => { - let index = self.vm.read::(); - let object = self.vm.pop(); - let value = self.vm.pop(); - let object = if let Some(object) = object.as_object() { - object.clone() - } else { - object.to_object(self)? - }; - let name = self.vm.frame().code.names[index as usize]; - let name = self - .interner() - .resolve_expect(name.sym()) - .into_common::(false); - object.__define_own_property__( - name.into(), - PropertyDescriptor::builder() - .value(value) - .writable(true) - .enumerable(true) - .configurable(true) - .build(), - self, - )?; - } - Opcode::DefineClassMethodByName => { - let index = self.vm.read::(); - let object = self.vm.pop(); - let value = self.vm.pop(); - let object = if let Some(object) = object.as_object() { - object.clone() - } else { - object.to_object(self)? - }; - value - .as_object() - .expect("method must be function object") - .borrow_mut() - .as_function_mut() - .expect("method must be function object") - .set_home_object(object.clone()); - let name = self.vm.frame().code.names[index as usize]; - let name = self.interner().resolve_expect(name.sym()); - object.__define_own_property__( - name.into_common::(false).into(), - PropertyDescriptor::builder() - .value(value) - .writable(true) - .enumerable(false) - .configurable(true) - .build(), - self, - )?; - } - Opcode::SetPropertyByValue => { - let object = self.vm.pop(); - let key = self.vm.pop(); - let value = self.vm.pop(); - let object = if let Some(object) = object.as_object() { - object.clone() - } else { - object.to_object(self)? - }; - - let key = key.to_property_key(self)?; - object.set(key, value, self.vm.frame().code.strict, self)?; - } - Opcode::DefineOwnPropertyByValue => { - let value = self.vm.pop(); - let key = self.vm.pop(); - let object = self.vm.pop(); - let object = if let Some(object) = object.as_object() { - object.clone() - } else { - object.to_object(self)? - }; - let key = key.to_property_key(self)?; - object.__define_own_property__( - key, - PropertyDescriptor::builder() - .value(value) - .writable(true) - .enumerable(true) - .configurable(true) - .build(), - self, - )?; - } - Opcode::DefineClassMethodByValue => { - let value = self.vm.pop(); - let key = self.vm.pop(); - let object = self.vm.pop(); - let object = if let Some(object) = object.as_object() { - object.clone() - } else { - object.to_object(self)? - }; - value - .as_object() - .expect("method must be function object") - .borrow_mut() - .as_function_mut() - .expect("method must be function object") - .set_home_object(object.clone()); - let key = key.to_property_key(self)?; - object.__define_own_property__( - key, - PropertyDescriptor::builder() - .value(value) - .writable(true) - .enumerable(false) - .configurable(true) - .build(), - self, - )?; - } - Opcode::SetPropertyGetterByName => { - let index = self.vm.read::(); - let object = self.vm.pop(); - let value = self.vm.pop(); - let object = object.to_object(self)?; - let name = self.vm.frame().code.names[index as usize]; - let name = self - .interner() - .resolve_expect(name.sym()) - .into_common::(false) - .into(); - let set = object - .__get_own_property__(&name, self)? - .as_ref() - .and_then(PropertyDescriptor::set) - .cloned(); - object.__define_own_property__( - name, - PropertyDescriptor::builder() - .maybe_get(Some(value)) - .maybe_set(set) - .enumerable(true) - .configurable(true) - .build(), - self, - )?; - } - Opcode::DefineClassGetterByName => { - let index = self.vm.read::(); - let object = self.vm.pop(); - let value = self.vm.pop(); - let object = object.to_object(self)?; - value - .as_object() - .expect("method must be function object") - .borrow_mut() - .as_function_mut() - .expect("method must be function object") - .set_home_object(object.clone()); - let name = self.vm.frame().code.names[index as usize]; - let name = self - .interner() - .resolve_expect(name.sym()) - .into_common::(false) - .into(); - let set = object - .__get_own_property__(&name, self)? - .as_ref() - .and_then(PropertyDescriptor::set) - .cloned(); - object.__define_own_property__( - name, - PropertyDescriptor::builder() - .maybe_get(Some(value)) - .maybe_set(set) - .enumerable(false) - .configurable(true) - .build(), - self, - )?; - } - Opcode::SetPropertyGetterByValue => { - let value = self.vm.pop(); - let key = self.vm.pop(); - let object = self.vm.pop(); - let object = object.to_object(self)?; - let name = key.to_property_key(self)?; - let set = object - .__get_own_property__(&name, self)? - .as_ref() - .and_then(PropertyDescriptor::set) - .cloned(); - object.__define_own_property__( - name, - PropertyDescriptor::builder() - .maybe_get(Some(value)) - .maybe_set(set) - .enumerable(true) - .configurable(true) - .build(), - self, - )?; - } - Opcode::DefineClassGetterByValue => { - let value = self.vm.pop(); - let key = self.vm.pop(); - let object = self.vm.pop(); - let object = object.to_object(self)?; - value - .as_object() - .expect("method must be function object") - .borrow_mut() - .as_function_mut() - .expect("method must be function object") - .set_home_object(object.clone()); - let name = key.to_property_key(self)?; - let set = object - .__get_own_property__(&name, self)? - .as_ref() - .and_then(PropertyDescriptor::set) - .cloned(); - object.__define_own_property__( - name, - PropertyDescriptor::builder() - .maybe_get(Some(value)) - .maybe_set(set) - .enumerable(false) - .configurable(true) - .build(), - self, - )?; - } - Opcode::SetPropertySetterByName => { - let index = self.vm.read::(); - let object = self.vm.pop(); - let value = self.vm.pop(); - let object = object.to_object(self)?; - let name = self.vm.frame().code.names[index as usize]; - let name = self - .interner() - .resolve_expect(name.sym()) - .into_common::(false) - .into(); - let get = object - .__get_own_property__(&name, self)? - .as_ref() - .and_then(PropertyDescriptor::get) - .cloned(); - object.__define_own_property__( - name, - PropertyDescriptor::builder() - .maybe_set(Some(value)) - .maybe_get(get) - .enumerable(true) - .configurable(true) - .build(), - self, - )?; - } - Opcode::DefineClassSetterByName => { - let index = self.vm.read::(); - let object = self.vm.pop(); - let value = self.vm.pop(); - let object = object.to_object(self)?; - value - .as_object() - .expect("method must be function object") - .borrow_mut() - .as_function_mut() - .expect("method must be function object") - .set_home_object(object.clone()); - let name = self.vm.frame().code.names[index as usize]; - let name = self - .interner() - .resolve_expect(name.sym()) - .into_common::(false) - .into(); - let get = object - .__get_own_property__(&name, self)? - .as_ref() - .and_then(PropertyDescriptor::get) - .cloned(); - object.__define_own_property__( - name, - PropertyDescriptor::builder() - .maybe_set(Some(value)) - .maybe_get(get) - .enumerable(false) - .configurable(true) - .build(), - self, - )?; - } - Opcode::SetPropertySetterByValue => { - let value = self.vm.pop(); - let key = self.vm.pop(); - let object = self.vm.pop(); - let object = object.to_object(self)?; - let name = key.to_property_key(self)?; - let get = object - .__get_own_property__(&name, self)? - .as_ref() - .and_then(PropertyDescriptor::get) - .cloned(); - object.__define_own_property__( - name, - PropertyDescriptor::builder() - .maybe_set(Some(value)) - .maybe_get(get) - .enumerable(true) - .configurable(true) - .build(), - self, - )?; - } - Opcode::DefineClassSetterByValue => { - let value = self.vm.pop(); - let key = self.vm.pop(); - let object = self.vm.pop(); - let object = object.to_object(self)?; - value - .as_object() - .expect("method must be function object") - .borrow_mut() - .as_function_mut() - .expect("method must be function object") - .set_home_object(object.clone()); - let name = key.to_property_key(self)?; - let get = object - .__get_own_property__(&name, self)? - .as_ref() - .and_then(PropertyDescriptor::get) - .cloned(); - object.__define_own_property__( - name, - PropertyDescriptor::builder() - .maybe_set(Some(value)) - .maybe_get(get) - .enumerable(false) - .configurable(true) - .build(), - self, - )?; - } - Opcode::AssignPrivateField => { - let index = self.vm.read::(); - let name = self.vm.frame().code.names[index as usize]; - let value = self.vm.pop(); - let object = self.vm.pop(); - if let Some(object) = object.as_object() { - let mut object_borrow_mut = object.borrow_mut(); - match object_borrow_mut.get_private_element(name.sym()) { - Some(PrivateElement::Field(_)) => { - object_borrow_mut - .set_private_element(name.sym(), PrivateElement::Field(value)); - } - Some(PrivateElement::Method(_)) => { - return Err(JsNativeError::typ() - .with_message("private method is not writable") - .into()); - } - Some(PrivateElement::Accessor { - setter: Some(setter), - .. - }) => { - let setter = setter.clone(); - drop(object_borrow_mut); - setter.call(&object.clone().into(), &[value], self)?; - } - None => { - return Err(JsNativeError::typ() - .with_message("private field not defined") - .into()); - } - _ => { - return Err(JsNativeError::typ() - .with_message("private field defined without a setter") - .into()); - } - } - } else { - return Err(JsNativeError::typ() - .with_message("cannot set private property on non-object") - .into()); - } - } - Opcode::SetPrivateField => { - let index = self.vm.read::(); - let name = self.vm.frame().code.names[index as usize]; - let value = self.vm.pop(); - let object = self.vm.pop(); - if let Some(object) = object.as_object() { - let mut object_borrow_mut = object.borrow_mut(); - if let Some(PrivateElement::Accessor { - getter: _, - setter: Some(setter), - }) = object_borrow_mut.get_private_element(name.sym()) - { - let setter = setter.clone(); - drop(object_borrow_mut); - setter.call(&object.clone().into(), &[value], self)?; - } else { - object_borrow_mut - .set_private_element(name.sym(), PrivateElement::Field(value)); - } - } else { - return Err(JsNativeError::typ() - .with_message("cannot set private property on non-object") - .into()); - } - } - Opcode::SetPrivateMethod => { - let index = self.vm.read::(); - let name = self.vm.frame().code.names[index as usize]; - let value = self.vm.pop(); - let value = value.as_callable().expect("method must be callable"); - let object = self.vm.pop(); - if let Some(object) = object.as_object() { - let mut object_borrow_mut = object.borrow_mut(); - object_borrow_mut - .set_private_element(name.sym(), PrivateElement::Method(value.clone())); - } else { - return Err(JsNativeError::typ() - .with_message("cannot set private setter on non-object") - .into()); - } - } - Opcode::SetPrivateSetter => { - let index = self.vm.read::(); - let name = self.vm.frame().code.names[index as usize]; - let value = self.vm.pop(); - let value = value.as_callable().expect("setter must be callable"); - let object = self.vm.pop(); - if let Some(object) = object.as_object() { - let mut object_borrow_mut = object.borrow_mut(); - object_borrow_mut.set_private_element_setter(name.sym(), value.clone()); - } else { - return Err(JsNativeError::typ() - .with_message("cannot set private setter on non-object") - .into()); - } - } - Opcode::SetPrivateGetter => { - let index = self.vm.read::(); - let name = self.vm.frame().code.names[index as usize]; - let value = self.vm.pop(); - let value = value.as_callable().expect("getter must be callable"); - let object = self.vm.pop(); - if let Some(object) = object.as_object() { - let mut object_borrow_mut = object.borrow_mut(); - object_borrow_mut.set_private_element_getter(name.sym(), value.clone()); - } else { - return Err(JsNativeError::typ() - .with_message("cannot set private getter on non-object") - .into()); - } - } - Opcode::GetPrivateField => { - let index = self.vm.read::(); - let name = self.vm.frame().code.names[index as usize]; - let value = self.vm.pop(); - if let Some(object) = value.as_object() { - let object_borrow_mut = object.borrow(); - if let Some(element) = object_borrow_mut.get_private_element(name.sym()) { - match element { - PrivateElement::Field(value) => self.vm.push(value), - PrivateElement::Method(method) => self.vm.push(method.clone()), - PrivateElement::Accessor { - getter: Some(getter), - setter: _, - } => { - let value = getter.call(&value, &[], self)?; - self.vm.push(value); - } - PrivateElement::Accessor { .. } => { - return Err(JsNativeError::typ() - .with_message("private property was defined without a getter") - .into()); - } - } - } else { - return Err(JsNativeError::typ() - .with_message("private property does not exist") - .into()); - } - } else { - return Err(JsNativeError::typ() - .with_message("cannot read private property from non-object") - .into()); - } - } - Opcode::PushClassField => { - let field_function_value = self.vm.pop(); - let field_name_value = self.vm.pop(); - let class_value = self.vm.pop(); - - let field_name_key = field_name_value.to_property_key(self)?; - let field_function_object = field_function_value - .as_object() - .expect("field value must be function object"); - let mut field_function_object_borrow = field_function_object.borrow_mut(); - let field_function = field_function_object_borrow - .as_function_mut() - .expect("field value must be function object"); - let class_object = class_value - .as_object() - .expect("class must be function object"); - field_function.set_home_object(class_object.clone()); - class_object - .borrow_mut() - .as_function_mut() - .expect("class must be function object") - .push_field( - field_name_key, - JsFunction::from_object_unchecked(field_function_object.clone()), - ); - } - Opcode::PushClassFieldPrivate => { - let index = self.vm.read::(); - let name = self.vm.frame().code.names[index as usize]; - let field_function_value = self.vm.pop(); - let class_value = self.vm.pop(); - - let field_function_object = field_function_value - .as_object() - .expect("field value must be function object"); - let mut field_function_object_borrow = field_function_object.borrow_mut(); - let field_function = field_function_object_borrow - .as_function_mut() - .expect("field value must be function object"); - let class_object = class_value - .as_object() - .expect("class must be function object"); - field_function.set_home_object(class_object.clone()); - class_object - .borrow_mut() - .as_function_mut() - .expect("class must be function object") - .push_field_private( - name.sym(), - JsFunction::from_object_unchecked(field_function_object.clone()), - ); - } - Opcode::PushClassPrivateGetter => { - let index = self.vm.read::(); - let name = self.vm.frame().code.names[index as usize]; - let getter = self.vm.pop(); - let getter_object = getter.as_callable().expect("getter must be callable"); - let class = self.vm.pop(); - class - .as_object() - .expect("class must be function object") - .borrow_mut() - .as_function_mut() - .expect("class must be function object") - .push_private_method( - name.sym(), - PrivateElement::Accessor { - getter: Some(getter_object.clone()), - setter: None, - }, - ); - } - Opcode::PushClassPrivateSetter => { - let index = self.vm.read::(); - let name = self.vm.frame().code.names[index as usize]; - let setter = self.vm.pop(); - let setter_object = setter.as_callable().expect("getter must be callable"); - let class = self.vm.pop(); - class - .as_object() - .expect("class must be function object") - .borrow_mut() - .as_function_mut() - .expect("class must be function object") - .push_private_method( - name.sym(), - PrivateElement::Accessor { - getter: None, - setter: Some(setter_object.clone()), - }, - ); - } - Opcode::PushClassPrivateMethod => { - let index = self.vm.read::(); - let name = self.vm.frame().code.names[index as usize]; - let method = self.vm.pop(); - let method_object = method.as_callable().expect("method must be callable"); - let class = self.vm.pop(); - class - .as_object() - .expect("class must be function object") - .borrow_mut() - .as_function_mut() - .expect("class must be function object") - .push_private_method(name.sym(), PrivateElement::Method(method_object.clone())); - } - Opcode::DeletePropertyByName => { - let index = self.vm.read::(); - let key = self.vm.frame().code.names[index as usize]; - let key = self - .interner() - .resolve_expect(key.sym()) - .into_common::(false) - .into(); - let object = self.vm.pop(); - let result = object.to_object(self)?.__delete__(&key, self)?; - if !result && self.vm.frame().code.strict { - return Err(JsNativeError::typ() - .with_message("Cannot delete property") - .into()); - } - self.vm.push(result); - } - Opcode::DeletePropertyByValue => { - let object = self.vm.pop(); - let key = self.vm.pop(); - let result = object - .to_object(self)? - .__delete__(&key.to_property_key(self)?, self)?; - if !result && self.vm.frame().code.strict { - return Err(JsNativeError::typ() - .with_message("Cannot delete property") - .into()); - } - self.vm.push(result); - } - Opcode::CopyDataProperties => { - let excluded_key_count = self.vm.read::(); - let excluded_key_count_computed = self.vm.read::(); - let mut excluded_keys = Vec::with_capacity(excluded_key_count as usize); - for _ in 0..excluded_key_count { - let key = self.vm.pop(); - excluded_keys - .push(key.to_property_key(self).expect("key must be property key")); - } - let value = self.vm.pop(); - let object = value.as_object().expect("not an object"); - let source = self.vm.pop(); - for _ in 0..excluded_key_count_computed { - let key = self.vm.pop(); - excluded_keys - .push(key.to_property_key(self).expect("key must be property key")); - } - object.copy_data_properties(&source, excluded_keys, self)?; - self.vm.push(value); - } - Opcode::ToPropertyKey => { - let value = self.vm.pop(); - let key = value.to_property_key(self)?; - self.vm.push(key); - } - Opcode::Throw => { - let value = self.vm.pop(); - return Err(JsError::from_opaque(value)); - } - Opcode::TryStart => { - let next = self.vm.read::(); - let finally = self.vm.read::(); - let finally = if finally == 0 { None } else { Some(finally) }; - self.vm - .frame_mut() - .catch - .push(CatchAddresses { next, finally }); - self.vm.frame_mut().finally_jump.push(None); - self.vm.frame_mut().finally_return = FinallyReturn::None; - self.vm.frame_mut().try_env_stack.push(TryStackEntry { - num_env: 0, - num_loop_stack_entries: 0, - }); - } - Opcode::TryEnd | Opcode::CatchEnd => { - self.vm.frame_mut().catch.pop(); - let try_stack_entry = self.vm.frame_mut().try_env_stack.pop().expect("must exist"); - for _ in 0..try_stack_entry.num_env { - self.realm.environments.pop(); - } - let mut num_env = try_stack_entry.num_env; - for _ in 0..try_stack_entry.num_loop_stack_entries { - num_env -= self - .vm - .frame_mut() - .loop_env_stack - .pop() - .expect("must exist"); - } - *self - .vm - .frame_mut() - .loop_env_stack - .last_mut() - .expect("must exist") -= num_env; - self.vm.frame_mut().finally_return = FinallyReturn::None; - } - Opcode::CatchStart => { - let finally = self.vm.read::(); - self.vm.frame_mut().catch.push(CatchAddresses { - next: finally, - finally: Some(finally), - }); - self.vm.frame_mut().try_env_stack.push(TryStackEntry { - num_env: 0, - num_loop_stack_entries: 0, - }); - self.vm.frame_mut().thrown = false; - } - Opcode::CatchEnd2 => { - let frame = self.vm.frame_mut(); - if frame.finally_return == FinallyReturn::Err { - frame.finally_return = FinallyReturn::None; - } - } - Opcode::FinallyStart => { - *self - .vm - .frame_mut() - .finally_jump - .last_mut() - .expect("finally jump must exist here") = None; - } - Opcode::FinallyEnd => { - let address = self - .vm - .frame_mut() - .finally_jump - .pop() - .expect("finally jump must exist here"); - match self.vm.frame_mut().finally_return { - FinallyReturn::None => { - if let Some(address) = address { - self.vm.frame_mut().pc = address as usize; - } - } - FinallyReturn::Ok => { - return Ok(ShouldExit::True); - } - FinallyReturn::Err => { - return Err(JsError::from_opaque(self.vm.pop())); - } - } - } - Opcode::FinallySetJump => { - let address = self.vm.read::(); - *self - .vm - .frame_mut() - .finally_jump - .last_mut() - .expect("finally jump must exist here") = Some(address); - } - Opcode::This => { - let env = self.realm.environments.get_this_environment(); - match env { - EnvironmentSlots::Function(env) => { - self.vm.push(env.borrow().get_this_binding()?); - } - EnvironmentSlots::Global => { - let this = self.realm.global_object(); - self.vm.push(this.clone()); - } - } - } - Opcode::Super => { - let home = { - let env = self - .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"); - - function.get_home_object().or(this.as_object()).cloned() - }; - - if let Some(home) = home { - if let Some(proto) = home.__get_prototype_of__(self)? { - self.vm.push(JsValue::from(proto)); - } else { - self.vm.push(JsValue::Null); - } - } else { - self.vm.push(JsValue::Null); - }; - } - Opcode::SuperCall => { - let argument_count = self.vm.read::(); - let mut arguments = Vec::with_capacity(argument_count as usize); - for _ in 0..argument_count { - arguments.push(self.vm.pop()); - } - arguments.reverse(); - - let (new_target, active_function) = { - let this_env = self - .realm - .environments - .get_this_environment() - .as_function_slots() - .expect("super call must be in function environment"); - let this_env_borrow = this_env.borrow(); - let new_target = this_env_borrow - .new_target() - .expect("must have new target") - .clone(); - let active_function = this_env.borrow().function_object().clone(); - (new_target, active_function) - }; - let super_constructor = active_function - .__get_prototype_of__(self) - .expect("function object must have prototype") - .expect("function object must have prototype"); - - if !super_constructor.is_constructor() { - return Err(JsNativeError::typ() - .with_message("super constructor object must be constructor") - .into()); - } - - let result = super_constructor.__construct__(&arguments, &new_target, self)?; - - initialize_instance_elements(&result, &active_function, self)?; - - let this_env = self - .realm - .environments - .get_this_environment() - .as_function_slots() - .expect("super call must be in function environment"); - - if !this_env.borrow_mut().bind_this_value(&result) { - return Err(JsNativeError::reference() - .with_message("this already initialized") - .into()); - } - self.vm.push(result); - } - Opcode::SuperCallSpread => { - // Get the arguments that are stored as an array object on the stack. - let arguments_array = self.vm.pop(); - let arguments_array_object = arguments_array - .as_object() - .expect("arguments array in call spread function must be an object"); - let arguments = arguments_array_object - .borrow() - .properties() - .dense_indexed_properties() - .expect("arguments array in call spread function must be dense") - .clone(); - - let (new_target, active_function) = { - let this_env = self - .realm - .environments - .get_this_environment() - .as_function_slots() - .expect("super call must be in function environment"); - let this_env_borrow = this_env.borrow(); - let new_target = this_env_borrow - .new_target() - .expect("must have new target") - .clone(); - let active_function = this_env.borrow().function_object().clone(); - (new_target, active_function) - }; - let super_constructor = active_function - .__get_prototype_of__(self) - .expect("function object must have prototype") - .expect("function object must have prototype"); - - if !super_constructor.is_constructor() { - return Err(JsNativeError::typ() - .with_message("super constructor object must be constructor") - .into()); - } - - let result = super_constructor.__construct__(&arguments, &new_target, self)?; - - initialize_instance_elements(&result, &active_function, self)?; - - let this_env = self - .realm - .environments - .get_this_environment() - .as_function_slots() - .expect("super call must be in function environment"); - - if !this_env.borrow_mut().bind_this_value(&result) { - return Err(JsNativeError::reference() - .with_message("this already initialized") - .into()); - } - self.vm.push(result); - } - Opcode::SuperCallDerived => { - let argument_count = self.vm.frame().arg_count; - let mut arguments = Vec::with_capacity(argument_count); - for _ in 0..argument_count { - arguments.push(self.vm.pop()); - } - arguments.reverse(); - - let (new_target, active_function) = { - let this_env = self - .realm - .environments - .get_this_environment() - .as_function_slots() - .expect("super call must be in function environment"); - let this_env_borrow = this_env.borrow(); - let new_target = this_env_borrow - .new_target() - .expect("must have new target") - .clone(); - let active_function = this_env.borrow().function_object().clone(); - (new_target, active_function) - }; - let super_constructor = active_function - .__get_prototype_of__(self) - .expect("function object must have prototype") - .expect("function object must have prototype"); - - if !super_constructor.is_constructor() { - return Err(JsNativeError::typ() - .with_message("super constructor object must be constructor") - .into()); - } - - let result = super_constructor.__construct__(&arguments, &new_target, self)?; - - initialize_instance_elements(&result, &active_function, self)?; - - let this_env = self - .realm - .environments - .get_this_environment() - .as_function_slots() - .expect("super call must be in function environment"); - if !this_env.borrow_mut().bind_this_value(&result) { - return Err(JsNativeError::reference() - .with_message("this already initialized") - .into()); - } - - self.vm.push(result); - } - Opcode::Case => { - let address = self.vm.read::(); - let cond = self.vm.pop(); - let value = self.vm.pop(); - - if value.strict_equals(&cond) { - self.vm.frame_mut().pc = address as usize; - } else { - self.vm.push(value); - } - } - Opcode::Default => { - let exit = self.vm.read::(); - let _val = self.vm.pop(); - self.vm.frame_mut().pc = exit as usize; - } - Opcode::GetFunction => { - let index = self.vm.read::(); - let code = self.vm.frame().code.functions[index as usize].clone(); - let function = create_function_object(code, false, None, self); - self.vm.push(function); - } - Opcode::GetFunctionAsync => { - let index = self.vm.read::(); - let code = self.vm.frame().code.functions[index as usize].clone(); - let function = create_function_object(code, true, None, self); - self.vm.push(function); - } - Opcode::GetGenerator => { - let index = self.vm.read::(); - let code = self.vm.frame().code.functions[index as usize].clone(); - let function = create_generator_function_object(code, false, self); - self.vm.push(function); - } - Opcode::GetGeneratorAsync => { - let index = self.vm.read::(); - let code = self.vm.frame().code.functions[index as usize].clone(); - let function = create_generator_function_object(code, true, self); - self.vm.push(function); - } - Opcode::CallEval => { - if self.vm.stack_size_limit <= self.vm.stack.len() { - return Err(JsNativeError::range() - .with_message("Maximum call stack size exceeded") - .into()); - } - let argument_count = self.vm.read::(); - let mut arguments = Vec::with_capacity(argument_count as usize); - for _ in 0..argument_count { - arguments.push(self.vm.pop()); - } - arguments.reverse(); - - let func = self.vm.pop(); - let this = self.vm.pop(); - - let object = match func { - JsValue::Object(ref object) if object.is_callable() => object.clone(), - _ => { - 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. - let eval = matches!(object.borrow().as_function(), Some(Function::Native { .. })); - - let strict = self.vm.frame().code.strict; - - if eval { - if let Some(x) = arguments.get(0) { - let result = - crate::builtins::eval::Eval::perform_eval(x, true, strict, self)?; - self.vm.push(result); - } else { - self.vm.push(JsValue::Undefined); - } - } else { - let result = object.__call__(&this, &arguments, self)?; - self.vm.push(result); - } - } - Opcode::CallEvalSpread => { - if self.vm.stack_size_limit <= self.vm.stack.len() { - 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 = self.vm.pop(); - let arguments_array_object = arguments_array - .as_object() - .expect("arguments array in call spread function must be an object"); - let arguments = arguments_array_object - .borrow() - .properties() - .dense_indexed_properties() - .expect("arguments array in call spread function must be dense") - .clone(); - - let func = self.vm.pop(); - let this = self.vm.pop(); - - let object = match func { - JsValue::Object(ref object) if object.is_callable() => object.clone(), - _ => { - 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. - let eval = matches!(object.borrow().as_function(), Some(Function::Native { .. })); - - let strict = self.vm.frame().code.strict; - - if eval { - if let Some(x) = arguments.get(0) { - let result = - crate::builtins::eval::Eval::perform_eval(x, true, strict, self)?; - self.vm.push(result); - } else { - self.vm.push(JsValue::Undefined); - } - } else { - let result = object.__call__(&this, &arguments, self)?; - self.vm.push(result); - } - } - Opcode::Call => { - if self.vm.stack_size_limit <= self.vm.stack.len() { - return Err(JsNativeError::range() - .with_message("Maximum call stack size exceeded") - .into()); - } - let argument_count = self.vm.read::(); - let mut arguments = Vec::with_capacity(argument_count as usize); - for _ in 0..argument_count { - arguments.push(self.vm.pop()); - } - arguments.reverse(); - - let func = self.vm.pop(); - let this = self.vm.pop(); - - let object = match func { - JsValue::Object(ref object) if object.is_callable() => object.clone(), - _ => { - return Err(JsNativeError::typ() - .with_message("not a callable function") - .into()) - } - }; - - let result = object.__call__(&this, &arguments, self)?; - - self.vm.push(result); - } - Opcode::CallSpread => { - if self.vm.stack_size_limit <= self.vm.stack.len() { - 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 = self.vm.pop(); - let arguments_array_object = arguments_array - .as_object() - .expect("arguments array in call spread function must be an object"); - let arguments = arguments_array_object - .borrow() - .properties() - .dense_indexed_properties() - .expect("arguments array in call spread function must be dense") - .clone(); - - let func = self.vm.pop(); - let this = self.vm.pop(); - - let object = match func { - JsValue::Object(ref object) if object.is_callable() => object.clone(), - _ => { - return Err(JsNativeError::typ() - .with_message("not a callable function") - .into()) - } - }; - - let result = object.__call__(&this, &arguments, self)?; - - self.vm.push(result); - } - Opcode::New => { - if self.vm.stack_size_limit <= self.vm.stack.len() { - return Err(JsNativeError::range() - .with_message("Maximum call stack size exceeded") - .into()); - } - let argument_count = self.vm.read::(); - let mut arguments = Vec::with_capacity(argument_count as usize); - for _ in 0..argument_count { - arguments.push(self.vm.pop()); - } - arguments.reverse(); - let func = self.vm.pop(); - - let result = func - .as_constructor() - .ok_or_else(|| { - JsNativeError::typ() - .with_message("not a constructor") - .into() - }) - .and_then(|cons| cons.__construct__(&arguments, cons, self))?; - - self.vm.push(result); - } - Opcode::NewSpread => { - if self.vm.stack_size_limit <= self.vm.stack.len() { - 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 = self.vm.pop(); - let arguments_array_object = arguments_array - .as_object() - .expect("arguments array in call spread function must be an object"); - let arguments = arguments_array_object - .borrow() - .properties() - .dense_indexed_properties() - .expect("arguments array in call spread function must be dense") - .clone(); - - let func = self.vm.pop(); - - let result = func - .as_constructor() - .ok_or_else(|| { - JsNativeError::typ() - .with_message("not a constructor") - .into() - }) - .and_then(|cons| cons.__construct__(&arguments, cons, self))?; - self.vm.push(result); - } - Opcode::Return => { - if let Some(finally_address) = self.vm.frame().catch.last().and_then(|c| c.finally) - { - let frame = self.vm.frame_mut(); - frame.pc = finally_address as usize; - frame.finally_return = FinallyReturn::Ok; - frame.catch.pop(); - let try_stack_entry = - self.vm.frame_mut().try_env_stack.pop().expect("must exist"); - for _ in 0..try_stack_entry.num_env { - self.realm.environments.pop(); - } - let mut num_env = try_stack_entry.num_env; - for _ in 0..try_stack_entry.num_loop_stack_entries { - num_env -= self - .vm - .frame_mut() - .loop_env_stack - .pop() - .expect("must exist"); - } - *self - .vm - .frame_mut() - .loop_env_stack - .last_mut() - .expect("must exist") -= num_env; - } else { - return Ok(ShouldExit::True); - } - } - Opcode::PushDeclarativeEnvironment => { - let num_bindings = self.vm.read::(); - let compile_environments_index = self.vm.read::(); - let compile_environment = self.vm.frame().code.compile_environments - [compile_environments_index as usize] - .clone(); - self.realm - .environments - .push_declarative(num_bindings as usize, compile_environment); - self.vm.frame_mut().loop_env_stack_inc(); - self.vm.frame_mut().try_env_stack_inc(); - } - Opcode::PushFunctionEnvironment => { - let num_bindings = self.vm.read::(); - let compile_environments_index = self.vm.read::(); - let compile_environment = self.vm.frame().code.compile_environments - [compile_environments_index as usize] - .clone(); - self.realm - .environments - .push_function_inherit(num_bindings as usize, compile_environment); - } - Opcode::PopEnvironment => { - self.realm.environments.pop(); - self.vm.frame_mut().loop_env_stack_dec(); - self.vm.frame_mut().try_env_stack_dec(); - } - Opcode::LoopStart => { - self.vm.frame_mut().loop_env_stack.push(0); - self.vm.frame_mut().try_env_stack_loop_inc(); - } - Opcode::LoopContinue => { - let env_num = self - .vm - .frame_mut() - .loop_env_stack - .last_mut() - .expect("loop env stack entry must exist"); - let env_num_copy = *env_num; - *env_num = 0; - for _ in 0..env_num_copy { - self.realm.environments.pop(); - } - } - Opcode::LoopEnd => { - let env_num = self - .vm - .frame_mut() - .loop_env_stack - .pop() - .expect("loop env stack entry must exist"); - for _ in 0..env_num { - self.realm.environments.pop(); - self.vm.frame_mut().try_env_stack_dec(); - } - self.vm.frame_mut().try_env_stack_loop_dec(); - } - Opcode::ForInLoopInitIterator => { - let address = self.vm.read::(); - - let object = self.vm.pop(); - if object.is_null_or_undefined() { - self.vm.frame_mut().pc = address as usize; - return Ok(ShouldExit::False); - } - - let object = object.to_object(self)?; - let iterator = ForInIterator::create_for_in_iterator(JsValue::new(object), self); - let next_method = iterator - .get_property("next") - .as_ref() - .map(PropertyDescriptor::expect_value) - .cloned() - .ok_or_else(|| { - JsNativeError::typ().with_message("Could not find property `next`") - })?; - - self.vm.push(iterator); - self.vm.push(next_method); - self.vm.push(false); - } - Opcode::InitIterator => { - let object = self.vm.pop(); - let iterator = object.get_iterator(self, None, None)?; - self.vm.push(iterator.iterator().clone()); - self.vm.push(iterator.next_method().clone()); - self.vm.push(iterator.done()); - } - Opcode::InitIteratorAsync => { - let object = self.vm.pop(); - let iterator = object.get_iterator(self, Some(IteratorHint::Async), None)?; - self.vm.push(iterator.iterator().clone()); - self.vm.push(iterator.next_method().clone()); - self.vm.push(iterator.done()); - } - Opcode::IteratorNext => { - let done = self - .vm - .pop() - .as_boolean() - .expect("iterator [[Done]] was not a boolean"); - let next_method = self.vm.pop(); - let iterator = self.vm.pop(); - let iterator = iterator.as_object().expect("iterator was not an object"); - - let iterator_record = - IteratorRecord::new(iterator.clone(), next_method.clone(), done); - let next = iterator_record.step(self)?; - - self.vm.push(iterator.clone()); - self.vm.push(next_method); - if let Some(next) = next { - let value = next.value(self)?; - self.vm.push(false); - self.vm.push(value); - } else { - self.vm.push(true); - self.vm.push(JsValue::undefined()); - } - } - Opcode::IteratorClose => { - let done = self - .vm - .pop() - .as_boolean() - .expect("iterator [[Done]] was not a boolean"); - let next_method = self.vm.pop(); - let iterator = self.vm.pop(); - let iterator = iterator.as_object().expect("iterator was not an object"); - if !done { - let iterator_record = IteratorRecord::new(iterator.clone(), next_method, done); - iterator_record.close(Ok(JsValue::Null), self)?; - } - } - Opcode::IteratorToArray => { - let done = self - .vm - .pop() - .as_boolean() - .expect("iterator [[Done]] was not a boolean"); - let next_method = self.vm.pop(); - let iterator = self.vm.pop(); - let iterator = iterator.as_object().expect("iterator was not an object"); - - let iterator_record = - IteratorRecord::new(iterator.clone(), next_method.clone(), done); - let mut values = Vec::new(); - - while let Some(result) = iterator_record.step(self)? { - values.push(result.value(self)?); - } - - let array = Array::create_array_from_list(values, self); - - self.vm.push(iterator.clone()); - self.vm.push(next_method); - self.vm.push(true); - self.vm.push(array); - } - Opcode::ForInLoopNext => { - let address = self.vm.read::(); - - let done = self - .vm - .pop() - .as_boolean() - .expect("iterator [[Done]] was not a boolean"); - let next_method = self.vm.pop(); - let iterator = self.vm.pop(); - let iterator = iterator.as_object().expect("iterator was not an object"); - - let iterator_record = - IteratorRecord::new(iterator.clone(), next_method.clone(), done); - if let Some(next) = iterator_record.step(self)? { - self.vm.push(iterator.clone()); - self.vm.push(next_method); - self.vm.push(done); - let value = next.value(self)?; - self.vm.push(value); - } else { - self.vm.frame_mut().pc = address as usize; - self.vm.frame_mut().loop_env_stack_dec(); - self.vm.frame_mut().try_env_stack_dec(); - self.realm.environments.pop(); - self.vm.push(iterator.clone()); - self.vm.push(next_method); - self.vm.push(done); - } - } - Opcode::ForAwaitOfLoopIterate => { - let _done = self - .vm - .pop() - .as_boolean() - .expect("iterator [[Done]] was not a boolean"); - let next_method = self.vm.pop(); - let next_method_object = if let Some(object) = next_method.as_callable() { - object - } else { - return Err(JsNativeError::typ() - .with_message("iterable next method not a function") - .into()); - }; - let iterator = self.vm.pop(); - let next_result = next_method_object.call(&iterator, &[], self)?; - self.vm.push(iterator); - self.vm.push(next_method); - self.vm.push(next_result); - } - Opcode::ForAwaitOfLoopNext => { - let address = self.vm.read::(); - - let next_result = self.vm.pop(); - let next_result = if let Some(next_result) = next_result.as_object() { - IteratorResult::new(next_result.clone()) - } else { - return Err(JsNativeError::typ() - .with_message("next value should be an object") - .into()); - }; - - if next_result.complete(self)? { - self.vm.frame_mut().pc = address as usize; - self.vm.frame_mut().loop_env_stack_dec(); - self.vm.frame_mut().try_env_stack_dec(); - self.realm.environments.pop(); - self.vm.push(true); - } else { - self.vm.push(false); - let value = next_result.value(self)?; - self.vm.push(value); - } - } - Opcode::ConcatToString => { - let value_count = self.vm.read::(); - let mut strings = Vec::with_capacity(value_count as usize); - for _ in 0..value_count { - strings.push(self.vm.pop().to_string(self)?); - } - strings.reverse(); - let s = JsString::concat_array( - &strings - .iter() - .map(JsString::as_slice) - .collect::>(), - ); - self.vm.push(s); - } - Opcode::RequireObjectCoercible => { - let value = self.vm.pop(); - let value = value.require_object_coercible()?; - self.vm.push(value); - } - Opcode::ValueNotNullOrUndefined => { - let value = self.vm.pop(); - if value.is_null() { - return Err(JsNativeError::typ() - .with_message("Cannot destructure 'null' value") - .into()); - } - if value.is_undefined() { - return Err(JsNativeError::typ() - .with_message("Cannot destructure 'undefined' value") - .into()); - } - self.vm.push(value); - } - Opcode::RestParameterInit => { - let arg_count = self.vm.frame().arg_count; - let param_count = self.vm.frame().param_count; - if arg_count >= param_count { - let rest_count = arg_count - param_count + 1; - let mut args = Vec::with_capacity(rest_count); - for _ in 0..rest_count { - args.push(self.vm.pop()); - } - let array: _ = Array::create_array_from_list(args, self); - - self.vm.push(array); - } else { - self.vm.pop(); - - let array = Array::array_create(0, None, self) - .expect("could not create an empty array"); - self.vm.push(array); - } - } - Opcode::RestParameterPop => { - let arg_count = self.vm.frame().arg_count; - let param_count = self.vm.frame().param_count; - if arg_count > param_count { - for _ in 0..(arg_count - param_count) { - self.vm.pop(); - } - } - } - Opcode::PopOnReturnAdd => { - self.vm.frame_mut().pop_on_return += 1; - } - Opcode::PopOnReturnSub => { - self.vm.frame_mut().pop_on_return -= 1; - } - Opcode::Yield => return Ok(ShouldExit::Yield), - Opcode::GeneratorNext => match self.vm.frame().generator_resume_kind { - GeneratorResumeKind::Normal => return Ok(ShouldExit::False), - GeneratorResumeKind::Throw => { - let received = self.vm.pop(); - return Err(JsError::from_opaque(received)); - } - GeneratorResumeKind::Return => { - let mut finally_left = false; - - while let Some(catch_addresses) = self.vm.frame().catch.last() { - if let Some(finally_address) = catch_addresses.finally { - let frame = self.vm.frame_mut(); - frame.pc = finally_address as usize; - frame.finally_return = FinallyReturn::Ok; - frame.catch.pop(); - finally_left = true; - break; - } - self.vm.frame_mut().catch.pop(); - } - - if finally_left { - return Ok(ShouldExit::False); - } - return Ok(ShouldExit::True); - } - }, - Opcode::AsyncGeneratorNext => { - let value = self.vm.pop(); - - if self.vm.frame().generator_resume_kind == GeneratorResumeKind::Throw { - return Err(JsError::from_opaque(value)); - } - - let completion = Ok(value); - let generator_object = self - .vm - .frame() - .async_generator - .as_ref() - .expect("must be in generator context here") - .clone(); - let next = generator_object - .borrow_mut() - .as_async_generator_mut() - .expect("must be async generator object") - .queue - .pop_front() - .expect("must have item in queue"); - AsyncGenerator::complete_step(&next, completion, false, self); - - let mut generator_object_mut = generator_object.borrow_mut(); - let gen = generator_object_mut - .as_async_generator_mut() - .expect("must be async generator object"); - - if let Some(next) = gen.queue.front() { - let (completion, r#return) = &next.completion; - if *r#return { - let value = match completion { - Ok(value) => value.clone(), - Err(e) => e.clone().to_opaque(self), - }; - self.vm.push(value); - self.vm.push(true); - } else { - self.vm.push(completion.clone()?); - self.vm.push(false); - } - - self.vm.push(false); - } else { - gen.state = AsyncGeneratorState::SuspendedYield; - self.vm.push(true); - self.vm.push(true); - } - } - Opcode::GeneratorNextDelegate => { - let done_address = self.vm.read::(); - let received = self.vm.pop(); - let done = self - .vm - .pop() - .as_boolean() - .expect("iterator [[Done]] was not a boolean"); - let next_method = self.vm.pop(); - let iterator = self.vm.pop(); - let iterator = iterator.as_object().expect("iterator was not an object"); - - match self.vm.frame().generator_resume_kind { - GeneratorResumeKind::Normal => { - let result = - self.call(&next_method, &iterator.clone().into(), &[received])?; - let result_object = result.as_object().ok_or_else(|| { - JsNativeError::typ() - .with_message("generator next method returned non-object") - })?; - let done = result_object.get("done", self)?.to_boolean(); - if done { - self.vm.frame_mut().pc = done_address as usize; - let value = result_object.get("value", self)?; - self.vm.push(value); - return Ok(ShouldExit::False); - } - let value = result_object.get("value", self)?; - self.vm.push(iterator.clone()); - self.vm.push(next_method.clone()); - self.vm.push(done); - self.vm.push(value); - return Ok(ShouldExit::Yield); - } - GeneratorResumeKind::Throw => { - let throw = iterator.get_method("throw", self)?; - if let Some(throw) = throw { - let result = throw.call(&iterator.clone().into(), &[received], self)?; - let result_object = result.as_object().ok_or_else(|| { - JsNativeError::typ() - .with_message("generator throw method returned non-object") - })?; - let done = result_object.get("done", self)?.to_boolean(); - if done { - self.vm.frame_mut().pc = done_address as usize; - let value = result_object.get("value", self)?; - self.vm.push(value); - return Ok(ShouldExit::False); - } - let value = result_object.get("value", self)?; - self.vm.push(iterator.clone()); - self.vm.push(next_method.clone()); - self.vm.push(done); - self.vm.push(value); - return Ok(ShouldExit::Yield); - } - self.vm.frame_mut().pc = done_address as usize; - let iterator_record = - IteratorRecord::new(iterator.clone(), next_method, done); - iterator_record.close(Ok(JsValue::Undefined), self)?; - return Err(JsNativeError::typ() - .with_message("iterator does not have a throw method") - .into()); - } - GeneratorResumeKind::Return => { - let r#return = iterator.get_method("return", self)?; - if let Some(r#return) = r#return { - let result = - r#return.call(&iterator.clone().into(), &[received], self)?; - let result_object = result.as_object().ok_or_else(|| { - JsNativeError::typ() - .with_message("generator return method returned non-object") - })?; - let done = result_object.get("done", self)?.to_boolean(); - if done { - self.vm.frame_mut().pc = done_address as usize; - let value = result_object.get("value", self)?; - self.vm.push(value); - return Ok(ShouldExit::True); - } - let value = result_object.get("value", self)?; - self.vm.push(iterator.clone()); - self.vm.push(next_method.clone()); - self.vm.push(done); - self.vm.push(value); - return Ok(ShouldExit::Yield); - } - self.vm.frame_mut().pc = done_address as usize; - self.vm.push(received); - return Ok(ShouldExit::True); - } - } - } - Opcode::Await => { - let value = self.vm.pop(); - - // 2. Let promise be ? PromiseResolve(%Promise%, value). - let promise = Promise::promise_resolve( - self.intrinsics().constructors().promise().constructor(), - value, - self, - )?; - - // 3. Let fulfilledClosure be a new Abstract Closure with parameters (value) that captures asyncContext and performs the following steps when called: - // 4. Let onFulfilled be CreateBuiltinFunction(fulfilledClosure, 1, "", « »). - let on_fulfilled = FunctionBuilder::closure_with_captures( - self, - |_this, args, (environment, stack, frame), context| { - // a. Let prevContext be the running execution context. - // b. Suspend prevContext. - // c. Push asyncContext onto the execution context stack; asyncContext is now the running execution context. - // d. Resume the suspended evaluation of asyncContext using NormalCompletion(value) as the result of the operation that suspended it. - // e. Assert: When we reach this step, asyncContext has already been removed from the execution context stack and prevContext is the currently running execution context. - // f. Return undefined. - - std::mem::swap(&mut context.realm.environments, environment); - std::mem::swap(&mut context.vm.stack, stack); - context.vm.push_frame(frame.clone()); - - context.vm.frame_mut().generator_resume_kind = GeneratorResumeKind::Normal; - context.vm.push(args.get_or_undefined(0)); - context.run()?; - - *frame = context - .vm - .pop_frame() - .expect("generator call frame must exist"); - std::mem::swap(&mut context.realm.environments, environment); - std::mem::swap(&mut context.vm.stack, stack); - - Ok(JsValue::undefined()) - }, - ( - self.realm.environments.clone(), - self.vm.stack.clone(), - self.vm.frame().clone(), - ), - ) - .name("") - .length(1) - .build(); - - // 5. Let rejectedClosure be a new Abstract Closure with parameters (reason) that captures asyncContext and performs the following steps when called: - // 6. Let onRejected be CreateBuiltinFunction(rejectedClosure, 1, "", « »). - let on_rejected = FunctionBuilder::closure_with_captures( - self, - |_this, args, (environment, stack, frame), context| { - // a. Let prevContext be the running execution context. - // b. Suspend prevContext. - // c. Push asyncContext onto the execution context stack; asyncContext is now the running execution context. - // d. Resume the suspended evaluation of asyncContext using ThrowCompletion(reason) as the result of the operation that suspended it. - // e. Assert: When we reach this step, asyncContext has already been removed from the execution context stack and prevContext is the currently running execution context. - // f. Return undefined. - - std::mem::swap(&mut context.realm.environments, environment); - std::mem::swap(&mut context.vm.stack, stack); - context.vm.push_frame(frame.clone()); - - context.vm.frame_mut().generator_resume_kind = GeneratorResumeKind::Throw; - context.vm.push(args.get_or_undefined(0)); - context.run()?; - - *frame = context - .vm - .pop_frame() - .expect("generator call frame must exist"); - std::mem::swap(&mut context.realm.environments, environment); - std::mem::swap(&mut context.vm.stack, stack); - - Ok(JsValue::undefined()) - }, - ( - self.realm.environments.clone(), - self.vm.stack.clone(), - self.vm.frame().clone(), - ), - ) - .name("") - .length(1) - .build(); - - // 7. Perform PerformPromiseThen(promise, onFulfilled, onRejected). - promise - .as_object() - .expect("promise was not an object") - .borrow_mut() - .as_promise_mut() - .expect("promise was not a promise") - .perform_promise_then(&on_fulfilled.into(), &on_rejected.into(), None, self); - - self.vm.push(JsValue::undefined()); - return Ok(ShouldExit::Await); - } - Opcode::PushNewTarget => { - if let Some(env) = self - .realm - .environments - .get_this_environment() - .as_function_slots() - { - if let Some(new_target) = env.borrow().new_target() { - self.vm.push(new_target.clone()); - } else { - self.vm.push(JsValue::undefined()); - } - } else { - self.vm.push(JsValue::undefined()); - } - } + Opcode::PushNewArray(op) => PushNewArray::execute(self)?, + Opcode::PushValueToArray(op) => PushValueToArray::execute(self)?, + Opcode::PushElisionToArray(op) => PushElisionToArray::execute(self)?, + Opcode::PushIteratorToArray(op) => PushIteratorToArray::execute(self)?, + Opcode::Add(op) => Add::execute(self)?, + Opcode::Sub(op) => Sub::execute(self)?, + Opcode::Mul(op) => Mul::execute(self)?, + Opcode::Div(op) => Div::execute(self)?, + Opcode::Pow(op) => Pow::execute(self)?, + Opcode::Mod(op) => Mod::execute(self)?, + Opcode::BitAnd(op) => BitAnd::execute(self)?, + Opcode::BitOr(op) => BitOr::execute(self)?, + Opcode::BitXor(op) => BitXor::execute(self)?, + Opcode::ShiftLeft(op) => ShiftLeft::execute(self)?, + Opcode::ShiftRight(op) => ShiftRight::execute(self)?, + Opcode::UnsignedShiftRight(op) => UnsignedShiftRight::execute(self)?, + Opcode::Eq(op) => Eq::execute(self)?, + Opcode::NotEq(op) => NotEq::execute(self)?, + Opcode::StrictEq(op) => StrictEq::execute(self)?, + Opcode::StrictNotEq(op) => StrictNotEq::execute(self)?, + Opcode::GreaterThan(op) => GreaterThan::execute(self)?, + Opcode::GreaterThanOrEq(op) => GreaterThanOrEq::execute(self)?, + Opcode::LessThan(op) => LessThan::execute(self)?, + Opcode::LessThanOrEq(op) => LessThanOrEq::execute(self)?, + Opcode::In(op) => In::execute(self)?, + Opcode::InstanceOf(op) => InstanceOf::execute(self)?, + Opcode::Void(op) => Void::execute(self)?, + Opcode::TypeOf(op) => TypeOf::execute(self)?, + Opcode::Pos(op) => Pos::execute(self)?, + Opcode::Neg(op) => Neg::execute(self)?, + Opcode::Inc(op) => Inc::execute(self)?, + Opcode::IncPost(op) => IncPost::execute(self)?, + Opcode::Dec(op) => Dec::execute(self)?, + Opcode::DecPost(op) => DecPost::execute(self)?, + Opcode::LogicalNot(op) => LogicalNot::execute(self)?, + Opcode::BitNot(op) => BitNot::execute(self)?, + Opcode::DefVar(op) => DefVar::execute(self)?, + Opcode::DefInitVar(op) => DefInitVar::execute(self)?, + Opcode::DefLet(op) => DefLet::execute(self)?, + Opcode::DefInitLet(op) => DefInitLet::execute(self)?, + Opcode::DefInitConst(op) => DefInitConst::execute(self)?, + Opcode::DefInitArg(op) => DefInitArg::execute(self)?, + Opcode::GetName(op) => GetName::execute(self)?, + Opcode::GetNameOrUndefined(op) => GetNameOrUndefined::execute(self)?, + Opcode::SetName(op) => SetName::execute(self)?, + Opcode::Jump(op) => Jump::execute(self)?, + Opcode::JumpIfFalse(op) => JumpIfFalse::execute(self)?, + Opcode::JumpIfNotUndefined(op) => JumpIfNotUndefined::execute(self)?, + Opcode::LogicalAnd(op) => LogicalAnd::execute(self)?, + Opcode::LogicalOr(op) => LogicalOr::execute(self)?, + Opcode::Coalesce(op) => Coalesce::execute(self)?, + Opcode::ToBoolean(op) => ToBoolean::execute(self)?, + Opcode::GetPropertyByName(op) => GetPropertyByName::execute(self)?, + Opcode::GetPropertyByValue(op) => GetPropertyByValue::execute(self)?, + Opcode::GetPropertyByValuePush(op) => GetPropertyByValuePush::execute(self)?, + Opcode::SetPropertyByName(op) => SetPropertyByName::execute(self)?, + Opcode::DefineOwnPropertyByName(op) => DefineOwnPropertyByName::execute(self)?, + Opcode::DefineClassMethodByName(op) => DefineClassMethodByName::execute(self)?, + Opcode::SetPropertyByValue(op) => SetPropertyByValue::execute(self)?, + Opcode::DefineOwnPropertyByValue(op) => DefineOwnPropertyByValue::execute(self)?, + Opcode::DefineClassMethodByValue(op) => DefineClassMethodByValue::execute(self)?, + Opcode::SetPropertyGetterByName(op) => SetPropertyGetterByName::execute(self)?, + Opcode::DefineClassGetterByName(op) => DefineClassGetterByName::execute(self)?, + Opcode::SetPropertyGetterByValue(op) => SetPropertyGetterByValue::execute(self)?, + Opcode::DefineClassGetterByValue(op) => DefineClassGetterByValue::execute(self)?, + Opcode::SetPropertySetterByName(op) => SetPropertySetterByName::execute(self)?, + Opcode::DefineClassSetterByName(op) => DefineClassSetterByName::execute(self)?, + Opcode::SetPropertySetterByValue(op) => SetPropertySetterByValue::execute(self)?, + Opcode::DefineClassSetterByValue(op) => DefineClassSetterByValue::execute(self)?, + Opcode::AssignPrivateField(op) => AssignPrivateField::execute(self)?, + Opcode::SetPrivateField(op) => SetPrivateField::execute(self)?, + Opcode::SetPrivateMethod(op) => SetPrivateMethod::execute(self)?, + Opcode::SetPrivateSetter(op) => SetPrivateSetter::execute(self)?, + Opcode::SetPrivateGetter(op) => SetPrivateGetter::execute(self)?, + Opcode::GetPrivateField(op) => GetPrivateField::execute(self)?, + Opcode::PushClassField(op) => PushClassField::execute(self)?, + Opcode::PushClassFieldPrivate(op) => PushClassFieldPrivate::execute(self)?, + Opcode::PushClassPrivateGetter(op) => PushClassPrivateGetter::execute(self)?, + Opcode::PushClassPrivateSetter(op) => PushClassPrivateSetter::execute(self)?, + Opcode::PushClassPrivateMethod(op) => PushClassPrivateMethod::execute(self)?, + Opcode::DeletePropertyByName(op) => DeletePropertyByName::execute(self)?, + Opcode::DeletePropertyByValue(op) => DeletePropertyByValue::execute(self)?, + Opcode::CopyDataProperties(op) => CopyDataProperties::execute(self)?, + Opcode::ToPropertyKey(op) => ToPropertyKey::execute(self)?, + Opcode::Throw(op) => Throw::execute(self)?, + Opcode::TryStart(op) => TryStart::execute(self)?, + Opcode::TryEnd(op) => TryEnd::execute(self)?, + Opcode::CatchEnd(op) => CatchEnd::execute(self)?, + Opcode::CatchStart(op) => CatchStart::execute(self)?, + Opcode::CatchEnd2(op) => CatchEnd2::execute(self)?, + Opcode::FinallyStart(op) => FinallyStart::execute(self)?, + Opcode::FinallyEnd(op) => FinallyEnd::execute(self)?, + Opcode::FinallySetJump(op) => FinallySetJump::execute(self)?, + Opcode::This(op) => This::execute(self)?, + Opcode::Super(op) => Super::execute(self)?, + Opcode::SuperCall(op) => SuperCall::execute(self)?, + Opcode::SuperCallSpread(op) => SuperCallSpread::execute(self)?, + Opcode::SuperCallDerived(op) => SuperCallDerived::execute(self)?, + Opcode::Case(op) => Case::execute(self)?, + Opcode::Default(op) => Default::execute(self)?, + Opcode::GetFunction(op) => GetFunction::execute(self)?, + Opcode::GetFunctionAsync(op) => GetFunctionAsync::execute(self)?, + Opcode::GetGenerator(op) => GetGenerator::execute(self)?, + Opcode::GetGeneratorAsync(op) => GetGeneratorAsync::execute(self)?, + Opcode::CallEval(op) => CallEval::execute(self)?, + Opcode::CallEvalSpread(op) => CallEvalSpread::execute(self)?, + Opcode::Call(op) => Call::execute(self)?, + Opcode::CallSpread(op) => CallSpread::execute(self)?, + Opcode::New(op) => New::execute(self)?, + Opcode::NewSpread(op) => NewSpread::execute(self)?, + Opcode::Return(op) => Return::execute(self)?, + Opcode::PushDeclarativeEnvironment(op) => PushDeclarativeEnvironment::execute(self)?, + Opcode::PushFunctionEnvironment(op) => PushFunctionEnvironment::execute(self)?, + Opcode::PopEnvironment(op) => PopEnvironment::execute(self)?, + Opcode::LoopStart(op) => LoopStart::execute(self)?, + Opcode::LoopContinue(op) => LoopContinue::execute(self)?, + Opcode::LoopEnd(op) => LoopEnd::execute(self)?, + Opcode::ForInLoopInitIterator(op) => ForInLoopInitIterator::execute(self)?, + Opcode::InitIterator(op) => InitIterator::execute(self)?, + Opcode::InitIteratorAsync(op) => InitIteratorAsync::execute(self)?, + Opcode::IteratorNext(op) => IteratorNext::execute(self)?, + Opcode::IteratorClose(op) => IteratorClose::execute(self)?, + Opcode::IteratorToArray(op) => IteratorToArray::execute(self)?, + Opcode::ForInLoopNext(op) => ForInLoopNext::execute(self)?, + Opcode::ForAwaitOfLoopIterate(op) => ForAwaitOfLoopIterate::execute(self)?, + Opcode::ForAwaitOfLoopNext(op) => ForAwaitOfLoopNext::execute(self)?, + Opcode::ConcatToString(op) => ConcatToString::execute(self)?, + Opcode::RequireObjectCoercible(op) => RequireObjectCoercible::execute(self)?, + Opcode::ValueNotNullOrUndefined(op) => ValueNotNullOrUndefined::execute(self)?, + Opcode::RestParameterInit(op) => RestParameterInit::execute(self)?, + Opcode::RestParameterPop(op) => RestParameterPop::execute(self)?, + Opcode::PopOnReturnAdd(op) => PopOnReturnAdd::execute(self)?, + Opcode::PopOnReturnSub(op) => PopOnReturnSub::execute(self)?, + Opcode::Yield(op) => Yield::execute(self)?, + Opcode::GeneratorNext(op) => GeneratorNext::execute(self)?, + Opcode::AsyncGeneratorNext(op) => AsyncGeneratorNext::execute(self)?, + Opcode::GeneratorNextDelegate(op) => GeneratorNextDelegate::execute(self)?, + Opcode::Await(op) => Await::execute(self)?, + Opcode::PushNewTarget(op) => PushNewTarget::execute(self)?, }; Ok(result) diff --git a/boa_engine/src/vm/opcode/await_stm/mod.rs b/boa_engine/src/vm/opcode/await_stm/mod.rs new file mode 100644 index 00000000000..68709626b42 --- /dev/null +++ b/boa_engine/src/vm/opcode/await_stm/mod.rs @@ -0,0 +1,115 @@ +use crate::{ + builtins::{JsArgs, Promise}, + object::FunctionBuilder, + vm::{call_frame::GeneratorResumeKind, opcode::Operation, ShouldExit}, + Context, JsResult, JsValue, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Await; + +impl Operation for Await { + const NAME: &'static str = "Await"; + const INSTRUCTION: &'static str = "INST - Await"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + + // 2. Let promise be ? PromiseResolve(%Promise%, value). + let promise = Promise::promise_resolve( + context.intrinsics().constructors().promise().constructor(), + value, + context, + )?; + + // 3. Let fulfilledClosure be a new Abstract Closure with parameters (value) that captures asyncContext and performs the following steps when called: + // 4. Let onFulfilled be CreateBuiltinFunction(fulfilledClosure, 1, "", « »). + let on_fulfilled = FunctionBuilder::closure_with_captures( + context, + |_this, args, (environment, stack, frame), context| { + // a. Let prevContext be the running execution context. + // b. Suspend prevContext. + // c. Push asyncContext onto the execution context stack; asyncContext is now the running execution context. + // d. Resume the suspended evaluation of asyncContext using NormalCompletion(value) as the result of the operation that suspended it. + // e. Assert: When we reach this step, asyncContext has already been removed from the execution context stack and prevContext is the currently running execution context. + // f. Return undefined. + + std::mem::swap(&mut context.realm.environments, environment); + std::mem::swap(&mut context.vm.stack, stack); + context.vm.push_frame(frame.clone()); + + context.vm.frame_mut().generator_resume_kind = GeneratorResumeKind::Normal; + context.vm.push(args.get_or_undefined(0)); + context.run()?; + + *frame = context + .vm + .pop_frame() + .expect("generator call frame must exist"); + std::mem::swap(&mut context.realm.environments, environment); + std::mem::swap(&mut context.vm.stack, stack); + + Ok(JsValue::undefined()) + }, + ( + context.realm.environments.clone(), + context.vm.stack.clone(), + context.vm.frame().clone(), + ), + ) + .name("") + .length(1) + .build(); + + // 5. Let rejectedClosure be a new Abstract Closure with parameters (reason) that captures asyncContext and performs the following steps when called: + // 6. Let onRejected be CreateBuiltinFunction(rejectedClosure, 1, "", « »). + let on_rejected = FunctionBuilder::closure_with_captures( + context, + |_this, args, (environment, stack, frame), context| { + // a. Let prevContext be the running execution context. + // b. Suspend prevContext. + // c. Push asyncContext onto the execution context stack; asyncContext is now the running execution context. + // d. Resume the suspended evaluation of asyncContext using ThrowCompletion(reason) as the result of the operation that suspended it. + // e. Assert: When we reach this step, asyncContext has already been removed from the execution context stack and prevContext is the currently running execution context. + // f. Return undefined. + + std::mem::swap(&mut context.realm.environments, environment); + std::mem::swap(&mut context.vm.stack, stack); + context.vm.push_frame(frame.clone()); + + context.vm.frame_mut().generator_resume_kind = GeneratorResumeKind::Throw; + context.vm.push(args.get_or_undefined(0)); + context.run()?; + + *frame = context + .vm + .pop_frame() + .expect("generator call frame must exist"); + std::mem::swap(&mut context.realm.environments, environment); + std::mem::swap(&mut context.vm.stack, stack); + + Ok(JsValue::undefined()) + }, + ( + context.realm.environments.clone(), + context.vm.stack.clone(), + context.vm.frame().clone(), + ), + ) + .name("") + .length(1) + .build(); + + // 7. Perform PerformPromiseThen(promise, onFulfilled, onRejected). + promise + .as_object() + .expect("promise was not an object") + .borrow_mut() + .as_promise_mut() + .expect("promise was not a promise") + .perform_promise_then(&on_fulfilled.into(), &on_rejected.into(), None, context); + + context.vm.push(JsValue::undefined()); + Ok(ShouldExit::Await) + } +} diff --git a/boa_engine/src/vm/opcode/call/mod.rs b/boa_engine/src/vm/opcode/call/mod.rs new file mode 100644 index 00000000000..4cf3eb26834 --- /dev/null +++ b/boa_engine/src/vm/opcode/call/mod.rs @@ -0,0 +1,175 @@ +use crate::{ + builtins::function::Function, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsValue, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct CallEval; + +impl Operation for CallEval { + const NAME: &'static str = "CallEval"; + const INSTRUCTION: &'static str = "INST - 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"); + } + let argument_count = context.vm.read::(); + let mut arguments = Vec::with_capacity(argument_count as usize); + for _ in 0..argument_count { + arguments.push(context.vm.pop()); + } + arguments.reverse(); + + let func = context.vm.pop(); + let this = context.vm.pop(); + + let object = match func { + JsValue::Object(ref object) if object.is_callable() => object.clone(), + _ => return context.throw_type_error("not a callable function"), + }; + + // A native function with the name "eval" implies, that is this the built-in eval function. + let eval = matches!(object.borrow().as_function(), Some(Function::Native { .. })); + + let strict = context.vm.frame().code.strict; + + if eval { + if let Some(x) = arguments.get(0) { + let result = crate::builtins::eval::Eval::perform_eval(x, true, strict, context)?; + context.vm.push(result); + } else { + context.vm.push(JsValue::Undefined); + } + } else { + let result = object.__call__(&this, &arguments, context)?; + context.vm.push(result); + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct CallEvalSpread; + +impl Operation for CallEvalSpread { + const NAME: &'static str = "CallEvalSpread"; + const INSTRUCTION: &'static str = "INST - 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"); + } + + // Get the arguments that are stored as an array object on the stack. + let arguments_array = context.vm.pop(); + let arguments_array_object = arguments_array + .as_object() + .expect("arguments array in call spread function must be an object"); + let arguments = arguments_array_object + .borrow() + .properties() + .dense_indexed_properties() + .expect("arguments array in call spread function must be dense") + .clone(); + + let func = context.vm.pop(); + let this = context.vm.pop(); + + let object = match func { + JsValue::Object(ref object) if object.is_callable() => object.clone(), + _ => return context.throw_type_error("not a callable function"), + }; + + // A native function with the name "eval" implies, that is this the built-in eval function. + let eval = matches!(object.borrow().as_function(), Some(Function::Native { .. })); + + let strict = context.vm.frame().code.strict; + + if eval { + if let Some(x) = arguments.get(0) { + let result = crate::builtins::eval::Eval::perform_eval(x, true, strict, context)?; + context.vm.push(result); + } else { + context.vm.push(JsValue::Undefined); + } + } else { + let result = object.__call__(&this, &arguments, context)?; + context.vm.push(result); + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Call; + +impl Operation for Call { + const NAME: &'static str = "Call"; + const INSTRUCTION: &'static str = "INST - 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"); + } + let argument_count = context.vm.read::(); + let mut arguments = Vec::with_capacity(argument_count as usize); + for _ in 0..argument_count { + arguments.push(context.vm.pop()); + } + arguments.reverse(); + + let func = context.vm.pop(); + let this = context.vm.pop(); + + let object = match func { + JsValue::Object(ref object) if object.is_callable() => object.clone(), + _ => return context.throw_type_error("not a callable function"), + }; + + let result = object.__call__(&this, &arguments, context)?; + + context.vm.push(result); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct CallSpread; + +impl Operation for CallSpread { + const NAME: &'static str = "CallSpread"; + const INSTRUCTION: &'static str = "INST - 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"); + } + + // Get the arguments that are stored as an array object on the stack. + let arguments_array = context.vm.pop(); + let arguments_array_object = arguments_array + .as_object() + .expect("arguments array in call spread function must be an object"); + let arguments = arguments_array_object + .borrow() + .properties() + .dense_indexed_properties() + .expect("arguments array in call spread function must be dense") + .clone(); + + let func = context.vm.pop(); + let this = context.vm.pop(); + + let object = match func { + JsValue::Object(ref object) if object.is_callable() => object.clone(), + _ => return context.throw_type_error("not a callable function"), + }; + + let result = object.__call__(&this, &arguments, context)?; + + context.vm.push(result); + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/concat/mod.rs b/boa_engine/src/vm/opcode/concat/mod.rs new file mode 100644 index 00000000000..4eb9d1149bf --- /dev/null +++ b/boa_engine/src/vm/opcode/concat/mod.rs @@ -0,0 +1,25 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsString, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct ConcatToString; + +impl Operation for ConcatToString { + const NAME: &'static str = "ConcatToString"; + const INSTRUCTION: &'static str = "INST - ConcatToString"; + + fn execute(context: &mut Context) -> JsResult { + let value_count = context.vm.read::(); + let mut strings = Vec::with_capacity(value_count as usize); + for _ in 0..value_count { + strings.push(context.vm.pop().to_string(context)?); + } + strings.reverse(); + let s = + JsString::concat_array(&strings.iter().map(JsString::as_str).collect::>()); + context.vm.push(s); + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/conversion/mod.rs b/boa_engine/src/vm/opcode/conversion/mod.rs new file mode 100644 index 00000000000..a021a6d48f7 --- /dev/null +++ b/boa_engine/src/vm/opcode/conversion/mod.rs @@ -0,0 +1,33 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct ToBoolean; + +impl Operation for ToBoolean { + const NAME: &'static str = "ToBoolean"; + const INSTRUCTION: &'static str = "INST - ToBoolean"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + context.vm.push(value.to_boolean()); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct ToPropertyKey; + +impl Operation for ToPropertyKey { + const NAME: &'static str = "ToPropertyKey"; + const INSTRUCTION: &'static str = "INST - ToPropertyKey"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + let key = value.to_property_key(context)?; + context.vm.push(key); + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/copy/mod.rs b/boa_engine/src/vm/opcode/copy/mod.rs new file mode 100644 index 00000000000..4cabe63b204 --- /dev/null +++ b/boa_engine/src/vm/opcode/copy/mod.rs @@ -0,0 +1,38 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct CopyDataProperties; + +impl Operation for CopyDataProperties { + const NAME: &'static str = "CopyDataProperties"; + const INSTRUCTION: &'static str = "INST - CopyDataProperties"; + + fn execute(context: &mut Context) -> JsResult { + let excluded_key_count = context.vm.read::(); + let excluded_key_count_computed = context.vm.read::(); + let mut excluded_keys = Vec::with_capacity(excluded_key_count as usize); + for _ in 0..excluded_key_count { + let key = context.vm.pop(); + excluded_keys.push( + key.to_property_key(context) + .expect("key must be property key"), + ); + } + let value = context.vm.pop(); + let object = value.as_object().expect("not an object"); + let source = context.vm.pop(); + for _ in 0..excluded_key_count_computed { + let key = context.vm.pop(); + excluded_keys.push( + key.to_property_key(context) + .expect("key must be property key"), + ); + } + object.copy_data_properties(&source, excluded_keys, context)?; + context.vm.push(value); + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/define/class.rs b/boa_engine/src/vm/opcode/define/class.rs new file mode 100644 index 00000000000..8512dead9ac --- /dev/null +++ b/boa_engine/src/vm/opcode/define/class.rs @@ -0,0 +1,240 @@ +use crate::{ + property::PropertyDescriptor, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct DefineClassMethodByName; + +impl Operation for DefineClassMethodByName { + const NAME: &'static str = "DefineClassMethodByName"; + const INSTRUCTION: &'static str = "INST - DefineClassMethodByName"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let object = context.vm.pop(); + let value = context.vm.pop(); + let object = if let Some(object) = object.as_object() { + object.clone() + } else { + object.to_object(context)? + }; + value + .as_object() + .expect("method must be function object") + .borrow_mut() + .as_function_mut() + .expect("method must be function object") + .set_home_object(object.clone()); + let name = context.vm.frame().code.names[index as usize]; + let name = context.interner().resolve_expect(name); + object.__define_own_property__( + name.into(), + PropertyDescriptor::builder() + .value(value) + .writable(true) + .enumerable(false) + .configurable(true) + .build(), + context, + )?; + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct DefineClassMethodByValue; + +impl Operation for DefineClassMethodByValue { + const NAME: &'static str = "DefineClassMethodByName"; + const INSTRUCTION: &'static str = "INST - DefineClassMethodByName"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + let key = context.vm.pop(); + let object = context.vm.pop(); + let object = if let Some(object) = object.as_object() { + object.clone() + } else { + object.to_object(context)? + }; + value + .as_object() + .expect("method must be function object") + .borrow_mut() + .as_function_mut() + .expect("method must be function object") + .set_home_object(object.clone()); + let key = key.to_property_key(context)?; + object.__define_own_property__( + key, + PropertyDescriptor::builder() + .value(value) + .writable(true) + .enumerable(false) + .configurable(true) + .build(), + context, + )?; + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct DefineClassGetterByName; + +impl Operation for DefineClassGetterByName { + const NAME: &'static str = "DefineClassGetterByName"; + const INSTRUCTION: &'static str = "INST - DefineClassGetterByName"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let object = context.vm.pop(); + let value = context.vm.pop(); + let object = object.to_object(context)?; + value + .as_object() + .expect("method must be function object") + .borrow_mut() + .as_function_mut() + .expect("method must be function object") + .set_home_object(object.clone()); + let name = context.vm.frame().code.names[index as usize]; + let name = context.interner().resolve_expect(name).into(); + let set = object + .__get_own_property__(&name, context)? + .as_ref() + .and_then(PropertyDescriptor::set) + .cloned(); + object.__define_own_property__( + name, + PropertyDescriptor::builder() + .maybe_get(Some(value)) + .maybe_set(set) + .enumerable(false) + .configurable(true) + .build(), + context, + )?; + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct DefineClassGetterByValue; + +impl Operation for DefineClassGetterByValue { + const NAME: &'static str = "DefineClassGetterByValue"; + const INSTRUCTION: &'static str = "INST - DefineClassGetterByValue"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + let key = context.vm.pop(); + let object = context.vm.pop(); + let object = object.to_object(context)?; + value + .as_object() + .expect("method must be function object") + .borrow_mut() + .as_function_mut() + .expect("method must be function object") + .set_home_object(object.clone()); + let name = key.to_property_key(context)?; + let set = object + .__get_own_property__(&name, context)? + .as_ref() + .and_then(PropertyDescriptor::set) + .cloned(); + object.__define_own_property__( + name, + PropertyDescriptor::builder() + .maybe_get(Some(value)) + .maybe_set(set) + .enumerable(false) + .configurable(true) + .build(), + context, + )?; + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct DefineClassSetterByName; + +impl Operation for DefineClassSetterByName { + const NAME: &'static str = "DefineClassSetterByName"; + const INSTRUCTION: &'static str = "INST - DefineClassSetterByName"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let object = context.vm.pop(); + let value = context.vm.pop(); + let object = object.to_object(context)?; + value + .as_object() + .expect("method must be function object") + .borrow_mut() + .as_function_mut() + .expect("method must be function object") + .set_home_object(object.clone()); + let name = context.vm.frame().code.names[index as usize]; + let name = context.interner().resolve_expect(name).into(); + let get = object + .__get_own_property__(&name, context)? + .as_ref() + .and_then(PropertyDescriptor::get) + .cloned(); + object.__define_own_property__( + name, + PropertyDescriptor::builder() + .maybe_set(Some(value)) + .maybe_get(get) + .enumerable(false) + .configurable(true) + .build(), + context, + )?; + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct DefineClassSetterByValue; + +impl Operation for DefineClassSetterByValue { + const NAME: &'static str = "DefineClassSetterByValue"; + const INSTRUCTION: &'static str = "INST - DefineClassSetterByValue"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + let key = context.vm.pop(); + let object = context.vm.pop(); + let object = object.to_object(context)?; + value + .as_object() + .expect("method must be function object") + .borrow_mut() + .as_function_mut() + .expect("method must be function object") + .set_home_object(object.clone()); + let name = key.to_property_key(context)?; + let get = object + .__get_own_property__(&name, context)? + .as_ref() + .and_then(PropertyDescriptor::get) + .cloned(); + object.__define_own_property__( + name, + PropertyDescriptor::builder() + .maybe_set(Some(value)) + .maybe_get(get) + .enumerable(false) + .configurable(true) + .build(), + context, + )?; + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/define/mod.rs b/boa_engine/src/vm/opcode/define/mod.rs new file mode 100644 index 00000000000..2784160a819 --- /dev/null +++ b/boa_engine/src/vm/opcode/define/mod.rs @@ -0,0 +1,123 @@ +use crate::{ + property::PropertyDescriptor, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsValue, +}; + +pub(crate) mod class; +pub(crate) mod own_property; + +pub(crate) use class::*; +pub(crate) use own_property::*; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct DefVar; + +impl Operation for DefVar { + const NAME: &'static str = "DefVar"; + const INSTRUCTION: &'static str = "INST - DefVar"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let binding_locator = context.vm.frame().code.bindings[index as usize]; + + if binding_locator.is_global() { + let key = context + .interner() + .resolve_expect(binding_locator.name()) + .into(); + context.global_bindings_mut().entry(key).or_insert( + PropertyDescriptor::builder() + .value(JsValue::Undefined) + .writable(true) + .enumerable(true) + .configurable(true) + .build(), + ); + } else { + context.realm.environments.put_value_if_uninitialized( + binding_locator.environment_index(), + binding_locator.binding_index(), + JsValue::Undefined, + ); + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct DefInitVar; + +impl Operation for DefInitVar { + const NAME: &'static str = "DefInitVar"; + const INSTRUCTION: &'static str = "INST - DefInitVar"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let value = context.vm.pop(); + let binding_locator = context.vm.frame().code.bindings[index as usize]; + binding_locator.throw_mutate_immutable(context)?; + + if binding_locator.is_global() { + let key = context + .interner() + .resolve_expect(binding_locator.name()) + .into(); + crate::object::internal_methods::global::global_set_no_receiver(&key, value, context)?; + } else { + context.realm.environments.put_value( + binding_locator.environment_index(), + binding_locator.binding_index(), + value, + ); + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct DefLet; + +impl Operation for DefLet { + const NAME: &'static str = "DefLet"; + const INSTRUCTION: &'static str = "INST - DefLet"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let binding_locator = context.vm.frame().code.bindings[index as usize]; + context.realm.environments.put_value( + binding_locator.environment_index(), + binding_locator.binding_index(), + JsValue::Undefined, + ); + Ok(ShouldExit::False) + } +} + +macro_rules! implement_declaritives { + ($name:ident) => { + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub(crate) struct $name; + + impl Operation for $name { + const NAME: &'static str = stringify!($name); + const INSTRUCTION: &'static str = stringify!("INST - " + $name); + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let value = context.vm.pop(); + let binding_locator = context.vm.frame().code.bindings[index as usize]; + context.realm.environments.put_value( + binding_locator.environment_index(), + binding_locator.binding_index(), + value, + ); + Ok(ShouldExit::False) + } + } + }; +} + +implement_declaritives!(DefInitLet); +implement_declaritives!(DefInitConst); +implement_declaritives!(DefInitArg); diff --git a/boa_engine/src/vm/opcode/define/own_property.rs b/boa_engine/src/vm/opcode/define/own_property.rs new file mode 100644 index 00000000000..fbd66d09b18 --- /dev/null +++ b/boa_engine/src/vm/opcode/define/own_property.rs @@ -0,0 +1,68 @@ +use crate::{ + property::{PropertyDescriptor, PropertyKey}, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct DefineOwnPropertyByName; + +impl Operation for DefineOwnPropertyByName { + const NAME: &'static str = "DefineOwnPropertyByName"; + const INSTRUCTION: &'static str = "INST - DefineOwnPropertyByName"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let object = context.vm.pop(); + let value = context.vm.pop(); + let object = if let Some(object) = object.as_object() { + object.clone() + } else { + object.to_object(context)? + }; + let name = context.vm.frame().code.names[index as usize]; + let name = context.interner().resolve_expect(name); + object.__define_own_property__( + name.into(), + PropertyDescriptor::builder() + .value(value) + .writable(true) + .enumerable(true) + .configurable(true) + .build(), + context, + )?; + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct DefineOwnPropertyByValue; + +impl Operation for DefineOwnPropertyByValue { + const NAME: &'static str = "DefineOwnPropertyByValue"; + const INSTRUCTION: &'static str = "INST - DefineOwnPropertyByValue"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + let key = context.vm.pop(); + let object = context.vm.pop(); + let object = if let Some(object) = object.as_object() { + object.clone() + } else { + object.to_object(context)? + }; + let key = key.to_property_key(context)?; + object.__define_own_property__( + key, + PropertyDescriptor::builder() + .value(value) + .writable(true) + .enumerable(true) + .configurable(true) + .build(), + context, + )?; + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/delete/mod.rs b/boa_engine/src/vm/opcode/delete/mod.rs new file mode 100644 index 00000000000..b9de6e3ebb5 --- /dev/null +++ b/boa_engine/src/vm/opcode/delete/mod.rs @@ -0,0 +1,46 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct DeletePropertyByName; + +impl Operation for DeletePropertyByName { + const NAME: &'static str = "DeletePropertyByName"; + const INSTRUCTION: &'static str = "INST - DeletePropertyByName"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let key = context.vm.frame().code.names[index as usize]; + let key = context.interner().resolve_expect(key).into(); + 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")); + } + context.vm.push(result); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct DeletePropertyByValue; + +impl Operation for DeletePropertyByValue { + const NAME: &'static str = "DeletePropertyByValue"; + const INSTRUCTION: &'static str = "INST - DeletePropertyByValue"; + + fn execute(context: &mut Context) -> JsResult { + let object = context.vm.pop(); + let key = context.vm.pop(); + let result = object + .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")); + } + context.vm.push(result); + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/dup/mod.rs b/boa_engine/src/vm/opcode/dup/mod.rs index 7095d20f1d4..6e562f6e937 100644 --- a/boa_engine/src/vm/opcode/dup/mod.rs +++ b/boa_engine/src/vm/opcode/dup/mod.rs @@ -1,6 +1,6 @@ use crate::{ vm::{opcode::Operation, ShouldExit}, - Context, JsResult + Context, JsResult, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -16,4 +16,4 @@ impl Operation for Dup { context.vm.push(value); Ok(ShouldExit::False) } -} \ No newline at end of file +} diff --git a/boa_engine/src/vm/opcode/environment/mod.rs b/boa_engine/src/vm/opcode/environment/mod.rs new file mode 100644 index 00000000000..cf6f01d68eb --- /dev/null +++ b/boa_engine/src/vm/opcode/environment/mod.rs @@ -0,0 +1,261 @@ +use crate::{ + environments::EnvironmentSlots, + vm::{code_block::initialize_instance_elements, opcode::Operation, ShouldExit}, + Context, JsResult, JsValue, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct This; + +impl Operation for This { + const NAME: &'static str = "This"; + const INSTRUCTION: &'static str = "INST - 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::Global => { + let this = context.realm.global_object(); + context.vm.push(this.clone()); + } + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Super; + +impl Operation for Super { + const NAME: &'static str = "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 env = env.borrow(); + 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"); + }; + + if let Some(home) = home { + if let Some(proto) = home.__get_prototype_of__(context)? { + context.vm.push(JsValue::from(proto)); + } else { + context.vm.push(JsValue::Null); + } + } else { + context.vm.push(JsValue::Null); + }; + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct SuperCall; + +impl Operation for SuperCall { + const NAME: &'static str = "SuperCall"; + const INSTRUCTION: &'static str = "INST - SuperCall"; + + fn execute(context: &mut Context) -> JsResult { + let argument_count = context.vm.read::(); + let mut arguments = Vec::with_capacity(argument_count as usize); + for _ in 0..argument_count { + arguments.push(context.vm.pop()); + } + arguments.reverse(); + + let (new_target, active_function) = { + let this_env = context + .realm + .environments + .get_this_environment() + .as_function_slots() + .expect("super call must be in function environment"); + let this_env_borrow = this_env.borrow(); + let new_target = this_env_borrow + .new_target() + .expect("must have new target") + .clone(); + let active_function = this_env.borrow().function_object().clone(); + (new_target, active_function) + }; + let super_constructor = active_function + .__get_prototype_of__(context) + .expect("function object must have prototype") + .expect("function object must have prototype"); + + if !super_constructor.is_constructor() { + return context.throw_type_error("super constructor object must be constructor"); + } + + let result = super_constructor.__construct__(&arguments, &new_target, context)?; + + initialize_instance_elements(&result, &active_function, context)?; + + let this_env = context + .realm + .environments + .get_this_environment() + .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"); + } + context.vm.push(result); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct SuperCallSpread; + +impl Operation for SuperCallSpread { + const NAME: &'static str = "SuperCallWithRest"; + const INSTRUCTION: &'static str = "INST - SuperCallWithRest"; + + fn execute(context: &mut Context) -> JsResult { + // Get the arguments that are stored as an array object on the stack. + let arguments_array = context.vm.pop(); + let arguments_array_object = arguments_array + .as_object() + .expect("arguments array in call spread function must be an object"); + let arguments = arguments_array_object + .borrow() + .properties() + .dense_indexed_properties() + .expect("arguments array in call spread function must be dense") + .clone(); + + let (new_target, active_function) = { + let this_env = context + .realm + .environments + .get_this_environment() + .as_function_slots() + .expect("super call must be in function environment"); + let this_env_borrow = this_env.borrow(); + let new_target = this_env_borrow + .new_target() + .expect("must have new target") + .clone(); + let active_function = this_env.borrow().function_object().clone(); + (new_target, active_function) + }; + let super_constructor = active_function + .__get_prototype_of__(context) + .expect("function object must have prototype") + .expect("function object must have prototype"); + + if !super_constructor.is_constructor() { + return context.throw_type_error("super constructor object must be constructor"); + } + + let result = super_constructor.__construct__(&arguments, &new_target, context)?; + + initialize_instance_elements(&result, &active_function, context)?; + + let this_env = context + .realm + .environments + .get_this_environment() + .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"); + } + context.vm.push(result); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct SuperCallDerived; + +impl Operation for SuperCallDerived { + const NAME: &'static str = "SuperCallDerived"; + const INSTRUCTION: &'static str = "INST - SuperCallDerived"; + + fn execute(context: &mut Context) -> JsResult { + let argument_count = context.vm.frame().arg_count; + let mut arguments = Vec::with_capacity(argument_count); + for _ in 0..argument_count { + arguments.push(context.vm.pop()); + } + arguments.reverse(); + + let (new_target, active_function) = { + let this_env = context + .realm + .environments + .get_this_environment() + .as_function_slots() + .expect("super call must be in function environment"); + let this_env_borrow = this_env.borrow(); + let new_target = this_env_borrow + .new_target() + .expect("must have new target") + .clone(); + let active_function = this_env.borrow().function_object().clone(); + (new_target, active_function) + }; + let super_constructor = active_function + .__get_prototype_of__(context) + .expect("function object must have prototype") + .expect("function object must have prototype"); + + if !super_constructor.is_constructor() { + return context.throw_type_error("super constructor object must be constructor"); + } + + let result = super_constructor.__construct__(&arguments, &new_target, context)?; + + initialize_instance_elements(&result, &active_function, context)?; + + let this_env = context + .realm + .environments + .get_this_environment() + .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"); + } + + context.vm.push(result); + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/general/jump.rs b/boa_engine/src/vm/opcode/general/jump.rs new file mode 100644 index 00000000000..586c4697397 --- /dev/null +++ b/boa_engine/src/vm/opcode/general/jump.rs @@ -0,0 +1,52 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsValue, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Jump; + +impl Operation for Jump { + const NAME: &'static str = "Jump"; + const INSTRUCTION: &'static str = "INST - Jump"; + + fn execute(context: &mut Context) -> JsResult { + let address = context.vm.read::(); + context.vm.frame_mut().pc = address as usize; + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct JumpIfFalse; + +impl Operation for JumpIfFalse { + const NAME: &'static str = "JumpIfFalse"; + const INSTRUCTION: &'static str = "INST - JumpIfFalse"; + + fn execute(context: &mut Context) -> JsResult { + let address = context.vm.read::(); + if !context.vm.pop().to_boolean() { + context.vm.frame_mut().pc = address as usize; + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct JumpIfNotUndefined; + +impl Operation for JumpIfNotUndefined { + const NAME: &'static str = "JumpIfNotUndefined"; + const INSTRUCTION: &'static str = "INST - JumpIfNotUndefined"; + + fn execute(context: &mut Context) -> JsResult { + let address = context.vm.read::(); + let value = context.vm.pop(); + if !value.is_undefined() { + context.vm.frame_mut().pc = address as usize; + context.vm.push(value); + } + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/general/logical.rs b/boa_engine/src/vm/opcode/general/logical.rs new file mode 100644 index 00000000000..7654c1ffcd8 --- /dev/null +++ b/boa_engine/src/vm/opcode/general/logical.rs @@ -0,0 +1,72 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct LogicalNot; + +impl Operation for LogicalNot { + const NAME: &'static str = "LogicalNot"; + const INSTRUCTION: &'static str = "INST - LogicalNot"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + context.vm.push(!value.to_boolean()); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct LogicalAnd; + +impl Operation for LogicalAnd { + const NAME: &'static str = "LogicalAnd"; + const INSTRUCTION: &'static str = "INST - LogicalAnd"; + + fn execute(context: &mut Context) -> JsResult { + let exit = context.vm.read::(); + let lhs = context.vm.pop(); + if !lhs.to_boolean() { + context.vm.frame_mut().pc = exit as usize; + context.vm.push(lhs); + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct LogicalOr; + +impl Operation for LogicalOr { + const NAME: &'static str = "LogicalOr"; + const INSTRUCTION: &'static str = "INST - LogicalOr"; + + fn execute(context: &mut Context) -> JsResult { + let exit = context.vm.read::(); + let lhs = context.vm.pop(); + if lhs.to_boolean() { + context.vm.frame_mut().pc = exit as usize; + context.vm.push(lhs); + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Coalesce; + +impl Operation for Coalesce { + const NAME: &'static str = "Coalesce"; + const INSTRUCTION: &'static str = "INST - Coalesce"; + + fn execute(context: &mut Context) -> JsResult { + let exit = context.vm.read::(); + let lhs = context.vm.pop(); + if !lhs.is_null_or_undefined() { + context.vm.frame_mut().pc = exit as usize; + context.vm.push(lhs); + } + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/general/mod.rs b/boa_engine/src/vm/opcode/general/mod.rs new file mode 100644 index 00000000000..7d97a2edf0f --- /dev/null +++ b/boa_engine/src/vm/opcode/general/mod.rs @@ -0,0 +1,307 @@ +use crate::{ + builtins::Number, + value::Numeric, + vm::{opcode::Operation, ShouldExit}, + Context, JsBigInt, JsResult, JsValue, +}; +use std::ops::Neg as StdNeg; + +pub(crate) mod jump; +pub(crate) mod logical; + +pub(crate) use jump::*; +pub(crate) use logical::*; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Nop; + +impl Operation for Nop { + const NAME: &'static str = "Nop"; + const INSTRUCTION: &'static str = "INST - Nop"; + + fn execute(context: &mut Context) -> JsResult { + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct NotEq; + +impl Operation for NotEq { + const NAME: &'static str = "NotEq"; + const INSTRUCTION: &'static str = "INST - NotEq"; + + fn execute(context: &mut Context) -> JsResult { + let rhs = context.vm.pop(); + let lhs = context.vm.pop(); + let value = !lhs.equals(&rhs, context)?; + context.vm.push(value); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct StrictEq; + +impl Operation for StrictEq { + const NAME: &'static str = "StrictEq"; + const INSTRUCTION: &'static str = "INST - StrictEq"; + + fn execute(context: &mut Context) -> JsResult { + let rhs = context.vm.pop(); + let lhs = context.vm.pop(); + context.vm.push(lhs.strict_equals(&rhs)); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct StrictNotEq; + +impl Operation for StrictNotEq { + const NAME: &'static str = "StrictNotEq"; + const INSTRUCTION: &'static str = "INST - StrictNotEq"; + + fn execute(context: &mut Context) -> JsResult { + let rhs = context.vm.pop(); + let lhs = context.vm.pop(); + context.vm.push(!lhs.strict_equals(&rhs)); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct In; + +impl Operation for In { + const NAME: &'static str = "In"; + const INSTRUCTION: &'static str = "INST - In"; + + fn execute(context: &mut Context) -> JsResult { + let rhs = context.vm.pop(); + 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() + )); + } + let key = lhs.to_property_key(context)?; + let value = context.has_property(&rhs, &key)?; + context.vm.push(value); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct InstanceOf; + +impl Operation for InstanceOf { + const NAME: &'static str = "InstanceOf"; + const INSTRUCTION: &'static str = "INST - InstanceOf"; + + fn execute(context: &mut Context) -> JsResult { + let target = context.vm.pop(); + let v = context.vm.pop(); + let value = v.instance_of(&target, context)?; + + context.vm.push(value); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Void; + +impl Operation for Void { + const NAME: &'static str = "Void"; + const INSTRUCTION: &'static str = "INST - Void"; + + fn execute(context: &mut Context) -> JsResult { + let _old = context.vm.pop(); + context.vm.push(JsValue::undefined()); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct TypeOf; + +impl Operation for TypeOf { + const NAME: &'static str = "TypeOf"; + const INSTRUCTION: &'static str = "INST - TypeOf"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + context.vm.push(value.type_of()); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Pos; + +impl Operation for Pos { + const NAME: &'static str = "Pos"; + const INSTRUCTION: &'static str = "INST - Pos"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + let value = value.to_number(context)?; + context.vm.push(value); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Neg; + +impl Operation for Neg { + const NAME: &'static str = "Neg"; + const INSTRUCTION: &'static str = "INST - Neg"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + match value.to_numeric(context)? { + Numeric::Number(number) => context.vm.push(number.neg()), + Numeric::BigInt(bigint) => context.vm.push(JsBigInt::neg(&bigint)), + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Inc; + +impl Operation for Inc { + const NAME: &'static str = "Inc"; + const INSTRUCTION: &'static str = "INST - Inc"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + match value.to_numeric(context)? { + Numeric::Number(number) => context.vm.push(number + 1f64), + Numeric::BigInt(bigint) => { + context.vm.push(JsBigInt::add(&bigint, &JsBigInt::one())); + } + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct IncPost; + +impl Operation for IncPost { + const NAME: &'static str = "IncPost"; + const INSTRUCTION: &'static str = "INST - IncPost"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + let value = value.to_numeric(context)?; + context.vm.push(value.clone()); + match value { + Numeric::Number(number) => context.vm.push(number + 1f64), + Numeric::BigInt(bigint) => { + context.vm.push(JsBigInt::add(&bigint, &JsBigInt::one())); + } + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Dec; + +impl Operation for Dec { + const NAME: &'static str = "Dec"; + const INSTRUCTION: &'static str = "INST - Dec"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + match value.to_numeric(context)? { + Numeric::Number(number) => context.vm.push(number - 1f64), + Numeric::BigInt(bigint) => { + context.vm.push(JsBigInt::sub(&bigint, &JsBigInt::one())); + } + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct DecPost; + +impl Operation for DecPost { + const NAME: &'static str = "DecPost"; + const INSTRUCTION: &'static str = "INST - DecPost"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + let value = value.to_numeric(context)?; + context.vm.push(value.clone()); + match value { + Numeric::Number(number) => context.vm.push(number - 1f64), + Numeric::BigInt(bigint) => { + context.vm.push(JsBigInt::sub(&bigint, &JsBigInt::one())); + } + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct BitNot; + +impl Operation for BitNot { + const NAME: &'static str = "BitNot"; + const INSTRUCTION: &'static str = "INST - BitNot"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + match value.to_numeric(context)? { + Numeric::Number(number) => context.vm.push(Number::not(number)), + Numeric::BigInt(bigint) => context.vm.push(JsBigInt::not(&bigint)), + } + Ok(ShouldExit::False) + } +} + +macro_rules! implement_bin_ops { + ($name:ident, $op:ident) => { + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub(crate) struct $name; + + impl Operation for $name { + const NAME: &'static str = stringify!($name); + const INSTRUCTION: &'static str = stringify!("INST - " + $name); + + fn execute(context: &mut Context) -> JsResult { + let rhs = context.vm.pop(); + let lhs = context.vm.pop(); + let value = lhs.$op(&rhs, context)?; + context.vm.push(value); + Ok(ShouldExit::False) + } + } + }; +} + +implement_bin_ops!(Add, add); +implement_bin_ops!(Sub, sub); +implement_bin_ops!(Mul, mul); +implement_bin_ops!(Div, div); +implement_bin_ops!(Pow, pow); +implement_bin_ops!(Mod, rem); +implement_bin_ops!(BitAnd, bitand); +implement_bin_ops!(BitOr, bitor); +implement_bin_ops!(BitXor, bitxor); +implement_bin_ops!(ShiftLeft, shl); +implement_bin_ops!(ShiftRight, shr); +implement_bin_ops!(UnsignedShiftRight, ushr); +implement_bin_ops!(Eq, equals); +implement_bin_ops!(GreaterThan, gt); +implement_bin_ops!(GreaterThanOrEq, ge); +implement_bin_ops!(LessThan, lt); +implement_bin_ops!(LessThanOrEq, le); diff --git a/boa_engine/src/vm/opcode/generator/mod.rs b/boa_engine/src/vm/opcode/generator/mod.rs new file mode 100644 index 00000000000..140b4000854 --- /dev/null +++ b/boa_engine/src/vm/opcode/generator/mod.rs @@ -0,0 +1,215 @@ +use crate::{ + builtins::{ + async_generator::{AsyncGenerator, AsyncGeneratorState}, + iterable::IteratorRecord, + }, + vm::{ + call_frame::{FinallyReturn, GeneratorResumeKind}, + opcode::Operation, + ShouldExit, + }, + Context, JsResult, JsValue, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Yield; + +impl Operation for Yield { + const NAME: &'static str = "Yield"; + const INSTRUCTION: &'static str = "INST - Yield"; + + fn execute(context: &mut Context) -> JsResult { + Ok(ShouldExit::Yield) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct GeneratorNext; + +impl Operation for GeneratorNext { + const NAME: &'static str = "GeneratorNext"; + const INSTRUCTION: &'static str = "INST - GeneratorNext"; + + fn execute(context: &mut Context) -> JsResult { + match context.vm.frame().generator_resume_kind { + GeneratorResumeKind::Normal => return Ok(ShouldExit::False), + GeneratorResumeKind::Throw => { + let received = context.vm.pop(); + return Err(received); + } + GeneratorResumeKind::Return => { + let mut finally_left = false; + + while let Some(catch_addresses) = context.vm.frame().catch.last() { + if let Some(finally_address) = catch_addresses.finally { + let frame = context.vm.frame_mut(); + frame.pc = finally_address as usize; + frame.finally_return = FinallyReturn::Ok; + frame.catch.pop(); + finally_left = true; + break; + } + context.vm.frame_mut().catch.pop(); + } + + if finally_left { + return Ok(ShouldExit::False); + } + return Ok(ShouldExit::True); + } + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct AsyncGeneratorNext; + +impl Operation for AsyncGeneratorNext { + const NAME: &'static str = "AsyncGeneratorNext"; + const INSTRUCTION: &'static str = "INST - AsyncGeneratorNext"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + + if context.vm.frame().generator_resume_kind == GeneratorResumeKind::Throw { + return Err(value); + } + + let completion = Ok(value); + let generator_object = context + .vm + .frame() + .async_generator + .as_ref() + .expect("must be in generator context here") + .clone(); + let next = generator_object + .borrow_mut() + .as_async_generator_mut() + .expect("must be async generator object") + .queue + .pop_front() + .expect("must have item in queue"); + AsyncGenerator::complete_step(&next, completion, false, context); + + let mut generator_object_mut = generator_object.borrow_mut(); + let gen = generator_object_mut + .as_async_generator_mut() + .expect("must be async generator object"); + + 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), + } + context.vm.push(true); + } else { + context.vm.push(completion.clone()?); + context.vm.push(false); + } + + context.vm.push(false); + } else { + gen.state = AsyncGeneratorState::SuspendedYield; + context.vm.push(true); + context.vm.push(true); + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct GeneratorNextDelegate; + +impl Operation for GeneratorNextDelegate { + const NAME: &'static str = "GeneratorNextDelegate"; + const INSTRUCTION: &'static str = "INST - GeneratorNextDelegate"; + + fn execute(context: &mut Context) -> JsResult { + let done_address = context.vm.read::(); + let received = context.vm.pop(); + let done = context + .vm + .pop() + .as_boolean() + .expect("iterator [[Done]] was not a boolean"); + let next_method = context.vm.pop(); + let iterator = context.vm.pop(); + let iterator = iterator.as_object().expect("iterator was not an object"); + + match context.vm.frame().generator_resume_kind { + 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") + })?; + let done = result_object.get("done", context)?.to_boolean(); + if done { + context.vm.frame_mut().pc = done_address as usize; + let value = result_object.get("value", context)?; + context.vm.push(value); + return Ok(ShouldExit::False); + } + let value = result_object.get("value", context)?; + context.vm.push(iterator.clone()); + context.vm.push(next_method.clone()); + context.vm.push(done); + context.vm.push(value); + return Ok(ShouldExit::Yield); + } + GeneratorResumeKind::Throw => { + let throw = iterator.get_method("throw", context)?; + 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") + })?; + let done = result_object.get("done", context)?.to_boolean(); + if done { + context.vm.frame_mut().pc = done_address as usize; + let value = result_object.get("value", context)?; + context.vm.push(value); + return Ok(ShouldExit::False); + } + let value = result_object.get("value", context)?; + context.vm.push(iterator.clone()); + context.vm.push(next_method.clone()); + context.vm.push(done); + context.vm.push(value); + return Ok(ShouldExit::Yield); + } + 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"); + return Err(error); + } + 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") + })?; + let done = result_object.get("done", context)?.to_boolean(); + if done { + context.vm.frame_mut().pc = done_address as usize; + let value = result_object.get("value", context)?; + context.vm.push(value); + return Ok(ShouldExit::True); + } + let value = result_object.get("value", context)?; + context.vm.push(iterator.clone()); + context.vm.push(next_method.clone()); + context.vm.push(done); + context.vm.push(value); + return Ok(ShouldExit::Yield); + } + context.vm.frame_mut().pc = done_address as usize; + context.vm.push(received); + return Ok(ShouldExit::True); + } + } + } +} diff --git a/boa_engine/src/vm/opcode/get/function.rs b/boa_engine/src/vm/opcode/get/function.rs new file mode 100644 index 00000000000..5858f32188c --- /dev/null +++ b/boa_engine/src/vm/opcode/get/function.rs @@ -0,0 +1,36 @@ +use crate::{ + vm::{code_block::create_function_object, opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct GetFunction; + +impl Operation for GetFunction { + const NAME: &'static str = "GetFunction"; + const INSTRUCTION: &'static str = "INST - GetFunction"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let code = context.vm.frame().code.functions[index as usize].clone(); + let function = create_function_object(code, false, None, context); + context.vm.push(function); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct GetFunctionAsync; + +impl Operation for GetFunctionAsync { + const NAME: &'static str = "GetFunctionAsyn"; + const INSTRUCTION: &'static str = "INST - GetFunctionAsync"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let code = context.vm.frame().code.functions[index as usize].clone(); + let function = create_function_object(code, true, None, context); + context.vm.push(function); + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/get/generator.rs b/boa_engine/src/vm/opcode/get/generator.rs new file mode 100644 index 00000000000..ce345c25000 --- /dev/null +++ b/boa_engine/src/vm/opcode/get/generator.rs @@ -0,0 +1,36 @@ +use crate::{ + vm::{code_block::create_generator_function_object, opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct GetGenerator; + +impl Operation for GetGenerator { + const NAME: &'static str = "GetGenerator"; + const INSTRUCTION: &'static str = "INST - GetGenerator"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let code = context.vm.frame().code.functions[index as usize].clone(); + let function = create_generator_function_object(code, false, context); + context.vm.push(function); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct GetGeneratorAsync; + +impl Operation for GetGeneratorAsync { + const NAME: &'static str = "GetGeneratorAsync"; + const INSTRUCTION: &'static str = "INST - GetGeneratorAsync"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let code = context.vm.frame().code.functions[index as usize].clone(); + let function = create_generator_function_object(code, true, context); + context.vm.push(function); + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/get/mod.rs b/boa_engine/src/vm/opcode/get/mod.rs new file mode 100644 index 00000000000..a3f09232e5f --- /dev/null +++ b/boa_engine/src/vm/opcode/get/mod.rs @@ -0,0 +1,11 @@ +pub(crate) mod function; +pub(crate) mod generator; +pub(crate) mod name; +pub(crate) mod private; +pub(crate) mod property; + +pub(crate) use function::*; +pub(crate) use generator::*; +pub(crate) use name::*; +pub(crate) use private::*; +pub(crate) use property::*; diff --git a/boa_engine/src/vm/opcode/get/name.rs b/boa_engine/src/vm/opcode/get/name.rs new file mode 100644 index 00000000000..a97251b9a45 --- /dev/null +++ b/boa_engine/src/vm/opcode/get/name.rs @@ -0,0 +1,111 @@ +use crate::{ + property::DescriptorKind, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsString, JsValue, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct GetName; + +impl Operation for GetName { + const NAME: &'static str = "GetName"; + const INSTRUCTION: &'static str = "INST - GetName"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let binding_locator = context.vm.frame().code.bindings[index as usize]; + binding_locator.throw_mutate_immutable(context)?; + + let value = if binding_locator.is_global() { + if let Some(value) = context + .realm + .environments + .get_value_global_poisoned(binding_locator.name()) + { + value + } else { + let key: JsString = context + .interner() + .resolve_expect(binding_locator.name()) + .into(); + match context.global_bindings_mut().get(&key) { + Some(desc) => match desc.kind() { + DescriptorKind::Data { + value: Some(value), .. + } => value.clone(), + DescriptorKind::Accessor { get: Some(get), .. } if !get.is_undefined() => { + let get = get.clone(); + context.call(&get, &context.global_object().clone().into(), &[])? + } + _ => return context.throw_reference_error(format!("{key} is not defined")), + }, + _ => return context.throw_reference_error(format!("{key} is not defined")), + } + } + } else if let Some(value) = context.realm.environments.get_value_optional( + binding_locator.environment_index(), + binding_locator.binding_index(), + binding_locator.name(), + ) { + value + } else { + let name = JsString::from(context.interner().resolve_expect(binding_locator.name())); + return context.throw_reference_error(format!("{name} is not initialized")); + }; + + context.vm.push(value); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct GetNameOrUndefined; + +impl Operation for GetNameOrUndefined { + const NAME: &'static str = "GetNameOrUndefined"; + const INSTRUCTION: &'static str = "INST - GetNameOrUndefined"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let binding_locator = context.vm.frame().code.bindings[index as usize]; + binding_locator.throw_mutate_immutable(context)?; + let value = if binding_locator.is_global() { + if let Some(value) = context + .realm + .environments + .get_value_global_poisoned(binding_locator.name()) + { + value + } else { + let key: JsString = context + .interner() + .resolve_expect(binding_locator.name()) + .into(); + match context.global_bindings_mut().get(&key) { + Some(desc) => match desc.kind() { + DescriptorKind::Data { + value: Some(value), .. + } => value.clone(), + DescriptorKind::Accessor { get: Some(get), .. } if !get.is_undefined() => { + let get = get.clone(); + context.call(&get, &context.global_object().clone().into(), &[])? + } + _ => JsValue::undefined(), + }, + _ => JsValue::undefined(), + } + } + } else if let Some(value) = context.realm.environments.get_value_optional( + binding_locator.environment_index(), + binding_locator.binding_index(), + binding_locator.name(), + ) { + value + } else { + JsValue::undefined() + }; + + context.vm.push(value); + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/get/private.rs b/boa_engine/src/vm/opcode/get/private.rs new file mode 100644 index 00000000000..7c87f4878ee --- /dev/null +++ b/boa_engine/src/vm/opcode/get/private.rs @@ -0,0 +1,44 @@ +use crate::{ + object::PrivateElement, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct GetPrivateField; + +impl Operation for GetPrivateField { + const NAME: &'static str = "GetPrivateField"; + const INSTRUCTION: &'static str = "INST - GetPrivateField"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let name = context.vm.frame().code.names[index as usize]; + let value = context.vm.pop(); + if let Some(object) = value.as_object() { + let object_borrow_mut = object.borrow(); + if let Some(element) = object_borrow_mut.get_private_element(name) { + match element { + PrivateElement::Field(value) => context.vm.push(value), + PrivateElement::Method(method) => context.vm.push(method.clone()), + PrivateElement::Accessor { + getter: Some(getter), + setter: _, + } => { + let value = getter.call(&value, &[], context)?; + context.vm.push(value); + } + PrivateElement::Accessor { .. } => { + return context + .throw_type_error("private property was defined without a getter"); + } + } + } else { + return context.throw_type_error("private property does not exist"); + } + } else { + return context.throw_type_error("cannot read private property from non-object"); + } + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/get/property.rs b/boa_engine/src/vm/opcode/get/property.rs new file mode 100644 index 00000000000..7cccedb42a2 --- /dev/null +++ b/boa_engine/src/vm/opcode/get/property.rs @@ -0,0 +1,80 @@ +use crate::{ + property::PropertyKey, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsString, JsValue, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct GetPropertyByName; + +impl Operation for GetPropertyByName { + const NAME: &'static str = "GetPropertyName"; + const INSTRUCTION: &'static str = "INST - GetPropertyName"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + + let value = context.vm.pop(); + let object = if let Some(object) = value.as_object() { + object.clone() + } else { + value.to_object(context)? + }; + + let name = context.vm.frame().code.names[index as usize]; + let name: PropertyKey = context.interner().resolve_expect(name).into(); + let result = object.get(name, context)?; + + context.vm.push(result); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct GetPropertyByValue; + +impl Operation for GetPropertyByValue { + const NAME: &'static str = "GetPropertyByValue"; + const INSTRUCTION: &'static str = "INST - GetPropertyByValue"; + + fn execute(context: &mut Context) -> JsResult { + let object = context.vm.pop(); + let key = context.vm.pop(); + let object = if let Some(object) = object.as_object() { + object.clone() + } else { + object.to_object(context)? + }; + + let key = key.to_property_key(context)?; + let value = object.get(key, context)?; + + context.vm.push(value); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct GetPropertyByValuePush; + +impl Operation for GetPropertyByValuePush { + const NAME: &'static str = "GetPropertyByValuePush"; + const INSTRUCTION: &'static str = "INST - GetPropertyByValuePush"; + + fn execute(context: &mut Context) -> JsResult { + let object = context.vm.pop(); + let key = context.vm.pop(); + let object = if let Some(object) = object.as_object() { + object.clone() + } else { + object.to_object(context)? + }; + + let property_key = key.to_property_key(context)?; + let value = object.get(property_key, context)?; + + context.vm.push(key); + context.vm.push(value); + 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 new file mode 100644 index 00000000000..9cdb112d12f --- /dev/null +++ b/boa_engine/src/vm/opcode/iteration/for_await.rs @@ -0,0 +1,65 @@ +use crate::{ + builtins::iterable::IteratorResult, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct ForAwaitOfLoopIterate; + +impl Operation for ForAwaitOfLoopIterate { + const NAME: &'static str = "ForAwaitOfLoopIterate"; + const INSTRUCTION: &'static str = "INST - ForAwaitOfLoopIterate"; + + fn execute(context: &mut Context) -> JsResult { + let _done = context + .vm + .pop() + .as_boolean() + .expect("iterator [[Done]] was not a boolean"); + let next_method = context.vm.pop(); + 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"); + }; + let iterator = context.vm.pop(); + let next_result = next_method_object.call(&iterator, &[], context)?; + context.vm.push(iterator); + context.vm.push(next_method); + context.vm.push(next_result); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct ForAwaitOfLoopNext; + +impl Operation for ForAwaitOfLoopNext { + const NAME: &'static str = "ForAwaitOfLoopNext"; + const INSTRUCTION: &'static str = "INST - ForAwaitOfLoopNext"; + + fn execute(context: &mut Context) -> JsResult { + let address = context.vm.read::(); + + let next_result = context.vm.pop(); + 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"); + }; + + if next_result.complete(context)? { + context.vm.frame_mut().pc = address as usize; + context.vm.frame_mut().loop_env_stack_dec(); + context.vm.frame_mut().try_env_stack_dec(); + context.realm.environments.pop(); + context.vm.push(true); + } else { + context.vm.push(false); + let value = next_result.value(context)?; + context.vm.push(value); + } + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/iteration/for_in.rs b/boa_engine/src/vm/opcode/iteration/for_in.rs new file mode 100644 index 00000000000..d5d0d53df36 --- /dev/null +++ b/boa_engine/src/vm/opcode/iteration/for_in.rs @@ -0,0 +1,77 @@ +use crate::{ + builtins::{iterable::IteratorRecord, ForInIterator}, + property::PropertyDescriptor, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsValue, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct ForInLoopInitIterator; + +impl Operation for ForInLoopInitIterator { + const NAME: &'static str = "ForInLoopInitIterator"; + const INSTRUCTION: &'static str = "INST - ForInLoopInitIterator"; + + fn execute(context: &mut Context) -> JsResult { + let address = context.vm.read::(); + + let object = context.vm.pop(); + if object.is_null_or_undefined() { + context.vm.frame_mut().pc = address as usize; + return Ok(ShouldExit::False); + } + + let object = object.to_object(context)?; + let iterator = ForInIterator::create_for_in_iterator(JsValue::new(object), context); + let next_method = iterator + .get_property("next") + .as_ref() + .map(PropertyDescriptor::expect_value) + .cloned() + .ok_or_else(|| context.construct_type_error("Could not find property `next`"))?; + + context.vm.push(iterator); + context.vm.push(next_method); + context.vm.push(false); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct ForInLoopNext; + +impl Operation for ForInLoopNext { + const NAME: &'static str = "ForInLoopInitIterator"; + const INSTRUCTION: &'static str = "INST - ForInLoopInitIterator"; + + fn execute(context: &mut Context) -> JsResult { + let address = context.vm.read::(); + + let done = context + .vm + .pop() + .as_boolean() + .expect("iterator [[Done]] was not a boolean"); + let next_method = context.vm.pop(); + let iterator = context.vm.pop(); + let iterator = iterator.as_object().expect("iterator was not an object"); + + let iterator_record = IteratorRecord::new(iterator.clone(), next_method.clone(), done); + if let Some(next) = iterator_record.step(context)? { + context.vm.push(iterator.clone()); + context.vm.push(next_method); + context.vm.push(done); + let value = next.value(context)?; + context.vm.push(value); + } else { + context.vm.frame_mut().pc = address as usize; + context.vm.frame_mut().loop_env_stack_dec(); + context.vm.frame_mut().try_env_stack_dec(); + context.realm.environments.pop(); + context.vm.push(iterator.clone()); + context.vm.push(next_method); + context.vm.push(done); + } + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/iteration/init.rs b/boa_engine/src/vm/opcode/iteration/init.rs new file mode 100644 index 00000000000..9ecdbf6ffa2 --- /dev/null +++ b/boa_engine/src/vm/opcode/iteration/init.rs @@ -0,0 +1,39 @@ +use crate::{ + builtins::iterable::IteratorHint, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct InitIterator; + +impl Operation for InitIterator { + const NAME: &'static str = "InitIterator"; + const INSTRUCTION: &'static str = "INST - InitIterator"; + + fn execute(context: &mut Context) -> JsResult { + let object = context.vm.pop(); + let iterator = object.get_iterator(context, None, None)?; + context.vm.push(iterator.iterator().clone()); + context.vm.push(iterator.next_method().clone()); + context.vm.push(iterator.done()); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct InitIteratorAsync; + +impl Operation for InitIteratorAsync { + const NAME: &'static str = "InitIteratorAsync"; + const INSTRUCTION: &'static str = "INST - InitIteratorAsync"; + + fn execute(context: &mut Context) -> JsResult { + let object = context.vm.pop(); + let iterator = object.get_iterator(context, Some(IteratorHint::Async), None)?; + context.vm.push(iterator.iterator().clone()); + context.vm.push(iterator.next_method().clone()); + context.vm.push(iterator.done()); + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/iteration/iterator.rs b/boa_engine/src/vm/opcode/iteration/iterator.rs new file mode 100644 index 00000000000..896d296a312 --- /dev/null +++ b/boa_engine/src/vm/opcode/iteration/iterator.rs @@ -0,0 +1,97 @@ +use crate::{ + builtins::{iterable::IteratorRecord, Array}, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsValue, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct IteratorNext; + +impl Operation for IteratorNext { + const NAME: &'static str = "IteratorNext"; + const INSTRUCTION: &'static str = "INST - IteratorNext"; + + fn execute(context: &mut Context) -> JsResult { + let done = context + .vm + .pop() + .as_boolean() + .expect("iterator [[Done]] was not a boolean"); + let next_method = context.vm.pop(); + let iterator = context.vm.pop(); + let iterator = iterator.as_object().expect("iterator was not an object"); + + let iterator_record = IteratorRecord::new(iterator.clone(), next_method.clone(), done); + let next = iterator_record.step(context)?; + + context.vm.push(iterator.clone()); + context.vm.push(next_method); + if let Some(next) = next { + let value = next.value(context)?; + context.vm.push(false); + context.vm.push(value); + } else { + context.vm.push(true); + context.vm.push(JsValue::undefined()); + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct IteratorClose; + +impl Operation for IteratorClose { + const NAME: &'static str = "IteratorClose"; + const INSTRUCTION: &'static str = "INST - IteratorClose"; + + fn execute(context: &mut Context) -> JsResult { + let done = context + .vm + .pop() + .as_boolean() + .expect("iterator [[Done]] was not a boolean"); + let next_method = context.vm.pop(); + let iterator = context.vm.pop(); + let iterator = iterator.as_object().expect("iterator was not an object"); + if !done { + let iterator_record = IteratorRecord::new(iterator.clone(), next_method, done); + iterator_record.close(Ok(JsValue::Null), context)?; + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct IteratorToArray; + +impl Operation for IteratorToArray { + const NAME: &'static str = "IteratorToArray"; + const INSTRUCTION: &'static str = "INST - IteratorToArray"; + + fn execute(context: &mut Context) -> JsResult { + let done = context + .vm + .pop() + .as_boolean() + .expect("iterator [[Done]] was not a boolean"); + let next_method = context.vm.pop(); + let iterator = context.vm.pop(); + let iterator = iterator.as_object().expect("iterator was not an object"); + + let iterator_record = IteratorRecord::new(iterator.clone(), next_method.clone(), done); + let mut values = Vec::new(); + + while let Some(result) = iterator_record.step(context)? { + values.push(result.value(context)?); + } + + let array = Array::create_array_from_list(values, context); + + context.vm.push(iterator.clone()); + context.vm.push(next_method); + context.vm.push(true); + context.vm.push(array); + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/iteration/mod.rs b/boa_engine/src/vm/opcode/iteration/mod.rs new file mode 100644 index 00000000000..b1f04a726d7 --- /dev/null +++ b/boa_engine/src/vm/opcode/iteration/mod.rs @@ -0,0 +1,74 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +pub(crate) mod for_await; +pub(crate) mod for_in; +pub(crate) mod init; +pub(crate) mod iterator; + +pub(crate) use for_await::*; +pub(crate) use for_in::*; +pub(crate) use init::*; +pub(crate) use iterator::*; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct LoopStart; + +impl Operation for LoopStart { + const NAME: &'static str = "LoopStart"; + const INSTRUCTION: &'static str = "INST - LoopStart"; + + fn execute(context: &mut Context) -> JsResult { + context.vm.frame_mut().loop_env_stack.push(0); + context.vm.frame_mut().try_env_stack_loop_inc(); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct LoopContinue; + +impl Operation for LoopContinue { + const NAME: &'static str = "LoopContinue"; + const INSTRUCTION: &'static str = "INST - LoopContinue"; + + fn execute(context: &mut Context) -> JsResult { + let env_num = context + .vm + .frame_mut() + .loop_env_stack + .last_mut() + .expect("loop env stack entry must exist"); + let env_num_copy = *env_num; + *env_num = 0; + for _ in 0..env_num_copy { + context.realm.environments.pop(); + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct LoopEnd; + +impl Operation for LoopEnd { + const NAME: &'static str = "LoopEnd"; + const INSTRUCTION: &'static str = "INST - LoopEnd"; + + fn execute(context: &mut Context) -> JsResult { + let env_num = context + .vm + .frame_mut() + .loop_env_stack + .pop() + .expect("loop env stack entry must exist"); + for _ in 0..env_num { + context.realm.environments.pop(); + context.vm.frame_mut().try_env_stack_dec(); + } + context.vm.frame_mut().try_env_stack_loop_dec(); + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/mod.rs b/boa_engine/src/vm/opcode/mod.rs index 4a498f57aba..9d671efc664 100644 --- a/boa_engine/src/vm/opcode/mod.rs +++ b/boa_engine/src/vm/opcode/mod.rs @@ -1,27 +1,61 @@ /// The opcodes of the vm. -use crate::{ - vm::ShouldExit, - Context,JsResult -}; +use crate::{vm::ShouldExit, Context, JsResult}; // Operation modules -pub(crate) mod pop; +pub(crate) mod await_stm; +pub(crate) mod call; +pub(crate) mod concat; +pub(crate) mod conversion; +pub(crate) mod copy; +pub(crate) mod define; +pub(crate) mod delete; pub(crate) mod dup; -pub(crate) mod swap; +pub(crate) mod environment; +pub(crate) mod general; +pub(crate) mod generator; +pub(crate) mod get; +pub(crate) mod iteration; +pub(crate) mod new; +pub(crate) mod pop; +pub(crate) mod promise; pub(crate) mod push; +pub(crate) mod require; +pub(crate) mod rest_parameter; +pub(crate) mod return_stm; pub(crate) mod set; +pub(crate) mod swap; +pub(crate) mod switch; +pub(crate) mod throw; +pub(crate) mod try_catch; +pub(crate) mod value; // Operation structs -pub(crate) use pop::{Pop, PopIfThrown}; -pub(crate) use dup::Dup; -pub(crate) use swap::Swap; -pub(crate) use push::{ - PushUndefined, PushNull, PushTrue, PushFalse, - PushZero, PushOne, PushInt8, PushInt16, PushInt32, - PushRational, PushNaN, PushPositiveInfinity, PushNegativeInfinity, - PushLiteral, PushEmptyObject, PushClassPrototype -}; -pub(crate) use set::{SetClassPrototype, SetHomeObject}; +pub(crate) use await_stm::*; +pub(crate) use call::*; +pub(crate) use concat::*; +pub(crate) use conversion::*; +pub(crate) use copy::*; +pub(crate) use define::*; +pub(crate) use delete::*; +pub(crate) use dup::*; +pub(crate) use environment::*; +pub(crate) use general::*; +pub(crate) use generator::*; +pub(crate) use get::*; +pub(crate) use iteration::*; +pub(crate) use new::*; +pub(crate) use pop::*; +pub(crate) use promise::*; +pub(crate) use push::*; +pub(crate) use require::*; +pub(crate) use rest_parameter::*; +pub(crate) use return_stm::*; +pub(crate) use set::*; +pub(crate) use swap::*; +pub(crate) use switch::*; +pub(crate) use throw::*; +pub(crate) use try_catch::*; +pub(crate) use value::*; pub(crate) trait Operation { const NAME: &'static str; @@ -195,189 +229,189 @@ pub enum Opcode { /// Operands: /// /// Stack: **=>** `[]` - PushNewArray, + PushNewArray(PushNewArray), /// Push a value to an array. /// /// Operands: /// /// Stack: array, value **=>** array - PushValueToArray, + PushValueToArray(PushValueToArray), /// Push an empty element/hole to an array. /// /// Operands: /// /// Stack: array **=>** array - PushElisionToArray, + PushElisionToArray(PushElisionToArray), /// Push all iterator values to an array. /// /// Operands: /// /// Stack: array, iterator, next_method, done **=>** array - PushIteratorToArray, + PushIteratorToArray(PushIteratorToArray), /// Binary `+` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs + rhs) - Add, + Add(Add), /// Binary `-` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs - rhs) - Sub, + Sub(Sub), /// Binary `/` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs / rhs) - Div, + Div(Div), /// Binary `*` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs * rhs) - Mul, + Mul(Mul), /// Binary `%` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs % rhs) - Mod, + Mod(Mod), /// Binary `**` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs ** rhs) - Pow, + Pow(Pow), /// Binary `>>` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs >> rhs) - ShiftRight, + ShiftRight(ShiftRight), /// Binary `<<` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs << rhs) - ShiftLeft, + ShiftLeft(ShiftLeft), /// Binary `>>>` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs >>> rhs) - UnsignedShiftRight, + UnsignedShiftRight(UnsignedShiftRight), /// Binary bitwise `|` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs | rhs) - BitOr, + BitOr(BitOr), /// Binary bitwise `&` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs & rhs) - BitAnd, + BitAnd(BitAnd), /// Binary bitwise `^` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs ^ rhs) - BitXor, + BitXor(BitXor), /// Unary bitwise `~` operator. /// /// Operands: /// /// Stack: value **=>** ~value - BitNot, + BitNot(BitNot), /// Binary `in` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs `in` rhs) - In, + In(In), /// Binary `==` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs `==` rhs) - Eq, + Eq(Eq), /// Binary `===` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs `===` rhs) - StrictEq, + StrictEq(StrictEq), /// Binary `!=` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs `!=` rhs) - NotEq, + NotEq(NotEq), /// Binary `!==` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs `!==` rhs) - StrictNotEq, + StrictNotEq(StrictNotEq), /// Binary `>` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs > rhs) - GreaterThan, + GreaterThan(GreaterThan), /// Binary `>=` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs >= rhs) - GreaterThanOrEq, + GreaterThanOrEq(GreaterThanOrEq), /// Binary `<` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs < rhs) - LessThan, + LessThan(LessThan), /// Binary `<=` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs <= rhs) - LessThanOrEq, + LessThanOrEq(LessThanOrEq), /// Binary `instanceof` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs instanceof rhs) - InstanceOf, + InstanceOf(InstanceOf), /// Binary logical `&&` operator. /// @@ -386,7 +420,7 @@ pub enum Opcode { /// Operands: exit: `u32` /// /// Stack: lhs, rhs **=>** (lhs && rhs) - LogicalAnd, + LogicalAnd(LogicalAnd), /// Binary logical `||` operator. /// @@ -395,7 +429,7 @@ pub enum Opcode { /// Operands: exit: `u32` /// /// Stack: lhs, rhs **=>** (lhs || rhs) - LogicalOr, + LogicalOr(LogicalOr), /// Binary `??` operator. /// @@ -412,126 +446,126 @@ pub enum Opcode { /// Operands: /// /// Stack: value **=>** (`typeof` value) - TypeOf, + TypeOf(TypeOf), /// Unary `void` operator. /// /// Operands: /// /// Stack: value **=>** `undefined` - Void, + Void(Void), /// Unary logical `!` operator. /// /// Operands: /// /// Stack: value **=>** (!value) - LogicalNot, + LogicalNot(LogicalNot), /// Unary `+` operator. /// /// Operands: /// /// Stack: value **=>** (+value) - Pos, + Pos(Pos), /// Unary `-` operator. /// /// Operands: /// /// Stack: value **=>** (-value) - Neg, + Neg(Neg), /// Unary `++` operator. /// /// Operands: /// /// Stack: value **=>** (value + 1) - Inc, + Inc(Inc), /// Unary postfix `++` operator. /// /// Operands: /// /// Stack: value **=>** (ToNumeric(value)), (value + 1) - IncPost, + IncPost(IncPost), /// Unary `--` operator. /// /// Operands: /// /// Stack: value **=>** (value - 1) - Dec, + Dec(Dec), /// Unary postfix `--` operator. /// /// Operands: /// /// Stack: value **=>** (ToNumeric(value)), (value - 1) - DecPost, + DecPost(DecPost), /// Declare and initialize a function argument. /// /// Operands: name_index: `u32` /// /// Stack: value **=>** - DefInitArg, + DefInitArg(DefInitArg), /// Declare `var` type variable. /// /// Operands: name_index: `u32` /// /// Stack: **=>** - DefVar, + DefVar(DefVar), /// Declare and initialize `var` type variable. /// /// Operands: name_index: `u32` /// /// Stack: value, has_declarative_binding **=>** - DefInitVar, + DefInitVar(DefInitVar), /// Declare `let` type variable. /// /// Operands: name_index: `u32` /// /// Stack: **=>** - DefLet, + DefLet(DefLet), /// Declare and initialize `let` type variable. /// /// Operands: name_index: `u32` /// /// Stack: value **=>** - DefInitLet, + DefInitLet(DefInitLet), /// Declare and initialize `const` type variable. /// /// Operands: name_index: `u32` /// /// Stack: value **=>** - DefInitConst, + DefInitConst(DefInitConst), /// Find a binding on the environment chain and push its value. /// /// Operands: name_index: `u32` /// /// Stack: **=>** value - GetName, + GetName(GetName), /// Find a binding on the environment chain and push its value. If the binding does not exist push undefined. /// /// Operands: name_index: `u32` /// /// Stack: **=>** value - GetNameOrUndefined, + GetNameOrUndefined(GetNameOrUndefined), /// Find a binding on the environment chain and assign its value. /// /// Operands: name_index: `u32` /// /// Stack: value **=>** - SetName, + SetName(SetName), /// Get a property by name from an object an push it on the stack. /// @@ -540,7 +574,7 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: object **=>** value - GetPropertyByName, + GetPropertyByName(GetPropertyByName), /// Get a property by value from an object an push it on the stack. /// @@ -549,7 +583,7 @@ pub enum Opcode { /// Operands: /// /// Stack: key, object **=>** value - GetPropertyByValue, + GetPropertyByValue(GetPropertyByValue), /// Get a property by value from an object an push the key and value on the stack. /// @@ -558,7 +592,7 @@ pub enum Opcode { /// Operands: /// /// Stack: key, object **=>** key, value - GetPropertyByValuePush, + GetPropertyByValuePush(GetPropertyByValuePush), /// Sets a property by name of an object. /// @@ -567,21 +601,21 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: value, object **=>** - SetPropertyByName, + SetPropertyByName(SetPropertyByName), /// Defines a own property of an object by name. /// /// Operands: name_index: `u32` /// /// Stack: value, object **=>** - DefineOwnPropertyByName, + DefineOwnPropertyByName(DefineOwnPropertyByName), /// Defines a class method by name. /// /// Operands: name_index: `u32` /// /// Stack: value, object **=>** - DefineClassMethodByName, + DefineClassMethodByName(DefineClassMethodByName), /// Sets a property by value of an object. /// @@ -590,21 +624,21 @@ pub enum Opcode { /// Operands: /// /// Stack: value, key, object **=>** - SetPropertyByValue, + SetPropertyByValue(SetPropertyByValue), /// Defines a own property of an object by value. /// /// Operands: /// /// Stack: object, key, value **=>** - DefineOwnPropertyByValue, + DefineOwnPropertyByValue(DefineOwnPropertyByValue), /// Defines a class method by value. /// /// Operands: /// /// Stack: object, key, value **=>** - DefineClassMethodByValue, + DefineClassMethodByValue(DefineClassMethodByValue), /// Sets a getter property by name of an object. /// @@ -613,7 +647,7 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: value, object **=>** - SetPropertyGetterByName, + SetPropertyGetterByName(SetPropertyGetterByName), /// Defines a getter class method by name. /// @@ -622,7 +656,7 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: value, object **=>** - DefineClassGetterByName, + DefineClassGetterByName(DefineClassGetterByName), /// Sets a getter property by value of an object. /// @@ -631,7 +665,7 @@ pub enum Opcode { /// Operands: /// /// Stack: object, key, value **=>** - SetPropertyGetterByValue, + SetPropertyGetterByValue(SetPropertyGetterByValue), /// Defines a getter class method by value. /// @@ -640,7 +674,7 @@ pub enum Opcode { /// Operands: /// /// Stack: object, key, value **=>** - DefineClassGetterByValue, + DefineClassGetterByValue(DefineClassGetterByValue), /// Sets a setter property by name of an object. /// @@ -649,7 +683,7 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: value, object **=>** - SetPropertySetterByName, + SetPropertySetterByName(SetPropertySetterByName), /// Defines a setter class method by name. /// @@ -658,7 +692,7 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: value, object **=>** - DefineClassSetterByName, + DefineClassSetterByName(DefineClassSetterByName), /// Sets a setter property by value of an object. /// @@ -667,7 +701,7 @@ pub enum Opcode { /// Operands: /// /// Stack: object, key, value **=>** - SetPropertySetterByValue, + SetPropertySetterByValue(SetPropertySetterByValue), /// Defines a setter class method by value. /// @@ -676,7 +710,7 @@ pub enum Opcode { /// Operands: /// /// Stack: object, key, value **=>** - DefineClassSetterByValue, + DefineClassSetterByValue(DefineClassSetterByValue), /// Assign the value of a private property of an object by it's name. /// @@ -685,7 +719,7 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: object, value **=>** - AssignPrivateField, + AssignPrivateField(AssignPrivateField), /// Set a private property of a class constructor by it's name. /// @@ -694,7 +728,7 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: object, value **=>** - SetPrivateField, + SetPrivateField(SetPrivateField), /// Set a private method of a class constructor by it's name. /// @@ -703,7 +737,7 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: object, value **=>** - SetPrivateMethod, + SetPrivateMethod(SetPrivateMethod), /// Set a private setter property of a class constructor by it's name. /// @@ -712,7 +746,7 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: object, value **=>** - SetPrivateSetter, + SetPrivateSetter(SetPrivateSetter), /// Set a private getter property of a class constructor by it's name. /// @@ -721,7 +755,7 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: object, value **=>** - SetPrivateGetter, + SetPrivateGetter(SetPrivateGetter), /// Get a private property by name from an object an push it on the stack. /// @@ -730,42 +764,42 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: object **=>** value - GetPrivateField, + GetPrivateField(GetPrivateField), /// Push a field to a class. /// /// Operands: /// /// Stack: class, field_name, field_function **=>** - PushClassField, + PushClassField(PushClassField), /// Push a private field to the class. /// /// Operands: name_index: `u32` /// /// Stack: class, field_function **=>** - PushClassFieldPrivate, + PushClassFieldPrivate(PushClassFieldPrivate), /// Push a private getter to the class. /// /// Operands: name_index: `u32` /// /// Stack: class, getter **=>** - PushClassPrivateGetter, + PushClassPrivateGetter(PushClassPrivateGetter), /// Push a private setter to the class. /// /// Operands: name_index: `u32` /// /// Stack: class, setter **=>** - PushClassPrivateSetter, + PushClassPrivateSetter(PushClassPrivateSetter), /// Push a private method to the class. /// /// Operands: name_index: `u32` /// /// Stack: class, method **=>** - PushClassPrivateMethod, + PushClassPrivateMethod(PushClassPrivateMethod), /// Deletes a property by name of an object. /// @@ -774,7 +808,7 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: object **=>** - DeletePropertyByName, + DeletePropertyByName(DeletePropertyByName), /// Deletes a property by value of an object. /// @@ -783,28 +817,28 @@ pub enum Opcode { /// Operands: /// /// Stack: key, object **=>** - DeletePropertyByValue, + DeletePropertyByValue(DeletePropertyByValue), /// Copy all properties of one object to another object. /// /// Operands: excluded_key_count: `u32`, excluded_key_count_computed: `u32` /// /// Stack: excluded_key_computed_0 ... excluded_key_computed_n, source, value, excluded_key_0 ... excluded_key_n **=>** value - CopyDataProperties, + CopyDataProperties(CopyDataProperties), /// Call ToPropertyKey on the value on the stack. /// /// Operands: /// /// Stack: value **=>** key - ToPropertyKey, + ToPropertyKey(ToPropertyKey), /// Unconditional jump to address. /// /// Operands: address: `u32` /// /// Stack: **=>** - Jump, + Jump(Jump), /// Conditional jump to address. /// @@ -815,7 +849,7 @@ pub enum Opcode { /// Stack: cond **=>** /// /// [falsy]: https://developer.mozilla.org/en-US/docs/Glossary/Falsy - JumpIfFalse, + JumpIfFalse(Jump), /// Conditional jump to address. /// @@ -824,112 +858,112 @@ pub enum Opcode { /// Operands: address: `u32` /// /// Stack: value **=>** value - JumpIfNotUndefined, + JumpIfNotUndefined(Jump), /// Throw exception /// /// Operands: /// /// Stack: value **=>** - Throw, + Throw(Throw), /// Start of a try block. /// /// Operands: next_address: `u32`, finally_address: `u32` /// /// Stack: **=>** - TryStart, + TryStart(TryStart), /// End of a try block. /// /// Operands: /// /// Stack: **=>** - TryEnd, + TryEnd(TryEnd), /// Start of a catch block. /// /// Operands: /// /// Stack: **=>** - CatchStart, + CatchStart(CatchStart), /// End of a catch block. /// /// Operands: /// /// Stack: **=>** - CatchEnd, + CatchEnd(CatchEnd), /// End of a catch block. /// /// Operands: /// /// Stack: **=>** - CatchEnd2, + CatchEnd2(CatchEnd2), /// Start of a finally block. /// /// Operands: /// /// Stack: **=>** - FinallyStart, + FinallyStart(FinallyStart), /// End of a finally block. /// /// Operands: /// /// Stack: **=>** - FinallyEnd, + FinallyEnd(FinallyEnd), /// Set the address for a finally jump. /// /// Operands: /// /// Stack: **=>** - FinallySetJump, + FinallySetJump(FinallySetJump), /// Pops value converts it to boolean and pushes it back. /// /// Operands: /// /// Stack: value **=>** (`ToBoolean(value)`) - ToBoolean, + ToBoolean(ToBoolean), /// Pushes `this` value /// /// Operands: /// /// Stack: **=>** this - This, + This(This), /// Pushes the current `super` value to the stack. /// /// Operands: /// /// Stack: **=>** super - Super, + Super(Super), /// Execute the `super()` method. /// /// Operands: argument_count: `u32` /// /// Stack: argument_1, ... argument_n **=>** - SuperCall, + SuperCall(SuperCall), /// Execute the `super()` method where the arguments contain spreads. /// /// Operands: /// /// Stack: arguments_array **=>** - SuperCallSpread, + SuperCallSpread(SuperCallSpread), /// Execute the `super()` method when no constructor of the class is defined. /// /// Operands: /// /// Stack: argument_1, ... argument_n **=>** - SuperCallDerived, + SuperCallDerived(SuperCallDerived), /// Pop the two values of the stack, strict equal compares the two values, /// if true jumps to address, otherwise push the second pop'ed value. @@ -937,175 +971,175 @@ pub enum Opcode { /// Operands: address: `u32` /// /// Stack: value, cond **=>** cond (if `cond !== value`). - Case, + Case(Case), /// Pops the top of stack and jump to address. /// /// Operands: address: `u32` /// /// Stack: `value` **=>** - Default, + Default(Default), /// Get function from the pre-compiled inner functions. /// /// Operands: address: `u32` /// /// Stack: **=>** func - GetFunction, + GetFunction(GetFunction), /// Get async function from the pre-compiled inner functions. /// /// Operands: address: `u32` /// /// Stack: **=>** func - GetFunctionAsync, + GetFunctionAsync(GetFunctionAsync), /// Get generator function from the pre-compiled inner functions. /// /// Operands: address: `u32` /// /// Stack: **=>** func - GetGenerator, + GetGenerator(GetGenerator), /// Get async generator function from the pre-compiled inner functions. /// /// Operands: address: `u32` /// /// Stack: **=>** func - GetGeneratorAsync, + GetGeneratorAsync(GetGeneratorAsync), /// Call a function named "eval". /// /// Operands: argument_count: `u32` /// /// Stack: func, this, argument_1, ... argument_n **=>** result - CallEval, + CallEval(CallEval), /// Call a function named "eval" where the arguments contain spreads. /// /// Operands: /// /// Stack: arguments_array, func, this **=>** result - CallEvalSpread, + CallEvalSpread(CallEvalSpread), /// Call a function. /// /// Operands: argument_count: `u32` /// /// Stack: func, this, argument_1, ... argument_n **=>** result - Call, + Call(Call), /// Call a function where the arguments contain spreads. /// /// Operands: /// /// Stack: arguments_array, func, this **=>** result - CallSpread, + CallSpread(CallSpread), /// Call construct on a function. /// /// Operands: argument_count: `u32` /// /// Stack: func, argument_1, ... argument_n **=>** result - New, + New(New), /// Call construct on a function where the arguments contain spreads. /// /// Operands: /// /// Stack: arguments_array, func **=>** result - NewSpread, + NewSpread(NewSpread), /// Return from a function. /// /// Operands: /// /// Stack: **=>** - Return, + Return(Return), /// Push a declarative environment. /// /// Operands: num_bindings: `u32`, compile_environments_index: `u32` /// /// Stack: **=>** - PushDeclarativeEnvironment, + PushDeclarativeEnvironment(PushDeclarativeEnvironment), /// Push a function environment. /// /// Operands: num_bindings: `u32`, compile_environments_index: `u32` /// /// Stack: **=>** - PushFunctionEnvironment, + PushFunctionEnvironment(PushFunctionEnvironment), /// Pop the current environment. /// /// Operands: /// /// Stack: **=>** - PopEnvironment, + PopEnvironment(PopEnvironment), /// Push loop start marker. /// /// Operands: /// /// Stack: **=>** - LoopStart, + LoopStart(LoopStart), /// Clean up environments when a loop continues. /// /// Operands: /// /// Stack: **=>** - LoopContinue, + LoopContinue(LoopContinue), /// Clean up environments at the end of a loop. /// /// Operands: /// /// Stack: **=>** - LoopEnd, + LoopEnd(LoopEnd), /// Initialize the iterator for a for..in loop or jump to after the loop if object is null or undefined. /// /// Operands: address: `u32` /// /// Stack: object **=>** iterator, next_method, done - ForInLoopInitIterator, + ForInLoopInitIterator(ForInLoopInitIterator), /// Initialize an iterator. /// /// Operands: /// /// Stack: object **=>** iterator, next_method, done - InitIterator, + InitIterator(InitIterator), /// Initialize an async iterator. /// /// Operands: /// /// Stack: object **=>** iterator, next_method, done - InitIteratorAsync, + InitIteratorAsync(InitIteratorAsync), /// Advance the iterator by one and put the value on the stack. /// /// Operands: /// /// Stack: iterator, next_method, done **=>** iterator, next_method, done, next_value - IteratorNext, + IteratorNext(IteratorNext), /// Close an iterator. /// /// Operands: /// /// Stack: iterator, next_method, done **=>** - IteratorClose, + IteratorClose(IteratorClose), /// Consume the iterator and construct and array with all the values. /// /// Operands: /// /// Stack: iterator, next_method, done **=>** iterator, next_method, done, array - IteratorToArray, + IteratorToArray(IteratorToArray), /// Move to the next value in a for..in loop or jump to exit of the loop if done. /// @@ -1114,112 +1148,112 @@ pub enum Opcode { /// Operands: address: `u32` /// /// Stack: iterator, next_method, done **=>** iterator, next_method, done, next_result - ForInLoopNext, + ForInLoopNext(ForInLoopNext), /// Move to the next value in a for await..of loop. /// /// Operands: /// /// Stack: iterator, next_method, done **=>** iterator, next_method, next_result - ForAwaitOfLoopIterate, + ForAwaitOfLoopIterate(ForAwaitOfLoopIterate), /// Get the value from a for await..of loop next result. /// /// Operands: address: `u32` /// /// Stack: next_result **=>** done, value - ForAwaitOfLoopNext, + ForAwaitOfLoopNext(ForAwaitOfLoopNext), /// Concat multiple stack objects into a string. /// /// Operands: value_count: `u32` /// /// Stack: value_1,...value_n **=>** string - ConcatToString, + ConcatToString(ConcatToString), /// Call RequireObjectCoercible on the stack value. /// /// Operands: /// /// Stack: value **=>** value - RequireObjectCoercible, + RequireObjectCoercible(RequireObjectCoercible), /// Require the stack value to be neither null nor undefined. /// /// Operands: /// /// Stack: value **=>** value - ValueNotNullOrUndefined, + ValueNotNullOrUndefined(ValueNotNullOrUndefined), /// Initialize the rest parameter value of a function from the remaining arguments. /// /// Operands: /// /// Stack: `argument_1` .. `argument_n` **=>** `array` - RestParameterInit, + RestParameterInit(RestParameterInit), /// Pop the remaining arguments of a function. /// /// Operands: /// /// Stack: `argument_1` .. `argument_n` **=>** - RestParameterPop, + RestParameterPop(RestParameterPop), /// Add one to the pop on return count. /// /// Operands: /// /// Stack: **=>** - PopOnReturnAdd, + PopOnReturnAdd(PopOnReturnAdd), /// Subtract one from the pop on return count. /// /// Operands: /// /// Stack: **=>** - PopOnReturnSub, + PopOnReturnSub(PopOnReturnSub), /// Yield from the current execution. /// /// Operands: /// /// Stack: value **=>** - Yield, + Yield(Yield), /// Resumes the current generator function. /// /// Operands: /// /// Stack: received **=>** - GeneratorNext, + GeneratorNext(GeneratorNext), /// Resumes the current generator function. /// /// Operands: /// /// Stack: received **=>** Option, skip_0, skip_1 - AsyncGeneratorNext, + AsyncGeneratorNext(AsyncGeneratorNext), /// Delegates the current generator function another generator. /// /// Operands: done_address: `u32` /// /// Stack: iterator, next_method, done, received **=>** iterator, next_method, done - GeneratorNextDelegate, + GeneratorNextDelegate(GeneratorNextDelegate), /// Stops the current async function and schedules it to resume later. /// /// Operands: /// /// Stack: promise **=>** - Await, + Await(Await), /// Push the current new target to the stack. /// /// Operands: /// /// Stack: **=>** new_target - PushNewTarget, + PushNewTarget(PushNewTarget), /// No-operation instruction, does nothing. /// @@ -1228,7 +1262,7 @@ pub enum Opcode { /// Stack: **=>** // Safety: Must be last in the list since, we use this for range checking // in TryFrom impl. - Nop, + Nop(Nop), } impl Opcode { @@ -1265,146 +1299,146 @@ impl Opcode { Self::PushClassPrototype(op) => PushClassPrototype::NAME, Self::SetClassPrototype(op) => SetClassPrototype::NAME, Self::SetHomeObject(op) => SetHomeObject::NAME, - Self::PushNewArray => "PushNewArray", - Self::PushValueToArray => "PushValueToArray", - Self::PushElisionToArray => "PushElisionToArray", - Self::PushIteratorToArray => "PushIteratorToArray", - Self::Add => "Add", - Self::Sub => "Sub", - Self::Div => "Div", - Self::Mul => "Mul", - Self::Mod => "Mod", - Self::Pow => "Pow", - Self::ShiftRight => "ShiftRight", - Self::ShiftLeft => "ShiftLeft", - Self::UnsignedShiftRight => "UnsignedShiftRight", - Self::BitOr => "BitOr", - Self::BitAnd => "BitAnd", - Self::BitXor => "BitXor", - Self::BitNot => "BitNot", - Self::In => "In", - Self::Eq => "Eq", - Self::StrictEq => "StrictEq", - Self::NotEq => "NotEq", - Self::StrictNotEq => "StrictNotEq", - Self::GreaterThan => "GreaterThan", - Self::GreaterThanOrEq => "GreaterThanOrEq", - Self::LessThan => "LessThan", - Self::LessThanOrEq => "LessThanOrEq", - Self::InstanceOf => "InstanceOf", - Self::TypeOf => "TypeOf", - Self::Void => "Void", - Self::LogicalNot => "LogicalNot", - Self::LogicalAnd => "LogicalAnd", - Self::LogicalOr => "LogicalOr", - Self::Coalesce => "Coalesce", - Self::Pos => "Pos", - Self::Neg => "Neg", - Self::Inc => "Inc", - Self::IncPost => "IncPost", - Self::Dec => "Dec", - Self::DecPost => "DecPost", - Self::DefInitArg => "DefInitArg", - Self::DefVar => "DefVar", - Self::DefInitVar => "DefInitVar", - Self::DefLet => "DefLet", - Self::DefInitLet => "DefInitLet", - Self::DefInitConst => "DefInitConst", - Self::GetName => "GetName", - Self::GetNameOrUndefined => "GetNameOrUndefined", - Self::SetName => "SetName", - Self::GetPropertyByName => "GetPropertyByName", - Self::GetPropertyByValue => "GetPropertyByValue", - Self::GetPropertyByValuePush => "GetPropertyByValuePush", - Self::SetPropertyByName => "SetPropertyByName", - Self::DefineOwnPropertyByName => "DefineOwnPropertyByName", - Self::DefineClassMethodByName => "DefineClassMethodByName", - Self::SetPropertyByValue => "SetPropertyByValue", - Self::DefineOwnPropertyByValue => "DefineOwnPropertyByValue", - Self::DefineClassMethodByValue => "DefineClassMethodByValue", - Self::SetPropertyGetterByName => "SetPropertyGetterByName", - Self::DefineClassGetterByName => "DefineClassGetterByName", - Self::SetPropertyGetterByValue => "SetPropertyGetterByValue", - Self::DefineClassGetterByValue => "DefineClassGetterByValue", - Self::SetPropertySetterByName => "SetPropertySetterByName", - Self::DefineClassSetterByName => "DefineClassSetterByName", - Self::SetPropertySetterByValue => "SetPropertySetterByValue", - Self::DefineClassSetterByValue => "DefineClassSetterByValue", - Self::AssignPrivateField => "AssignPrivateField", - Self::SetPrivateField => "SetPrivateValue", - Self::SetPrivateMethod => "SetPrivateMethod", - Self::SetPrivateSetter => "SetPrivateSetter", - Self::SetPrivateGetter => "SetPrivateGetter", - Self::GetPrivateField => "GetPrivateField", - Self::PushClassField => "PushClassField", - Self::PushClassFieldPrivate => "PushClassFieldPrivate", - Self::PushClassPrivateGetter => "PushClassPrivateGetter", - Self::PushClassPrivateSetter => "PushClassPrivateSetter", - Self::PushClassPrivateMethod => "PushClassPrivateMethod", - Self::DeletePropertyByName => "DeletePropertyByName", - Self::DeletePropertyByValue => "DeletePropertyByValue", - Self::CopyDataProperties => "CopyDataProperties", - Self::ToPropertyKey => "ToPropertyKey", - Self::Jump => "Jump", - Self::JumpIfFalse => "JumpIfFalse", - Self::JumpIfNotUndefined => "JumpIfNotUndefined", - Self::Throw => "Throw", - Self::TryStart => "TryStart", - Self::TryEnd => "TryEnd", - Self::CatchStart => "CatchStart", - Self::CatchEnd => "CatchEnd", - Self::CatchEnd2 => "CatchEnd2", - Self::FinallyStart => "FinallyStart", - Self::FinallyEnd => "FinallyEnd", - Self::FinallySetJump => "FinallySetJump", - Self::ToBoolean => "ToBoolean", - Self::This => "This", - Self::Super => "Super", - Self::SuperCall => "SuperCall", - Self::SuperCallSpread => "SuperCallWithRest", - Self::SuperCallDerived => "SuperCallDerived", - Self::Case => "Case", - Self::Default => "Default", - Self::GetFunction => "GetFunction", - Self::GetFunctionAsync => "GetFunctionAsync", - Self::GetGenerator => "GetGenerator", - Self::GetGeneratorAsync => "GetGeneratorAsync", - Self::CallEval => "CallEval", - Self::CallEvalSpread => "CallEvalSpread", - Self::Call => "Call", - Self::CallSpread => "CallSpread", - Self::New => "New", - Self::NewSpread => "NewSpread", - Self::Return => "Return", - Self::PushDeclarativeEnvironment => "PushDeclarativeEnvironment", - Self::PushFunctionEnvironment => "PushFunctionEnvironment", - Self::PopEnvironment => "PopEnvironment", - Self::LoopStart => "LoopStart", - Self::LoopContinue => "LoopContinue", - Self::LoopEnd => "LoopEnd", - Self::ForInLoopInitIterator => "ForInLoopInitIterator", - Self::InitIterator => "InitIterator", - Self::InitIteratorAsync => "InitIteratorAsync", - Self::IteratorNext => "IteratorNext", - Self::IteratorClose => "IteratorClose", - Self::IteratorToArray => "IteratorToArray", - Self::ForInLoopNext => "ForInLoopNext", - Self::ForAwaitOfLoopNext => "ForAwaitOfLoopNext", - Self::ForAwaitOfLoopIterate => "ForAwaitOfLoopIterate", - Self::ConcatToString => "ConcatToString", - Self::RequireObjectCoercible => "RequireObjectCoercible", - Self::ValueNotNullOrUndefined => "ValueNotNullOrUndefined", - Self::RestParameterInit => "FunctionRestParameter", - Self::RestParameterPop => "RestParameterPop", - Self::PopOnReturnAdd => "PopOnReturnAdd", - Self::PopOnReturnSub => "PopOnReturnSub", - Self::Yield => "Yield", - Self::GeneratorNext => "GeneratorNext", - Self::AsyncGeneratorNext => "AsyncGeneratorNext", - Self::Await => "Await", - Self::PushNewTarget => "PushNewTarget", - Self::GeneratorNextDelegate => "GeneratorNextDelegate", - Self::Nop => "Nop", + Self::PushNewArray(op) => PushNewArray::NAME, + Self::PushValueToArray(op) => PushValueToArray::NAME, + Self::PushElisionToArray(op) => PushElisionToArray::NAME, + Self::PushIteratorToArray(op) => PushIteratorToArray::NAME, + Self::Add(op) => Add::NAME, + Self::Sub(op) => Sub::NAME, + Self::Div(op) => Div::NAME, + Self::Mul(op) => Mul::NAME, + Self::Mod(op) => Mod::NAME, + Self::Pow(op) => Pow::NAME, + Self::ShiftRight(op) => ShiftRight::NAME, + Self::ShiftLeft(op) => ShiftLeft::NAME, + Self::UnsignedShiftRight(op) => UnsignedShiftRight::NAME, + Self::BitOr(op) => BitOr::NAME, + Self::BitAnd(op) => BitAnd::NAME, + Self::BitXor(op) => BitXor::NAME, + Self::BitNot(op) => "BitNot", + Self::In(op) => "In", + Self::Eq(op) => Eq::NAME, + Self::StrictEq(op) => "StrictEq", + Self::NotEq(op) => "NotEq", + Self::StrictNotEq(op) => "StrictNotEq", + Self::GreaterThan(op) => GreaterThan::NAME, + Self::GreaterThanOrEq(op) => GreaterThanOrEq::NAME, + Self::LessThan(op) => LessThan::NAME, + Self::LessThanOrEq(op) => LessThanOrEq::NAME, + Self::InstanceOf(op) => InstanceOf::NAME, + Self::TypeOf(op) => TypeOf::NAME, + Self::Void(op) => Void::NAME, + Self::LogicalNot(op) => LogicalNot::NAME, + Self::LogicalAnd(op) => "LogicalAnd", + Self::LogicalOr(op) => "LogicalOr", + Self::Coalesce(op) => "Coalesce", + Self::Pos(op) => Pos::NAME, + Self::Neg(op) => Neg::NAME, + Self::Inc(op) => Inc::NAME, + Self::IncPost(op) => IncPost::NAME, + Self::Dec(op) => Dec::NAME, + Self::DecPost(op) => DecPost::NAME, + Self::DefInitArg(op) => DefInitArg::NAME, + Self::DefVar(op) => DefVar::NAME, + Self::DefInitVar(op) => DefInitVar::NAME, + Self::DefLet(op) => DefLet::NAME, + Self::DefInitLet(op) => DefInitLet::NAME, + Self::DefInitConst(op) => DefInitConst::NAME, + Self::GetName(op) => GetName::NAME, + Self::GetNameOrUndefined(op) => GetNameOrUndefined::NAME, + Self::SetName(op) => SetName::NAME, + Self::GetPropertyByName(op) => GetPropertyByName::NAME, + Self::GetPropertyByValue(op) => GetPropertyByValue::NAME, + Self::GetPropertyByValuePush(op) => GetPropertyByValuePush::NAME, + Self::SetPropertyByName(op) => "SetPropertyByName", + Self::DefineOwnPropertyByName(op) => "DefineOwnPropertyByName", + Self::DefineClassMethodByName(op) => "DefineClassMethodByName", + Self::SetPropertyByValue(op) => "SetPropertyByValue", + Self::DefineOwnPropertyByValue(op) => "DefineOwnPropertyByValue", + Self::DefineClassMethodByValue(op) => "DefineClassMethodByValue", + Self::SetPropertyGetterByName(op) => "SetPropertyGetterByName", + Self::DefineClassGetterByName(op) => "DefineClassGetterByName", + Self::SetPropertyGetterByValue(op) => "SetPropertyGetterByValue", + Self::DefineClassGetterByValue(op) => "DefineClassGetterByValue", + Self::SetPropertySetterByName(op) => "SetPropertySetterByName", + Self::DefineClassSetterByName(op) => "DefineClassSetterByName", + Self::SetPropertySetterByValue(op) => "SetPropertySetterByValue", + Self::DefineClassSetterByValue(op) => "DefineClassSetterByValue", + Self::AssignPrivateField(op) => "AssignPrivateField", + Self::SetPrivateField(op) => "SetPrivateValue", + Self::SetPrivateMethod(op) => "SetPrivateMethod", + Self::SetPrivateSetter(op) => "SetPrivateSetter", + Self::SetPrivateGetter(op) => "SetPrivateGetter", + Self::GetPrivateField(op) => "GetPrivateField", + Self::PushClassField(op) => "PushClassField", + Self::PushClassFieldPrivate(op) => "PushClassFieldPrivate", + Self::PushClassPrivateGetter(op) => "PushClassPrivateGetter", + Self::PushClassPrivateSetter(op) => "PushClassPrivateSetter", + Self::PushClassPrivateMethod(op) => "PushClassPrivateMethod", + Self::DeletePropertyByName(op) => "DeletePropertyByName", + Self::DeletePropertyByValue(op) => "DeletePropertyByValue", + Self::CopyDataProperties(op) => "CopyDataProperties", + Self::ToPropertyKey(op) => "ToPropertyKey", + Self::Jump(op) => Jump::NAME, + Self::JumpIfFalse(op) => JumpIfFalse::NAME, + Self::JumpIfNotUndefined(op) => JumpIfNotUndefined::NAME, + Self::Throw(op) => "Throw", + Self::TryStart(op) => "TryStart", + Self::TryEnd(op) => "TryEnd", + Self::CatchStart(op) => "CatchStart", + Self::CatchEnd(op) => "CatchEnd", + Self::CatchEnd2(op) => "CatchEnd2", + Self::FinallyStart(op) => "FinallyStart", + Self::FinallyEnd(op) => "FinallyEnd", + Self::FinallySetJump(op) => "FinallySetJump", + Self::ToBoolean(op) => "ToBoolean", + Self::This(op) => "This", + Self::Super(op) => "Super", + Self::SuperCall(op) => "SuperCall", + Self::SuperCallSpread(op) => "SuperCallWithRest", + Self::SuperCallDerived(op) => "SuperCallDerived", + Self::Case(op) => "Case", + Self::Default(op) => "Default", + Self::GetFunction(op) => "GetFunction", + Self::GetFunctionAsync(op) => "GetFunctionAsync", + Self::GetGenerator(op) => "GetGenerator", + Self::GetGeneratorAsync(op) => "GetGeneratorAsync", + Self::CallEval(op) => "CallEval", + Self::CallEvalSpread(op) => "CallEvalSpread", + Self::Call(op) => "Call", + Self::CallSpread(op) => "CallSpread", + Self::New(op) => "New", + Self::NewSpread(op) => "NewSpread", + Self::Return(op) => "Return", + Self::PushDeclarativeEnvironment(op) => "PushDeclarativeEnvironment", + Self::PushFunctionEnvironment(op) => "PushFunctionEnvironment", + Self::PopEnvironment(op) => "PopEnvironment", + Self::LoopStart(op) => "LoopStart", + Self::LoopContinue(op) => "LoopContinue", + Self::LoopEnd(op) => "LoopEnd", + Self::ForInLoopInitIterator(op) => "ForInLoopInitIterator", + Self::InitIterator(op) => "InitIterator", + Self::InitIteratorAsync(op) => "InitIteratorAsync", + Self::IteratorNext(op) => "IteratorNext", + Self::IteratorClose(op) => "IteratorClose", + Self::IteratorToArray(op) => "IteratorToArray", + Self::ForInLoopNext(op) => "ForInLoopNext", + Self::ForAwaitOfLoopNext(op) => "ForAwaitOfLoopNext", + Self::ForAwaitOfLoopIterate(op) => "ForAwaitOfLoopIterate", + Self::ConcatToString(op) => "ConcatToString", + Self::RequireObjectCoercible(op) => "RequireObjectCoercible", + Self::ValueNotNullOrUndefined(op) => "ValueNotNullOrUndefined", + Self::RestParameterInit(op) => "FunctionRestParameter", + Self::RestParameterPop(op) => "RestParameterPop", + Self::PopOnReturnAdd(op) => "PopOnReturnAdd", + Self::PopOnReturnSub(op) => "PopOnReturnSub", + Self::Yield(op) => "Yield", + Self::GeneratorNext(op) => "GeneratorNext", + Self::AsyncGeneratorNext(op) => "AsyncGeneratorNext", + Self::Await(op) => "Await", + Self::PushNewTarget(op) => "PushNewTarget", + Self::GeneratorNextDelegate(op) => "GeneratorNextDelegate", + Self::Nop(op) => "Nop", } } @@ -1414,12 +1448,12 @@ impl Opcode { Self::Pop(op) => Pop::INSTRUCTION, Self::PopIfThrown(op) => PopIfThrown::INSTRUCTION, Self::Dup(op) => Dup::INSTRUCTION, - Self::Swap(op) => Swap::INSTRUCTION, + Self::Swap(op) => Swap::INSTRUCTION, Self::PushZero(op) => PushZero::INSTRUCTION, Self::PushOne(op) => PushOne::INSTRUCTION, - Self::PushInt8(op) => PushInt8::INSTRUCTION, - Self::PushInt16(op) => PushInt16::INSTRUCTION, - Self::PushInt32(op) => PushInt32::INSTRUCTION, + Self::PushInt8(op) => PushInt8::INSTRUCTION, + Self::PushInt16(op) => PushInt16::INSTRUCTION, + Self::PushInt32(op) => PushInt32::INSTRUCTION, Self::PushRational(op) => PushRational::INSTRUCTION, Self::PushNaN(op) => PushNaN::INSTRUCTION, Self::PushPositiveInfinity(op) => PushPositiveInfinity::INSTRUCTION, @@ -1428,151 +1462,151 @@ impl Opcode { Self::PushTrue(op) => PushTrue::INSTRUCTION, Self::PushFalse(op) => PushFalse::INSTRUCTION, Self::PushUndefined(op) => PushUndefined::INSTRUCTION, - Self::PushLiteral(op) => PushLiteral::INSTRUCTION, + Self::PushLiteral(op) => PushLiteral::INSTRUCTION, Self::PushEmptyObject(op) => PushEmptyObject::INSTRUCTION, - Self::PushNewArray => "INST - PushNewArray", - Self::PushValueToArray => "INST - PushValueToArray", - Self::PushElisionToArray => "INST - PushElisionToArray", - Self::PushIteratorToArray => "INST - PushIteratorToArray", - Self::Add => "INST - Add", - Self::Sub => "INST - Sub", - Self::Div => "INST - Div", - Self::Mul => "INST - Mul", - Self::Mod => "INST - Mod", - Self::Pow => "INST - Pow", - Self::ShiftRight => "INST - ShiftRight", - Self::ShiftLeft => "INST - ShiftLeft", - Self::UnsignedShiftRight => "INST - UnsignedShiftRight", - Self::BitOr => "INST - BitOr", - Self::BitAnd => "INST - BitAnd", - Self::BitXor => "INST - BitXor", - Self::BitNot => "INST - BitNot", - Self::In => "INST - In", - Self::Eq => "INST - Eq", - Self::StrictEq => "INST - StrictEq", - Self::NotEq => "INST - NotEq", - Self::StrictNotEq => "INST - StrictNotEq", - Self::GreaterThan => "INST - GreaterThan", - Self::GreaterThanOrEq => "INST - GreaterThanOrEq", - Self::LessThan => "INST - LessThan", - Self::LessThanOrEq => "INST - LessThanOrEq", - Self::InstanceOf => "INST - InstanceOf", - Self::TypeOf => "INST - TypeOf", - Self::Void => "INST - Void", - Self::LogicalNot => "INST - LogicalNot", - Self::LogicalAnd => "INST - LogicalAnd", - Self::LogicalOr => "INST - LogicalOr", - Self::Coalesce => "INST - Coalesce", - Self::Pos => "INST - Pos", - Self::Neg => "INST - Neg", - Self::Inc => "INST - Inc", - Self::IncPost => "INST - IncPost", - Self::Dec => "INST - Dec", - Self::DecPost => "INST - DecPost", - Self::DefInitArg => "INST - DefInitArg", - Self::DefVar => "INST - DefVar", - Self::DefInitVar => "INST - DefInitVar", - Self::DefLet => "INST - DefLet", - Self::DefInitLet => "INST - DefInitLet", - Self::DefInitConst => "INST - DefInitConst", - Self::GetName => "INST - GetName", - Self::GetNameOrUndefined => "INST - GetNameOrUndefined", - Self::SetName => "INST - SetName", - Self::GetPropertyByName => "INST - GetPropertyByName", - Self::GetPropertyByValue => "INST - GetPropertyByValue", - Self::GetPropertyByValuePush => "INST - GetPropertyByValuePush", - Self::SetPropertyByName => "INST - SetPropertyByName", - Self::DefineOwnPropertyByName => "INST - DefineOwnPropertyByName", - Self::SetPropertyByValue => "INST - SetPropertyByValue", - Self::DefineOwnPropertyByValue => "INST - DefineOwnPropertyByValue", - Self::SetPropertyGetterByName => "INST - SetPropertyGetterByName", - Self::SetPropertyGetterByValue => "INST - SetPropertyGetterByValue", - Self::SetPropertySetterByName => "INST - SetPropertySetterByName", - Self::SetPropertySetterByValue => "INST - SetPropertySetterByValue", - Self::DeletePropertyByName => "INST - DeletePropertyByName", - Self::DeletePropertyByValue => "INST - DeletePropertyByValue", - Self::CopyDataProperties => "INST - CopyDataProperties", - Self::Jump => "INST - Jump", - Self::JumpIfFalse => "INST - JumpIfFalse", - Self::JumpIfNotUndefined => "INST - JumpIfNotUndefined", - Self::Throw => "INST - Throw", - Self::TryStart => "INST - TryStart", - Self::TryEnd => "INST - TryEnd", - Self::CatchStart => "INST - CatchStart", - Self::CatchEnd => "INST - CatchEnd", - Self::CatchEnd2 => "INST - CatchEnd2", - Self::FinallyStart => "INST - FinallyStart", - Self::FinallyEnd => "INST - FinallyEnd", - Self::FinallySetJump => "INST - FinallySetJump", - Self::ToBoolean => "INST - ToBoolean", - Self::This => "INST - This", - Self::Super => "INST - Super", - Self::SuperCall => "INST - SuperCall", - Self::SuperCallSpread => "INST - SuperCallWithRest", - Self::SuperCallDerived => "INST - SuperCallDerived", - Self::Case => "INST - Case", - Self::Default => "INST - Default", - Self::GetFunction => "INST - GetFunction", - Self::GetFunctionAsync => "INST - GetFunctionAsync", - Self::GetGenerator => "INST - GetGenerator", - Self::GetGeneratorAsync => "INST - GetGeneratorAsync", - Self::CallEval => "INST - CallEval", - Self::CallEvalSpread => "INST - CallEvalSpread", - Self::Call => "INST - Call", - Self::CallSpread => "INST - CallSpread", - Self::New => "INST - New", - Self::NewSpread => "INST - NewSpread", - Self::Return => "INST - Return", - Self::PushDeclarativeEnvironment => "INST - PushDeclarativeEnvironment", - Self::PushFunctionEnvironment => "INST - PushFunctionEnvironment", - Self::PopEnvironment => "INST - PopEnvironment", - Self::LoopStart => "INST - LoopStart", - Self::LoopContinue => "INST - LoopContinue", - Self::LoopEnd => "INST - LoopEnd", - Self::ForInLoopInitIterator => "INST - ForInLoopInitIterator", - Self::InitIterator => "INST - InitIterator", - Self::InitIteratorAsync => "INST - InitIteratorAsync", - Self::IteratorNext => "INST - IteratorNext", - Self::IteratorClose => "INST - IteratorClose", - Self::IteratorToArray => "INST - IteratorToArray", - Self::ForInLoopNext => "INST - ForInLoopNext", - Self::ForAwaitOfLoopIterate => "INST - ForAwaitOfLoopIterate", - Self::ForAwaitOfLoopNext => "INST - ForAwaitOfLoopNext", - Self::ConcatToString => "INST - ConcatToString", - Self::RequireObjectCoercible => "INST - RequireObjectCoercible", - Self::ValueNotNullOrUndefined => "INST - ValueNotNullOrUndefined", - Self::RestParameterInit => "INST - FunctionRestParameter", - Self::RestParameterPop => "INST - RestParameterPop", - Self::PopOnReturnAdd => "INST - PopOnReturnAdd", - Self::PopOnReturnSub => "INST - PopOnReturnSub", - Self::Yield => "INST - Yield", - Self::GeneratorNext => "INST - GeneratorNext", - Self::AsyncGeneratorNext => "INST - AsyncGeneratorNext", - Self::PushNewTarget => "INST - PushNewTarget", - Self::Await => "INST - Await", - Self::GeneratorNextDelegate => "INST - GeneratorNextDelegate", - Self::Nop => "INST - Nop", + Self::PushNewArray(op) => PushNewArray::INSTRUCTION, + Self::PushValueToArray(op) => PushValueToArray::INSTRUCTION, + Self::PushElisionToArray(op) => PushElisionToArray::INSTRUCTION, + Self::PushIteratorToArray(op) => PushIteratorToArray::INSTRUCTION, + Self::Add(op) => Add::INSTRUCTION, + Self::Sub(op) => Sub::INSTRUCTION, + Self::Div(op) => Div::INSTRUCTION, + Self::Mul(op) => Mul::INSTRUCTION, + Self::Mod(op) => Mod::INSTRUCTION, + Self::Pow(op) => Pow::INSTRUCTION, + Self::ShiftRight(op) => ShiftRight::INSTRUCTION, + Self::ShiftLeft(op) => ShiftLeft::INSTRUCTION, + Self::UnsignedShiftRight(op) => UnsignedShiftRight::INSTRUCTION, + Self::BitOr(op) => BitOr::INSTRUCTION, + Self::BitAnd(op) => BitAnd::INSTRUCTION, + Self::BitXor(op) => BitXor::INSTRUCTION, + Self::BitNot(op) => BitNot::INSTRUCTION, + Self::In(op) => In::INSTRUCTION, + Self::Eq(op) => Eq::INSTRUCTION, + Self::StrictEq(op) => StrictEq::INSTRUCTION, + Self::NotEq(op) => NotEq::INSTRUCTION, + Self::StrictNotEq(op) => StrictNotEq::INSTRUCTION, + Self::GreaterThan(op) => GreaterThan::INSTRUCTION, + Self::GreaterThanOrEq(op) => GreaterThanOrEq::INSTRUCTION, + Self::LessThan(op) => LessThan::INSTRUCTION, + Self::LessThanOrEq(op) => LessThanOrEq::INSTRUCTION, + Self::InstanceOf(op) => InstanceOf::INSTRUCTION, + Self::TypeOf(op) => TypeOf::INSTRUCTION, + Self::Void(op) => Void::INSTRUCTION, + Self::LogicalNot(op) => LogicalNot::INSTRUCTION, + Self::LogicalAnd(op) => "INST - LogicalAnd", + Self::LogicalOr(op) => "INST - LogicalOr", + Self::Coalesce(op) => "INST - Coalesce", + Self::Pos(op) => Pos::INSTRUCTION, + Self::Neg(op) => Neg::INSTRUCTION, + Self::Inc(op) => Inc::INSTRUCTION, + Self::IncPost(op) => IncPost::INSTRUCTION, + Self::Dec(op) => Dec::INSTRUCTION, + Self::DecPost(op) => DecPost::INSTRUCTION, + Self::DefInitArg(op) => DefInitArg::INSTRUCTION, + Self::DefVar(op) => DefVar::INSTRUCTION, + Self::DefInitVar(op) => DefInitVar::INSTRUCTION, + Self::DefLet(op) => DefLet::INSTRUCTION, + Self::DefInitLet(op) => DefInitLet::INSTRUCTION, + Self::DefInitConst(op) => DefInitConst::INSTRUCTION, + Self::GetName(op) => GetName::INSTRUCTION, + Self::GetNameOrUndefined(op) => GetNameOrUndefined::INSTRUCTION, + Self::SetName(op) => SetName::INSTRUCTION, + Self::GetPropertyByName(op) => GetPropertyByName::INSTRUCTION, + Self::GetPropertyByValue(op) => GetPropertyByValue::INSTRUCTION, + Self::GetPropertyByValuePush(op) => GetPropertyByValuePush::INSTRUCTION, + Self::SetPropertyByName(op) => "INST - SetPropertyByName", + Self::DefineOwnPropertyByName(op) => "INST - DefineOwnPropertyByName", + Self::SetPropertyByValue(op) => "INST - SetPropertyByValue", + Self::DefineOwnPropertyByValue(op) => "INST - DefineOwnPropertyByValue", + Self::SetPropertyGetterByName(op) => "INST - SetPropertyGetterByName", + Self::SetPropertyGetterByValue(op) => "INST - SetPropertyGetterByValue", + Self::SetPropertySetterByName(op) => "INST - SetPropertySetterByName", + Self::SetPropertySetterByValue(op) => "INST - SetPropertySetterByValue", + Self::DeletePropertyByName(op) => "INST - DeletePropertyByName", + Self::DeletePropertyByValue(op) => "INST - DeletePropertyByValue", + Self::CopyDataProperties(op) => "INST - CopyDataProperties", + Self::Jump(op) => Jump::INSTRUCTION, + Self::JumpIfFalse(op) => JumpIfFalse::INSTRUCTION, + Self::JumpIfNotUndefined(op) => JumpIfNotUndefined::INSTRUCTION, + Self::Throw(op) => "INST - Throw", + Self::TryStart(op) => "INST - TryStart", + Self::TryEnd(op) => "INST - TryEnd", + Self::CatchStart(op) => "INST - CatchStart", + Self::CatchEnd(op) => "INST - CatchEnd", + Self::CatchEnd2(op) => "INST - CatchEnd2", + Self::FinallyStart(op) => "INST - FinallyStart", + Self::FinallyEnd(op) => "INST - FinallyEnd", + Self::FinallySetJump(op) => "INST - FinallySetJump", + Self::ToBoolean(op) => "INST - ToBoolean", + Self::This(op) => "INST - This", + Self::Super(op) => "INST - Super", + Self::SuperCall(op) => "INST - SuperCall", + Self::SuperCallSpread(op) => "INST - SuperCallWithRest", + Self::SuperCallDerived(op) => "INST - SuperCallDerived", + Self::Case(op) => "INST - Case", + Self::Default(op) => "INST - Default", + Self::GetFunction(op) => "INST - GetFunction", + Self::GetFunctionAsync(op) => "INST - GetFunctionAsync", + Self::GetGenerator(op) => "INST - GetGenerator", + Self::GetGeneratorAsync(op) => "INST - GetGeneratorAsync", + Self::CallEval(op) => "INST - CallEval", + Self::CallEvalSpread(op) => "INST - CallEvalSpread", + Self::Call(op) => "INST - Call", + Self::CallSpread(op) => "INST - CallSpread", + Self::New(op) => "INST - New", + Self::NewSpread(op) => "INST - NewSpread", + Self::Return(op) => "INST - Return", + Self::PushDeclarativeEnvironment(op) => "INST - PushDeclarativeEnvironment", + Self::PushFunctionEnvironment(op) => "INST - PushFunctionEnvironment", + Self::PopEnvironment(op) => "INST - PopEnvironment", + Self::LoopStart(op) => "INST - LoopStart", + Self::LoopContinue(op) => "INST - LoopContinue", + Self::LoopEnd(op) => "INST - LoopEnd", + Self::ForInLoopInitIterator(op) => "INST - ForInLoopInitIterator", + Self::InitIterator(op) => "INST - InitIterator", + Self::InitIteratorAsync(op) => "INST - InitIteratorAsync", + Self::IteratorNext(op) => "INST - IteratorNext", + Self::IteratorClose(op) => "INST - IteratorClose", + Self::IteratorToArray(op) => "INST - IteratorToArray", + Self::ForInLoopNext(op) => "INST - ForInLoopNext", + Self::ForAwaitOfLoopIterate(op) => "INST - ForAwaitOfLoopIterate", + Self::ForAwaitOfLoopNext(op) => "INST - ForAwaitOfLoopNext", + Self::ConcatToString(op) => "INST - ConcatToString", + Self::RequireObjectCoercible(op) => "INST - RequireObjectCoercible", + Self::ValueNotNullOrUndefined(op) => "INST - ValueNotNullOrUndefined", + Self::RestParameterInit(op) => "INST - FunctionRestParameter", + Self::RestParameterPop(op) => "INST - RestParameterPop", + Self::PopOnReturnAdd(op) => "INST - PopOnReturnAdd", + Self::PopOnReturnSub(op) => "INST - PopOnReturnSub", + Self::Yield(op) => "INST - Yield", + Self::GeneratorNext(op) => "INST - GeneratorNext", + Self::AsyncGeneratorNext(op) => "INST - AsyncGeneratorNext", + Self::PushNewTarget(op) => "INST - PushNewTarget", + Self::Await(op) => "INST - Await", + Self::GeneratorNextDelegate(op) => "INST - GeneratorNextDelegate", + Self::Nop(op) => "INST - Nop", Self::PushClassPrototype(op) => PushClassPrototype::INSTRUCTION, Self::SetClassPrototype(op) => SetClassPrototype::INSTRUCTION, Self::SetHomeObject(op) => SetHomeObject::INSTRUCTION, - Self::DefineClassMethodByName => "INST - DefineClassMethodByName", - Self::DefineClassMethodByValue => "INST - DefineClassMethodByValue", - Self::DefineClassGetterByName => "INST - DefineClassGetterByName", - Self::DefineClassGetterByValue => "INST - DefineClassGetterByValue", - Self::DefineClassSetterByName => "INST - DefineClassSetterByName", - Self::DefineClassSetterByValue => "INST - DefineClassSetterByValue", - Self::AssignPrivateField => "INST - AssignPrivateField", - Self::SetPrivateField => "INST - SetPrivateValue", - Self::SetPrivateMethod => "INST - SetPrivateMethod", - Self::SetPrivateSetter => "INST - SetPrivateSetter", - Self::SetPrivateGetter => "INST - SetPrivateGetter", - Self::GetPrivateField => "INST - GetPrivateField", - Self::PushClassField => "INST - PushClassField", - Self::PushClassFieldPrivate => "INST - PushClassFieldPrivate", - Self::PushClassPrivateGetter => "INST - PushClassPrivateGetter", - Self::PushClassPrivateSetter => "INST - PushClassPrivateSetter", - Self::PushClassPrivateMethod => "INST - PushClassPrivateMethod", - Self::ToPropertyKey => "INST - ToPropertyKey", + Self::DefineClassMethodByName(op) => "INST - DefineClassMethodByName", + Self::DefineClassMethodByValue(op) => "INST - DefineClassMethodByValue", + Self::DefineClassGetterByName(op) => "INST - DefineClassGetterByName", + Self::DefineClassGetterByValue(op) => "INST - DefineClassGetterByValue", + Self::DefineClassSetterByName(op) => "INST - DefineClassSetterByName", + Self::DefineClassSetterByValue(op) => "INST - DefineClassSetterByValue", + Self::AssignPrivateField(op) => "INST - AssignPrivateField", + Self::SetPrivateField(op) => "INST - SetPrivateValue", + Self::SetPrivateMethod(op) => "INST - SetPrivateMethod", + Self::SetPrivateSetter(op) => "INST - SetPrivateSetter", + Self::SetPrivateGetter(op) => "INST - SetPrivateGetter", + Self::GetPrivateField(op) => "INST - GetPrivateField", + Self::PushClassField(op) => "INST - PushClassField", + Self::PushClassFieldPrivate(op) => "INST - PushClassFieldPrivate", + Self::PushClassPrivateGetter(op) => "INST - PushClassPrivateGetter", + Self::PushClassPrivateSetter(op) => "INST - PushClassPrivateSetter", + Self::PushClassPrivateMethod(op) => "INST - PushClassPrivateMethod", + Self::ToPropertyKey(op) => "INST - ToPropertyKey", } } } diff --git a/boa_engine/src/vm/opcode/new/mod.rs b/boa_engine/src/vm/opcode/new/mod.rs new file mode 100644 index 00000000000..2d081b5e4df --- /dev/null +++ b/boa_engine/src/vm/opcode/new/mod.rs @@ -0,0 +1,68 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct New; + +impl Operation for New { + const NAME: &'static str = "New"; + const INSTRUCTION: &'static str = "INST - 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"); + } + let argument_count = context.vm.read::(); + let mut arguments = Vec::with_capacity(argument_count as usize); + for _ in 0..argument_count { + arguments.push(context.vm.pop()); + } + arguments.reverse(); + let func = context.vm.pop(); + + let result = func + .as_constructor() + .ok_or_else(|| context.construct_type_error("not a constructor")) + .and_then(|cons| cons.__construct__(&arguments, cons, context))?; + + context.vm.push(result); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct NewSpread; + +impl Operation for NewSpread { + const NAME: &'static str = "NewSpread"; + const INSTRUCTION: &'static str = "INST - 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"); + } + // Get the arguments that are stored as an array object on the stack. + let arguments_array = context.vm.pop(); + let arguments_array_object = arguments_array + .as_object() + .expect("arguments array in call spread function must be an object"); + let arguments = arguments_array_object + .borrow() + .properties() + .dense_indexed_properties() + .expect("arguments array in call spread function must be dense") + .clone(); + + let func = context.vm.pop(); + + let result = func + .as_constructor() + .ok_or_else(|| context.construct_type_error("not a constructor")) + .and_then(|cons| cons.__construct__(&arguments, cons, context))?; + + context.vm.push(result); + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/pop/if_thrown.rs b/boa_engine/src/vm/opcode/pop/if_thrown.rs index 7dade24dc1e..46ecac122b5 100644 --- a/boa_engine/src/vm/opcode/pop/if_thrown.rs +++ b/boa_engine/src/vm/opcode/pop/if_thrown.rs @@ -1,6 +1,6 @@ use crate::{ vm::{opcode::Operation, ShouldExit}, - Context, JsResult + Context, JsResult, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -18,4 +18,4 @@ impl Operation for PopIfThrown { } Ok(ShouldExit::False) } -} \ No newline at end of file +} diff --git a/boa_engine/src/vm/opcode/pop/mod.rs b/boa_engine/src/vm/opcode/pop/mod.rs index c33cda75817..d3a58a4bbda 100644 --- a/boa_engine/src/vm/opcode/pop/mod.rs +++ b/boa_engine/src/vm/opcode/pop/mod.rs @@ -1,6 +1,6 @@ use crate::{ vm::{opcode::Operation, ShouldExit}, - Context, JsResult + Context, JsResult, }; pub(crate) mod if_thrown; @@ -18,4 +18,45 @@ impl Operation for Pop { let _val = context.vm.pop(); Ok(ShouldExit::False) } -} \ No newline at end of file +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PopEnvironment; + +impl Operation for PopEnvironment { + const NAME: &'static str = "PopEnvironment"; + const INSTRUCTION: &'static str = "INST - PopEnvironment"; + + fn execute(context: &mut Context) -> JsResult { + context.realm.environments.pop(); + context.vm.frame_mut().loop_env_stack_dec(); + context.vm.frame_mut().try_env_stack_dec(); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PopOnReturnAdd; + +impl Operation for PopOnReturnAdd { + const NAME: &'static str = "PopOnReturnAdd"; + const INSTRUCTION: &'static str = "INST - PopOnReturnAdd"; + + fn execute(context: &mut Context) -> JsResult { + context.vm.frame_mut().pop_on_return += 1; + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PopOnReturnSub; + +impl Operation for PopOnReturnSub { + const NAME: &'static str = "PopOnReturnSub"; + const INSTRUCTION: &'static str = "INST - PopOnReturnSub"; + + fn execute(context: &mut Context) -> JsResult { + context.vm.frame_mut().pop_on_return -= 1; + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/promise/mod.rs b/boa_engine/src/vm/opcode/promise/mod.rs new file mode 100644 index 00000000000..9440b6fe2b7 --- /dev/null +++ b/boa_engine/src/vm/opcode/promise/mod.rs @@ -0,0 +1,72 @@ +use crate::{ + vm::{opcode::Operation, FinallyReturn, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct FinallyStart; + +impl Operation for FinallyStart { + const NAME: &'static str = "FinallyStart"; + const INSTRUCTION: &'static str = "INST - FinallyStart"; + + fn execute(context: &mut Context) -> JsResult { + *context + .vm + .frame_mut() + .finally_jump + .last_mut() + .expect("finally jump must exist here") = None; + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct FinallyEnd; + +impl Operation for FinallyEnd { + const NAME: &'static str = "FinallyEnd"; + const INSTRUCTION: &'static str = "INST - FinallyEnd"; + + fn execute(context: &mut Context) -> JsResult { + let address = context + .vm + .frame_mut() + .finally_jump + .pop() + .expect("finally jump must exist here"); + match context.vm.frame_mut().finally_return { + FinallyReturn::None => { + if let Some(address) = address { + context.vm.frame_mut().pc = address as usize; + } + return Ok(ShouldExit::False); + } + FinallyReturn::Ok => { + return Ok(ShouldExit::True); + } + FinallyReturn::Err => { + return Err(context.vm.pop()); + } + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct FinallySetJump; + +impl Operation for FinallySetJump { + const NAME: &'static str = "FinallySetJump"; + const INSTRUCTION: &'static str = "INST - FinallySetJump"; + + fn execute(context: &mut Context) -> JsResult { + let address = context.vm.read::(); + *context + .vm + .frame_mut() + .finally_jump + .last_mut() + .expect("finally jump must exist here") = Some(address); + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/push/array.rs b/boa_engine/src/vm/opcode/push/array.rs new file mode 100644 index 00000000000..f0cbe4ae8fa --- /dev/null +++ b/boa_engine/src/vm/opcode/push/array.rs @@ -0,0 +1,90 @@ +use crate::{ + builtins::{iterable::IteratorRecord, Array}, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PushNewArray; + +impl Operation for PushNewArray { + const NAME: &'static str = "PushNewArray"; + const INSTRUCTION: &'static str = "INST - PushNewArray"; + + fn execute(context: &mut Context) -> JsResult { + let array = Array::array_create(0, None, context) + .expect("Array creation with 0 length should never fail"); + context.vm.push(array); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PushValueToArray; + +impl Operation for PushValueToArray { + const NAME: &'static str = "PushValueToArray"; + const INSTRUCTION: &'static str = "INST - PushValueToArray"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + let array = context.vm.pop(); + let o = array.as_object().expect("should be an object"); + let len = o + .length_of_array_like(context) + .expect("should have 'length' property"); + o.create_data_property_or_throw(len, value, context) + .expect("should be able to create new data property"); + context.vm.push(array); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PushElisionToArray; + +impl Operation for PushElisionToArray { + const NAME: &'static str = "PushElisionToArray"; + const INSTRUCTION: &'static str = "INST - PushElisionToArray"; + + fn execute(context: &mut Context) -> JsResult { + let array = context.vm.pop(); + let o = array.as_object().expect("should always be an object"); + + let len = o + .length_of_array_like(context) + .expect("arrays should always have a 'length' property"); + + o.set("length", len + 1, true, context)?; + context.vm.push(array); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PushIteratorToArray; + +impl Operation for PushIteratorToArray { + const NAME: &'static str = "PushIteratorToArray"; + const INSTRUCTION: &'static str = "INST - PushIteratorToArray"; + + fn execute(context: &mut Context) -> JsResult { + let done = context + .vm + .pop() + .as_boolean() + .expect("iterator [[Done]] was not a boolean"); + let next_method = context.vm.pop(); + let iterator = context.vm.pop(); + let iterator = iterator.as_object().expect("iterator was not an object"); + let array = context.vm.pop(); + + let iterator = IteratorRecord::new(iterator.clone(), next_method, done); + while let Some(next) = iterator.step(context)? { + Array::push(&array, &[next.value(context)?], context)?; + } + + context.vm.push(array); + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/push/class.rs b/boa_engine/src/vm/opcode/push/class.rs new file mode 100644 index 00000000000..4462365f579 --- /dev/null +++ b/boa_engine/src/vm/opcode/push/class.rs @@ -0,0 +1,207 @@ +use crate::{ + builtins::function::{ConstructorKind, Function}, + object::{JsFunction, PrivateElement}, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsValue, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PushClassPrototype; + +impl Operation for PushClassPrototype { + const NAME: &'static str = "PushClassPrototype"; + const INSTRUCTION: &'static str = "INST - PushClassPrototype"; + + fn execute(context: &mut Context) -> JsResult { + let superclass = context.vm.pop(); + + 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"); + } + + let class = context.vm.pop(); + { + let class_object = class.as_object().expect("class must be object"); + class_object.set_prototype(Some(superclass.clone())); + + let mut class_object_mut = class_object.borrow_mut(); + let class_function = class_object_mut + .as_function_mut() + .expect("class must be function object"); + if let Function::Ordinary { + constructor_kind, .. + } = class_function + { + *constructor_kind = ConstructorKind::Derived; + } + } + + context.vm.push(class); + context.vm.push(proto); + Ok(ShouldExit::False) + } else if superclass.is_null() { + context.vm.push(JsValue::Null); + Ok(ShouldExit::False) + } else { + return context.throw_type_error("superclass must be a constructor"); + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PushClassField; + +impl Operation for PushClassField { + const NAME: &'static str = "PushClassField"; + const INSTRUCTION: &'static str = "INST - PushClassField"; + + fn execute(context: &mut Context) -> JsResult { + let field_function_value = context.vm.pop(); + let field_name_value = context.vm.pop(); + let class_value = context.vm.pop(); + + let field_name_key = field_name_value.to_property_key(context)?; + let field_function_object = field_function_value + .as_object() + .expect("field value must be function object"); + let mut field_function_object_borrow = field_function_object.borrow_mut(); + let field_function = field_function_object_borrow + .as_function_mut() + .expect("field value must be function object"); + let class_object = class_value + .as_object() + .expect("class must be function object"); + field_function.set_home_object(class_object.clone()); + class_object + .borrow_mut() + .as_function_mut() + .expect("class must be function object") + .push_field( + field_name_key, + JsFunction::from_object_unchecked(field_function_object.clone()), + ); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PushClassFieldPrivate; + +impl Operation for PushClassFieldPrivate { + const NAME: &'static str = "PushClassFieldPrivate"; + const INSTRUCTION: &'static str = "INST - PushClassFieldPrivate"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let name = context.vm.frame().code.names[index as usize]; + let field_function_value = context.vm.pop(); + let class_value = context.vm.pop(); + + let field_function_object = field_function_value + .as_object() + .expect("field value must be function object"); + let mut field_function_object_borrow = field_function_object.borrow_mut(); + let field_function = field_function_object_borrow + .as_function_mut() + .expect("field value must be function object"); + let class_object = class_value + .as_object() + .expect("class must be function object"); + field_function.set_home_object(class_object.clone()); + class_object + .borrow_mut() + .as_function_mut() + .expect("class must be function object") + .push_field_private( + name, + JsFunction::from_object_unchecked(field_function_object.clone()), + ); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PushClassPrivateMethod; + +impl Operation for PushClassPrivateMethod { + const NAME: &'static str = "PushClassPrivateMethod"; + const INSTRUCTION: &'static str = "INST - PushClassPrivateMethod"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let name = context.vm.frame().code.names[index as usize]; + let method = context.vm.pop(); + let method_object = method.as_callable().expect("method must be callable"); + let class = context.vm.pop(); + class + .as_object() + .expect("class must be function object") + .borrow_mut() + .as_function_mut() + .expect("class must be function object") + .push_private_method(name, PrivateElement::Method(method_object.clone())); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PushClassPrivateGetter; + +impl Operation for PushClassPrivateGetter { + const NAME: &'static str = "PushClassPrivateGetter"; + const INSTRUCTION: &'static str = "INST - PushClassPrivateGetter"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let name = context.vm.frame().code.names[index as usize]; + let getter = context.vm.pop(); + let getter_object = getter.as_callable().expect("getter must be callable"); + let class = context.vm.pop(); + class + .as_object() + .expect("class must be function object") + .borrow_mut() + .as_function_mut() + .expect("class must be function object") + .push_private_method( + name, + PrivateElement::Accessor { + getter: Some(getter_object.clone()), + setter: None, + }, + ); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PushClassPrivateSetter; + +impl Operation for PushClassPrivateSetter { + const NAME: &'static str = "PushClassPrivateSetter"; + const INSTRUCTION: &'static str = "INST - PushClassPrivateSetter"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let name = context.vm.frame().code.names[index as usize]; + let setter = context.vm.pop(); + let setter_object = setter.as_callable().expect("getter must be callable"); + let class = context.vm.pop(); + class + .as_object() + .expect("class must be function object") + .borrow_mut() + .as_function_mut() + .expect("class must be function object") + .push_private_method( + name, + PrivateElement::Accessor { + getter: None, + setter: Some(setter_object.clone()), + }, + ); + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/push/class_prototype.rs b/boa_engine/src/vm/opcode/push/class_prototype.rs deleted file mode 100644 index 0901e58ec40..00000000000 --- a/boa_engine/src/vm/opcode/push/class_prototype.rs +++ /dev/null @@ -1,50 +0,0 @@ -use crate::{ - vm::{ShouldExit, opcode::Operation}, - builtins::function::{Function, ConstructorKind}, - Context, JsValue, JsResult, -}; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct PushClassPrototype; - -impl Operation for PushClassPrototype { - const NAME: &'static str = "PushClassPrototype"; - const INSTRUCTION: &'static str = "INST - PushClassPrototype"; - - fn execute(context: &mut Context) -> JsResult { - let superclass = context.vm.pop(); - - 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"); - } - - let class = context.vm.pop(); - { - let class_object = class.as_object().expect("class must be object"); - class_object.set_prototype(Some(superclass.clone())); - - let mut class_object_mut = class_object.borrow_mut(); - let class_function = class_object_mut - .as_function_mut() - .expect("class must be function object"); - if let Function::Ordinary { - constructor_kind, .. - } = class_function - { - *constructor_kind = ConstructorKind::Derived; - } - } - - context.vm.push(class); - context.vm.push(proto); - Ok(ShouldExit::False) - } else if superclass.is_null() { - context.vm.push(JsValue::Null); - Ok(ShouldExit::False) - } else { - return context.throw_type_error("superclass must be a constructor"); - } - } -} \ No newline at end of file diff --git a/boa_engine/src/vm/opcode/push/environment.rs b/boa_engine/src/vm/opcode/push/environment.rs new file mode 100644 index 00000000000..998d92f63c0 --- /dev/null +++ b/boa_engine/src/vm/opcode/push/environment.rs @@ -0,0 +1,48 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PushDeclarativeEnvironment; + +impl Operation for PushDeclarativeEnvironment { + const NAME: &'static str = "PushDeclarativeEnvironment"; + const INSTRUCTION: &'static str = "INST - PushDeclarativeEnvironment"; + + fn execute(context: &mut Context) -> JsResult { + let num_bindings = context.vm.read::(); + let compile_environments_index = context.vm.read::(); + let compile_environment = context.vm.frame().code.compile_environments + [compile_environments_index as usize] + .clone(); + context + .realm + .environments + .push_declarative(num_bindings as usize, compile_environment); + context.vm.frame_mut().loop_env_stack_inc(); + context.vm.frame_mut().try_env_stack_inc(); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PushFunctionEnvironment; + +impl Operation for PushFunctionEnvironment { + const NAME: &'static str = "PushFunctionEnvironment"; + const INSTRUCTION: &'static str = "INST - PushFunctionEnvironment"; + + fn execute(context: &mut Context) -> JsResult { + let num_bindings = context.vm.read::(); + let compile_environments_index = context.vm.read::(); + let compile_environment = context.vm.frame().code.compile_environments + [compile_environments_index as usize] + .clone(); + context + .realm + .environments + .push_function_inherit(num_bindings as usize, compile_environment); + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/push/literal.rs b/boa_engine/src/vm/opcode/push/literal.rs index d0b809d492e..09640f8e4f1 100644 --- a/boa_engine/src/vm/opcode/push/literal.rs +++ b/boa_engine/src/vm/opcode/push/literal.rs @@ -1,5 +1,5 @@ use crate::{ - vm::{ShouldExit, opcode::Operation}, + vm::{opcode::Operation, ShouldExit}, Context, JsResult, }; @@ -16,4 +16,4 @@ impl Operation for PushLiteral { context.vm.push(value); Ok(ShouldExit::False) } -} \ No newline at end of file +} diff --git a/boa_engine/src/vm/opcode/push/mod.rs b/boa_engine/src/vm/opcode/push/mod.rs index 81b27c7011a..01a39899eba 100644 --- a/boa_engine/src/vm/opcode/push/mod.rs +++ b/boa_engine/src/vm/opcode/push/mod.rs @@ -3,17 +3,22 @@ use crate::{ Context, JsResult, JsValue, }; -pub(crate) mod numbers; +pub(crate) mod array; +pub(crate) mod class; +pub(crate) mod environment; pub(crate) mod literal; -pub(crate) mod class_prototype; +pub(crate) mod new_target; +pub(crate) mod numbers; pub(crate) mod object; -pub(crate) use numbers::*; +pub(crate) use array::*; +pub(crate) use class::*; +pub(crate) use environment::*; pub(crate) use literal::*; -pub(crate) use class_prototype::*; +pub(crate) use new_target::*; +pub(crate) use numbers::*; pub(crate) use object::*; - macro_rules! implement_push_generics { ($name:ident, $push_value:expr) => { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -28,41 +33,23 @@ macro_rules! implement_push_generics { Ok(ShouldExit::False) } } - } + }; } -implement_push_generics!( - PushUndefined, {JsValue::undefined()} -); +implement_push_generics!(PushUndefined, { JsValue::undefined() }); -implement_push_generics!( - PushNull, {JsValue::null()} -); +implement_push_generics!(PushNull, { JsValue::null() }); -implement_push_generics!( - PushTrue, true -); +implement_push_generics!(PushTrue, true); -implement_push_generics!( - PushFalse, false -); +implement_push_generics!(PushFalse, false); -implement_push_generics!( - PushZero, 0 -); +implement_push_generics!(PushZero, 0); -implement_push_generics!( - PushOne, 1 -); +implement_push_generics!(PushOne, 1); -implement_push_generics!( - PushNaN, JsValue::nan() -); +implement_push_generics!(PushNaN, JsValue::nan()); -implement_push_generics!( - PushPositiveInfinity, JsValue::positive_infinity() -); +implement_push_generics!(PushPositiveInfinity, JsValue::positive_infinity()); -implement_push_generics!( - PushNegativeInfinity, JsValue::negative_infinity() -); \ No newline at end of file +implement_push_generics!(PushNegativeInfinity, JsValue::negative_infinity()); diff --git a/boa_engine/src/vm/opcode/push/new_target.rs b/boa_engine/src/vm/opcode/push/new_target.rs new file mode 100644 index 00000000000..7eb61993a44 --- /dev/null +++ b/boa_engine/src/vm/opcode/push/new_target.rs @@ -0,0 +1,30 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsValue, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PushNewTarget; + +impl Operation for PushNewTarget { + const NAME: &'static str = "PushNewTarget"; + const INSTRUCTION: &'static str = "INST - PushNewTarget"; + + fn execute(context: &mut Context) -> JsResult { + if let Some(env) = context + .realm + .environments + .get_this_environment() + .as_function_slots() + { + if let Some(new_target) = env.borrow().new_target() { + context.vm.push(new_target.clone()); + } else { + context.vm.push(JsValue::undefined()); + } + } else { + context.vm.push(JsValue::undefined()); + } + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/push/numbers.rs b/boa_engine/src/vm/opcode/push/numbers.rs index 1500cbea027..1b8724d433d 100644 --- a/boa_engine/src/vm/opcode/push/numbers.rs +++ b/boa_engine/src/vm/opcode/push/numbers.rs @@ -1,6 +1,6 @@ use crate::{ vm::{opcode::Operation, ShouldExit}, - Context, JsResult + Context, JsResult, }; macro_rules! implement_push_numbers_with_conversion { @@ -18,7 +18,7 @@ macro_rules! implement_push_numbers_with_conversion { Ok(ShouldExit::False) } } - } + }; } macro_rules! implement_push_numbers_no_conversion { @@ -36,20 +36,12 @@ macro_rules! implement_push_numbers_no_conversion { Ok(ShouldExit::False) } } - } + }; } -implement_push_numbers_with_conversion! ( - PushInt8, i8 -); +implement_push_numbers_with_conversion!(PushInt8, i8); -implement_push_numbers_with_conversion!( - PushInt16, i16 -); +implement_push_numbers_with_conversion!(PushInt16, i16); -implement_push_numbers_no_conversion!( - PushInt32, i32 -); +implement_push_numbers_no_conversion!(PushInt32, i32); -implement_push_numbers_no_conversion!( - PushRational, f64 -); +implement_push_numbers_no_conversion!(PushRational, f64); diff --git a/boa_engine/src/vm/opcode/push/object.rs b/boa_engine/src/vm/opcode/push/object.rs index 857e1d52735..98770100562 100644 --- a/boa_engine/src/vm/opcode/push/object.rs +++ b/boa_engine/src/vm/opcode/push/object.rs @@ -1,6 +1,6 @@ use crate::{ vm::{opcode::Operation, ShouldExit}, - Context, JsResult + Context, JsResult, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -14,4 +14,4 @@ impl Operation for PushEmptyObject { context.vm.push(context.construct_object()); Ok(ShouldExit::False) } -} \ No newline at end of file +} diff --git a/boa_engine/src/vm/opcode/require/mod.rs b/boa_engine/src/vm/opcode/require/mod.rs new file mode 100644 index 00000000000..13692d8cb11 --- /dev/null +++ b/boa_engine/src/vm/opcode/require/mod.rs @@ -0,0 +1,19 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct RequireObjectCoercible; + +impl Operation for RequireObjectCoercible { + const NAME: &'static str = "RequireObjectCoercible"; + const INSTRUCTION: &'static str = "INST - RequireObjectCoercible"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + let value = value.require_object_coercible(context)?; + context.vm.push(value); + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/rest_parameter/mod.rs b/boa_engine/src/vm/opcode/rest_parameter/mod.rs new file mode 100644 index 00000000000..84c371c2b80 --- /dev/null +++ b/boa_engine/src/vm/opcode/rest_parameter/mod.rs @@ -0,0 +1,54 @@ +use crate::{ + builtins::Array, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct RestParameterInit; + +impl Operation for RestParameterInit { + const NAME: &'static str = "RestParameterInit"; + const INSTRUCTION: &'static str = "INST - RestParameterInit"; + + fn execute(context: &mut Context) -> JsResult { + let arg_count = context.vm.frame().arg_count; + let param_count = context.vm.frame().param_count; + if arg_count >= param_count { + let rest_count = arg_count - param_count + 1; + let mut args = Vec::with_capacity(rest_count); + for _ in 0..rest_count { + args.push(context.vm.pop()); + } + let array: _ = Array::create_array_from_list(args, context); + + context.vm.push(array); + } else { + context.vm.pop(); + + let array = + Array::array_create(0, None, context).expect("could not create an empty array"); + context.vm.push(array); + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct RestParameterPop; + +impl Operation for RestParameterPop { + const NAME: &'static str = "RestParameterPop"; + const INSTRUCTION: &'static str = "INST - RestParameterPop"; + + fn execute(context: &mut Context) -> JsResult { + let arg_count = context.vm.frame().arg_count; + let param_count = context.vm.frame().param_count; + if arg_count > param_count { + for _ in 0..(arg_count - param_count) { + context.vm.pop(); + } + } + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/return_stm/mod.rs b/boa_engine/src/vm/opcode/return_stm/mod.rs new file mode 100644 index 00000000000..fb10beb8a5b --- /dev/null +++ b/boa_engine/src/vm/opcode/return_stm/mod.rs @@ -0,0 +1,48 @@ +use crate::{ + vm::{opcode::Operation, FinallyReturn, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Return; + +impl Operation for Return { + const NAME: &'static str = "Return"; + const INSTRUCTION: &'static str = "INST - Return"; + + fn execute(context: &mut Context) -> JsResult { + if let Some(finally_address) = context.vm.frame().catch.last().and_then(|c| c.finally) { + let frame = context.vm.frame_mut(); + frame.pc = finally_address as usize; + frame.finally_return = FinallyReturn::Ok; + frame.catch.pop(); + let try_stack_entry = context + .vm + .frame_mut() + .try_env_stack + .pop() + .expect("must exist"); + for _ in 0..try_stack_entry.num_env { + context.realm.environments.pop(); + } + let mut num_env = try_stack_entry.num_env; + for _ in 0..try_stack_entry.num_loop_stack_entries { + num_env -= context + .vm + .frame_mut() + .loop_env_stack + .pop() + .expect("must exist"); + } + *context + .vm + .frame_mut() + .loop_env_stack + .last_mut() + .expect("must exist") -= num_env; + } else { + return Ok(ShouldExit::True); + } + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/set/class_prototype.rs b/boa_engine/src/vm/opcode/set/class_prototype.rs index 00167f1b18e..c19a7b40199 100644 --- a/boa_engine/src/vm/opcode/set/class_prototype.rs +++ b/boa_engine/src/vm/opcode/set/class_prototype.rs @@ -2,7 +2,7 @@ use crate::{ object::{JsObject, ObjectData}, property::PropertyDescriptorBuilder, vm::{opcode::Operation, ShouldExit}, - Context, JsResult, JsValue + Context, JsResult, JsValue, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -17,9 +17,14 @@ impl Operation for SetClassPrototype { let prototype = match &prototype_value { JsValue::Object(proto) => Some(proto.clone()), JsValue::Null => None, - JsValue::Undefined => { - Some(context.intrinsics().constructors().object().prototype.clone()) - } + JsValue::Undefined => Some( + context + .intrinsics() + .constructors() + .object() + .prototype + .clone(), + ), _ => unreachable!(), }; @@ -62,4 +67,4 @@ impl Operation for SetClassPrototype { context.vm.push(proto); Ok(ShouldExit::False) } -} \ No newline at end of file +} diff --git a/boa_engine/src/vm/opcode/set/home_object.rs b/boa_engine/src/vm/opcode/set/home_object.rs index 7c59766db37..39279774359 100644 --- a/boa_engine/src/vm/opcode/set/home_object.rs +++ b/boa_engine/src/vm/opcode/set/home_object.rs @@ -2,7 +2,7 @@ use crate::{ object::{JsObject, ObjectData}, property::PropertyDescriptorBuilder, vm::{opcode::Operation, ShouldExit}, - Context, JsResult, JsValue + Context, JsResult, JsValue, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -28,4 +28,4 @@ impl Operation for SetHomeObject { context.vm.push(function); Ok(ShouldExit::False) } -} \ No newline at end of file +} diff --git a/boa_engine/src/vm/opcode/set/mod.rs b/boa_engine/src/vm/opcode/set/mod.rs index f72f12e773d..8e7b8edcdac 100644 --- a/boa_engine/src/vm/opcode/set/mod.rs +++ b/boa_engine/src/vm/opcode/set/mod.rs @@ -1,6 +1,11 @@ +pub(crate) mod class_prototype; +pub(crate) mod home_object; +pub(crate) mod name; +pub(crate) mod private; +pub(crate) mod property; -pub mod class_prototype; -pub mod home_object; - -pub use class_prototype::*; -pub use home_object::*; \ No newline at end of file +pub(crate) use class_prototype::*; +pub(crate) use home_object::*; +pub(crate) use name::*; +pub(crate) use private::*; +pub(crate) use property::*; diff --git a/boa_engine/src/vm/opcode/set/name.rs b/boa_engine/src/vm/opcode/set/name.rs new file mode 100644 index 00000000000..980624cd3a1 --- /dev/null +++ b/boa_engine/src/vm/opcode/set/name.rs @@ -0,0 +1,60 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsString, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct SetName; + +impl Operation for SetName { + const NAME: &'static str = "SetName"; + const INSTRUCTION: &'static str = "INST - SetName"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let binding_locator = context.vm.frame().code.bindings[index as usize]; + let value = context.vm.pop(); + binding_locator.throw_mutate_immutable(context)?; + + if binding_locator.is_global() { + if !context + .realm + .environments + .put_value_global_poisoned(binding_locator.name(), &value) + { + let key: JsString = context + .interner() + .resolve_expect(binding_locator.name()) + .into(); + 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}")); + } + + let success = crate::object::internal_methods::global::global_set_no_receiver( + &key.clone().into(), + value, + context, + )?; + + if !success && context.vm.frame().code.strict { + return context + .throw_type_error(format!("cannot set non-writable property: {key}",)); + } + } + } else if !context.realm.environments.put_value_if_initialized( + binding_locator.environment_index(), + binding_locator.binding_index(), + binding_locator.name(), + value, + ) { + context.throw_reference_error(format!( + "cannot access '{}' before initialization", + context.interner().resolve_expect(binding_locator.name()) + ))?; + } + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/set/private.rs b/boa_engine/src/vm/opcode/set/private.rs new file mode 100644 index 00000000000..751ea9439c7 --- /dev/null +++ b/boa_engine/src/vm/opcode/set/private.rs @@ -0,0 +1,149 @@ +use crate::{ + object::PrivateElement, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct AssignPrivateField; + +impl Operation for AssignPrivateField { + const NAME: &'static str = "AssignPrivateField"; + const INSTRUCTION: &'static str = "INST - AssignPrivateField"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let name = context.vm.frame().code.names[index as usize]; + let value = context.vm.pop(); + let object = context.vm.pop(); + if let Some(object) = object.as_object() { + let mut object_borrow_mut = object.borrow_mut(); + match object_borrow_mut.get_private_element(name) { + Some(PrivateElement::Field(_)) => { + object_borrow_mut.set_private_element(name, PrivateElement::Field(value)); + } + Some(PrivateElement::Method(_)) => { + return context.throw_type_error("private method is not writable"); + } + Some(PrivateElement::Accessor { + setter: Some(setter), + .. + }) => { + let setter = setter.clone(); + drop(object_borrow_mut); + setter.call(&object.clone().into(), &[value], context)?; + } + None => { + return context.throw_type_error("private field not defined"); + } + _ => { + return context.throw_type_error("private field defined without a setter"); + } + } + } else { + return context.throw_type_error("cannot set private property on non-object"); + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct SetPrivateField; + +impl Operation for SetPrivateField { + const NAME: &'static str = "SetPrivateField"; + const INSTRUCTION: &'static str = "INST - SetPrivateField"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let name = context.vm.frame().code.names[index as usize]; + let value = context.vm.pop(); + let object = context.vm.pop(); + if let Some(object) = object.as_object() { + let mut object_borrow_mut = object.borrow_mut(); + if let Some(PrivateElement::Accessor { + getter: _, + setter: Some(setter), + }) = object_borrow_mut.get_private_element(name) + { + let setter = setter.clone(); + drop(object_borrow_mut); + setter.call(&object.clone().into(), &[value], context)?; + } else { + object_borrow_mut.set_private_element(name, PrivateElement::Field(value)); + } + } else { + return context.throw_type_error("cannot set private property on non-object"); + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct SetPrivateMethod; + +impl Operation for SetPrivateMethod { + const NAME: &'static str = "SetPrivateMethod"; + const INSTRUCTION: &'static str = "INST - SetPrivateMethod"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let name = context.vm.frame().code.names[index as usize]; + let value = context.vm.pop(); + let value = value.as_callable().expect("method must be callable"); + let object = context.vm.pop(); + if let Some(object) = object.as_object() { + let mut object_borrow_mut = object.borrow_mut(); + object_borrow_mut.set_private_element(name, PrivateElement::Method(value.clone())); + } else { + return context.throw_type_error("cannot set private setter on non-object"); + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct SetPrivateSetter; + +impl Operation for SetPrivateSetter { + const NAME: &'static str = "SetPrivateSetter"; + const INSTRUCTION: &'static str = "INST - SetPrivateSetter"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let name = context.vm.frame().code.names[index as usize]; + let value = context.vm.pop(); + let value = value.as_callable().expect("setter must be callable"); + let object = context.vm.pop(); + if let Some(object) = object.as_object() { + let mut object_borrow_mut = object.borrow_mut(); + object_borrow_mut.set_private_element_setter(name, value.clone()); + } else { + return context.throw_type_error("cannot set private setter on non-object"); + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct SetPrivateGetter; + +impl Operation for SetPrivateGetter { + const NAME: &'static str = "SetPrivateGetter"; + const INSTRUCTION: &'static str = "INST - SetPrivateGetter"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let name = context.vm.frame().code.names[index as usize]; + let value = context.vm.pop(); + let value = value.as_callable().expect("getter must be callable"); + let object = context.vm.pop(); + if let Some(object) = object.as_object() { + let mut object_borrow_mut = object.borrow_mut(); + object_borrow_mut.set_private_element_getter(name, value.clone()); + } else { + return context.throw_type_error("cannot set private getter on non-object"); + } + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/set/property.rs b/boa_engine/src/vm/opcode/set/property.rs new file mode 100644 index 00000000000..87cd372a6d5 --- /dev/null +++ b/boa_engine/src/vm/opcode/set/property.rs @@ -0,0 +1,184 @@ +use crate::{ + property::{PropertyDescriptor, PropertyKey}, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct SetPropertyByName; + +impl Operation for SetPropertyByName { + const NAME: &'static str = "SetPropertyByName"; + const INSTRUCTION: &'static str = "INST - SetPropertyByName"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + + let object = context.vm.pop(); + let value = context.vm.pop(); + let object = if let Some(object) = object.as_object() { + object.clone() + } else { + object.to_object(context)? + }; + + let name = context.vm.frame().code.names[index as usize]; + let name: PropertyKey = context.interner().resolve_expect(name).into(); + + object.set(name, value, context.vm.frame().code.strict, context)?; + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct SetPropertyByValue; + +impl Operation for SetPropertyByValue { + const NAME: &'static str = "SetPropertyByValue"; + const INSTRUCTION: &'static str = "INST - SetPropertyByValue"; + + fn execute(context: &mut Context) -> JsResult { + let object = context.vm.pop(); + let key = context.vm.pop(); + let value = context.vm.pop(); + let object = if let Some(object) = object.as_object() { + object.clone() + } else { + object.to_object(context)? + }; + + let key = key.to_property_key(context)?; + object.set(key, value, context.vm.frame().code.strict, context)?; + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct SetPropertyGetterByName; + +impl Operation for SetPropertyGetterByName { + const NAME: &'static str = "SetPropertyGetterByName"; + const INSTRUCTION: &'static str = "INST - SetPropertyGetterByName"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let object = context.vm.pop(); + let value = context.vm.pop(); + let object = object.to_object(context)?; + let name = context.vm.frame().code.names[index as usize]; + let name = context.interner().resolve_expect(name).into(); + let set = object + .__get_own_property__(&name, context)? + .as_ref() + .and_then(PropertyDescriptor::set) + .cloned(); + object.__define_own_property__( + name, + PropertyDescriptor::builder() + .maybe_get(Some(value)) + .maybe_set(set) + .enumerable(true) + .configurable(true) + .build(), + context, + )?; + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct SetPropertyGetterByValue; + +impl Operation for SetPropertyGetterByValue { + const NAME: &'static str = "SetPropertyGetterByValue"; + const INSTRUCTION: &'static str = "INST - SetPropertyGetterByValue"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + let key = context.vm.pop(); + let object = context.vm.pop(); + let object = object.to_object(context)?; + let name = key.to_property_key(context)?; + let set = object + .__get_own_property__(&name, context)? + .as_ref() + .and_then(PropertyDescriptor::set) + .cloned(); + object.__define_own_property__( + name, + PropertyDescriptor::builder() + .maybe_get(Some(value)) + .maybe_set(set) + .enumerable(true) + .configurable(true) + .build(), + context, + )?; + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct SetPropertySetterByName; + +impl Operation for SetPropertySetterByName { + const NAME: &'static str = "SetPropertySetterByName"; + const INSTRUCTION: &'static str = "INST - SetPropertySetterByName"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let object = context.vm.pop(); + let value = context.vm.pop(); + let object = object.to_object(context)?; + let name = context.vm.frame().code.names[index as usize]; + let name = context.interner().resolve_expect(name).into(); + let get = object + .__get_own_property__(&name, context)? + .as_ref() + .and_then(PropertyDescriptor::get) + .cloned(); + object.__define_own_property__( + name, + PropertyDescriptor::builder() + .maybe_set(Some(value)) + .maybe_get(get) + .enumerable(true) + .configurable(true) + .build(), + context, + )?; + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct SetPropertySetterByValue; + +impl Operation for SetPropertySetterByValue { + const NAME: &'static str = "SetPropertySetterByValue"; + const INSTRUCTION: &'static str = "INST - SetPropertySetterByValue"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + let key = context.vm.pop(); + let object = context.vm.pop(); + let object = object.to_object(context)?; + let name = key.to_property_key(context)?; + let get = object + .__get_own_property__(&name, context)? + .as_ref() + .and_then(PropertyDescriptor::get) + .cloned(); + object.__define_own_property__( + name, + PropertyDescriptor::builder() + .maybe_set(Some(value)) + .maybe_get(get) + .enumerable(true) + .configurable(true) + .build(), + context, + )?; + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/swap/mod.rs b/boa_engine/src/vm/opcode/swap/mod.rs index 8c08fec1ad3..03048e6c59e 100644 --- a/boa_engine/src/vm/opcode/swap/mod.rs +++ b/boa_engine/src/vm/opcode/swap/mod.rs @@ -1,5 +1,5 @@ use crate::{ - vm::{ShouldExit, opcode::Operation}, + vm::{opcode::Operation, ShouldExit}, Context, JsResult, }; @@ -18,4 +18,4 @@ impl Operation for Swap { context.vm.push(second); Ok(ShouldExit::False) } -} \ No newline at end of file +} diff --git a/boa_engine/src/vm/opcode/switch/mod.rs b/boa_engine/src/vm/opcode/switch/mod.rs new file mode 100644 index 00000000000..7e0d4cdf857 --- /dev/null +++ b/boa_engine/src/vm/opcode/switch/mod.rs @@ -0,0 +1,40 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Case; + +impl Operation for Case { + const NAME: &'static str = "Case"; + const INSTRUCTION: &'static str = "INST - Case"; + + fn execute(context: &mut Context) -> JsResult { + let address = context.vm.read::(); + let cond = context.vm.pop(); + let value = context.vm.pop(); + + if value.strict_equals(&cond) { + context.vm.frame_mut().pc = address as usize; + } else { + context.vm.push(value); + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Default; + +impl Operation for Default { + const NAME: &'static str = "Default"; + const INSTRUCTION: &'static str = "INST - Default"; + + fn execute(context: &mut Context) -> JsResult { + let exit = context.vm.read::(); + let _val = context.vm.pop(); + context.vm.frame_mut().pc = exit as usize; + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/throw/mod.rs b/boa_engine/src/vm/opcode/throw/mod.rs new file mode 100644 index 00000000000..5ab7cf4ef99 --- /dev/null +++ b/boa_engine/src/vm/opcode/throw/mod.rs @@ -0,0 +1,17 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Throw; + +impl Operation for Throw { + const NAME: &'static str = "Throw"; + const INSTRUCTION: &'static str = "INST - Throw"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + Err(value) + } +} diff --git a/boa_engine/src/vm/opcode/try_catch/mod.rs b/boa_engine/src/vm/opcode/try_catch/mod.rs new file mode 100644 index 00000000000..6671556e554 --- /dev/null +++ b/boa_engine/src/vm/opcode/try_catch/mod.rs @@ -0,0 +1,144 @@ +use crate::{ + vm::{opcode::Operation, CatchAddresses, FinallyReturn, ShouldExit, TryStackEntry}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct TryStart; + +impl Operation for TryStart { + const NAME: &'static str = "TryStart"; + const INSTRUCTION: &'static str = "INST - TryStart"; + + fn execute(context: &mut Context) -> JsResult { + let next = context.vm.read::(); + let finally = context.vm.read::(); + let finally = if finally == 0 { None } else { Some(finally) }; + context + .vm + .frame_mut() + .catch + .push(CatchAddresses { next, finally }); + context.vm.frame_mut().finally_jump.push(None); + context.vm.frame_mut().finally_return = FinallyReturn::None; + context.vm.frame_mut().try_env_stack.push(TryStackEntry { + num_env: 0, + num_loop_stack_entries: 0, + }); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct TryEnd; + +impl Operation for TryEnd { + const NAME: &'static str = "TryEnd"; + const INSTRUCTION: &'static str = "INST - TryEnd"; + + fn execute(context: &mut Context) -> JsResult { + context.vm.frame_mut().catch.pop(); + let try_stack_entry = context + .vm + .frame_mut() + .try_env_stack + .pop() + .expect("must exist"); + for _ in 0..try_stack_entry.num_env { + context.realm.environments.pop(); + } + let mut num_env = try_stack_entry.num_env; + for _ in 0..try_stack_entry.num_loop_stack_entries { + num_env -= context + .vm + .frame_mut() + .loop_env_stack + .pop() + .expect("must exist"); + } + *context + .vm + .frame_mut() + .loop_env_stack + .last_mut() + .expect("must exist") -= num_env; + context.vm.frame_mut().finally_return = FinallyReturn::None; + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct CatchStart; + +impl Operation for CatchStart { + const NAME: &'static str = "CatchStart"; + const INSTRUCTION: &'static str = "INST - CatchStart"; + + fn execute(context: &mut Context) -> JsResult { + let finally = context.vm.read::(); + context.vm.frame_mut().catch.push(CatchAddresses { + next: finally, + finally: Some(finally), + }); + context.vm.frame_mut().try_env_stack.push(TryStackEntry { + num_env: 0, + num_loop_stack_entries: 0, + }); + context.vm.frame_mut().thrown = false; + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct CatchEnd; + +impl Operation for CatchEnd { + const NAME: &'static str = "CatchEnd"; + const INSTRUCTION: &'static str = "INST - CatchEnd"; + + fn execute(context: &mut Context) -> JsResult { + context.vm.frame_mut().catch.pop(); + let try_stack_entry = context + .vm + .frame_mut() + .try_env_stack + .pop() + .expect("must exist"); + for _ in 0..try_stack_entry.num_env { + context.realm.environments.pop(); + } + let mut num_env = try_stack_entry.num_env; + for _ in 0..try_stack_entry.num_loop_stack_entries { + num_env -= context + .vm + .frame_mut() + .loop_env_stack + .pop() + .expect("must exist"); + } + *context + .vm + .frame_mut() + .loop_env_stack + .last_mut() + .expect("must exist") -= num_env; + context.vm.frame_mut().finally_return = FinallyReturn::None; + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct CatchEnd2; + +impl Operation for CatchEnd2 { + const NAME: &'static str = "CatchEnd2"; + const INSTRUCTION: &'static str = "INST - CatchEnd2"; + + fn execute(context: &mut Context) -> JsResult { + let frame = context.vm.frame_mut(); + if frame.finally_return == FinallyReturn::Err { + frame.finally_return = FinallyReturn::None; + } + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/value/mod.rs b/boa_engine/src/vm/opcode/value/mod.rs new file mode 100644 index 00000000000..c439aee4076 --- /dev/null +++ b/boa_engine/src/vm/opcode/value/mod.rs @@ -0,0 +1,24 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct ValueNotNullOrUndefined; + +impl Operation for ValueNotNullOrUndefined { + const NAME: &'static str = "ValueNotNullOrUndefined"; + const INSTRUCTION: &'static str = "INST - 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"); + } + if value.is_undefined() { + return context.throw_type_error("Cannot destructure 'undefined' value"); + } + context.vm.push(value); + Ok(ShouldExit::False) + } +} From e1a763b4d790efb92229fd0d72e0cbb170016816 Mon Sep 17 00:00:00 2001 From: nekevss Date: Sun, 9 Oct 2022 18:47:44 -0400 Subject: [PATCH 03/12] Revert enum changes, finish implementation and clippy lints --- boa_engine/src/vm/code_block.rs | 328 +++--- boa_engine/src/vm/mod.rs | 346 +++---- .../src/vm/opcode/define/own_property.rs | 2 +- boa_engine/src/vm/opcode/general/bin_ops.rs | 42 + boa_engine/src/vm/opcode/general/decrement.rs | 45 + boa_engine/src/vm/opcode/general/increment.rs | 45 + boa_engine/src/vm/opcode/general/jump.rs | 2 +- boa_engine/src/vm/opcode/general/mod.rs | 126 +-- boa_engine/src/vm/opcode/generator/mod.rs | 14 +- boa_engine/src/vm/opcode/get/property.rs | 2 +- boa_engine/src/vm/opcode/mod.rs | 970 +++++++++--------- boa_engine/src/vm/opcode/promise/mod.rs | 6 +- boa_engine/src/vm/opcode/push/class.rs | 2 +- boa_engine/src/vm/opcode/push/mod.rs | 12 +- .../src/vm/opcode/rest_parameter/mod.rs | 4 +- boa_engine/src/vm/opcode/set/home_object.rs | 4 +- boa_engine/src/vm/opcode/set/private.rs | 4 +- 17 files changed, 976 insertions(+), 978 deletions(-) create mode 100644 boa_engine/src/vm/opcode/general/bin_ops.rs create mode 100644 boa_engine/src/vm/opcode/general/decrement.rs create mode 100644 boa_engine/src/vm/opcode/general/increment.rs diff --git a/boa_engine/src/vm/code_block.rs b/boa_engine/src/vm/code_block.rs index 204eb376c3e..3e63f15226d 100644 --- a/boa_engine/src/vm/code_block.rs +++ b/boa_engine/src/vm/code_block.rs @@ -165,68 +165,68 @@ impl CodeBlock { /// Modifies the `pc` to point to the next instruction. /// /// Returns an empty `String` if no operands are present. - pub(crate) fn instruction_erands(&self, pc: &mut usize, interner: &Interner) -> String { + pub(crate) fn instruction_operands(&self, pc: &mut usize, interner: &Interner) -> String { let opcode: Opcode = self.code[*pc].try_into().expect("invalid opcode"); *pc += size_of::(); match opcode { - Opcode::PushInt8(_) => { + Opcode::PushInt8 => { let result = self.read::(*pc).to_string(); *pc += size_of::(); result } - Opcode::PushInt16(_) => { + Opcode::PushInt16 => { let result = self.read::(*pc).to_string(); *pc += size_of::(); result } - Opcode::PushInt32(_) => { + Opcode::PushInt32 => { let result = self.read::(*pc).to_string(); *pc += size_of::(); result } - Opcode::PushRational(_) => { + Opcode::PushRational => { let operand = self.read::(*pc); *pc += size_of::(); ryu_js::Buffer::new().format(operand).to_string() } - Opcode::PushLiteral(_) - | Opcode::Jump(_) - | Opcode::JumpIfFalse(_) - | Opcode::JumpIfNotUndefined(_) - | Opcode::CatchStart(_) - | Opcode::FinallySetJump(_) - | Opcode::Case(_) - | Opcode::Default(_) - | Opcode::LogicalAnd(_) - | Opcode::LogicalOr(_) - | Opcode::Coalesce(_) - | Opcode::CallEval(_) - | Opcode::Call(_) - | Opcode::New(_) - | Opcode::SuperCall(_) - | Opcode::ForInLoopInitIterator(_) - | Opcode::ForInLoopNext(_) - | Opcode::ForAwaitOfLoopNext(_) - | Opcode::ConcatToString(_) - | Opcode::GeneratorNextDelegate(_) => { + Opcode::PushLiteral + | Opcode::Jump + | Opcode::JumpIfFalse + | Opcode::JumpIfNotUndefined + | Opcode::CatchStart + | Opcode::FinallySetJump + | Opcode::Case + | Opcode::Default + | Opcode::LogicalAnd + | Opcode::LogicalOr + | Opcode::Coalesce + | Opcode::CallEval + | Opcode::Call + | Opcode::New + | Opcode::SuperCall + | Opcode::ForInLoopInitIterator + | Opcode::ForInLoopNext + | Opcode::ForAwaitOfLoopNext + | Opcode::ConcatToString + | Opcode::GeneratorNextDelegate => { let result = self.read::(*pc).to_string(); *pc += size_of::(); result } - Opcode::TryStart(_) - | Opcode::PushDeclarativeEnvironment(_) - | Opcode::PushFunctionEnvironment(_) - | Opcode::CopyDataProperties(_) => { + Opcode::TryStart + | Opcode::PushDeclarativeEnvironment + | Opcode::PushFunctionEnvironment + | Opcode::CopyDataProperties => { let operand1 = self.read::(*pc); *pc += size_of::(); let operand2 = self.read::(*pc); *pc += size_of::(); format!("{operand1}, {operand2}") } - Opcode::GetFunction(_) - | Opcode::GetFunctionAsync(_) - | Opcode::GetGenerator(_) - | Opcode::GetGeneratorAsync(_) => { + Opcode::GetFunction + | Opcode::GetFunctionAsync + | Opcode::GetGenerator + | Opcode::GetGeneratorAsync => { let operand = self.read::(*pc); *pc += size_of::(); format!( @@ -235,15 +235,15 @@ impl CodeBlock { self.functions[operand as usize].length ) } - Opcode::DefInitArg(_) - | Opcode::DefVar(_) - | Opcode::DefInitVar(_) - | Opcode::DefLet(_) - | Opcode::DefInitLet(_) - | Opcode::DefInitConst(_) - | Opcode::GetName(_) - | Opcode::GetNameOrUndefined(_) - | Opcode::SetName(_) => { + Opcode::DefInitArg + | Opcode::DefVar + | Opcode::DefInitVar + | Opcode::DefLet + | Opcode::DefInitLet + | Opcode::DefInitConst + | Opcode::GetName + | Opcode::GetNameOrUndefined + | Opcode::SetName => { let operand = self.read::(*pc); *pc += size_of::(); format!( @@ -252,25 +252,25 @@ impl CodeBlock { interner.resolve_expect(self.bindings[operand as usize].name().sym()), ) } - Opcode::GetPropertyByName(_) - | Opcode::SetPropertyByName(_) - | Opcode::DefineOwnPropertyByName(_) - | Opcode::DefineClassMethodByName(_) - | Opcode::SetPropertyGetterByName(_) - | Opcode::DefineClassGetterByName(_) - | Opcode::SetPropertySetterByName(_) - | Opcode::DefineClassSetterByName(_) - | Opcode::AssignPrivateField(_) - | Opcode::SetPrivateField(_) - | Opcode::SetPrivateMethod(_) - | Opcode::SetPrivateSetter(_) - | Opcode::SetPrivateGetter(_) - | Opcode::GetPrivateField(_) - | Opcode::DeletePropertyByName(_) - | Opcode::PushClassFieldPrivate(_) - | Opcode::PushClassPrivateGetter(_) - | Opcode::PushClassPrivateSetter(_) - | Opcode::PushClassPrivateMethod(_) => { + Opcode::GetPropertyByName + | Opcode::SetPropertyByName + | Opcode::DefineOwnPropertyByName + | Opcode::DefineClassMethodByName + | Opcode::SetPropertyGetterByName + | Opcode::DefineClassGetterByName + | Opcode::SetPropertySetterByName + | Opcode::DefineClassSetterByName + | Opcode::AssignPrivateField + | Opcode::SetPrivateField + | Opcode::SetPrivateMethod + | Opcode::SetPrivateSetter + | Opcode::SetPrivateGetter + | Opcode::GetPrivateField + | Opcode::DeletePropertyByName + | Opcode::PushClassFieldPrivate + | Opcode::PushClassPrivateGetter + | Opcode::PushClassPrivateSetter + | Opcode::PushClassPrivateMethod => { let operand = self.read::(*pc); *pc += size_of::(); format!( @@ -278,108 +278,108 @@ impl CodeBlock { interner.resolve_expect(self.names[operand as usize].sym()), ) } - Opcode::Pop(_) - | Opcode::PopIfThrown(_) - | Opcode::Dup(_) - | Opcode::Swap(_) - | Opcode::PushZero(_) - | Opcode::PushOne(_) - | Opcode::PushNaN(_) - | Opcode::PushPositiveInfinity(_) - | Opcode::PushNegativeInfinity(_) - | Opcode::PushNull(_) - | Opcode::PushTrue(_) - | Opcode::PushFalse(_) - | Opcode::PushUndefined(_) - | Opcode::PushEmptyObject(_) - | Opcode::PushClassPrototype(_) - | Opcode::SetClassPrototype(_) - | Opcode::SetHomeObject(_) - | Opcode::Add(_) - | Opcode::Sub(_) - | Opcode::Div(_) - | Opcode::Mul(_) - | Opcode::Mod(_) - | Opcode::Pow(_) - | Opcode::ShiftRight(_) - | Opcode::ShiftLeft(_) - | Opcode::UnsignedShiftRight(_) - | Opcode::BitOr(_) - | Opcode::BitAnd(_) - | Opcode::BitXor(_) - | Opcode::BitNot(_) - | Opcode::In(_) - | Opcode::Eq(_) - | Opcode::StrictEq(_) - | Opcode::NotEq(_) - | Opcode::StrictNotEq(_) - | Opcode::GreaterThan(_) - | Opcode::GreaterThanOrEq(_) - | Opcode::LessThan(_) - | Opcode::LessThanOrEq(_) - | Opcode::InstanceOf(_) - | Opcode::TypeOf(_) - | Opcode::Void(_) - | Opcode::LogicalNot(_) - | Opcode::Pos(_) - | Opcode::Neg(_) - | Opcode::Inc(_) - | Opcode::IncPost(_) - | Opcode::Dec(_) - | Opcode::DecPost(_) - | Opcode::GetPropertyByValue(_) - | Opcode::GetPropertyByValuePush(_) - | Opcode::SetPropertyByValue(_) - | Opcode::DefineOwnPropertyByValue(_) - | Opcode::DefineClassMethodByValue(_) - | Opcode::SetPropertyGetterByValue(_) - | Opcode::DefineClassGetterByValue(_) - | Opcode::SetPropertySetterByValue(_) - | Opcode::DefineClassSetterByValue(_) - | Opcode::DeletePropertyByValue(_) - | Opcode::ToPropertyKey(_) - | Opcode::ToBoolean(_) - | Opcode::Throw(_) - | Opcode::TryEnd(_) - | Opcode::CatchEnd(_) - | Opcode::CatchEnd2(_) - | Opcode::FinallyStart(_) - | Opcode::FinallyEnd(_) - | Opcode::This(_) - | Opcode::Super(_) - | Opcode::Return(_) - | Opcode::PopEnvironment(_) - | Opcode::LoopStart(_) - | Opcode::LoopContinue(_) - | Opcode::LoopEnd(_) - | Opcode::InitIterator(_) - | Opcode::InitIteratorAsync(_) - | Opcode::IteratorNext(_) - | Opcode::IteratorClose(_) - | Opcode::IteratorToArray(_) - | Opcode::RequireObjectCoercible(_) - | Opcode::ValueNotNullOrUndefined(_) - | Opcode::RestParameterInit(_) - | Opcode::RestParameterPop(_) - | Opcode::PushValueToArray(_) - | Opcode::PushElisionToArray(_) - | Opcode::PushIteratorToArray(_) - | Opcode::PushNewArray(_) - | Opcode::PopOnReturnAdd(_) - | Opcode::PopOnReturnSub(_) - | Opcode::Yield(_) - | Opcode::GeneratorNext(_) - | Opcode::AsyncGeneratorNext(_) - | Opcode::PushClassField(_) - | Opcode::SuperCallDerived(_) - | Opcode::Await(_) - | Opcode::PushNewTarget(_) - | Opcode::CallEvalSpread(_) - | Opcode::CallSpread(_) - | Opcode::NewSpread(_) - | Opcode::SuperCallSpread(_) - | Opcode::ForAwaitOfLoopIterate(_) - | Opcode::Nop(_) => String::new(), + Opcode::Pop + | Opcode::PopIfThrown + | Opcode::Dup + | Opcode::Swap + | Opcode::PushZero + | Opcode::PushOne + | Opcode::PushNaN + | Opcode::PushPositiveInfinity + | Opcode::PushNegativeInfinity + | Opcode::PushNull + | Opcode::PushTrue + | Opcode::PushFalse + | Opcode::PushUndefined + | Opcode::PushEmptyObject + | Opcode::PushClassPrototype + | Opcode::SetClassPrototype + | Opcode::SetHomeObject + | Opcode::Add + | Opcode::Sub + | Opcode::Div + | Opcode::Mul + | Opcode::Mod + | Opcode::Pow + | Opcode::ShiftRight + | Opcode::ShiftLeft + | Opcode::UnsignedShiftRight + | Opcode::BitOr + | Opcode::BitAnd + | Opcode::BitXor + | Opcode::BitNot + | Opcode::In + | Opcode::Eq + | Opcode::StrictEq + | Opcode::NotEq + | Opcode::StrictNotEq + | Opcode::GreaterThan + | Opcode::GreaterThanOrEq + | Opcode::LessThan + | Opcode::LessThanOrEq + | Opcode::InstanceOf + | Opcode::TypeOf + | Opcode::Void + | Opcode::LogicalNot + | Opcode::Pos + | Opcode::Neg + | Opcode::Inc + | Opcode::IncPost + | Opcode::Dec + | Opcode::DecPost + | Opcode::GetPropertyByValue + | Opcode::GetPropertyByValuePush + | Opcode::SetPropertyByValue + | Opcode::DefineOwnPropertyByValue + | Opcode::DefineClassMethodByValue + | Opcode::SetPropertyGetterByValue + | Opcode::DefineClassGetterByValue + | Opcode::SetPropertySetterByValue + | Opcode::DefineClassSetterByValue + | Opcode::DeletePropertyByValue + | Opcode::ToPropertyKey + | Opcode::ToBoolean + | Opcode::Throw + | Opcode::TryEnd + | Opcode::CatchEnd + | Opcode::CatchEnd2 + | Opcode::FinallyStart + | Opcode::FinallyEnd + | Opcode::This + | Opcode::Super + | Opcode::Return + | Opcode::PopEnvironment + | Opcode::LoopStart + | Opcode::LoopContinue + | Opcode::LoopEnd + | Opcode::InitIterator + | Opcode::InitIteratorAsync + | Opcode::IteratorNext + | Opcode::IteratorClose + | Opcode::IteratorToArray + | Opcode::RequireObjectCoercible + | Opcode::ValueNotNullOrUndefined + | Opcode::RestParameterInit + | Opcode::RestParameterPop + | Opcode::PushValueToArray + | Opcode::PushElisionToArray + | Opcode::PushIteratorToArray + | Opcode::PushNewArray + | Opcode::PopOnReturnAdd + | Opcode::PopOnReturnSub + | Opcode::Yield + | Opcode::GeneratorNext + | Opcode::AsyncGeneratorNext + | Opcode::PushClassField + | Opcode::SuperCallDerived + | Opcode::Await + | Opcode::PushNewTarget + | Opcode::CallEvalSpread + | Opcode::CallSpread + | Opcode::NewSpread + | Opcode::SuperCallSpread + | Opcode::ForAwaitOfLoopIterate + | Opcode::Nop => String::new(), } } } @@ -404,7 +404,7 @@ impl ToInternedString for CodeBlock { let opcode: Opcode = self.code[pc].try_into().expect("invalid opcode"); let opcode = opcode.as_str(); let previous_pc = pc; - let operands = self.instruction_erands(&mut pc, interner); + let operands = self.instruction_operands(&mut pc, interner); f.push_str(&format!( "{previous_pc:06} {count:04} {opcode:<27}{operands}\n", )); diff --git a/boa_engine/src/vm/mod.rs b/boa_engine/src/vm/mod.rs index 0a35e98ff2e..bc22b9688fe 100644 --- a/boa_engine/src/vm/mod.rs +++ b/boa_engine/src/vm/mod.rs @@ -3,22 +3,9 @@ //! plus an interpreter to execute those instructions use crate::{ - builtins::{ - async_generator::{AsyncGenerator, AsyncGeneratorState}, - function::{ConstructorKind, Function}, - iterable::{IteratorHint, IteratorRecord, IteratorResult}, - Array, ForInIterator, JsArgs, Number, Promise, - }, - environments::EnvironmentSlots, - error::JsNativeError, - object::{FunctionBuilder, JsFunction, JsObject, ObjectData, PrivateElement}, - property::{DescriptorKind, PropertyDescriptor, PropertyDescriptorBuilder, PropertyKey}, - value::Numeric, - vm::{ - call_frame::CatchAddresses, - code_block::{initialize_instance_elements, Readable}, - }, - Context, JsBigInt, JsError, JsResult, JsString, JsValue, + builtins::async_generator::{AsyncGenerator, AsyncGeneratorState}, + vm::{call_frame::CatchAddresses, code_block::Readable}, + Context, JsResult, JsValue, }; use boa_interner::ToInternedString; use boa_profiler::Profiler; @@ -28,6 +15,7 @@ mod call_frame; mod code_block; mod opcode; +#[allow(clippy::wildcard_imports)] use opcode::*; pub use {call_frame::CallFrame, code_block::CodeBlock, opcode::Opcode}; @@ -111,7 +99,7 @@ impl Vm { /// Indicates if the execution should continue, exit or yield. #[derive(Debug, Clone, Copy)] -enum ShouldExit { +pub(crate) enum ShouldExit { True, False, Yield, @@ -139,168 +127,168 @@ impl Context { let _timer = Profiler::global().start_event(opcode.as_instruction_str(), "vm"); let result = match opcode { - Opcode::Nop(op) => Nop::execute(self)?, - Opcode::Pop(op) => Pop::execute(self)?, - Opcode::PopIfThrown(op) => PopIfThrown::execute(self)?, - Opcode::Dup(op) => Dup::execute(self)?, - Opcode::Swap(op) => Swap::execute(self)?, - Opcode::PushUndefined(op) => PushUndefined::execute(self)?, - Opcode::PushNull(op) => PushNull::execute(self)?, - Opcode::PushTrue(op) => PushTrue::execute(self)?, - Opcode::PushFalse(op) => PushFalse::execute(self)?, - Opcode::PushZero(op) => PushZero::execute(self)?, - Opcode::PushOne(op) => PushOne::execute(self)?, - Opcode::PushInt8(op) => PushInt8::execute(self)?, - Opcode::PushInt16(op) => PushInt16::execute(self)?, - Opcode::PushInt32(op) => PushInt32::execute(self)?, - Opcode::PushRational(op) => PushRational::execute(self)?, - Opcode::PushNaN(op) => PushNaN::execute(self)?, - Opcode::PushPositiveInfinity(op) => PushPositiveInfinity::execute(self)?, - Opcode::PushNegativeInfinity(op) => PushNegativeInfinity::execute(self)?, - Opcode::PushLiteral(op) => PushLiteral::execute(self)?, - Opcode::PushEmptyObject(op) => PushEmptyObject::execute(self)?, - Opcode::PushClassPrototype(op) => PushClassPrototype::execute(self)?, - Opcode::SetClassPrototype(op) => SetClassPrototype::execute(self)?, - Opcode::SetHomeObject(op) => SetHomeObject::execute(self)?, - Opcode::PushNewArray(op) => PushNewArray::execute(self)?, - Opcode::PushValueToArray(op) => PushValueToArray::execute(self)?, - Opcode::PushElisionToArray(op) => PushElisionToArray::execute(self)?, - Opcode::PushIteratorToArray(op) => PushIteratorToArray::execute(self)?, - Opcode::Add(op) => Add::execute(self)?, - Opcode::Sub(op) => Sub::execute(self)?, - Opcode::Mul(op) => Mul::execute(self)?, - Opcode::Div(op) => Div::execute(self)?, - Opcode::Pow(op) => Pow::execute(self)?, - Opcode::Mod(op) => Mod::execute(self)?, - Opcode::BitAnd(op) => BitAnd::execute(self)?, - Opcode::BitOr(op) => BitOr::execute(self)?, - Opcode::BitXor(op) => BitXor::execute(self)?, - Opcode::ShiftLeft(op) => ShiftLeft::execute(self)?, - Opcode::ShiftRight(op) => ShiftRight::execute(self)?, - Opcode::UnsignedShiftRight(op) => UnsignedShiftRight::execute(self)?, - Opcode::Eq(op) => Eq::execute(self)?, - Opcode::NotEq(op) => NotEq::execute(self)?, - Opcode::StrictEq(op) => StrictEq::execute(self)?, - Opcode::StrictNotEq(op) => StrictNotEq::execute(self)?, - Opcode::GreaterThan(op) => GreaterThan::execute(self)?, - Opcode::GreaterThanOrEq(op) => GreaterThanOrEq::execute(self)?, - Opcode::LessThan(op) => LessThan::execute(self)?, - Opcode::LessThanOrEq(op) => LessThanOrEq::execute(self)?, - Opcode::In(op) => In::execute(self)?, - Opcode::InstanceOf(op) => InstanceOf::execute(self)?, - Opcode::Void(op) => Void::execute(self)?, - Opcode::TypeOf(op) => TypeOf::execute(self)?, - Opcode::Pos(op) => Pos::execute(self)?, - Opcode::Neg(op) => Neg::execute(self)?, - Opcode::Inc(op) => Inc::execute(self)?, - Opcode::IncPost(op) => IncPost::execute(self)?, - Opcode::Dec(op) => Dec::execute(self)?, - Opcode::DecPost(op) => DecPost::execute(self)?, - Opcode::LogicalNot(op) => LogicalNot::execute(self)?, - Opcode::BitNot(op) => BitNot::execute(self)?, - Opcode::DefVar(op) => DefVar::execute(self)?, - Opcode::DefInitVar(op) => DefInitVar::execute(self)?, - Opcode::DefLet(op) => DefLet::execute(self)?, - Opcode::DefInitLet(op) => DefInitLet::execute(self)?, - Opcode::DefInitConst(op) => DefInitConst::execute(self)?, - Opcode::DefInitArg(op) => DefInitArg::execute(self)?, - Opcode::GetName(op) => GetName::execute(self)?, - Opcode::GetNameOrUndefined(op) => GetNameOrUndefined::execute(self)?, - Opcode::SetName(op) => SetName::execute(self)?, - Opcode::Jump(op) => Jump::execute(self)?, - Opcode::JumpIfFalse(op) => JumpIfFalse::execute(self)?, - Opcode::JumpIfNotUndefined(op) => JumpIfNotUndefined::execute(self)?, - Opcode::LogicalAnd(op) => LogicalAnd::execute(self)?, - Opcode::LogicalOr(op) => LogicalOr::execute(self)?, - Opcode::Coalesce(op) => Coalesce::execute(self)?, - Opcode::ToBoolean(op) => ToBoolean::execute(self)?, - Opcode::GetPropertyByName(op) => GetPropertyByName::execute(self)?, - Opcode::GetPropertyByValue(op) => GetPropertyByValue::execute(self)?, - Opcode::GetPropertyByValuePush(op) => GetPropertyByValuePush::execute(self)?, - Opcode::SetPropertyByName(op) => SetPropertyByName::execute(self)?, - Opcode::DefineOwnPropertyByName(op) => DefineOwnPropertyByName::execute(self)?, - Opcode::DefineClassMethodByName(op) => DefineClassMethodByName::execute(self)?, - Opcode::SetPropertyByValue(op) => SetPropertyByValue::execute(self)?, - Opcode::DefineOwnPropertyByValue(op) => DefineOwnPropertyByValue::execute(self)?, - Opcode::DefineClassMethodByValue(op) => DefineClassMethodByValue::execute(self)?, - Opcode::SetPropertyGetterByName(op) => SetPropertyGetterByName::execute(self)?, - Opcode::DefineClassGetterByName(op) => DefineClassGetterByName::execute(self)?, - Opcode::SetPropertyGetterByValue(op) => SetPropertyGetterByValue::execute(self)?, - Opcode::DefineClassGetterByValue(op) => DefineClassGetterByValue::execute(self)?, - Opcode::SetPropertySetterByName(op) => SetPropertySetterByName::execute(self)?, - Opcode::DefineClassSetterByName(op) => DefineClassSetterByName::execute(self)?, - Opcode::SetPropertySetterByValue(op) => SetPropertySetterByValue::execute(self)?, - Opcode::DefineClassSetterByValue(op) => DefineClassSetterByValue::execute(self)?, - Opcode::AssignPrivateField(op) => AssignPrivateField::execute(self)?, - Opcode::SetPrivateField(op) => SetPrivateField::execute(self)?, - Opcode::SetPrivateMethod(op) => SetPrivateMethod::execute(self)?, - Opcode::SetPrivateSetter(op) => SetPrivateSetter::execute(self)?, - Opcode::SetPrivateGetter(op) => SetPrivateGetter::execute(self)?, - Opcode::GetPrivateField(op) => GetPrivateField::execute(self)?, - Opcode::PushClassField(op) => PushClassField::execute(self)?, - Opcode::PushClassFieldPrivate(op) => PushClassFieldPrivate::execute(self)?, - Opcode::PushClassPrivateGetter(op) => PushClassPrivateGetter::execute(self)?, - Opcode::PushClassPrivateSetter(op) => PushClassPrivateSetter::execute(self)?, - Opcode::PushClassPrivateMethod(op) => PushClassPrivateMethod::execute(self)?, - Opcode::DeletePropertyByName(op) => DeletePropertyByName::execute(self)?, - Opcode::DeletePropertyByValue(op) => DeletePropertyByValue::execute(self)?, - Opcode::CopyDataProperties(op) => CopyDataProperties::execute(self)?, - Opcode::ToPropertyKey(op) => ToPropertyKey::execute(self)?, - Opcode::Throw(op) => Throw::execute(self)?, - Opcode::TryStart(op) => TryStart::execute(self)?, - Opcode::TryEnd(op) => TryEnd::execute(self)?, - Opcode::CatchEnd(op) => CatchEnd::execute(self)?, - Opcode::CatchStart(op) => CatchStart::execute(self)?, - Opcode::CatchEnd2(op) => CatchEnd2::execute(self)?, - Opcode::FinallyStart(op) => FinallyStart::execute(self)?, - Opcode::FinallyEnd(op) => FinallyEnd::execute(self)?, - Opcode::FinallySetJump(op) => FinallySetJump::execute(self)?, - Opcode::This(op) => This::execute(self)?, - Opcode::Super(op) => Super::execute(self)?, - Opcode::SuperCall(op) => SuperCall::execute(self)?, - Opcode::SuperCallSpread(op) => SuperCallSpread::execute(self)?, - Opcode::SuperCallDerived(op) => SuperCallDerived::execute(self)?, - Opcode::Case(op) => Case::execute(self)?, - Opcode::Default(op) => Default::execute(self)?, - Opcode::GetFunction(op) => GetFunction::execute(self)?, - Opcode::GetFunctionAsync(op) => GetFunctionAsync::execute(self)?, - Opcode::GetGenerator(op) => GetGenerator::execute(self)?, - Opcode::GetGeneratorAsync(op) => GetGeneratorAsync::execute(self)?, - Opcode::CallEval(op) => CallEval::execute(self)?, - Opcode::CallEvalSpread(op) => CallEvalSpread::execute(self)?, - Opcode::Call(op) => Call::execute(self)?, - Opcode::CallSpread(op) => CallSpread::execute(self)?, - Opcode::New(op) => New::execute(self)?, - Opcode::NewSpread(op) => NewSpread::execute(self)?, - Opcode::Return(op) => Return::execute(self)?, - Opcode::PushDeclarativeEnvironment(op) => PushDeclarativeEnvironment::execute(self)?, - Opcode::PushFunctionEnvironment(op) => PushFunctionEnvironment::execute(self)?, - Opcode::PopEnvironment(op) => PopEnvironment::execute(self)?, - Opcode::LoopStart(op) => LoopStart::execute(self)?, - Opcode::LoopContinue(op) => LoopContinue::execute(self)?, - Opcode::LoopEnd(op) => LoopEnd::execute(self)?, - Opcode::ForInLoopInitIterator(op) => ForInLoopInitIterator::execute(self)?, - Opcode::InitIterator(op) => InitIterator::execute(self)?, - Opcode::InitIteratorAsync(op) => InitIteratorAsync::execute(self)?, - Opcode::IteratorNext(op) => IteratorNext::execute(self)?, - Opcode::IteratorClose(op) => IteratorClose::execute(self)?, - Opcode::IteratorToArray(op) => IteratorToArray::execute(self)?, - Opcode::ForInLoopNext(op) => ForInLoopNext::execute(self)?, - Opcode::ForAwaitOfLoopIterate(op) => ForAwaitOfLoopIterate::execute(self)?, - Opcode::ForAwaitOfLoopNext(op) => ForAwaitOfLoopNext::execute(self)?, - Opcode::ConcatToString(op) => ConcatToString::execute(self)?, - Opcode::RequireObjectCoercible(op) => RequireObjectCoercible::execute(self)?, - Opcode::ValueNotNullOrUndefined(op) => ValueNotNullOrUndefined::execute(self)?, - Opcode::RestParameterInit(op) => RestParameterInit::execute(self)?, - Opcode::RestParameterPop(op) => RestParameterPop::execute(self)?, - Opcode::PopOnReturnAdd(op) => PopOnReturnAdd::execute(self)?, - Opcode::PopOnReturnSub(op) => PopOnReturnSub::execute(self)?, - Opcode::Yield(op) => Yield::execute(self)?, - Opcode::GeneratorNext(op) => GeneratorNext::execute(self)?, - Opcode::AsyncGeneratorNext(op) => AsyncGeneratorNext::execute(self)?, - Opcode::GeneratorNextDelegate(op) => GeneratorNextDelegate::execute(self)?, - Opcode::Await(op) => Await::execute(self)?, - Opcode::PushNewTarget(op) => PushNewTarget::execute(self)?, + Opcode::Nop => Nop::execute(self)?, + Opcode::Pop => Pop::execute(self)?, + Opcode::PopIfThrown => PopIfThrown::execute(self)?, + Opcode::Dup => Dup::execute(self)?, + Opcode::Swap => Swap::execute(self)?, + Opcode::PushUndefined => PushUndefined::execute(self)?, + Opcode::PushNull => PushNull::execute(self)?, + Opcode::PushTrue => PushTrue::execute(self)?, + Opcode::PushFalse => PushFalse::execute(self)?, + Opcode::PushZero => PushZero::execute(self)?, + Opcode::PushOne => PushOne::execute(self)?, + Opcode::PushInt8 => PushInt8::execute(self)?, + Opcode::PushInt16 => PushInt16::execute(self)?, + Opcode::PushInt32 => PushInt32::execute(self)?, + Opcode::PushRational => PushRational::execute(self)?, + Opcode::PushNaN => PushNaN::execute(self)?, + Opcode::PushPositiveInfinity => PushPositiveInfinity::execute(self)?, + Opcode::PushNegativeInfinity => PushNegativeInfinity::execute(self)?, + Opcode::PushLiteral => PushLiteral::execute(self)?, + Opcode::PushEmptyObject => PushEmptyObject::execute(self)?, + Opcode::PushClassPrototype => PushClassPrototype::execute(self)?, + Opcode::SetClassPrototype => SetClassPrototype::execute(self)?, + Opcode::SetHomeObject => SetHomeObject::execute(self)?, + Opcode::PushNewArray => PushNewArray::execute(self)?, + Opcode::PushValueToArray => PushValueToArray::execute(self)?, + Opcode::PushElisionToArray => PushElisionToArray::execute(self)?, + Opcode::PushIteratorToArray => PushIteratorToArray::execute(self)?, + Opcode::Add => Add::execute(self)?, + Opcode::Sub => Sub::execute(self)?, + Opcode::Mul => Mul::execute(self)?, + Opcode::Div => Div::execute(self)?, + Opcode::Pow => Pow::execute(self)?, + Opcode::Mod => Mod::execute(self)?, + Opcode::BitAnd => BitAnd::execute(self)?, + Opcode::BitOr => BitOr::execute(self)?, + Opcode::BitXor => BitXor::execute(self)?, + Opcode::ShiftLeft => ShiftLeft::execute(self)?, + Opcode::ShiftRight => ShiftRight::execute(self)?, + Opcode::UnsignedShiftRight => UnsignedShiftRight::execute(self)?, + Opcode::Eq => Eq::execute(self)?, + Opcode::NotEq => NotEq::execute(self)?, + Opcode::StrictEq => StrictEq::execute(self)?, + Opcode::StrictNotEq => StrictNotEq::execute(self)?, + Opcode::GreaterThan => GreaterThan::execute(self)?, + Opcode::GreaterThanOrEq => GreaterThanOrEq::execute(self)?, + Opcode::LessThan => LessThan::execute(self)?, + Opcode::LessThanOrEq => LessThanOrEq::execute(self)?, + Opcode::In => In::execute(self)?, + Opcode::InstanceOf => InstanceOf::execute(self)?, + Opcode::Void => Void::execute(self)?, + Opcode::TypeOf => TypeOf::execute(self)?, + Opcode::Pos => Pos::execute(self)?, + Opcode::Neg => Neg::execute(self)?, + Opcode::Inc => Inc::execute(self)?, + Opcode::IncPost => IncPost::execute(self)?, + Opcode::Dec => Dec::execute(self)?, + Opcode::DecPost => DecPost::execute(self)?, + Opcode::LogicalNot => LogicalNot::execute(self)?, + Opcode::BitNot => BitNot::execute(self)?, + Opcode::DefVar => DefVar::execute(self)?, + Opcode::DefInitVar => DefInitVar::execute(self)?, + Opcode::DefLet => DefLet::execute(self)?, + Opcode::DefInitLet => DefInitLet::execute(self)?, + Opcode::DefInitConst => DefInitConst::execute(self)?, + Opcode::DefInitArg => DefInitArg::execute(self)?, + Opcode::GetName => GetName::execute(self)?, + Opcode::GetNameOrUndefined => GetNameOrUndefined::execute(self)?, + Opcode::SetName => SetName::execute(self)?, + Opcode::Jump => Jump::execute(self)?, + Opcode::JumpIfFalse => JumpIfFalse::execute(self)?, + Opcode::JumpIfNotUndefined => JumpIfNotUndefined::execute(self)?, + Opcode::LogicalAnd => LogicalAnd::execute(self)?, + Opcode::LogicalOr => LogicalOr::execute(self)?, + Opcode::Coalesce => Coalesce::execute(self)?, + Opcode::ToBoolean => ToBoolean::execute(self)?, + Opcode::GetPropertyByName => GetPropertyByName::execute(self)?, + Opcode::GetPropertyByValue => GetPropertyByValue::execute(self)?, + Opcode::GetPropertyByValuePush => GetPropertyByValuePush::execute(self)?, + Opcode::SetPropertyByName => SetPropertyByName::execute(self)?, + Opcode::DefineOwnPropertyByName => DefineOwnPropertyByName::execute(self)?, + Opcode::DefineClassMethodByName => DefineClassMethodByName::execute(self)?, + Opcode::SetPropertyByValue => SetPropertyByValue::execute(self)?, + Opcode::DefineOwnPropertyByValue => DefineOwnPropertyByValue::execute(self)?, + Opcode::DefineClassMethodByValue => DefineClassMethodByValue::execute(self)?, + Opcode::SetPropertyGetterByName => SetPropertyGetterByName::execute(self)?, + Opcode::DefineClassGetterByName => DefineClassGetterByName::execute(self)?, + Opcode::SetPropertyGetterByValue => SetPropertyGetterByValue::execute(self)?, + Opcode::DefineClassGetterByValue => DefineClassGetterByValue::execute(self)?, + Opcode::SetPropertySetterByName => SetPropertySetterByName::execute(self)?, + Opcode::DefineClassSetterByName => DefineClassSetterByName::execute(self)?, + Opcode::SetPropertySetterByValue => SetPropertySetterByValue::execute(self)?, + Opcode::DefineClassSetterByValue => DefineClassSetterByValue::execute(self)?, + Opcode::AssignPrivateField => AssignPrivateField::execute(self)?, + Opcode::SetPrivateField => SetPrivateField::execute(self)?, + Opcode::SetPrivateMethod => SetPrivateMethod::execute(self)?, + Opcode::SetPrivateSetter => SetPrivateSetter::execute(self)?, + Opcode::SetPrivateGetter => SetPrivateGetter::execute(self)?, + Opcode::GetPrivateField => GetPrivateField::execute(self)?, + Opcode::PushClassField => PushClassField::execute(self)?, + Opcode::PushClassFieldPrivate => PushClassFieldPrivate::execute(self)?, + Opcode::PushClassPrivateGetter => PushClassPrivateGetter::execute(self)?, + Opcode::PushClassPrivateSetter => PushClassPrivateSetter::execute(self)?, + Opcode::PushClassPrivateMethod => PushClassPrivateMethod::execute(self)?, + Opcode::DeletePropertyByName => DeletePropertyByName::execute(self)?, + Opcode::DeletePropertyByValue => DeletePropertyByValue::execute(self)?, + Opcode::CopyDataProperties => CopyDataProperties::execute(self)?, + Opcode::ToPropertyKey => ToPropertyKey::execute(self)?, + Opcode::Throw => Throw::execute(self)?, + Opcode::TryStart => TryStart::execute(self)?, + Opcode::TryEnd => TryEnd::execute(self)?, + Opcode::CatchEnd => CatchEnd::execute(self)?, + Opcode::CatchStart => CatchStart::execute(self)?, + Opcode::CatchEnd2 => CatchEnd2::execute(self)?, + Opcode::FinallyStart => FinallyStart::execute(self)?, + Opcode::FinallyEnd => FinallyEnd::execute(self)?, + Opcode::FinallySetJump => FinallySetJump::execute(self)?, + Opcode::This => This::execute(self)?, + Opcode::Super => Super::execute(self)?, + Opcode::SuperCall => SuperCall::execute(self)?, + Opcode::SuperCallSpread => SuperCallSpread::execute(self)?, + Opcode::SuperCallDerived => SuperCallDerived::execute(self)?, + Opcode::Case => Case::execute(self)?, + Opcode::Default => Default::execute(self)?, + Opcode::GetFunction => GetFunction::execute(self)?, + Opcode::GetFunctionAsync => GetFunctionAsync::execute(self)?, + Opcode::GetGenerator => GetGenerator::execute(self)?, + Opcode::GetGeneratorAsync => GetGeneratorAsync::execute(self)?, + Opcode::CallEval => CallEval::execute(self)?, + Opcode::CallEvalSpread => CallEvalSpread::execute(self)?, + Opcode::Call => Call::execute(self)?, + Opcode::CallSpread => CallSpread::execute(self)?, + Opcode::New => New::execute(self)?, + Opcode::NewSpread => NewSpread::execute(self)?, + Opcode::Return => Return::execute(self)?, + Opcode::PushDeclarativeEnvironment => PushDeclarativeEnvironment::execute(self)?, + Opcode::PushFunctionEnvironment => PushFunctionEnvironment::execute(self)?, + Opcode::PopEnvironment => PopEnvironment::execute(self)?, + Opcode::LoopStart => LoopStart::execute(self)?, + Opcode::LoopContinue => LoopContinue::execute(self)?, + Opcode::LoopEnd => LoopEnd::execute(self)?, + Opcode::ForInLoopInitIterator => ForInLoopInitIterator::execute(self)?, + Opcode::InitIterator => InitIterator::execute(self)?, + Opcode::InitIteratorAsync => InitIteratorAsync::execute(self)?, + Opcode::IteratorNext => IteratorNext::execute(self)?, + Opcode::IteratorClose => IteratorClose::execute(self)?, + Opcode::IteratorToArray => IteratorToArray::execute(self)?, + Opcode::ForInLoopNext => ForInLoopNext::execute(self)?, + Opcode::ForAwaitOfLoopIterate => ForAwaitOfLoopIterate::execute(self)?, + Opcode::ForAwaitOfLoopNext => ForAwaitOfLoopNext::execute(self)?, + Opcode::ConcatToString => ConcatToString::execute(self)?, + Opcode::RequireObjectCoercible => RequireObjectCoercible::execute(self)?, + Opcode::ValueNotNullOrUndefined => ValueNotNullOrUndefined::execute(self)?, + Opcode::RestParameterInit => RestParameterInit::execute(self)?, + Opcode::RestParameterPop => RestParameterPop::execute(self)?, + Opcode::PopOnReturnAdd => PopOnReturnAdd::execute(self)?, + Opcode::PopOnReturnSub => PopOnReturnSub::execute(self)?, + Opcode::Yield => Yield::execute(self)?, + Opcode::GeneratorNext => GeneratorNext::execute(self)?, + Opcode::AsyncGeneratorNext => AsyncGeneratorNext::execute(self)?, + Opcode::GeneratorNextDelegate => GeneratorNextDelegate::execute(self)?, + Opcode::Await => Await::execute(self)?, + Opcode::PushNewTarget => PushNewTarget::execute(self)?, }; Ok(result) diff --git a/boa_engine/src/vm/opcode/define/own_property.rs b/boa_engine/src/vm/opcode/define/own_property.rs index fbd66d09b18..a8ccf81249d 100644 --- a/boa_engine/src/vm/opcode/define/own_property.rs +++ b/boa_engine/src/vm/opcode/define/own_property.rs @@ -1,5 +1,5 @@ use crate::{ - property::{PropertyDescriptor, PropertyKey}, + property::PropertyDescriptor, vm::{opcode::Operation, ShouldExit}, Context, JsResult, }; diff --git a/boa_engine/src/vm/opcode/general/bin_ops.rs b/boa_engine/src/vm/opcode/general/bin_ops.rs new file mode 100644 index 00000000000..58cd11514fe --- /dev/null +++ b/boa_engine/src/vm/opcode/general/bin_ops.rs @@ -0,0 +1,42 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +macro_rules! implement_bin_ops { + ($name:ident, $op:ident) => { + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub(crate) struct $name; + + impl Operation for $name { + const NAME: &'static str = stringify!($name); + const INSTRUCTION: &'static str = stringify!("INST - " + $name); + + fn execute(context: &mut Context) -> JsResult { + let rhs = context.vm.pop(); + let lhs = context.vm.pop(); + let value = lhs.$op(&rhs, context)?; + context.vm.push(value); + Ok(ShouldExit::False) + } + } + }; +} + +implement_bin_ops!(Add, add); +implement_bin_ops!(Sub, sub); +implement_bin_ops!(Mul, mul); +implement_bin_ops!(Div, div); +implement_bin_ops!(Pow, pow); +implement_bin_ops!(Mod, rem); +implement_bin_ops!(BitAnd, bitand); +implement_bin_ops!(BitOr, bitor); +implement_bin_ops!(BitXor, bitxor); +implement_bin_ops!(ShiftLeft, shl); +implement_bin_ops!(ShiftRight, shr); +implement_bin_ops!(UnsignedShiftRight, ushr); +implement_bin_ops!(Eq, equals); +implement_bin_ops!(GreaterThan, gt); +implement_bin_ops!(GreaterThanOrEq, ge); +implement_bin_ops!(LessThan, lt); +implement_bin_ops!(LessThanOrEq, le); diff --git a/boa_engine/src/vm/opcode/general/decrement.rs b/boa_engine/src/vm/opcode/general/decrement.rs new file mode 100644 index 00000000000..0574056b996 --- /dev/null +++ b/boa_engine/src/vm/opcode/general/decrement.rs @@ -0,0 +1,45 @@ +use crate::{ + value::Numeric, + vm::{opcode::Operation, ShouldExit}, + Context, JsBigInt, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Dec; + +impl Operation for Dec { + const NAME: &'static str = "Dec"; + const INSTRUCTION: &'static str = "INST - Dec"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + match value.to_numeric(context)? { + Numeric::Number(number) => context.vm.push(number - 1f64), + Numeric::BigInt(bigint) => { + context.vm.push(JsBigInt::sub(&bigint, &JsBigInt::one())); + } + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct DecPost; + +impl Operation for DecPost { + const NAME: &'static str = "DecPost"; + const INSTRUCTION: &'static str = "INST - DecPost"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + let value = value.to_numeric(context)?; + context.vm.push(value.clone()); + match value { + Numeric::Number(number) => context.vm.push(number - 1f64), + Numeric::BigInt(bigint) => { + context.vm.push(JsBigInt::sub(&bigint, &JsBigInt::one())); + } + } + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/general/increment.rs b/boa_engine/src/vm/opcode/general/increment.rs new file mode 100644 index 00000000000..039d585fb84 --- /dev/null +++ b/boa_engine/src/vm/opcode/general/increment.rs @@ -0,0 +1,45 @@ +use crate::{ + value::Numeric, + vm::{opcode::Operation, ShouldExit}, + Context, JsBigInt, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Inc; + +impl Operation for Inc { + const NAME: &'static str = "Inc"; + const INSTRUCTION: &'static str = "INST - Inc"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + match value.to_numeric(context)? { + Numeric::Number(number) => context.vm.push(number + 1f64), + Numeric::BigInt(bigint) => { + context.vm.push(JsBigInt::add(&bigint, &JsBigInt::one())); + } + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct IncPost; + +impl Operation for IncPost { + const NAME: &'static str = "IncPost"; + const INSTRUCTION: &'static str = "INST - IncPost"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + let value = value.to_numeric(context)?; + context.vm.push(value.clone()); + match value { + Numeric::Number(number) => context.vm.push(number + 1f64), + Numeric::BigInt(bigint) => { + context.vm.push(JsBigInt::add(&bigint, &JsBigInt::one())); + } + } + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/general/jump.rs b/boa_engine/src/vm/opcode/general/jump.rs index 586c4697397..6dea7045b16 100644 --- a/boa_engine/src/vm/opcode/general/jump.rs +++ b/boa_engine/src/vm/opcode/general/jump.rs @@ -1,6 +1,6 @@ use crate::{ vm::{opcode::Operation, ShouldExit}, - Context, JsResult, JsValue, + Context, JsResult, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] diff --git a/boa_engine/src/vm/opcode/general/mod.rs b/boa_engine/src/vm/opcode/general/mod.rs index 7d97a2edf0f..dea02c62bbb 100644 --- a/boa_engine/src/vm/opcode/general/mod.rs +++ b/boa_engine/src/vm/opcode/general/mod.rs @@ -6,9 +6,15 @@ use crate::{ }; use std::ops::Neg as StdNeg; +pub(crate) mod bin_ops; +pub(crate) mod decrement; +pub(crate) mod increment; pub(crate) mod jump; pub(crate) mod logical; +pub(crate) use bin_ops::*; +pub(crate) use decrement::*; +pub(crate) use increment::*; pub(crate) use jump::*; pub(crate) use logical::*; @@ -19,7 +25,7 @@ impl Operation for Nop { const NAME: &'static str = "Nop"; const INSTRUCTION: &'static str = "INST - Nop"; - fn execute(context: &mut Context) -> JsResult { + fn execute(_context: &mut Context) -> JsResult { Ok(ShouldExit::False) } } @@ -171,86 +177,6 @@ impl Operation for Neg { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct Inc; - -impl Operation for Inc { - const NAME: &'static str = "Inc"; - const INSTRUCTION: &'static str = "INST - Inc"; - - fn execute(context: &mut Context) -> JsResult { - let value = context.vm.pop(); - match value.to_numeric(context)? { - Numeric::Number(number) => context.vm.push(number + 1f64), - Numeric::BigInt(bigint) => { - context.vm.push(JsBigInt::add(&bigint, &JsBigInt::one())); - } - } - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct IncPost; - -impl Operation for IncPost { - const NAME: &'static str = "IncPost"; - const INSTRUCTION: &'static str = "INST - IncPost"; - - fn execute(context: &mut Context) -> JsResult { - let value = context.vm.pop(); - let value = value.to_numeric(context)?; - context.vm.push(value.clone()); - match value { - Numeric::Number(number) => context.vm.push(number + 1f64), - Numeric::BigInt(bigint) => { - context.vm.push(JsBigInt::add(&bigint, &JsBigInt::one())); - } - } - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct Dec; - -impl Operation for Dec { - const NAME: &'static str = "Dec"; - const INSTRUCTION: &'static str = "INST - Dec"; - - fn execute(context: &mut Context) -> JsResult { - let value = context.vm.pop(); - match value.to_numeric(context)? { - Numeric::Number(number) => context.vm.push(number - 1f64), - Numeric::BigInt(bigint) => { - context.vm.push(JsBigInt::sub(&bigint, &JsBigInt::one())); - } - } - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct DecPost; - -impl Operation for DecPost { - const NAME: &'static str = "DecPost"; - const INSTRUCTION: &'static str = "INST - DecPost"; - - fn execute(context: &mut Context) -> JsResult { - let value = context.vm.pop(); - let value = value.to_numeric(context)?; - context.vm.push(value.clone()); - match value { - Numeric::Number(number) => context.vm.push(number - 1f64), - Numeric::BigInt(bigint) => { - context.vm.push(JsBigInt::sub(&bigint, &JsBigInt::one())); - } - } - Ok(ShouldExit::False) - } -} - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct BitNot; @@ -267,41 +193,3 @@ impl Operation for BitNot { Ok(ShouldExit::False) } } - -macro_rules! implement_bin_ops { - ($name:ident, $op:ident) => { - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] - pub(crate) struct $name; - - impl Operation for $name { - const NAME: &'static str = stringify!($name); - const INSTRUCTION: &'static str = stringify!("INST - " + $name); - - fn execute(context: &mut Context) -> JsResult { - let rhs = context.vm.pop(); - let lhs = context.vm.pop(); - let value = lhs.$op(&rhs, context)?; - context.vm.push(value); - Ok(ShouldExit::False) - } - } - }; -} - -implement_bin_ops!(Add, add); -implement_bin_ops!(Sub, sub); -implement_bin_ops!(Mul, mul); -implement_bin_ops!(Div, div); -implement_bin_ops!(Pow, pow); -implement_bin_ops!(Mod, rem); -implement_bin_ops!(BitAnd, bitand); -implement_bin_ops!(BitOr, bitor); -implement_bin_ops!(BitXor, bitxor); -implement_bin_ops!(ShiftLeft, shl); -implement_bin_ops!(ShiftRight, shr); -implement_bin_ops!(UnsignedShiftRight, ushr); -implement_bin_ops!(Eq, equals); -implement_bin_ops!(GreaterThan, gt); -implement_bin_ops!(GreaterThanOrEq, ge); -implement_bin_ops!(LessThan, lt); -implement_bin_ops!(LessThanOrEq, le); diff --git a/boa_engine/src/vm/opcode/generator/mod.rs b/boa_engine/src/vm/opcode/generator/mod.rs index 140b4000854..de6cd372d4c 100644 --- a/boa_engine/src/vm/opcode/generator/mod.rs +++ b/boa_engine/src/vm/opcode/generator/mod.rs @@ -18,7 +18,7 @@ impl Operation for Yield { const NAME: &'static str = "Yield"; const INSTRUCTION: &'static str = "INST - Yield"; - fn execute(context: &mut Context) -> JsResult { + fn execute(_context: &mut Context) -> JsResult { Ok(ShouldExit::Yield) } } @@ -32,10 +32,10 @@ impl Operation for GeneratorNext { fn execute(context: &mut Context) -> JsResult { match context.vm.frame().generator_resume_kind { - GeneratorResumeKind::Normal => return Ok(ShouldExit::False), + GeneratorResumeKind::Normal => Ok(ShouldExit::False), GeneratorResumeKind::Throw => { let received = context.vm.pop(); - return Err(received); + Err(received) } GeneratorResumeKind::Return => { let mut finally_left = false; @@ -55,7 +55,7 @@ impl Operation for GeneratorNext { if finally_left { return Ok(ShouldExit::False); } - return Ok(ShouldExit::True); + Ok(ShouldExit::True) } } } @@ -156,7 +156,7 @@ impl Operation for GeneratorNextDelegate { context.vm.push(next_method.clone()); context.vm.push(done); context.vm.push(value); - return Ok(ShouldExit::Yield); + Ok(ShouldExit::Yield) } GeneratorResumeKind::Throw => { let throw = iterator.get_method("throw", context)?; @@ -183,7 +183,7 @@ impl Operation for GeneratorNextDelegate { 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"); - return Err(error); + Err(error) } GeneratorResumeKind::Return => { let r#return = iterator.get_method("return", context)?; @@ -208,7 +208,7 @@ impl Operation for GeneratorNextDelegate { } context.vm.frame_mut().pc = done_address as usize; context.vm.push(received); - return Ok(ShouldExit::True); + Ok(ShouldExit::True) } } } diff --git a/boa_engine/src/vm/opcode/get/property.rs b/boa_engine/src/vm/opcode/get/property.rs index 7cccedb42a2..255cc22d7a7 100644 --- a/boa_engine/src/vm/opcode/get/property.rs +++ b/boa_engine/src/vm/opcode/get/property.rs @@ -1,7 +1,7 @@ use crate::{ property::PropertyKey, vm::{opcode::Operation, ShouldExit}, - Context, JsResult, JsString, JsValue, + Context, JsResult, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] diff --git a/boa_engine/src/vm/opcode/mod.rs b/boa_engine/src/vm/opcode/mod.rs index 9d671efc664..ac482981848 100644 --- a/boa_engine/src/vm/opcode/mod.rs +++ b/boa_engine/src/vm/opcode/mod.rs @@ -72,119 +72,119 @@ pub enum Opcode { /// Operands: /// /// Stack: value **=>** - Pop(Pop), + Pop, /// Pop the top value from the stack if the last try block has thrown a value. /// /// Operands: /// /// Stack: value **=>** - PopIfThrown(PopIfThrown), + PopIfThrown, /// Push a copy of the top value on the stack. /// /// Operands: /// /// Stack: value **=>** value, value - Dup(Dup), + Dup, /// Swap the top two values on the stack. /// /// Operands: /// /// Stack: second, first **=>** first, second - Swap(Swap), + Swap, /// Push integer `0` on the stack. /// /// Operands: /// /// Stack: **=>** `0` - PushZero(PushZero), + PushZero, /// Push integer `1` on the stack. /// /// Operands: /// /// Stack: **=>** `1` - PushOne(PushZero), + PushOne, /// Push `i8` value on the stack. /// /// Operands: value: `i8` /// /// Stack: **=>** value - PushInt8(PushInt8), + PushInt8, /// Push i16 value on the stack. /// /// Operands: value: `i16` /// /// Stack: **=>** value - PushInt16(PushInt16), + PushInt16, /// Push i32 value on the stack. /// /// Operands: value: `i32` /// /// Stack: **=>** value - PushInt32(PushInt32), + PushInt32, /// Push `f64` value on the stack. /// /// Operands: value: `f64` /// /// Stack: **=>** value - PushRational(PushRational), + PushRational, /// Push `NaN` integer on the stack. /// /// Operands: /// /// Stack: **=>** `NaN` - PushNaN(PushNaN), + PushNaN, /// Push `Infinity` value on the stack. /// /// Operands: /// /// Stack: **=>** `Infinity` - PushPositiveInfinity(PushPositiveInfinity), + PushPositiveInfinity, /// Push `-Infinity` value on the stack. /// /// Operands: /// /// Stack: **=>** `-Infinity` - PushNegativeInfinity(PushNegativeInfinity), + PushNegativeInfinity, /// Push `null` value on the stack. /// /// Operands: /// /// Stack: **=>** `null` - PushNull(PushNull), + PushNull, /// Push `true` value on the stack. /// /// Operands: /// /// Stack: **=>** `true` - PushTrue(PushTrue), + PushTrue, /// Push `false` value on the stack. /// /// Operands: /// /// Stack: **=>** `false` - PushFalse(PushFalse), + PushFalse, /// Push `undefined` value on the stack. /// /// Operands: /// /// Stack: **=>** `undefined` - PushUndefined(PushUndefined), + PushUndefined, /// Push literal value on the stack. /// @@ -194,224 +194,224 @@ pub enum Opcode { /// Operands: index: `u32` /// /// Stack: **=>** (`literals[index]`) - PushLiteral(PushLiteral), + PushLiteral, /// Push empty object `{}` value on the stack. /// /// Operands: /// /// Stack: **=>** `{}` - PushEmptyObject(PushEmptyObject), + PushEmptyObject, /// Get the prototype of a superclass and push it on the stack. /// /// Operands: /// /// Stack: class, superclass **=>** class, superclass.prototype - PushClassPrototype(PushClassPrototype), + PushClassPrototype, /// Set the prototype of a class object. /// /// Operands: /// /// Stack: class, prototype **=>** class.prototype - SetClassPrototype(SetClassPrototype), + SetClassPrototype, /// Set home object internal slot of a function object. /// /// Operands: /// /// Stack: home, function **=>** home, function - SetHomeObject(SetHomeObject), + SetHomeObject, /// Push an empty array value on the stack. /// /// Operands: /// /// Stack: **=>** `[]` - PushNewArray(PushNewArray), + PushNewArray, /// Push a value to an array. /// /// Operands: /// /// Stack: array, value **=>** array - PushValueToArray(PushValueToArray), + PushValueToArray, /// Push an empty element/hole to an array. /// /// Operands: /// /// Stack: array **=>** array - PushElisionToArray(PushElisionToArray), + PushElisionToArray, /// Push all iterator values to an array. /// /// Operands: /// /// Stack: array, iterator, next_method, done **=>** array - PushIteratorToArray(PushIteratorToArray), + PushIteratorToArray, /// Binary `+` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs + rhs) - Add(Add), + Add, /// Binary `-` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs - rhs) - Sub(Sub), + Sub, /// Binary `/` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs / rhs) - Div(Div), + Div, /// Binary `*` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs * rhs) - Mul(Mul), + Mul, /// Binary `%` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs % rhs) - Mod(Mod), + Mod, /// Binary `**` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs ** rhs) - Pow(Pow), + Pow, /// Binary `>>` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs >> rhs) - ShiftRight(ShiftRight), + ShiftRight, /// Binary `<<` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs << rhs) - ShiftLeft(ShiftLeft), + ShiftLeft, /// Binary `>>>` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs >>> rhs) - UnsignedShiftRight(UnsignedShiftRight), + UnsignedShiftRight, /// Binary bitwise `|` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs | rhs) - BitOr(BitOr), + BitOr, /// Binary bitwise `&` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs & rhs) - BitAnd(BitAnd), + BitAnd, /// Binary bitwise `^` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs ^ rhs) - BitXor(BitXor), + BitXor, /// Unary bitwise `~` operator. /// /// Operands: /// /// Stack: value **=>** ~value - BitNot(BitNot), + BitNot, /// Binary `in` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs `in` rhs) - In(In), + In, /// Binary `==` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs `==` rhs) - Eq(Eq), + Eq, /// Binary `===` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs `===` rhs) - StrictEq(StrictEq), + StrictEq, /// Binary `!=` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs `!=` rhs) - NotEq(NotEq), + NotEq, /// Binary `!==` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs `!==` rhs) - StrictNotEq(StrictNotEq), + StrictNotEq, /// Binary `>` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs > rhs) - GreaterThan(GreaterThan), + GreaterThan, /// Binary `>=` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs >= rhs) - GreaterThanOrEq(GreaterThanOrEq), + GreaterThanOrEq, /// Binary `<` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs < rhs) - LessThan(LessThan), + LessThan, /// Binary `<=` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs <= rhs) - LessThanOrEq(LessThanOrEq), + LessThanOrEq, /// Binary `instanceof` operator. /// /// Operands: /// /// Stack: lhs, rhs **=>** (lhs instanceof rhs) - InstanceOf(InstanceOf), + InstanceOf, /// Binary logical `&&` operator. /// @@ -420,7 +420,7 @@ pub enum Opcode { /// Operands: exit: `u32` /// /// Stack: lhs, rhs **=>** (lhs && rhs) - LogicalAnd(LogicalAnd), + LogicalAnd, /// Binary logical `||` operator. /// @@ -429,7 +429,7 @@ pub enum Opcode { /// Operands: exit: `u32` /// /// Stack: lhs, rhs **=>** (lhs || rhs) - LogicalOr(LogicalOr), + LogicalOr, /// Binary `??` operator. /// @@ -446,126 +446,126 @@ pub enum Opcode { /// Operands: /// /// Stack: value **=>** (`typeof` value) - TypeOf(TypeOf), + TypeOf, /// Unary `void` operator. /// /// Operands: /// /// Stack: value **=>** `undefined` - Void(Void), + Void, /// Unary logical `!` operator. /// /// Operands: /// /// Stack: value **=>** (!value) - LogicalNot(LogicalNot), + LogicalNot, /// Unary `+` operator. /// /// Operands: /// /// Stack: value **=>** (+value) - Pos(Pos), + Pos, /// Unary `-` operator. /// /// Operands: /// /// Stack: value **=>** (-value) - Neg(Neg), + Neg, /// Unary `++` operator. /// /// Operands: /// /// Stack: value **=>** (value + 1) - Inc(Inc), + Inc, /// Unary postfix `++` operator. /// /// Operands: /// /// Stack: value **=>** (ToNumeric(value)), (value + 1) - IncPost(IncPost), + IncPost, /// Unary `--` operator. /// /// Operands: /// /// Stack: value **=>** (value - 1) - Dec(Dec), + Dec, /// Unary postfix `--` operator. /// /// Operands: /// /// Stack: value **=>** (ToNumeric(value)), (value - 1) - DecPost(DecPost), + DecPost, /// Declare and initialize a function argument. /// /// Operands: name_index: `u32` /// /// Stack: value **=>** - DefInitArg(DefInitArg), + DefInitArg, /// Declare `var` type variable. /// /// Operands: name_index: `u32` /// /// Stack: **=>** - DefVar(DefVar), + DefVar, /// Declare and initialize `var` type variable. /// /// Operands: name_index: `u32` /// /// Stack: value, has_declarative_binding **=>** - DefInitVar(DefInitVar), + DefInitVar, /// Declare `let` type variable. /// /// Operands: name_index: `u32` /// /// Stack: **=>** - DefLet(DefLet), + DefLet, /// Declare and initialize `let` type variable. /// /// Operands: name_index: `u32` /// /// Stack: value **=>** - DefInitLet(DefInitLet), + DefInitLet, /// Declare and initialize `const` type variable. /// /// Operands: name_index: `u32` /// /// Stack: value **=>** - DefInitConst(DefInitConst), + DefInitConst, /// Find a binding on the environment chain and push its value. /// /// Operands: name_index: `u32` /// /// Stack: **=>** value - GetName(GetName), + GetName, /// Find a binding on the environment chain and push its value. If the binding does not exist push undefined. /// /// Operands: name_index: `u32` /// /// Stack: **=>** value - GetNameOrUndefined(GetNameOrUndefined), + GetNameOrUndefined, /// Find a binding on the environment chain and assign its value. /// /// Operands: name_index: `u32` /// /// Stack: value **=>** - SetName(SetName), + SetName, /// Get a property by name from an object an push it on the stack. /// @@ -574,7 +574,7 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: object **=>** value - GetPropertyByName(GetPropertyByName), + GetPropertyByName, /// Get a property by value from an object an push it on the stack. /// @@ -583,7 +583,7 @@ pub enum Opcode { /// Operands: /// /// Stack: key, object **=>** value - GetPropertyByValue(GetPropertyByValue), + GetPropertyByValue, /// Get a property by value from an object an push the key and value on the stack. /// @@ -592,7 +592,7 @@ pub enum Opcode { /// Operands: /// /// Stack: key, object **=>** key, value - GetPropertyByValuePush(GetPropertyByValuePush), + GetPropertyByValuePush, /// Sets a property by name of an object. /// @@ -601,21 +601,21 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: value, object **=>** - SetPropertyByName(SetPropertyByName), + SetPropertyByName, /// Defines a own property of an object by name. /// /// Operands: name_index: `u32` /// /// Stack: value, object **=>** - DefineOwnPropertyByName(DefineOwnPropertyByName), + DefineOwnPropertyByName, /// Defines a class method by name. /// /// Operands: name_index: `u32` /// /// Stack: value, object **=>** - DefineClassMethodByName(DefineClassMethodByName), + DefineClassMethodByName, /// Sets a property by value of an object. /// @@ -624,21 +624,21 @@ pub enum Opcode { /// Operands: /// /// Stack: value, key, object **=>** - SetPropertyByValue(SetPropertyByValue), + SetPropertyByValue, /// Defines a own property of an object by value. /// /// Operands: /// /// Stack: object, key, value **=>** - DefineOwnPropertyByValue(DefineOwnPropertyByValue), + DefineOwnPropertyByValue, /// Defines a class method by value. /// /// Operands: /// /// Stack: object, key, value **=>** - DefineClassMethodByValue(DefineClassMethodByValue), + DefineClassMethodByValue, /// Sets a getter property by name of an object. /// @@ -647,7 +647,7 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: value, object **=>** - SetPropertyGetterByName(SetPropertyGetterByName), + SetPropertyGetterByName, /// Defines a getter class method by name. /// @@ -656,7 +656,7 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: value, object **=>** - DefineClassGetterByName(DefineClassGetterByName), + DefineClassGetterByName, /// Sets a getter property by value of an object. /// @@ -665,7 +665,7 @@ pub enum Opcode { /// Operands: /// /// Stack: object, key, value **=>** - SetPropertyGetterByValue(SetPropertyGetterByValue), + SetPropertyGetterByValue, /// Defines a getter class method by value. /// @@ -674,7 +674,7 @@ pub enum Opcode { /// Operands: /// /// Stack: object, key, value **=>** - DefineClassGetterByValue(DefineClassGetterByValue), + DefineClassGetterByValue, /// Sets a setter property by name of an object. /// @@ -683,7 +683,7 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: value, object **=>** - SetPropertySetterByName(SetPropertySetterByName), + SetPropertySetterByName, /// Defines a setter class method by name. /// @@ -692,7 +692,7 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: value, object **=>** - DefineClassSetterByName(DefineClassSetterByName), + DefineClassSetterByName, /// Sets a setter property by value of an object. /// @@ -701,7 +701,7 @@ pub enum Opcode { /// Operands: /// /// Stack: object, key, value **=>** - SetPropertySetterByValue(SetPropertySetterByValue), + SetPropertySetterByValue, /// Defines a setter class method by value. /// @@ -710,7 +710,7 @@ pub enum Opcode { /// Operands: /// /// Stack: object, key, value **=>** - DefineClassSetterByValue(DefineClassSetterByValue), + DefineClassSetterByValue, /// Assign the value of a private property of an object by it's name. /// @@ -719,7 +719,7 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: object, value **=>** - AssignPrivateField(AssignPrivateField), + AssignPrivateField, /// Set a private property of a class constructor by it's name. /// @@ -728,7 +728,7 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: object, value **=>** - SetPrivateField(SetPrivateField), + SetPrivateField, /// Set a private method of a class constructor by it's name. /// @@ -737,7 +737,7 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: object, value **=>** - SetPrivateMethod(SetPrivateMethod), + SetPrivateMethod, /// Set a private setter property of a class constructor by it's name. /// @@ -746,7 +746,7 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: object, value **=>** - SetPrivateSetter(SetPrivateSetter), + SetPrivateSetter, /// Set a private getter property of a class constructor by it's name. /// @@ -755,7 +755,7 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: object, value **=>** - SetPrivateGetter(SetPrivateGetter), + SetPrivateGetter, /// Get a private property by name from an object an push it on the stack. /// @@ -764,42 +764,42 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: object **=>** value - GetPrivateField(GetPrivateField), + GetPrivateField, /// Push a field to a class. /// /// Operands: /// /// Stack: class, field_name, field_function **=>** - PushClassField(PushClassField), + PushClassField, /// Push a private field to the class. /// /// Operands: name_index: `u32` /// /// Stack: class, field_function **=>** - PushClassFieldPrivate(PushClassFieldPrivate), + PushClassFieldPrivate, /// Push a private getter to the class. /// /// Operands: name_index: `u32` /// /// Stack: class, getter **=>** - PushClassPrivateGetter(PushClassPrivateGetter), + PushClassPrivateGetter, /// Push a private setter to the class. /// /// Operands: name_index: `u32` /// /// Stack: class, setter **=>** - PushClassPrivateSetter(PushClassPrivateSetter), + PushClassPrivateSetter, /// Push a private method to the class. /// /// Operands: name_index: `u32` /// /// Stack: class, method **=>** - PushClassPrivateMethod(PushClassPrivateMethod), + PushClassPrivateMethod, /// Deletes a property by name of an object. /// @@ -808,7 +808,7 @@ pub enum Opcode { /// Operands: name_index: `u32` /// /// Stack: object **=>** - DeletePropertyByName(DeletePropertyByName), + DeletePropertyByName, /// Deletes a property by value of an object. /// @@ -817,28 +817,28 @@ pub enum Opcode { /// Operands: /// /// Stack: key, object **=>** - DeletePropertyByValue(DeletePropertyByValue), + DeletePropertyByValue, /// Copy all properties of one object to another object. /// /// Operands: excluded_key_count: `u32`, excluded_key_count_computed: `u32` /// /// Stack: excluded_key_computed_0 ... excluded_key_computed_n, source, value, excluded_key_0 ... excluded_key_n **=>** value - CopyDataProperties(CopyDataProperties), + CopyDataProperties, /// Call ToPropertyKey on the value on the stack. /// /// Operands: /// /// Stack: value **=>** key - ToPropertyKey(ToPropertyKey), + ToPropertyKey, /// Unconditional jump to address. /// /// Operands: address: `u32` /// /// Stack: **=>** - Jump(Jump), + Jump, /// Conditional jump to address. /// @@ -849,7 +849,7 @@ pub enum Opcode { /// Stack: cond **=>** /// /// [falsy]: https://developer.mozilla.org/en-US/docs/Glossary/Falsy - JumpIfFalse(Jump), + JumpIfFalse, /// Conditional jump to address. /// @@ -858,112 +858,112 @@ pub enum Opcode { /// Operands: address: `u32` /// /// Stack: value **=>** value - JumpIfNotUndefined(Jump), + JumpIfNotUndefined, /// Throw exception /// /// Operands: /// /// Stack: value **=>** - Throw(Throw), + Throw, /// Start of a try block. /// /// Operands: next_address: `u32`, finally_address: `u32` /// /// Stack: **=>** - TryStart(TryStart), + TryStart, /// End of a try block. /// /// Operands: /// /// Stack: **=>** - TryEnd(TryEnd), + TryEnd, /// Start of a catch block. /// /// Operands: /// /// Stack: **=>** - CatchStart(CatchStart), + CatchStart, /// End of a catch block. /// /// Operands: /// /// Stack: **=>** - CatchEnd(CatchEnd), + CatchEnd, /// End of a catch block. /// /// Operands: /// /// Stack: **=>** - CatchEnd2(CatchEnd2), + CatchEnd2, /// Start of a finally block. /// /// Operands: /// /// Stack: **=>** - FinallyStart(FinallyStart), + FinallyStart, /// End of a finally block. /// /// Operands: /// /// Stack: **=>** - FinallyEnd(FinallyEnd), + FinallyEnd, /// Set the address for a finally jump. /// /// Operands: /// /// Stack: **=>** - FinallySetJump(FinallySetJump), + FinallySetJump, /// Pops value converts it to boolean and pushes it back. /// /// Operands: /// /// Stack: value **=>** (`ToBoolean(value)`) - ToBoolean(ToBoolean), + ToBoolean, /// Pushes `this` value /// /// Operands: /// /// Stack: **=>** this - This(This), + This, /// Pushes the current `super` value to the stack. /// /// Operands: /// /// Stack: **=>** super - Super(Super), + Super, /// Execute the `super()` method. /// /// Operands: argument_count: `u32` /// /// Stack: argument_1, ... argument_n **=>** - SuperCall(SuperCall), + SuperCall, /// Execute the `super()` method where the arguments contain spreads. /// /// Operands: /// /// Stack: arguments_array **=>** - SuperCallSpread(SuperCallSpread), + SuperCallSpread, /// Execute the `super()` method when no constructor of the class is defined. /// /// Operands: /// /// Stack: argument_1, ... argument_n **=>** - SuperCallDerived(SuperCallDerived), + SuperCallDerived, /// Pop the two values of the stack, strict equal compares the two values, /// if true jumps to address, otherwise push the second pop'ed value. @@ -971,175 +971,175 @@ pub enum Opcode { /// Operands: address: `u32` /// /// Stack: value, cond **=>** cond (if `cond !== value`). - Case(Case), + Case, /// Pops the top of stack and jump to address. /// /// Operands: address: `u32` /// /// Stack: `value` **=>** - Default(Default), + Default, /// Get function from the pre-compiled inner functions. /// /// Operands: address: `u32` /// /// Stack: **=>** func - GetFunction(GetFunction), + GetFunction, /// Get async function from the pre-compiled inner functions. /// /// Operands: address: `u32` /// /// Stack: **=>** func - GetFunctionAsync(GetFunctionAsync), + GetFunctionAsync, /// Get generator function from the pre-compiled inner functions. /// /// Operands: address: `u32` /// /// Stack: **=>** func - GetGenerator(GetGenerator), + GetGenerator, /// Get async generator function from the pre-compiled inner functions. /// /// Operands: address: `u32` /// /// Stack: **=>** func - GetGeneratorAsync(GetGeneratorAsync), + GetGeneratorAsync, /// Call a function named "eval". /// /// Operands: argument_count: `u32` /// /// Stack: func, this, argument_1, ... argument_n **=>** result - CallEval(CallEval), + CallEval, /// Call a function named "eval" where the arguments contain spreads. /// /// Operands: /// /// Stack: arguments_array, func, this **=>** result - CallEvalSpread(CallEvalSpread), + CallEvalSpread, /// Call a function. /// /// Operands: argument_count: `u32` /// /// Stack: func, this, argument_1, ... argument_n **=>** result - Call(Call), + Call, /// Call a function where the arguments contain spreads. /// /// Operands: /// /// Stack: arguments_array, func, this **=>** result - CallSpread(CallSpread), + CallSpread, /// Call construct on a function. /// /// Operands: argument_count: `u32` /// /// Stack: func, argument_1, ... argument_n **=>** result - New(New), + New, /// Call construct on a function where the arguments contain spreads. /// /// Operands: /// /// Stack: arguments_array, func **=>** result - NewSpread(NewSpread), + NewSpread, /// Return from a function. /// /// Operands: /// /// Stack: **=>** - Return(Return), + Return, /// Push a declarative environment. /// /// Operands: num_bindings: `u32`, compile_environments_index: `u32` /// /// Stack: **=>** - PushDeclarativeEnvironment(PushDeclarativeEnvironment), + PushDeclarativeEnvironment, /// Push a function environment. /// /// Operands: num_bindings: `u32`, compile_environments_index: `u32` /// /// Stack: **=>** - PushFunctionEnvironment(PushFunctionEnvironment), + PushFunctionEnvironment, /// Pop the current environment. /// /// Operands: /// /// Stack: **=>** - PopEnvironment(PopEnvironment), + PopEnvironment, /// Push loop start marker. /// /// Operands: /// /// Stack: **=>** - LoopStart(LoopStart), + LoopStart, /// Clean up environments when a loop continues. /// /// Operands: /// /// Stack: **=>** - LoopContinue(LoopContinue), + LoopContinue, /// Clean up environments at the end of a loop. /// /// Operands: /// /// Stack: **=>** - LoopEnd(LoopEnd), + LoopEnd, /// Initialize the iterator for a for..in loop or jump to after the loop if object is null or undefined. /// /// Operands: address: `u32` /// /// Stack: object **=>** iterator, next_method, done - ForInLoopInitIterator(ForInLoopInitIterator), + ForInLoopInitIterator, /// Initialize an iterator. /// /// Operands: /// /// Stack: object **=>** iterator, next_method, done - InitIterator(InitIterator), + InitIterator, /// Initialize an async iterator. /// /// Operands: /// /// Stack: object **=>** iterator, next_method, done - InitIteratorAsync(InitIteratorAsync), + InitIteratorAsync, /// Advance the iterator by one and put the value on the stack. /// /// Operands: /// /// Stack: iterator, next_method, done **=>** iterator, next_method, done, next_value - IteratorNext(IteratorNext), + IteratorNext, /// Close an iterator. /// /// Operands: /// /// Stack: iterator, next_method, done **=>** - IteratorClose(IteratorClose), + IteratorClose, /// Consume the iterator and construct and array with all the values. /// /// Operands: /// /// Stack: iterator, next_method, done **=>** iterator, next_method, done, array - IteratorToArray(IteratorToArray), + IteratorToArray, /// Move to the next value in a for..in loop or jump to exit of the loop if done. /// @@ -1148,112 +1148,112 @@ pub enum Opcode { /// Operands: address: `u32` /// /// Stack: iterator, next_method, done **=>** iterator, next_method, done, next_result - ForInLoopNext(ForInLoopNext), + ForInLoopNext, /// Move to the next value in a for await..of loop. /// /// Operands: /// /// Stack: iterator, next_method, done **=>** iterator, next_method, next_result - ForAwaitOfLoopIterate(ForAwaitOfLoopIterate), + ForAwaitOfLoopIterate, /// Get the value from a for await..of loop next result. /// /// Operands: address: `u32` /// /// Stack: next_result **=>** done, value - ForAwaitOfLoopNext(ForAwaitOfLoopNext), + ForAwaitOfLoopNext, /// Concat multiple stack objects into a string. /// /// Operands: value_count: `u32` /// /// Stack: value_1,...value_n **=>** string - ConcatToString(ConcatToString), + ConcatToString, /// Call RequireObjectCoercible on the stack value. /// /// Operands: /// /// Stack: value **=>** value - RequireObjectCoercible(RequireObjectCoercible), + RequireObjectCoercible, /// Require the stack value to be neither null nor undefined. /// /// Operands: /// /// Stack: value **=>** value - ValueNotNullOrUndefined(ValueNotNullOrUndefined), + ValueNotNullOrUndefined, /// Initialize the rest parameter value of a function from the remaining arguments. /// /// Operands: /// /// Stack: `argument_1` .. `argument_n` **=>** `array` - RestParameterInit(RestParameterInit), + RestParameterInit, /// Pop the remaining arguments of a function. /// /// Operands: /// /// Stack: `argument_1` .. `argument_n` **=>** - RestParameterPop(RestParameterPop), + RestParameterPop, /// Add one to the pop on return count. /// /// Operands: /// /// Stack: **=>** - PopOnReturnAdd(PopOnReturnAdd), + PopOnReturnAdd, /// Subtract one from the pop on return count. /// /// Operands: /// /// Stack: **=>** - PopOnReturnSub(PopOnReturnSub), + PopOnReturnSub, /// Yield from the current execution. /// /// Operands: /// /// Stack: value **=>** - Yield(Yield), + Yield, /// Resumes the current generator function. /// /// Operands: /// /// Stack: received **=>** - GeneratorNext(GeneratorNext), + GeneratorNext, /// Resumes the current generator function. /// /// Operands: /// /// Stack: received **=>** Option, skip_0, skip_1 - AsyncGeneratorNext(AsyncGeneratorNext), + AsyncGeneratorNext, /// Delegates the current generator function another generator. /// /// Operands: done_address: `u32` /// /// Stack: iterator, next_method, done, received **=>** iterator, next_method, done - GeneratorNextDelegate(GeneratorNextDelegate), + GeneratorNextDelegate, /// Stops the current async function and schedules it to resume later. /// /// Operands: /// /// Stack: promise **=>** - Await(Await), + Await, /// Push the current new target to the stack. /// /// Operands: /// /// Stack: **=>** new_target - PushNewTarget(PushNewTarget), + PushNewTarget, /// No-operation instruction, does nothing. /// @@ -1262,7 +1262,7 @@ pub enum Opcode { /// Stack: **=>** // Safety: Must be last in the list since, we use this for range checking // in TryFrom impl. - Nop(Nop), + Nop, } impl Opcode { @@ -1277,336 +1277,336 @@ impl Opcode { pub fn as_str(self) -> &'static str { match self { - Self::Pop(op) => Pop::NAME, - Self::PopIfThrown(op) => PopIfThrown::NAME, - Self::Dup(op) => Dup::NAME, - Self::Swap(op) => Swap::NAME, - Self::PushZero(op) => PushZero::NAME, - Self::PushOne(op) => PushOne::NAME, - Self::PushInt8(op) => PushInt8::NAME, - Self::PushInt16(op) => PushInt16::NAME, - Self::PushInt32(op) => PushInt32::NAME, - Self::PushRational(op) => PushRational::NAME, - Self::PushNaN(op) => PushNaN::NAME, - Self::PushPositiveInfinity(op) => PushPositiveInfinity::NAME, - Self::PushNegativeInfinity(op) => PushNegativeInfinity::NAME, - Self::PushNull(op) => PushNull::NAME, - Self::PushTrue(op) => PushTrue::NAME, - Self::PushFalse(op) => PushFalse::NAME, - Self::PushUndefined(op) => PushUndefined::NAME, - Self::PushLiteral(op) => PushLiteral::NAME, - Self::PushEmptyObject(op) => PushEmptyObject::NAME, - Self::PushClassPrototype(op) => PushClassPrototype::NAME, - Self::SetClassPrototype(op) => SetClassPrototype::NAME, - Self::SetHomeObject(op) => SetHomeObject::NAME, - Self::PushNewArray(op) => PushNewArray::NAME, - Self::PushValueToArray(op) => PushValueToArray::NAME, - Self::PushElisionToArray(op) => PushElisionToArray::NAME, - Self::PushIteratorToArray(op) => PushIteratorToArray::NAME, - Self::Add(op) => Add::NAME, - Self::Sub(op) => Sub::NAME, - Self::Div(op) => Div::NAME, - Self::Mul(op) => Mul::NAME, - Self::Mod(op) => Mod::NAME, - Self::Pow(op) => Pow::NAME, - Self::ShiftRight(op) => ShiftRight::NAME, - Self::ShiftLeft(op) => ShiftLeft::NAME, - Self::UnsignedShiftRight(op) => UnsignedShiftRight::NAME, - Self::BitOr(op) => BitOr::NAME, - Self::BitAnd(op) => BitAnd::NAME, - Self::BitXor(op) => BitXor::NAME, - Self::BitNot(op) => "BitNot", - Self::In(op) => "In", - Self::Eq(op) => Eq::NAME, - Self::StrictEq(op) => "StrictEq", - Self::NotEq(op) => "NotEq", - Self::StrictNotEq(op) => "StrictNotEq", - Self::GreaterThan(op) => GreaterThan::NAME, - Self::GreaterThanOrEq(op) => GreaterThanOrEq::NAME, - Self::LessThan(op) => LessThan::NAME, - Self::LessThanOrEq(op) => LessThanOrEq::NAME, - Self::InstanceOf(op) => InstanceOf::NAME, - Self::TypeOf(op) => TypeOf::NAME, - Self::Void(op) => Void::NAME, - Self::LogicalNot(op) => LogicalNot::NAME, - Self::LogicalAnd(op) => "LogicalAnd", - Self::LogicalOr(op) => "LogicalOr", - Self::Coalesce(op) => "Coalesce", - Self::Pos(op) => Pos::NAME, - Self::Neg(op) => Neg::NAME, - Self::Inc(op) => Inc::NAME, - Self::IncPost(op) => IncPost::NAME, - Self::Dec(op) => Dec::NAME, - Self::DecPost(op) => DecPost::NAME, - Self::DefInitArg(op) => DefInitArg::NAME, - Self::DefVar(op) => DefVar::NAME, - Self::DefInitVar(op) => DefInitVar::NAME, - Self::DefLet(op) => DefLet::NAME, - Self::DefInitLet(op) => DefInitLet::NAME, - Self::DefInitConst(op) => DefInitConst::NAME, - Self::GetName(op) => GetName::NAME, - Self::GetNameOrUndefined(op) => GetNameOrUndefined::NAME, - Self::SetName(op) => SetName::NAME, - Self::GetPropertyByName(op) => GetPropertyByName::NAME, - Self::GetPropertyByValue(op) => GetPropertyByValue::NAME, - Self::GetPropertyByValuePush(op) => GetPropertyByValuePush::NAME, - Self::SetPropertyByName(op) => "SetPropertyByName", - Self::DefineOwnPropertyByName(op) => "DefineOwnPropertyByName", - Self::DefineClassMethodByName(op) => "DefineClassMethodByName", - Self::SetPropertyByValue(op) => "SetPropertyByValue", - Self::DefineOwnPropertyByValue(op) => "DefineOwnPropertyByValue", - Self::DefineClassMethodByValue(op) => "DefineClassMethodByValue", - Self::SetPropertyGetterByName(op) => "SetPropertyGetterByName", - Self::DefineClassGetterByName(op) => "DefineClassGetterByName", - Self::SetPropertyGetterByValue(op) => "SetPropertyGetterByValue", - Self::DefineClassGetterByValue(op) => "DefineClassGetterByValue", - Self::SetPropertySetterByName(op) => "SetPropertySetterByName", - Self::DefineClassSetterByName(op) => "DefineClassSetterByName", - Self::SetPropertySetterByValue(op) => "SetPropertySetterByValue", - Self::DefineClassSetterByValue(op) => "DefineClassSetterByValue", - Self::AssignPrivateField(op) => "AssignPrivateField", - Self::SetPrivateField(op) => "SetPrivateValue", - Self::SetPrivateMethod(op) => "SetPrivateMethod", - Self::SetPrivateSetter(op) => "SetPrivateSetter", - Self::SetPrivateGetter(op) => "SetPrivateGetter", - Self::GetPrivateField(op) => "GetPrivateField", - Self::PushClassField(op) => "PushClassField", - Self::PushClassFieldPrivate(op) => "PushClassFieldPrivate", - Self::PushClassPrivateGetter(op) => "PushClassPrivateGetter", - Self::PushClassPrivateSetter(op) => "PushClassPrivateSetter", - Self::PushClassPrivateMethod(op) => "PushClassPrivateMethod", - Self::DeletePropertyByName(op) => "DeletePropertyByName", - Self::DeletePropertyByValue(op) => "DeletePropertyByValue", - Self::CopyDataProperties(op) => "CopyDataProperties", - Self::ToPropertyKey(op) => "ToPropertyKey", - Self::Jump(op) => Jump::NAME, - Self::JumpIfFalse(op) => JumpIfFalse::NAME, - Self::JumpIfNotUndefined(op) => JumpIfNotUndefined::NAME, - Self::Throw(op) => "Throw", - Self::TryStart(op) => "TryStart", - Self::TryEnd(op) => "TryEnd", - Self::CatchStart(op) => "CatchStart", - Self::CatchEnd(op) => "CatchEnd", - Self::CatchEnd2(op) => "CatchEnd2", - Self::FinallyStart(op) => "FinallyStart", - Self::FinallyEnd(op) => "FinallyEnd", - Self::FinallySetJump(op) => "FinallySetJump", - Self::ToBoolean(op) => "ToBoolean", - Self::This(op) => "This", - Self::Super(op) => "Super", - Self::SuperCall(op) => "SuperCall", - Self::SuperCallSpread(op) => "SuperCallWithRest", - Self::SuperCallDerived(op) => "SuperCallDerived", - Self::Case(op) => "Case", - Self::Default(op) => "Default", - Self::GetFunction(op) => "GetFunction", - Self::GetFunctionAsync(op) => "GetFunctionAsync", - Self::GetGenerator(op) => "GetGenerator", - Self::GetGeneratorAsync(op) => "GetGeneratorAsync", - Self::CallEval(op) => "CallEval", - Self::CallEvalSpread(op) => "CallEvalSpread", - Self::Call(op) => "Call", - Self::CallSpread(op) => "CallSpread", - Self::New(op) => "New", - Self::NewSpread(op) => "NewSpread", - Self::Return(op) => "Return", - Self::PushDeclarativeEnvironment(op) => "PushDeclarativeEnvironment", - Self::PushFunctionEnvironment(op) => "PushFunctionEnvironment", - Self::PopEnvironment(op) => "PopEnvironment", - Self::LoopStart(op) => "LoopStart", - Self::LoopContinue(op) => "LoopContinue", - Self::LoopEnd(op) => "LoopEnd", - Self::ForInLoopInitIterator(op) => "ForInLoopInitIterator", - Self::InitIterator(op) => "InitIterator", - Self::InitIteratorAsync(op) => "InitIteratorAsync", - Self::IteratorNext(op) => "IteratorNext", - Self::IteratorClose(op) => "IteratorClose", - Self::IteratorToArray(op) => "IteratorToArray", - Self::ForInLoopNext(op) => "ForInLoopNext", - Self::ForAwaitOfLoopNext(op) => "ForAwaitOfLoopNext", - Self::ForAwaitOfLoopIterate(op) => "ForAwaitOfLoopIterate", - Self::ConcatToString(op) => "ConcatToString", - Self::RequireObjectCoercible(op) => "RequireObjectCoercible", - Self::ValueNotNullOrUndefined(op) => "ValueNotNullOrUndefined", - Self::RestParameterInit(op) => "FunctionRestParameter", - Self::RestParameterPop(op) => "RestParameterPop", - Self::PopOnReturnAdd(op) => "PopOnReturnAdd", - Self::PopOnReturnSub(op) => "PopOnReturnSub", - Self::Yield(op) => "Yield", - Self::GeneratorNext(op) => "GeneratorNext", - Self::AsyncGeneratorNext(op) => "AsyncGeneratorNext", - Self::Await(op) => "Await", - Self::PushNewTarget(op) => "PushNewTarget", - Self::GeneratorNextDelegate(op) => "GeneratorNextDelegate", - Self::Nop(op) => "Nop", + Self::Pop => Pop::NAME, + Self::PopIfThrown => PopIfThrown::NAME, + Self::Dup => Dup::NAME, + Self::Swap => Swap::NAME, + Self::PushZero => PushZero::NAME, + Self::PushOne => PushOne::NAME, + Self::PushInt8 => PushInt8::NAME, + Self::PushInt16 => PushInt16::NAME, + Self::PushInt32 => PushInt32::NAME, + Self::PushRational => PushRational::NAME, + Self::PushNaN => PushNaN::NAME, + Self::PushPositiveInfinity => PushPositiveInfinity::NAME, + Self::PushNegativeInfinity => PushNegativeInfinity::NAME, + Self::PushNull => PushNull::NAME, + Self::PushTrue => PushTrue::NAME, + Self::PushFalse => PushFalse::NAME, + Self::PushUndefined => PushUndefined::NAME, + Self::PushLiteral => PushLiteral::NAME, + Self::PushEmptyObject => PushEmptyObject::NAME, + Self::PushClassPrototype => PushClassPrototype::NAME, + Self::SetClassPrototype => SetClassPrototype::NAME, + Self::SetHomeObject => SetHomeObject::NAME, + Self::PushNewArray => PushNewArray::NAME, + Self::PushValueToArray => PushValueToArray::NAME, + Self::PushElisionToArray => PushElisionToArray::NAME, + Self::PushIteratorToArray => PushIteratorToArray::NAME, + Self::Add => Add::NAME, + Self::Sub => Sub::NAME, + Self::Div => Div::NAME, + Self::Mul => Mul::NAME, + Self::Mod => Mod::NAME, + Self::Pow => Pow::NAME, + Self::ShiftRight => ShiftRight::NAME, + Self::ShiftLeft => ShiftLeft::NAME, + Self::UnsignedShiftRight => UnsignedShiftRight::NAME, + Self::BitOr => BitOr::NAME, + Self::BitAnd => BitAnd::NAME, + Self::BitXor => BitXor::NAME, + Self::BitNot => BitNot::NAME, + Self::In => In::NAME, + Self::Eq => Eq::NAME, + Self::StrictEq => StrictEq::NAME, + Self::NotEq => NotEq::NAME, + Self::StrictNotEq => StrictNotEq::NAME, + Self::GreaterThan => GreaterThan::NAME, + Self::GreaterThanOrEq => GreaterThanOrEq::NAME, + Self::LessThan => LessThan::NAME, + Self::LessThanOrEq => LessThanOrEq::NAME, + Self::InstanceOf => InstanceOf::NAME, + Self::TypeOf => TypeOf::NAME, + Self::Void => Void::NAME, + Self::LogicalNot => LogicalNot::NAME, + Self::LogicalAnd => LogicalAnd::NAME, + Self::LogicalOr => LogicalOr::NAME, + Self::Coalesce => Coalesce::NAME, + Self::Pos => Pos::NAME, + Self::Neg => Neg::NAME, + Self::Inc => Inc::NAME, + Self::IncPost => IncPost::NAME, + Self::Dec => Dec::NAME, + Self::DecPost => DecPost::NAME, + Self::DefInitArg => DefInitArg::NAME, + Self::DefVar => DefVar::NAME, + Self::DefInitVar => DefInitVar::NAME, + Self::DefLet => DefLet::NAME, + Self::DefInitLet => DefInitLet::NAME, + Self::DefInitConst => DefInitConst::NAME, + Self::GetName => GetName::NAME, + Self::GetNameOrUndefined => GetNameOrUndefined::NAME, + Self::SetName => SetName::NAME, + Self::GetPropertyByName => GetPropertyByName::NAME, + Self::GetPropertyByValue => GetPropertyByValue::NAME, + Self::GetPropertyByValuePush => GetPropertyByValuePush::NAME, + Self::SetPropertyByName => SetPropertyByName::NAME, + Self::DefineOwnPropertyByName => DefineOwnPropertyByName::NAME, + Self::DefineClassMethodByName => DefineClassMethodByName::NAME, + Self::SetPropertyByValue => SetPropertyByValue::NAME, + Self::DefineOwnPropertyByValue => DefineOwnPropertyByValue::NAME, + Self::DefineClassMethodByValue => DefineClassMethodByValue::NAME, + Self::SetPropertyGetterByName => SetPropertyGetterByName::NAME, + Self::DefineClassGetterByName => DefineClassGetterByName::NAME, + Self::SetPropertyGetterByValue => SetPropertyGetterByValue::NAME, + Self::DefineClassGetterByValue => DefineClassGetterByValue::NAME, + Self::SetPropertySetterByName => SetPropertySetterByName::NAME, + Self::DefineClassSetterByName => DefineClassSetterByName::NAME, + Self::SetPropertySetterByValue => SetPropertySetterByValue::NAME, + Self::DefineClassSetterByValue => DefineClassSetterByValue::NAME, + Self::AssignPrivateField => AssignPrivateField::NAME, + Self::SetPrivateField => SetPrivateField::NAME, + Self::SetPrivateMethod => SetPrivateMethod::NAME, + Self::SetPrivateSetter => SetPrivateSetter::NAME, + Self::SetPrivateGetter => SetPrivateGetter::NAME, + Self::GetPrivateField => GetPrivateField::NAME, + Self::PushClassField => PushClassField::NAME, + Self::PushClassFieldPrivate => PushClassFieldPrivate::NAME, + Self::PushClassPrivateGetter => PushClassPrivateGetter::NAME, + Self::PushClassPrivateSetter => PushClassPrivateSetter::NAME, + Self::PushClassPrivateMethod => PushClassPrivateMethod::NAME, + Self::DeletePropertyByName => DeletePropertyByName::NAME, + Self::DeletePropertyByValue => DeletePropertyByValue::NAME, + Self::CopyDataProperties => CopyDataProperties::NAME, + Self::ToPropertyKey => ToPropertyKey::NAME, + Self::Jump => Jump::NAME, + Self::JumpIfFalse => JumpIfFalse::NAME, + Self::JumpIfNotUndefined => JumpIfNotUndefined::NAME, + Self::Throw => Throw::NAME, + Self::TryStart => TryStart::NAME, + Self::TryEnd => TryEnd::NAME, + Self::CatchStart => CatchStart::NAME, + Self::CatchEnd => CatchEnd::NAME, + Self::CatchEnd2 => CatchEnd2::NAME, + Self::FinallyStart => FinallyStart::NAME, + Self::FinallyEnd => FinallyEnd::NAME, + Self::FinallySetJump => FinallySetJump::NAME, + Self::ToBoolean => ToBoolean::NAME, + Self::This => This::NAME, + Self::Super => Super::NAME, + Self::SuperCall => SuperCall::NAME, + Self::SuperCallSpread => SuperCallSpread::NAME, + Self::SuperCallDerived => SuperCallDerived::NAME, + Self::Case => Case::NAME, + Self::Default => Default::NAME, + Self::GetFunction => GetFunction::NAME, + Self::GetFunctionAsync => GetFunctionAsync::NAME, + Self::GetGenerator => GetGenerator::NAME, + Self::GetGeneratorAsync => GetGeneratorAsync::NAME, + Self::CallEval => CallEval::NAME, + Self::CallEvalSpread => CallEvalSpread::NAME, + Self::Call => Call::NAME, + Self::CallSpread => CallSpread::NAME, + Self::New => New::NAME, + Self::NewSpread => NewSpread::NAME, + Self::Return => Return::NAME, + Self::PushDeclarativeEnvironment => PushDeclarativeEnvironment::NAME, + Self::PushFunctionEnvironment => PushFunctionEnvironment::NAME, + Self::PopEnvironment => PopEnvironment::NAME, + Self::LoopStart => LoopStart::NAME, + Self::LoopContinue => LoopContinue::NAME, + Self::LoopEnd => LoopEnd::NAME, + Self::ForInLoopInitIterator => ForInLoopInitIterator::NAME, + Self::InitIterator => InitIterator::NAME, + Self::InitIteratorAsync => InitIteratorAsync::NAME, + Self::IteratorNext => IteratorNext::NAME, + Self::IteratorClose => IteratorClose::NAME, + Self::IteratorToArray => IteratorToArray::NAME, + Self::ForInLoopNext => ForInLoopNext::NAME, + Self::ForAwaitOfLoopNext => ForAwaitOfLoopNext::NAME, + Self::ForAwaitOfLoopIterate => ForAwaitOfLoopIterate::NAME, + Self::ConcatToString => ConcatToString::NAME, + Self::RequireObjectCoercible => RequireObjectCoercible::NAME, + Self::ValueNotNullOrUndefined => ValueNotNullOrUndefined::NAME, + Self::RestParameterInit => RestParameterInit::NAME, + Self::RestParameterPop => RestParameterPop::NAME, + Self::PopOnReturnAdd => PopOnReturnAdd::NAME, + Self::PopOnReturnSub => PopOnReturnSub::NAME, + Self::Yield => Yield::NAME, + Self::GeneratorNext => GeneratorNext::NAME, + Self::AsyncGeneratorNext => AsyncGeneratorNext::NAME, + Self::Await => Await::NAME, + Self::PushNewTarget => PushNewTarget::NAME, + Self::GeneratorNextDelegate => GeneratorNextDelegate::NAME, + Self::Nop => Nop::NAME, } } /// Name of the profiler event for this opcode pub fn as_instruction_str(self) -> &'static str { match self { - Self::Pop(op) => Pop::INSTRUCTION, - Self::PopIfThrown(op) => PopIfThrown::INSTRUCTION, - Self::Dup(op) => Dup::INSTRUCTION, - Self::Swap(op) => Swap::INSTRUCTION, - Self::PushZero(op) => PushZero::INSTRUCTION, - Self::PushOne(op) => PushOne::INSTRUCTION, - Self::PushInt8(op) => PushInt8::INSTRUCTION, - Self::PushInt16(op) => PushInt16::INSTRUCTION, - Self::PushInt32(op) => PushInt32::INSTRUCTION, - Self::PushRational(op) => PushRational::INSTRUCTION, - Self::PushNaN(op) => PushNaN::INSTRUCTION, - Self::PushPositiveInfinity(op) => PushPositiveInfinity::INSTRUCTION, - Self::PushNegativeInfinity(op) => PushNegativeInfinity::INSTRUCTION, - Self::PushNull(op) => PushNull::INSTRUCTION, - Self::PushTrue(op) => PushTrue::INSTRUCTION, - Self::PushFalse(op) => PushFalse::INSTRUCTION, - Self::PushUndefined(op) => PushUndefined::INSTRUCTION, - Self::PushLiteral(op) => PushLiteral::INSTRUCTION, - Self::PushEmptyObject(op) => PushEmptyObject::INSTRUCTION, - Self::PushNewArray(op) => PushNewArray::INSTRUCTION, - Self::PushValueToArray(op) => PushValueToArray::INSTRUCTION, - Self::PushElisionToArray(op) => PushElisionToArray::INSTRUCTION, - Self::PushIteratorToArray(op) => PushIteratorToArray::INSTRUCTION, - Self::Add(op) => Add::INSTRUCTION, - Self::Sub(op) => Sub::INSTRUCTION, - Self::Div(op) => Div::INSTRUCTION, - Self::Mul(op) => Mul::INSTRUCTION, - Self::Mod(op) => Mod::INSTRUCTION, - Self::Pow(op) => Pow::INSTRUCTION, - Self::ShiftRight(op) => ShiftRight::INSTRUCTION, - Self::ShiftLeft(op) => ShiftLeft::INSTRUCTION, - Self::UnsignedShiftRight(op) => UnsignedShiftRight::INSTRUCTION, - Self::BitOr(op) => BitOr::INSTRUCTION, - Self::BitAnd(op) => BitAnd::INSTRUCTION, - Self::BitXor(op) => BitXor::INSTRUCTION, - Self::BitNot(op) => BitNot::INSTRUCTION, - Self::In(op) => In::INSTRUCTION, - Self::Eq(op) => Eq::INSTRUCTION, - Self::StrictEq(op) => StrictEq::INSTRUCTION, - Self::NotEq(op) => NotEq::INSTRUCTION, - Self::StrictNotEq(op) => StrictNotEq::INSTRUCTION, - Self::GreaterThan(op) => GreaterThan::INSTRUCTION, - Self::GreaterThanOrEq(op) => GreaterThanOrEq::INSTRUCTION, - Self::LessThan(op) => LessThan::INSTRUCTION, - Self::LessThanOrEq(op) => LessThanOrEq::INSTRUCTION, - Self::InstanceOf(op) => InstanceOf::INSTRUCTION, - Self::TypeOf(op) => TypeOf::INSTRUCTION, - Self::Void(op) => Void::INSTRUCTION, - Self::LogicalNot(op) => LogicalNot::INSTRUCTION, - Self::LogicalAnd(op) => "INST - LogicalAnd", - Self::LogicalOr(op) => "INST - LogicalOr", - Self::Coalesce(op) => "INST - Coalesce", - Self::Pos(op) => Pos::INSTRUCTION, - Self::Neg(op) => Neg::INSTRUCTION, - Self::Inc(op) => Inc::INSTRUCTION, - Self::IncPost(op) => IncPost::INSTRUCTION, - Self::Dec(op) => Dec::INSTRUCTION, - Self::DecPost(op) => DecPost::INSTRUCTION, - Self::DefInitArg(op) => DefInitArg::INSTRUCTION, - Self::DefVar(op) => DefVar::INSTRUCTION, - Self::DefInitVar(op) => DefInitVar::INSTRUCTION, - Self::DefLet(op) => DefLet::INSTRUCTION, - Self::DefInitLet(op) => DefInitLet::INSTRUCTION, - Self::DefInitConst(op) => DefInitConst::INSTRUCTION, - Self::GetName(op) => GetName::INSTRUCTION, - Self::GetNameOrUndefined(op) => GetNameOrUndefined::INSTRUCTION, - Self::SetName(op) => SetName::INSTRUCTION, - Self::GetPropertyByName(op) => GetPropertyByName::INSTRUCTION, - Self::GetPropertyByValue(op) => GetPropertyByValue::INSTRUCTION, - Self::GetPropertyByValuePush(op) => GetPropertyByValuePush::INSTRUCTION, - Self::SetPropertyByName(op) => "INST - SetPropertyByName", - Self::DefineOwnPropertyByName(op) => "INST - DefineOwnPropertyByName", - Self::SetPropertyByValue(op) => "INST - SetPropertyByValue", - Self::DefineOwnPropertyByValue(op) => "INST - DefineOwnPropertyByValue", - Self::SetPropertyGetterByName(op) => "INST - SetPropertyGetterByName", - Self::SetPropertyGetterByValue(op) => "INST - SetPropertyGetterByValue", - Self::SetPropertySetterByName(op) => "INST - SetPropertySetterByName", - Self::SetPropertySetterByValue(op) => "INST - SetPropertySetterByValue", - Self::DeletePropertyByName(op) => "INST - DeletePropertyByName", - Self::DeletePropertyByValue(op) => "INST - DeletePropertyByValue", - Self::CopyDataProperties(op) => "INST - CopyDataProperties", - Self::Jump(op) => Jump::INSTRUCTION, - Self::JumpIfFalse(op) => JumpIfFalse::INSTRUCTION, - Self::JumpIfNotUndefined(op) => JumpIfNotUndefined::INSTRUCTION, - Self::Throw(op) => "INST - Throw", - Self::TryStart(op) => "INST - TryStart", - Self::TryEnd(op) => "INST - TryEnd", - Self::CatchStart(op) => "INST - CatchStart", - Self::CatchEnd(op) => "INST - CatchEnd", - Self::CatchEnd2(op) => "INST - CatchEnd2", - Self::FinallyStart(op) => "INST - FinallyStart", - Self::FinallyEnd(op) => "INST - FinallyEnd", - Self::FinallySetJump(op) => "INST - FinallySetJump", - Self::ToBoolean(op) => "INST - ToBoolean", - Self::This(op) => "INST - This", - Self::Super(op) => "INST - Super", - Self::SuperCall(op) => "INST - SuperCall", - Self::SuperCallSpread(op) => "INST - SuperCallWithRest", - Self::SuperCallDerived(op) => "INST - SuperCallDerived", - Self::Case(op) => "INST - Case", - Self::Default(op) => "INST - Default", - Self::GetFunction(op) => "INST - GetFunction", - Self::GetFunctionAsync(op) => "INST - GetFunctionAsync", - Self::GetGenerator(op) => "INST - GetGenerator", - Self::GetGeneratorAsync(op) => "INST - GetGeneratorAsync", - Self::CallEval(op) => "INST - CallEval", - Self::CallEvalSpread(op) => "INST - CallEvalSpread", - Self::Call(op) => "INST - Call", - Self::CallSpread(op) => "INST - CallSpread", - Self::New(op) => "INST - New", - Self::NewSpread(op) => "INST - NewSpread", - Self::Return(op) => "INST - Return", - Self::PushDeclarativeEnvironment(op) => "INST - PushDeclarativeEnvironment", - Self::PushFunctionEnvironment(op) => "INST - PushFunctionEnvironment", - Self::PopEnvironment(op) => "INST - PopEnvironment", - Self::LoopStart(op) => "INST - LoopStart", - Self::LoopContinue(op) => "INST - LoopContinue", - Self::LoopEnd(op) => "INST - LoopEnd", - Self::ForInLoopInitIterator(op) => "INST - ForInLoopInitIterator", - Self::InitIterator(op) => "INST - InitIterator", - Self::InitIteratorAsync(op) => "INST - InitIteratorAsync", - Self::IteratorNext(op) => "INST - IteratorNext", - Self::IteratorClose(op) => "INST - IteratorClose", - Self::IteratorToArray(op) => "INST - IteratorToArray", - Self::ForInLoopNext(op) => "INST - ForInLoopNext", - Self::ForAwaitOfLoopIterate(op) => "INST - ForAwaitOfLoopIterate", - Self::ForAwaitOfLoopNext(op) => "INST - ForAwaitOfLoopNext", - Self::ConcatToString(op) => "INST - ConcatToString", - Self::RequireObjectCoercible(op) => "INST - RequireObjectCoercible", - Self::ValueNotNullOrUndefined(op) => "INST - ValueNotNullOrUndefined", - Self::RestParameterInit(op) => "INST - FunctionRestParameter", - Self::RestParameterPop(op) => "INST - RestParameterPop", - Self::PopOnReturnAdd(op) => "INST - PopOnReturnAdd", - Self::PopOnReturnSub(op) => "INST - PopOnReturnSub", - Self::Yield(op) => "INST - Yield", - Self::GeneratorNext(op) => "INST - GeneratorNext", - Self::AsyncGeneratorNext(op) => "INST - AsyncGeneratorNext", - Self::PushNewTarget(op) => "INST - PushNewTarget", - Self::Await(op) => "INST - Await", - Self::GeneratorNextDelegate(op) => "INST - GeneratorNextDelegate", - Self::Nop(op) => "INST - Nop", - Self::PushClassPrototype(op) => PushClassPrototype::INSTRUCTION, - Self::SetClassPrototype(op) => SetClassPrototype::INSTRUCTION, - Self::SetHomeObject(op) => SetHomeObject::INSTRUCTION, - Self::DefineClassMethodByName(op) => "INST - DefineClassMethodByName", - Self::DefineClassMethodByValue(op) => "INST - DefineClassMethodByValue", - Self::DefineClassGetterByName(op) => "INST - DefineClassGetterByName", - Self::DefineClassGetterByValue(op) => "INST - DefineClassGetterByValue", - Self::DefineClassSetterByName(op) => "INST - DefineClassSetterByName", - Self::DefineClassSetterByValue(op) => "INST - DefineClassSetterByValue", - Self::AssignPrivateField(op) => "INST - AssignPrivateField", - Self::SetPrivateField(op) => "INST - SetPrivateValue", - Self::SetPrivateMethod(op) => "INST - SetPrivateMethod", - Self::SetPrivateSetter(op) => "INST - SetPrivateSetter", - Self::SetPrivateGetter(op) => "INST - SetPrivateGetter", - Self::GetPrivateField(op) => "INST - GetPrivateField", - Self::PushClassField(op) => "INST - PushClassField", - Self::PushClassFieldPrivate(op) => "INST - PushClassFieldPrivate", - Self::PushClassPrivateGetter(op) => "INST - PushClassPrivateGetter", - Self::PushClassPrivateSetter(op) => "INST - PushClassPrivateSetter", - Self::PushClassPrivateMethod(op) => "INST - PushClassPrivateMethod", - Self::ToPropertyKey(op) => "INST - ToPropertyKey", + Self::Pop => Pop::INSTRUCTION, + Self::PopIfThrown => PopIfThrown::INSTRUCTION, + Self::Dup => Dup::INSTRUCTION, + Self::Swap => Swap::INSTRUCTION, + Self::PushZero => PushZero::INSTRUCTION, + Self::PushOne => PushOne::INSTRUCTION, + Self::PushInt8 => PushInt8::INSTRUCTION, + Self::PushInt16 => PushInt16::INSTRUCTION, + Self::PushInt32 => PushInt32::INSTRUCTION, + Self::PushRational => PushRational::INSTRUCTION, + Self::PushNaN => PushNaN::INSTRUCTION, + Self::PushPositiveInfinity => PushPositiveInfinity::INSTRUCTION, + Self::PushNegativeInfinity => PushNegativeInfinity::INSTRUCTION, + Self::PushNull => PushNull::INSTRUCTION, + Self::PushTrue => PushTrue::INSTRUCTION, + Self::PushFalse => PushFalse::INSTRUCTION, + Self::PushUndefined => PushUndefined::INSTRUCTION, + Self::PushLiteral => PushLiteral::INSTRUCTION, + Self::PushEmptyObject => PushEmptyObject::INSTRUCTION, + Self::PushNewArray => PushNewArray::INSTRUCTION, + Self::PushValueToArray => PushValueToArray::INSTRUCTION, + Self::PushElisionToArray => PushElisionToArray::INSTRUCTION, + Self::PushIteratorToArray => PushIteratorToArray::INSTRUCTION, + Self::Add => Add::INSTRUCTION, + Self::Sub => Sub::INSTRUCTION, + Self::Div => Div::INSTRUCTION, + Self::Mul => Mul::INSTRUCTION, + Self::Mod => Mod::INSTRUCTION, + Self::Pow => Pow::INSTRUCTION, + Self::ShiftRight => ShiftRight::INSTRUCTION, + Self::ShiftLeft => ShiftLeft::INSTRUCTION, + Self::UnsignedShiftRight => UnsignedShiftRight::INSTRUCTION, + Self::BitOr => BitOr::INSTRUCTION, + Self::BitAnd => BitAnd::INSTRUCTION, + Self::BitXor => BitXor::INSTRUCTION, + Self::BitNot => BitNot::INSTRUCTION, + Self::In => In::INSTRUCTION, + Self::Eq => Eq::INSTRUCTION, + Self::StrictEq => StrictEq::INSTRUCTION, + Self::NotEq => NotEq::INSTRUCTION, + Self::StrictNotEq => StrictNotEq::INSTRUCTION, + Self::GreaterThan => GreaterThan::INSTRUCTION, + Self::GreaterThanOrEq => GreaterThanOrEq::INSTRUCTION, + Self::LessThan => LessThan::INSTRUCTION, + Self::LessThanOrEq => LessThanOrEq::INSTRUCTION, + Self::InstanceOf => InstanceOf::INSTRUCTION, + Self::TypeOf => TypeOf::INSTRUCTION, + Self::Void => Void::INSTRUCTION, + Self::LogicalNot => LogicalNot::INSTRUCTION, + Self::LogicalAnd => LogicalAnd::INSTRUCTION, + Self::LogicalOr => LogicalOr::INSTRUCTION, + Self::Coalesce => Coalesce::INSTRUCTION, + Self::Pos => Pos::INSTRUCTION, + Self::Neg => Neg::INSTRUCTION, + Self::Inc => Inc::INSTRUCTION, + Self::IncPost => IncPost::INSTRUCTION, + Self::Dec => Dec::INSTRUCTION, + Self::DecPost => DecPost::INSTRUCTION, + Self::DefInitArg => DefInitArg::INSTRUCTION, + Self::DefVar => DefVar::INSTRUCTION, + Self::DefInitVar => DefInitVar::INSTRUCTION, + Self::DefLet => DefLet::INSTRUCTION, + Self::DefInitLet => DefInitLet::INSTRUCTION, + Self::DefInitConst => DefInitConst::INSTRUCTION, + Self::GetName => GetName::INSTRUCTION, + Self::GetNameOrUndefined => GetNameOrUndefined::INSTRUCTION, + Self::SetName => SetName::INSTRUCTION, + Self::GetPropertyByName => GetPropertyByName::INSTRUCTION, + Self::GetPropertyByValue => GetPropertyByValue::INSTRUCTION, + Self::GetPropertyByValuePush => GetPropertyByValuePush::INSTRUCTION, + Self::SetPropertyByName => SetPropertyByName::INSTRUCTION, + Self::DefineOwnPropertyByName => DefineOwnPropertyByName::INSTRUCTION, + Self::SetPropertyByValue => SetPropertyByValue::INSTRUCTION, + Self::DefineOwnPropertyByValue => DefineOwnPropertyByValue::INSTRUCTION, + Self::SetPropertyGetterByName => SetPropertyGetterByName::INSTRUCTION, + Self::SetPropertyGetterByValue => SetPropertyGetterByValue::INSTRUCTION, + Self::SetPropertySetterByName => SetPropertySetterByName::INSTRUCTION, + Self::SetPropertySetterByValue => SetPropertySetterByValue::INSTRUCTION, + Self::DeletePropertyByName => DeletePropertyByName::INSTRUCTION, + Self::DeletePropertyByValue => DeletePropertyByValue::INSTRUCTION, + Self::CopyDataProperties => CopyDataProperties::INSTRUCTION, + Self::Jump => Jump::INSTRUCTION, + Self::JumpIfFalse => JumpIfFalse::INSTRUCTION, + Self::JumpIfNotUndefined => JumpIfNotUndefined::INSTRUCTION, + Self::Throw => Throw::INSTRUCTION, + Self::TryStart => TryStart::INSTRUCTION, + Self::TryEnd => TryEnd::INSTRUCTION, + Self::CatchStart => CatchStart::INSTRUCTION, + Self::CatchEnd => CatchEnd::INSTRUCTION, + Self::CatchEnd2 => CatchEnd2::INSTRUCTION, + Self::FinallyStart => FinallyStart::INSTRUCTION, + Self::FinallyEnd => FinallyEnd::INSTRUCTION, + Self::FinallySetJump => FinallySetJump::INSTRUCTION, + Self::ToBoolean => ToBoolean::INSTRUCTION, + Self::This => This::INSTRUCTION, + Self::Super => Super::INSTRUCTION, + Self::SuperCall => SuperCall::INSTRUCTION, + Self::SuperCallSpread => SuperCallSpread::INSTRUCTION, + Self::SuperCallDerived => SuperCallDerived::INSTRUCTION, + Self::Case => Case::INSTRUCTION, + Self::Default => Default::INSTRUCTION, + Self::GetFunction => GetFunction::INSTRUCTION, + Self::GetFunctionAsync => GetFunctionAsync::INSTRUCTION, + Self::GetGenerator => GetGenerator::INSTRUCTION, + Self::GetGeneratorAsync => GetGeneratorAsync::INSTRUCTION, + Self::CallEval => CallEval::INSTRUCTION, + Self::CallEvalSpread => CallEvalSpread::INSTRUCTION, + Self::Call => Call::INSTRUCTION, + Self::CallSpread => CallSpread::INSTRUCTION, + Self::New => New::INSTRUCTION, + Self::NewSpread => NewSpread::INSTRUCTION, + Self::Return => Return::INSTRUCTION, + Self::PushDeclarativeEnvironment => PushDeclarativeEnvironment::INSTRUCTION, + Self::PushFunctionEnvironment => PushFunctionEnvironment::INSTRUCTION, + Self::PopEnvironment => PopEnvironment::INSTRUCTION, + Self::LoopStart => LoopStart::INSTRUCTION, + Self::LoopContinue => LoopContinue::INSTRUCTION, + Self::LoopEnd => LoopEnd::INSTRUCTION, + Self::ForInLoopInitIterator => ForInLoopInitIterator::INSTRUCTION, + Self::InitIterator => InitIterator::INSTRUCTION, + Self::InitIteratorAsync => InitIteratorAsync::INSTRUCTION, + Self::IteratorNext => IteratorNext::INSTRUCTION, + Self::IteratorClose => IteratorClose::INSTRUCTION, + Self::IteratorToArray => IteratorToArray::INSTRUCTION, + Self::ForInLoopNext => ForInLoopNext::INSTRUCTION, + Self::ForAwaitOfLoopIterate => ForAwaitOfLoopIterate::INSTRUCTION, + Self::ForAwaitOfLoopNext => ForAwaitOfLoopNext::INSTRUCTION, + Self::ConcatToString => ConcatToString::INSTRUCTION, + Self::RequireObjectCoercible => RequireObjectCoercible::INSTRUCTION, + Self::ValueNotNullOrUndefined => ValueNotNullOrUndefined::INSTRUCTION, + Self::RestParameterInit => RestParameterInit::INSTRUCTION, + Self::RestParameterPop => RestParameterPop::INSTRUCTION, + Self::PopOnReturnAdd => PopOnReturnAdd::INSTRUCTION, + Self::PopOnReturnSub => PopOnReturnSub::INSTRUCTION, + Self::Yield => Yield::INSTRUCTION, + Self::GeneratorNext => GeneratorNext::INSTRUCTION, + Self::AsyncGeneratorNext => AsyncGeneratorNext::INSTRUCTION, + Self::PushNewTarget => PushNewTarget::INSTRUCTION, + Self::Await => Await::INSTRUCTION, + Self::GeneratorNextDelegate => GeneratorNextDelegate::INSTRUCTION, + Self::Nop => Nop::INSTRUCTION, + Self::PushClassPrototype => PushClassPrototype::INSTRUCTION, + Self::SetClassPrototype => SetClassPrototype::INSTRUCTION, + Self::SetHomeObject => SetHomeObject::INSTRUCTION, + Self::DefineClassMethodByName => DefineClassMethodByName::INSTRUCTION, + Self::DefineClassMethodByValue => DefineClassMethodByValue::INSTRUCTION, + Self::DefineClassGetterByName => DefineClassGetterByName::INSTRUCTION, + Self::DefineClassGetterByValue => DefineClassGetterByValue::INSTRUCTION, + Self::DefineClassSetterByName => DefineClassSetterByName::INSTRUCTION, + Self::DefineClassSetterByValue => DefineClassSetterByValue::INSTRUCTION, + Self::AssignPrivateField => AssignPrivateField::INSTRUCTION, + Self::SetPrivateField => SetPrivateField::INSTRUCTION, + Self::SetPrivateMethod => SetPrivateMethod::INSTRUCTION, + Self::SetPrivateSetter => SetPrivateSetter::INSTRUCTION, + Self::SetPrivateGetter => SetPrivateGetter::INSTRUCTION, + Self::GetPrivateField => GetPrivateField::INSTRUCTION, + Self::PushClassField => PushClassField::INSTRUCTION, + Self::PushClassFieldPrivate => PushClassFieldPrivate::INSTRUCTION, + Self::PushClassPrivateGetter => PushClassPrivateGetter::INSTRUCTION, + Self::PushClassPrivateSetter => PushClassPrivateSetter::INSTRUCTION, + Self::PushClassPrivateMethod => PushClassPrivateMethod::INSTRUCTION, + Self::ToPropertyKey => ToPropertyKey::INSTRUCTION, } } } diff --git a/boa_engine/src/vm/opcode/promise/mod.rs b/boa_engine/src/vm/opcode/promise/mod.rs index 9440b6fe2b7..99698bb4c83 100644 --- a/boa_engine/src/vm/opcode/promise/mod.rs +++ b/boa_engine/src/vm/opcode/promise/mod.rs @@ -40,13 +40,13 @@ impl Operation for FinallyEnd { if let Some(address) = address { context.vm.frame_mut().pc = address as usize; } - return Ok(ShouldExit::False); + Ok(ShouldExit::False) } FinallyReturn::Ok => { - return Ok(ShouldExit::True); + Ok(ShouldExit::True) } FinallyReturn::Err => { - return Err(context.vm.pop()); + Err(context.vm.pop()) } } } diff --git a/boa_engine/src/vm/opcode/push/class.rs b/boa_engine/src/vm/opcode/push/class.rs index 4462365f579..d3d496333e0 100644 --- a/boa_engine/src/vm/opcode/push/class.rs +++ b/boa_engine/src/vm/opcode/push/class.rs @@ -45,7 +45,7 @@ impl Operation for PushClassPrototype { context.vm.push(JsValue::Null); Ok(ShouldExit::False) } else { - return context.throw_type_error("superclass must be a constructor"); + context.throw_type_error("superclass must be a constructor") } } } diff --git a/boa_engine/src/vm/opcode/push/mod.rs b/boa_engine/src/vm/opcode/push/mod.rs index 01a39899eba..cae0d14c115 100644 --- a/boa_engine/src/vm/opcode/push/mod.rs +++ b/boa_engine/src/vm/opcode/push/mod.rs @@ -36,20 +36,12 @@ macro_rules! implement_push_generics { }; } -implement_push_generics!(PushUndefined, { JsValue::undefined() }); - -implement_push_generics!(PushNull, { JsValue::null() }); - +implement_push_generics!(PushUndefined, JsValue::undefined()); +implement_push_generics!(PushNull, JsValue::null()); implement_push_generics!(PushTrue, true); - implement_push_generics!(PushFalse, false); - implement_push_generics!(PushZero, 0); - implement_push_generics!(PushOne, 1); - implement_push_generics!(PushNaN, JsValue::nan()); - implement_push_generics!(PushPositiveInfinity, JsValue::positive_infinity()); - implement_push_generics!(PushNegativeInfinity, JsValue::negative_infinity()); diff --git a/boa_engine/src/vm/opcode/rest_parameter/mod.rs b/boa_engine/src/vm/opcode/rest_parameter/mod.rs index 84c371c2b80..307d71fd31b 100644 --- a/boa_engine/src/vm/opcode/rest_parameter/mod.rs +++ b/boa_engine/src/vm/opcode/rest_parameter/mod.rs @@ -8,8 +8,8 @@ use crate::{ pub(crate) struct RestParameterInit; impl Operation for RestParameterInit { - const NAME: &'static str = "RestParameterInit"; - const INSTRUCTION: &'static str = "INST - RestParameterInit"; + const NAME: &'static str = "FunctionRestParameter"; + const INSTRUCTION: &'static str = "INST - FunctionRestParameter"; fn execute(context: &mut Context) -> JsResult { let arg_count = context.vm.frame().arg_count; diff --git a/boa_engine/src/vm/opcode/set/home_object.rs b/boa_engine/src/vm/opcode/set/home_object.rs index 39279774359..91750746ddc 100644 --- a/boa_engine/src/vm/opcode/set/home_object.rs +++ b/boa_engine/src/vm/opcode/set/home_object.rs @@ -1,8 +1,6 @@ use crate::{ - object::{JsObject, ObjectData}, - property::PropertyDescriptorBuilder, vm::{opcode::Operation, ShouldExit}, - Context, JsResult, JsValue, + Context, JsResult, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] diff --git a/boa_engine/src/vm/opcode/set/private.rs b/boa_engine/src/vm/opcode/set/private.rs index 751ea9439c7..910edc24555 100644 --- a/boa_engine/src/vm/opcode/set/private.rs +++ b/boa_engine/src/vm/opcode/set/private.rs @@ -51,8 +51,8 @@ impl Operation for AssignPrivateField { pub(crate) struct SetPrivateField; impl Operation for SetPrivateField { - const NAME: &'static str = "SetPrivateField"; - const INSTRUCTION: &'static str = "INST - SetPrivateField"; + const NAME: &'static str = "SetPrivateValue"; + const INSTRUCTION: &'static str = "INST - SetPrivateValue"; fn execute(context: &mut Context) -> JsResult { let index = context.vm.read::(); From 92b44ebc79f2636153ea725de7a8330297b8712c Mon Sep 17 00:00:00 2001 From: nekevss Date: Thu, 13 Oct 2022 20:28:59 -0400 Subject: [PATCH 04/12] Rebase and new JsString updates --- boa_engine/src/vm/opcode/concat/mod.rs | 8 +++++-- boa_engine/src/vm/opcode/define/class.rs | 16 +++++++++---- boa_engine/src/vm/opcode/define/mod.rs | 5 ++-- .../src/vm/opcode/define/own_property.rs | 7 ++++-- boa_engine/src/vm/opcode/delete/mod.rs | 8 +++++-- boa_engine/src/vm/opcode/general/mod.rs | 2 +- boa_engine/src/vm/opcode/get/name.rs | 23 +++++++++++++++---- boa_engine/src/vm/opcode/get/property.rs | 8 +++++-- boa_engine/src/vm/opcode/promise/mod.rs | 8 ++----- boa_engine/src/vm/opcode/set/name.rs | 14 +++++++---- boa_engine/src/vm/opcode/set/property.rs | 20 ++++++++++++---- 11 files changed, 84 insertions(+), 35 deletions(-) diff --git a/boa_engine/src/vm/opcode/concat/mod.rs b/boa_engine/src/vm/opcode/concat/mod.rs index 4eb9d1149bf..3a261f517d7 100644 --- a/boa_engine/src/vm/opcode/concat/mod.rs +++ b/boa_engine/src/vm/opcode/concat/mod.rs @@ -17,8 +17,12 @@ impl Operation for ConcatToString { strings.push(context.vm.pop().to_string(context)?); } strings.reverse(); - let s = - JsString::concat_array(&strings.iter().map(JsString::as_str).collect::>()); + let s = JsString::concat_array( + &strings + .iter() + .map(JsString::as_slice) + .collect::>(), + ); context.vm.push(s); Ok(ShouldExit::False) } diff --git a/boa_engine/src/vm/opcode/define/class.rs b/boa_engine/src/vm/opcode/define/class.rs index 8512dead9ac..cd61ed6970e 100644 --- a/boa_engine/src/vm/opcode/define/class.rs +++ b/boa_engine/src/vm/opcode/define/class.rs @@ -1,7 +1,7 @@ use crate::{ property::PropertyDescriptor, vm::{opcode::Operation, ShouldExit}, - Context, JsResult, + Context, JsResult, JsString, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -30,7 +30,7 @@ impl Operation for DefineClassMethodByName { let name = context.vm.frame().code.names[index as usize]; let name = context.interner().resolve_expect(name); object.__define_own_property__( - name.into(), + name.into_common::(false).into(), PropertyDescriptor::builder() .value(value) .writable(true) @@ -101,7 +101,11 @@ impl Operation for DefineClassGetterByName { .expect("method must be function object") .set_home_object(object.clone()); let name = context.vm.frame().code.names[index as usize]; - let name = context.interner().resolve_expect(name).into(); + let name = context + .interner() + .resolve_expect(name) + .into_common::(false) + .into(); let set = object .__get_own_property__(&name, context)? .as_ref() @@ -180,7 +184,11 @@ impl Operation for DefineClassSetterByName { .expect("method must be function object") .set_home_object(object.clone()); let name = context.vm.frame().code.names[index as usize]; - let name = context.interner().resolve_expect(name).into(); + let name = context + .interner() + .resolve_expect(name) + .into_common::(false) + .into(); let get = object .__get_own_property__(&name, context)? .as_ref() diff --git a/boa_engine/src/vm/opcode/define/mod.rs b/boa_engine/src/vm/opcode/define/mod.rs index 2784160a819..1532f0e84f7 100644 --- a/boa_engine/src/vm/opcode/define/mod.rs +++ b/boa_engine/src/vm/opcode/define/mod.rs @@ -1,7 +1,7 @@ use crate::{ property::PropertyDescriptor, vm::{opcode::Operation, ShouldExit}, - Context, JsResult, JsValue, + Context, JsResult, JsString, JsValue, }; pub(crate) mod class; @@ -25,7 +25,7 @@ impl Operation for DefVar { let key = context .interner() .resolve_expect(binding_locator.name()) - .into(); + .into_common(false); context.global_bindings_mut().entry(key).or_insert( PropertyDescriptor::builder() .value(JsValue::Undefined) @@ -62,6 +62,7 @@ impl Operation for DefInitVar { let key = context .interner() .resolve_expect(binding_locator.name()) + .into_common::(false) .into(); crate::object::internal_methods::global::global_set_no_receiver(&key, value, context)?; } else { diff --git a/boa_engine/src/vm/opcode/define/own_property.rs b/boa_engine/src/vm/opcode/define/own_property.rs index a8ccf81249d..cf9a7e92753 100644 --- a/boa_engine/src/vm/opcode/define/own_property.rs +++ b/boa_engine/src/vm/opcode/define/own_property.rs @@ -1,7 +1,7 @@ use crate::{ property::PropertyDescriptor, vm::{opcode::Operation, ShouldExit}, - Context, JsResult, + Context, JsResult, JsString, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -21,7 +21,10 @@ impl Operation for DefineOwnPropertyByName { object.to_object(context)? }; let name = context.vm.frame().code.names[index as usize]; - let name = context.interner().resolve_expect(name); + let name = context + .interner() + .resolve_expect(name) + .into_common::(false); object.__define_own_property__( name.into(), PropertyDescriptor::builder() diff --git a/boa_engine/src/vm/opcode/delete/mod.rs b/boa_engine/src/vm/opcode/delete/mod.rs index b9de6e3ebb5..516a6ef0348 100644 --- a/boa_engine/src/vm/opcode/delete/mod.rs +++ b/boa_engine/src/vm/opcode/delete/mod.rs @@ -1,6 +1,6 @@ use crate::{ vm::{opcode::Operation, ShouldExit}, - Context, JsResult, + Context, JsResult, JsString, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -13,7 +13,11 @@ impl Operation for DeletePropertyByName { fn execute(context: &mut Context) -> JsResult { let index = context.vm.read::(); let key = context.vm.frame().code.names[index as usize]; - let key = context.interner().resolve_expect(key).into(); + let key = context + .interner() + .resolve_expect(key) + .into_common::(false) + .into(); let object = context.vm.pop(); let result = object.to_object(context)?.__delete__(&key, context)?; if !result && context.vm.frame().code.strict { diff --git a/boa_engine/src/vm/opcode/general/mod.rs b/boa_engine/src/vm/opcode/general/mod.rs index dea02c62bbb..57468e6496f 100644 --- a/boa_engine/src/vm/opcode/general/mod.rs +++ b/boa_engine/src/vm/opcode/general/mod.rs @@ -90,7 +90,7 @@ impl Operation for In { if !rhs.is_object() { return context.throw_type_error(format!( "right-hand side of 'in' should be an object, got {}", - rhs.type_of() + rhs.type_of().to_std_string_escaped() )); } let key = lhs.to_property_key(context)?; diff --git a/boa_engine/src/vm/opcode/get/name.rs b/boa_engine/src/vm/opcode/get/name.rs index a97251b9a45..ba5f9039724 100644 --- a/boa_engine/src/vm/opcode/get/name.rs +++ b/boa_engine/src/vm/opcode/get/name.rs @@ -27,7 +27,7 @@ impl Operation for GetName { let key: JsString = context .interner() .resolve_expect(binding_locator.name()) - .into(); + .into_common(false); match context.global_bindings_mut().get(&key) { Some(desc) => match desc.kind() { DescriptorKind::Data { @@ -37,9 +37,19 @@ impl Operation for GetName { let get = get.clone(); context.call(&get, &context.global_object().clone().into(), &[])? } - _ => return context.throw_reference_error(format!("{key} is not defined")), + _ => { + return context.throw_reference_error(format!( + "{} is not defined", + key.to_std_string_escaped() + )) + } }, - _ => return context.throw_reference_error(format!("{key} is not defined")), + _ => { + return context.throw_reference_error(format!( + "{} is not defined", + key.to_std_string_escaped() + )) + } } } } else if let Some(value) = context.realm.environments.get_value_optional( @@ -49,7 +59,10 @@ impl Operation for GetName { ) { value } else { - let name = JsString::from(context.interner().resolve_expect(binding_locator.name())); + let name = context + .interner() + .resolve_expect(binding_locator.name()) + .to_string(); return context.throw_reference_error(format!("{name} is not initialized")); }; @@ -80,7 +93,7 @@ impl Operation for GetNameOrUndefined { let key: JsString = context .interner() .resolve_expect(binding_locator.name()) - .into(); + .into_common(false); match context.global_bindings_mut().get(&key) { Some(desc) => match desc.kind() { DescriptorKind::Data { diff --git a/boa_engine/src/vm/opcode/get/property.rs b/boa_engine/src/vm/opcode/get/property.rs index 255cc22d7a7..6da99de02ff 100644 --- a/boa_engine/src/vm/opcode/get/property.rs +++ b/boa_engine/src/vm/opcode/get/property.rs @@ -1,7 +1,7 @@ use crate::{ property::PropertyKey, vm::{opcode::Operation, ShouldExit}, - Context, JsResult, + Context, JsResult, JsString, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -22,7 +22,11 @@ impl Operation for GetPropertyByName { }; let name = context.vm.frame().code.names[index as usize]; - let name: PropertyKey = context.interner().resolve_expect(name).into(); + let name: PropertyKey = context + .interner() + .resolve_expect(name) + .into_common::(false) + .into(); let result = object.get(name, 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 99698bb4c83..544740e0189 100644 --- a/boa_engine/src/vm/opcode/promise/mod.rs +++ b/boa_engine/src/vm/opcode/promise/mod.rs @@ -42,12 +42,8 @@ impl Operation for FinallyEnd { } Ok(ShouldExit::False) } - FinallyReturn::Ok => { - Ok(ShouldExit::True) - } - FinallyReturn::Err => { - Err(context.vm.pop()) - } + FinallyReturn::Ok => Ok(ShouldExit::True), + FinallyReturn::Err => Err(context.vm.pop()), } } } diff --git a/boa_engine/src/vm/opcode/set/name.rs b/boa_engine/src/vm/opcode/set/name.rs index 980624cd3a1..7a3aac61b2f 100644 --- a/boa_engine/src/vm/opcode/set/name.rs +++ b/boa_engine/src/vm/opcode/set/name.rs @@ -25,12 +25,14 @@ impl Operation for SetName { let key: JsString = context .interner() .resolve_expect(binding_locator.name()) - .into(); + .into_common(false); 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}")); + return context.throw_reference_error(format!( + "assignment to undeclared variable {}", + key.to_std_string_escaped() + )); } let success = crate::object::internal_methods::global::global_set_no_receiver( @@ -40,8 +42,10 @@ impl Operation for SetName { )?; if !success && context.vm.frame().code.strict { - return context - .throw_type_error(format!("cannot set non-writable property: {key}",)); + return context.throw_type_error(format!( + "cannot set non-writable property: {}", + key.to_std_string_escaped() + )); } } } else if !context.realm.environments.put_value_if_initialized( diff --git a/boa_engine/src/vm/opcode/set/property.rs b/boa_engine/src/vm/opcode/set/property.rs index 87cd372a6d5..d90b3956270 100644 --- a/boa_engine/src/vm/opcode/set/property.rs +++ b/boa_engine/src/vm/opcode/set/property.rs @@ -1,7 +1,7 @@ use crate::{ property::{PropertyDescriptor, PropertyKey}, vm::{opcode::Operation, ShouldExit}, - Context, JsResult, + Context, JsResult, JsString, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -23,7 +23,11 @@ impl Operation for SetPropertyByName { }; let name = context.vm.frame().code.names[index as usize]; - let name: PropertyKey = context.interner().resolve_expect(name).into(); + let name: PropertyKey = context + .interner() + .resolve_expect(name) + .into_common::(false) + .into(); object.set(name, value, context.vm.frame().code.strict, context)?; Ok(ShouldExit::False) @@ -66,7 +70,11 @@ impl Operation for SetPropertyGetterByName { let value = context.vm.pop(); let object = object.to_object(context)?; let name = context.vm.frame().code.names[index as usize]; - let name = context.interner().resolve_expect(name).into(); + let name = context + .interner() + .resolve_expect(name) + .into_common::(false) + .into(); let set = object .__get_own_property__(&name, context)? .as_ref() @@ -131,7 +139,11 @@ impl Operation for SetPropertySetterByName { let value = context.vm.pop(); let object = object.to_object(context)?; let name = context.vm.frame().code.names[index as usize]; - let name = context.interner().resolve_expect(name).into(); + let name = context + .interner() + .resolve_expect(name) + .into_common::(false) + .into(); let get = object .__get_own_property__(&name, context)? .as_ref() From 490b0089930682129e4b03e5216fa0dcbd404335 Mon Sep 17 00:00:00 2001 From: nekevss Date: Thu, 13 Oct 2022 20:55:19 -0400 Subject: [PATCH 05/12] Missed a c in GetFunctionAsync --- boa_engine/src/vm/opcode/get/function.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boa_engine/src/vm/opcode/get/function.rs b/boa_engine/src/vm/opcode/get/function.rs index 5858f32188c..ea104d417c5 100644 --- a/boa_engine/src/vm/opcode/get/function.rs +++ b/boa_engine/src/vm/opcode/get/function.rs @@ -23,7 +23,7 @@ impl Operation for GetFunction { pub(crate) struct GetFunctionAsync; impl Operation for GetFunctionAsync { - const NAME: &'static str = "GetFunctionAsyn"; + const NAME: &'static str = "GetFunctionAsync"; const INSTRUCTION: &'static str = "INST - GetFunctionAsync"; fn execute(context: &mut Context) -> JsResult { From e803545f40db222af2fa0940127542d2b86282da Mon Sep 17 00:00:00 2001 From: nekevss Date: Fri, 14 Oct 2022 09:30:51 -0400 Subject: [PATCH 06/12] Clean up module naming and organization --- .../opcode/{general => binary_ops}/logical.rs | 0 .../macro_defined.rs} | 0 boa_engine/src/vm/opcode/binary_ops/mod.rs | 99 +++++++ boa_engine/src/vm/opcode/define/class.rs | 248 ------------------ .../src/vm/opcode/define/class/getter.rs | 89 +++++++ .../src/vm/opcode/define/class/method.rs | 83 ++++++ boa_engine/src/vm/opcode/define/class/mod.rs | 8 + .../src/vm/opcode/define/class/setter.rs | 88 +++++++ boa_engine/src/vm/opcode/general/mod.rs | 195 -------------- boa_engine/src/vm/opcode/generator/mod.rs | 13 +- .../src/vm/opcode/generator/yield_stm.rs | 17 ++ .../src/vm/opcode/iteration/loop_ops.rs | 64 +++++ boa_engine/src/vm/opcode/iteration/mod.rs | 66 +---- .../opcode/{general/jump.rs => jump/mod.rs} | 0 boa_engine/src/vm/opcode/mod.rs | 16 +- boa_engine/src/vm/opcode/nop/mod.rs | 16 ++ boa_engine/src/vm/opcode/pop/if_thrown.rs | 21 -- boa_engine/src/vm/opcode/pop/mod.rs | 21 +- boa_engine/src/vm/opcode/push/class.rs | 207 --------------- boa_engine/src/vm/opcode/push/class/field.rs | 78 ++++++ boa_engine/src/vm/opcode/push/class/mod.rs | 58 ++++ .../src/vm/opcode/push/class/private.rs | 90 +++++++ boa_engine/src/vm/opcode/push/numbers.rs | 3 +- .../src/vm/opcode/{conversion => to}/mod.rs | 0 .../{general => unary_ops}/decrement.rs | 0 .../{general => unary_ops}/increment.rs | 0 boa_engine/src/vm/opcode/unary_ops/mod.rs | 77 ++++++ boa_engine/src/vm/opcode/void/mod.rs | 18 ++ 28 files changed, 820 insertions(+), 755 deletions(-) rename boa_engine/src/vm/opcode/{general => binary_ops}/logical.rs (100%) rename boa_engine/src/vm/opcode/{general/bin_ops.rs => binary_ops/macro_defined.rs} (100%) create mode 100644 boa_engine/src/vm/opcode/binary_ops/mod.rs delete mode 100644 boa_engine/src/vm/opcode/define/class.rs create mode 100644 boa_engine/src/vm/opcode/define/class/getter.rs create mode 100644 boa_engine/src/vm/opcode/define/class/method.rs create mode 100644 boa_engine/src/vm/opcode/define/class/mod.rs create mode 100644 boa_engine/src/vm/opcode/define/class/setter.rs delete mode 100644 boa_engine/src/vm/opcode/general/mod.rs create mode 100644 boa_engine/src/vm/opcode/generator/yield_stm.rs create mode 100644 boa_engine/src/vm/opcode/iteration/loop_ops.rs rename boa_engine/src/vm/opcode/{general/jump.rs => jump/mod.rs} (100%) create mode 100644 boa_engine/src/vm/opcode/nop/mod.rs delete mode 100644 boa_engine/src/vm/opcode/pop/if_thrown.rs delete mode 100644 boa_engine/src/vm/opcode/push/class.rs create mode 100644 boa_engine/src/vm/opcode/push/class/field.rs create mode 100644 boa_engine/src/vm/opcode/push/class/mod.rs create mode 100644 boa_engine/src/vm/opcode/push/class/private.rs rename boa_engine/src/vm/opcode/{conversion => to}/mod.rs (100%) rename boa_engine/src/vm/opcode/{general => unary_ops}/decrement.rs (100%) rename boa_engine/src/vm/opcode/{general => unary_ops}/increment.rs (100%) create mode 100644 boa_engine/src/vm/opcode/unary_ops/mod.rs create mode 100644 boa_engine/src/vm/opcode/void/mod.rs diff --git a/boa_engine/src/vm/opcode/general/logical.rs b/boa_engine/src/vm/opcode/binary_ops/logical.rs similarity index 100% rename from boa_engine/src/vm/opcode/general/logical.rs rename to boa_engine/src/vm/opcode/binary_ops/logical.rs diff --git a/boa_engine/src/vm/opcode/general/bin_ops.rs b/boa_engine/src/vm/opcode/binary_ops/macro_defined.rs similarity index 100% rename from boa_engine/src/vm/opcode/general/bin_ops.rs rename to boa_engine/src/vm/opcode/binary_ops/macro_defined.rs diff --git a/boa_engine/src/vm/opcode/binary_ops/mod.rs b/boa_engine/src/vm/opcode/binary_ops/mod.rs new file mode 100644 index 00000000000..507aa0244fc --- /dev/null +++ b/boa_engine/src/vm/opcode/binary_ops/mod.rs @@ -0,0 +1,99 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsValue, +}; + +pub(crate) mod macro_defined; +pub(crate) mod logical; + +pub(crate) use macro_defined::*; +pub(crate) use logical::*; + + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct NotEq; + +impl Operation for NotEq { + const NAME: &'static str = "NotEq"; + const INSTRUCTION: &'static str = "INST - NotEq"; + + fn execute(context: &mut Context) -> JsResult { + let rhs = context.vm.pop(); + let lhs = context.vm.pop(); + let value = !lhs.equals(&rhs, context)?; + context.vm.push(value); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct StrictEq; + +impl Operation for StrictEq { + const NAME: &'static str = "StrictEq"; + const INSTRUCTION: &'static str = "INST - StrictEq"; + + fn execute(context: &mut Context) -> JsResult { + let rhs = context.vm.pop(); + let lhs = context.vm.pop(); + context.vm.push(lhs.strict_equals(&rhs)); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct StrictNotEq; + +impl Operation for StrictNotEq { + const NAME: &'static str = "StrictNotEq"; + const INSTRUCTION: &'static str = "INST - StrictNotEq"; + + fn execute(context: &mut Context) -> JsResult { + let rhs = context.vm.pop(); + let lhs = context.vm.pop(); + context.vm.push(!lhs.strict_equals(&rhs)); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct In; + +impl Operation for In { + const NAME: &'static str = "In"; + const INSTRUCTION: &'static str = "INST - In"; + + fn execute(context: &mut Context) -> JsResult { + let rhs = context.vm.pop(); + 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() + )); + } + let key = lhs.to_property_key(context)?; + let value = context.has_property(&rhs, &key)?; + context.vm.push(value); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct InstanceOf; + +impl Operation for InstanceOf { + const NAME: &'static str = "InstanceOf"; + const INSTRUCTION: &'static str = "INST - InstanceOf"; + + fn execute(context: &mut Context) -> JsResult { + let target = context.vm.pop(); + let v = context.vm.pop(); + let value = v.instance_of(&target, context)?; + + context.vm.push(value); + Ok(ShouldExit::False) + } +} + diff --git a/boa_engine/src/vm/opcode/define/class.rs b/boa_engine/src/vm/opcode/define/class.rs deleted file mode 100644 index cd61ed6970e..00000000000 --- a/boa_engine/src/vm/opcode/define/class.rs +++ /dev/null @@ -1,248 +0,0 @@ -use crate::{ - property::PropertyDescriptor, - vm::{opcode::Operation, ShouldExit}, - Context, JsResult, JsString, -}; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct DefineClassMethodByName; - -impl Operation for DefineClassMethodByName { - const NAME: &'static str = "DefineClassMethodByName"; - const INSTRUCTION: &'static str = "INST - DefineClassMethodByName"; - - fn execute(context: &mut Context) -> JsResult { - let index = context.vm.read::(); - let object = context.vm.pop(); - let value = context.vm.pop(); - let object = if let Some(object) = object.as_object() { - object.clone() - } else { - object.to_object(context)? - }; - value - .as_object() - .expect("method must be function object") - .borrow_mut() - .as_function_mut() - .expect("method must be function object") - .set_home_object(object.clone()); - let name = context.vm.frame().code.names[index as usize]; - let name = context.interner().resolve_expect(name); - object.__define_own_property__( - name.into_common::(false).into(), - PropertyDescriptor::builder() - .value(value) - .writable(true) - .enumerable(false) - .configurable(true) - .build(), - context, - )?; - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct DefineClassMethodByValue; - -impl Operation for DefineClassMethodByValue { - const NAME: &'static str = "DefineClassMethodByName"; - const INSTRUCTION: &'static str = "INST - DefineClassMethodByName"; - - fn execute(context: &mut Context) -> JsResult { - let value = context.vm.pop(); - let key = context.vm.pop(); - let object = context.vm.pop(); - let object = if let Some(object) = object.as_object() { - object.clone() - } else { - object.to_object(context)? - }; - value - .as_object() - .expect("method must be function object") - .borrow_mut() - .as_function_mut() - .expect("method must be function object") - .set_home_object(object.clone()); - let key = key.to_property_key(context)?; - object.__define_own_property__( - key, - PropertyDescriptor::builder() - .value(value) - .writable(true) - .enumerable(false) - .configurable(true) - .build(), - context, - )?; - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct DefineClassGetterByName; - -impl Operation for DefineClassGetterByName { - const NAME: &'static str = "DefineClassGetterByName"; - const INSTRUCTION: &'static str = "INST - DefineClassGetterByName"; - - fn execute(context: &mut Context) -> JsResult { - let index = context.vm.read::(); - let object = context.vm.pop(); - let value = context.vm.pop(); - let object = object.to_object(context)?; - value - .as_object() - .expect("method must be function object") - .borrow_mut() - .as_function_mut() - .expect("method must be function object") - .set_home_object(object.clone()); - let name = context.vm.frame().code.names[index as usize]; - let name = context - .interner() - .resolve_expect(name) - .into_common::(false) - .into(); - let set = object - .__get_own_property__(&name, context)? - .as_ref() - .and_then(PropertyDescriptor::set) - .cloned(); - object.__define_own_property__( - name, - PropertyDescriptor::builder() - .maybe_get(Some(value)) - .maybe_set(set) - .enumerable(false) - .configurable(true) - .build(), - context, - )?; - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct DefineClassGetterByValue; - -impl Operation for DefineClassGetterByValue { - const NAME: &'static str = "DefineClassGetterByValue"; - const INSTRUCTION: &'static str = "INST - DefineClassGetterByValue"; - - fn execute(context: &mut Context) -> JsResult { - let value = context.vm.pop(); - let key = context.vm.pop(); - let object = context.vm.pop(); - let object = object.to_object(context)?; - value - .as_object() - .expect("method must be function object") - .borrow_mut() - .as_function_mut() - .expect("method must be function object") - .set_home_object(object.clone()); - let name = key.to_property_key(context)?; - let set = object - .__get_own_property__(&name, context)? - .as_ref() - .and_then(PropertyDescriptor::set) - .cloned(); - object.__define_own_property__( - name, - PropertyDescriptor::builder() - .maybe_get(Some(value)) - .maybe_set(set) - .enumerable(false) - .configurable(true) - .build(), - context, - )?; - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct DefineClassSetterByName; - -impl Operation for DefineClassSetterByName { - const NAME: &'static str = "DefineClassSetterByName"; - const INSTRUCTION: &'static str = "INST - DefineClassSetterByName"; - - fn execute(context: &mut Context) -> JsResult { - let index = context.vm.read::(); - let object = context.vm.pop(); - let value = context.vm.pop(); - let object = object.to_object(context)?; - value - .as_object() - .expect("method must be function object") - .borrow_mut() - .as_function_mut() - .expect("method must be function object") - .set_home_object(object.clone()); - let name = context.vm.frame().code.names[index as usize]; - let name = context - .interner() - .resolve_expect(name) - .into_common::(false) - .into(); - let get = object - .__get_own_property__(&name, context)? - .as_ref() - .and_then(PropertyDescriptor::get) - .cloned(); - object.__define_own_property__( - name, - PropertyDescriptor::builder() - .maybe_set(Some(value)) - .maybe_get(get) - .enumerable(false) - .configurable(true) - .build(), - context, - )?; - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct DefineClassSetterByValue; - -impl Operation for DefineClassSetterByValue { - const NAME: &'static str = "DefineClassSetterByValue"; - const INSTRUCTION: &'static str = "INST - DefineClassSetterByValue"; - - fn execute(context: &mut Context) -> JsResult { - let value = context.vm.pop(); - let key = context.vm.pop(); - let object = context.vm.pop(); - let object = object.to_object(context)?; - value - .as_object() - .expect("method must be function object") - .borrow_mut() - .as_function_mut() - .expect("method must be function object") - .set_home_object(object.clone()); - let name = key.to_property_key(context)?; - let get = object - .__get_own_property__(&name, context)? - .as_ref() - .and_then(PropertyDescriptor::get) - .cloned(); - object.__define_own_property__( - name, - PropertyDescriptor::builder() - .maybe_set(Some(value)) - .maybe_get(get) - .enumerable(false) - .configurable(true) - .build(), - context, - )?; - Ok(ShouldExit::False) - } -} diff --git a/boa_engine/src/vm/opcode/define/class/getter.rs b/boa_engine/src/vm/opcode/define/class/getter.rs new file mode 100644 index 00000000000..786b4fdf127 --- /dev/null +++ b/boa_engine/src/vm/opcode/define/class/getter.rs @@ -0,0 +1,89 @@ +use crate::{ + property::PropertyDescriptor, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsString, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct DefineClassGetterByName; + +impl Operation for DefineClassGetterByName { + const NAME: &'static str = "DefineClassGetterByName"; + const INSTRUCTION: &'static str = "INST - DefineClassGetterByName"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let object = context.vm.pop(); + let value = context.vm.pop(); + let object = object.to_object(context)?; + value + .as_object() + .expect("method must be function object") + .borrow_mut() + .as_function_mut() + .expect("method must be function object") + .set_home_object(object.clone()); + let name = context.vm.frame().code.names[index as usize]; + let name = context + .interner() + .resolve_expect(name) + .into_common::(false) + .into(); + let set = object + .__get_own_property__(&name, context)? + .as_ref() + .and_then(PropertyDescriptor::set) + .cloned(); + object.__define_own_property__( + name, + PropertyDescriptor::builder() + .maybe_get(Some(value)) + .maybe_set(set) + .enumerable(false) + .configurable(true) + .build(), + context, + )?; + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct DefineClassGetterByValue; + +impl Operation for DefineClassGetterByValue { + const NAME: &'static str = "DefineClassGetterByValue"; + const INSTRUCTION: &'static str = "INST - DefineClassGetterByValue"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + let key = context.vm.pop(); + let object = context.vm.pop(); + let object = object.to_object(context)?; + value + .as_object() + .expect("method must be function object") + .borrow_mut() + .as_function_mut() + .expect("method must be function object") + .set_home_object(object.clone()); + let name = key.to_property_key(context)?; + let set = object + .__get_own_property__(&name, context)? + .as_ref() + .and_then(PropertyDescriptor::set) + .cloned(); + object.__define_own_property__( + name, + PropertyDescriptor::builder() + .maybe_get(Some(value)) + .maybe_set(set) + .enumerable(false) + .configurable(true) + .build(), + context, + )?; + Ok(ShouldExit::False) + } +} + diff --git a/boa_engine/src/vm/opcode/define/class/method.rs b/boa_engine/src/vm/opcode/define/class/method.rs new file mode 100644 index 00000000000..c2ca26d991b --- /dev/null +++ b/boa_engine/src/vm/opcode/define/class/method.rs @@ -0,0 +1,83 @@ +use crate::{ + property::PropertyDescriptor, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsString, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct DefineClassMethodByName; + +impl Operation for DefineClassMethodByName { + const NAME: &'static str = "DefineClassMethodByName"; + const INSTRUCTION: &'static str = "INST - DefineClassMethodByName"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let object = context.vm.pop(); + let value = context.vm.pop(); + let object = if let Some(object) = object.as_object() { + object.clone() + } else { + object.to_object(context)? + }; + value + .as_object() + .expect("method must be function object") + .borrow_mut() + .as_function_mut() + .expect("method must be function object") + .set_home_object(object.clone()); + let name = context.vm.frame().code.names[index as usize]; + let name = context.interner().resolve_expect(name); + object.__define_own_property__( + name.into_common::(false).into(), + PropertyDescriptor::builder() + .value(value) + .writable(true) + .enumerable(false) + .configurable(true) + .build(), + context, + )?; + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct DefineClassMethodByValue; + +impl Operation for DefineClassMethodByValue { + const NAME: &'static str = "DefineClassMethodByName"; + const INSTRUCTION: &'static str = "INST - DefineClassMethodByName"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + let key = context.vm.pop(); + let object = context.vm.pop(); + let object = if let Some(object) = object.as_object() { + object.clone() + } else { + object.to_object(context)? + }; + value + .as_object() + .expect("method must be function object") + .borrow_mut() + .as_function_mut() + .expect("method must be function object") + .set_home_object(object.clone()); + let key = key.to_property_key(context)?; + object.__define_own_property__( + key, + PropertyDescriptor::builder() + .value(value) + .writable(true) + .enumerable(false) + .configurable(true) + .build(), + context, + )?; + Ok(ShouldExit::False) + } +} + diff --git a/boa_engine/src/vm/opcode/define/class/mod.rs b/boa_engine/src/vm/opcode/define/class/mod.rs new file mode 100644 index 00000000000..c1affb1e2e3 --- /dev/null +++ b/boa_engine/src/vm/opcode/define/class/mod.rs @@ -0,0 +1,8 @@ + +pub(crate) mod method; +pub(crate) mod getter; +pub(crate) mod setter; + +pub(crate) use method::*; +pub(crate) use getter::*; +pub(crate) use setter::*; \ No newline at end of file diff --git a/boa_engine/src/vm/opcode/define/class/setter.rs b/boa_engine/src/vm/opcode/define/class/setter.rs new file mode 100644 index 00000000000..5f00333c9bc --- /dev/null +++ b/boa_engine/src/vm/opcode/define/class/setter.rs @@ -0,0 +1,88 @@ +use crate::{ + property::PropertyDescriptor, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsString, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct DefineClassSetterByName; + +impl Operation for DefineClassSetterByName { + const NAME: &'static str = "DefineClassSetterByName"; + const INSTRUCTION: &'static str = "INST - DefineClassSetterByName"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let object = context.vm.pop(); + let value = context.vm.pop(); + let object = object.to_object(context)?; + value + .as_object() + .expect("method must be function object") + .borrow_mut() + .as_function_mut() + .expect("method must be function object") + .set_home_object(object.clone()); + let name = context.vm.frame().code.names[index as usize]; + let name = context + .interner() + .resolve_expect(name) + .into_common::(false) + .into(); + let get = object + .__get_own_property__(&name, context)? + .as_ref() + .and_then(PropertyDescriptor::get) + .cloned(); + object.__define_own_property__( + name, + PropertyDescriptor::builder() + .maybe_set(Some(value)) + .maybe_get(get) + .enumerable(false) + .configurable(true) + .build(), + context, + )?; + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct DefineClassSetterByValue; + +impl Operation for DefineClassSetterByValue { + const NAME: &'static str = "DefineClassSetterByValue"; + const INSTRUCTION: &'static str = "INST - DefineClassSetterByValue"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + let key = context.vm.pop(); + let object = context.vm.pop(); + let object = object.to_object(context)?; + value + .as_object() + .expect("method must be function object") + .borrow_mut() + .as_function_mut() + .expect("method must be function object") + .set_home_object(object.clone()); + let name = key.to_property_key(context)?; + let get = object + .__get_own_property__(&name, context)? + .as_ref() + .and_then(PropertyDescriptor::get) + .cloned(); + object.__define_own_property__( + name, + PropertyDescriptor::builder() + .maybe_set(Some(value)) + .maybe_get(get) + .enumerable(false) + .configurable(true) + .build(), + context, + )?; + Ok(ShouldExit::False) + } +} \ No newline at end of file diff --git a/boa_engine/src/vm/opcode/general/mod.rs b/boa_engine/src/vm/opcode/general/mod.rs deleted file mode 100644 index 57468e6496f..00000000000 --- a/boa_engine/src/vm/opcode/general/mod.rs +++ /dev/null @@ -1,195 +0,0 @@ -use crate::{ - builtins::Number, - value::Numeric, - vm::{opcode::Operation, ShouldExit}, - Context, JsBigInt, JsResult, JsValue, -}; -use std::ops::Neg as StdNeg; - -pub(crate) mod bin_ops; -pub(crate) mod decrement; -pub(crate) mod increment; -pub(crate) mod jump; -pub(crate) mod logical; - -pub(crate) use bin_ops::*; -pub(crate) use decrement::*; -pub(crate) use increment::*; -pub(crate) use jump::*; -pub(crate) use logical::*; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct Nop; - -impl Operation for Nop { - const NAME: &'static str = "Nop"; - const INSTRUCTION: &'static str = "INST - Nop"; - - fn execute(_context: &mut Context) -> JsResult { - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct NotEq; - -impl Operation for NotEq { - const NAME: &'static str = "NotEq"; - const INSTRUCTION: &'static str = "INST - NotEq"; - - fn execute(context: &mut Context) -> JsResult { - let rhs = context.vm.pop(); - let lhs = context.vm.pop(); - let value = !lhs.equals(&rhs, context)?; - context.vm.push(value); - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct StrictEq; - -impl Operation for StrictEq { - const NAME: &'static str = "StrictEq"; - const INSTRUCTION: &'static str = "INST - StrictEq"; - - fn execute(context: &mut Context) -> JsResult { - let rhs = context.vm.pop(); - let lhs = context.vm.pop(); - context.vm.push(lhs.strict_equals(&rhs)); - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct StrictNotEq; - -impl Operation for StrictNotEq { - const NAME: &'static str = "StrictNotEq"; - const INSTRUCTION: &'static str = "INST - StrictNotEq"; - - fn execute(context: &mut Context) -> JsResult { - let rhs = context.vm.pop(); - let lhs = context.vm.pop(); - context.vm.push(!lhs.strict_equals(&rhs)); - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct In; - -impl Operation for In { - const NAME: &'static str = "In"; - const INSTRUCTION: &'static str = "INST - In"; - - fn execute(context: &mut Context) -> JsResult { - let rhs = context.vm.pop(); - 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() - )); - } - let key = lhs.to_property_key(context)?; - let value = context.has_property(&rhs, &key)?; - context.vm.push(value); - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct InstanceOf; - -impl Operation for InstanceOf { - const NAME: &'static str = "InstanceOf"; - const INSTRUCTION: &'static str = "INST - InstanceOf"; - - fn execute(context: &mut Context) -> JsResult { - let target = context.vm.pop(); - let v = context.vm.pop(); - let value = v.instance_of(&target, context)?; - - context.vm.push(value); - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct Void; - -impl Operation for Void { - const NAME: &'static str = "Void"; - const INSTRUCTION: &'static str = "INST - Void"; - - fn execute(context: &mut Context) -> JsResult { - let _old = context.vm.pop(); - context.vm.push(JsValue::undefined()); - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct TypeOf; - -impl Operation for TypeOf { - const NAME: &'static str = "TypeOf"; - const INSTRUCTION: &'static str = "INST - TypeOf"; - - fn execute(context: &mut Context) -> JsResult { - let value = context.vm.pop(); - context.vm.push(value.type_of()); - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct Pos; - -impl Operation for Pos { - const NAME: &'static str = "Pos"; - const INSTRUCTION: &'static str = "INST - Pos"; - - fn execute(context: &mut Context) -> JsResult { - let value = context.vm.pop(); - let value = value.to_number(context)?; - context.vm.push(value); - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct Neg; - -impl Operation for Neg { - const NAME: &'static str = "Neg"; - const INSTRUCTION: &'static str = "INST - Neg"; - - fn execute(context: &mut Context) -> JsResult { - let value = context.vm.pop(); - match value.to_numeric(context)? { - Numeric::Number(number) => context.vm.push(number.neg()), - Numeric::BigInt(bigint) => context.vm.push(JsBigInt::neg(&bigint)), - } - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct BitNot; - -impl Operation for BitNot { - const NAME: &'static str = "BitNot"; - const INSTRUCTION: &'static str = "INST - BitNot"; - - fn execute(context: &mut Context) -> JsResult { - let value = context.vm.pop(); - match value.to_numeric(context)? { - Numeric::Number(number) => context.vm.push(Number::not(number)), - Numeric::BigInt(bigint) => context.vm.push(JsBigInt::not(&bigint)), - } - Ok(ShouldExit::False) - } -} diff --git a/boa_engine/src/vm/opcode/generator/mod.rs b/boa_engine/src/vm/opcode/generator/mod.rs index de6cd372d4c..7d9c56e1365 100644 --- a/boa_engine/src/vm/opcode/generator/mod.rs +++ b/boa_engine/src/vm/opcode/generator/mod.rs @@ -11,18 +11,9 @@ use crate::{ Context, JsResult, JsValue, }; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct Yield; - -impl Operation for Yield { - const NAME: &'static str = "Yield"; - const INSTRUCTION: &'static str = "INST - Yield"; - - fn execute(_context: &mut Context) -> JsResult { - Ok(ShouldExit::Yield) - } -} +pub(crate) mod yield_stm; +pub(crate) use yield_stm::*; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct GeneratorNext; diff --git a/boa_engine/src/vm/opcode/generator/yield_stm.rs b/boa_engine/src/vm/opcode/generator/yield_stm.rs new file mode 100644 index 00000000000..d60fc3854e7 --- /dev/null +++ b/boa_engine/src/vm/opcode/generator/yield_stm.rs @@ -0,0 +1,17 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Yield; + +impl Operation for Yield { + const NAME: &'static str = "Yield"; + const INSTRUCTION: &'static str = "INST - Yield"; + + fn execute(_context: &mut Context) -> JsResult { + Ok(ShouldExit::Yield) + } +} + diff --git a/boa_engine/src/vm/opcode/iteration/loop_ops.rs b/boa_engine/src/vm/opcode/iteration/loop_ops.rs new file mode 100644 index 00000000000..c88d9d0da44 --- /dev/null +++ b/boa_engine/src/vm/opcode/iteration/loop_ops.rs @@ -0,0 +1,64 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct LoopStart; + +impl Operation for LoopStart { + const NAME: &'static str = "LoopStart"; + const INSTRUCTION: &'static str = "INST - LoopStart"; + + fn execute(context: &mut Context) -> JsResult { + context.vm.frame_mut().loop_env_stack.push(0); + context.vm.frame_mut().try_env_stack_loop_inc(); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct LoopContinue; + +impl Operation for LoopContinue { + const NAME: &'static str = "LoopContinue"; + const INSTRUCTION: &'static str = "INST - LoopContinue"; + + fn execute(context: &mut Context) -> JsResult { + let env_num = context + .vm + .frame_mut() + .loop_env_stack + .last_mut() + .expect("loop env stack entry must exist"); + let env_num_copy = *env_num; + *env_num = 0; + for _ in 0..env_num_copy { + context.realm.environments.pop(); + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct LoopEnd; + +impl Operation for LoopEnd { + const NAME: &'static str = "LoopEnd"; + const INSTRUCTION: &'static str = "INST - LoopEnd"; + + fn execute(context: &mut Context) -> JsResult { + let env_num = context + .vm + .frame_mut() + .loop_env_stack + .pop() + .expect("loop env stack entry must exist"); + for _ in 0..env_num { + context.realm.environments.pop(); + context.vm.frame_mut().try_env_stack_dec(); + } + context.vm.frame_mut().try_env_stack_loop_dec(); + Ok(ShouldExit::False) + } +} \ No newline at end of file diff --git a/boa_engine/src/vm/opcode/iteration/mod.rs b/boa_engine/src/vm/opcode/iteration/mod.rs index b1f04a726d7..c9a04731e0d 100644 --- a/boa_engine/src/vm/opcode/iteration/mod.rs +++ b/boa_engine/src/vm/opcode/iteration/mod.rs @@ -1,74 +1,14 @@ -use crate::{ - vm::{opcode::Operation, ShouldExit}, - Context, JsResult, -}; + pub(crate) mod for_await; pub(crate) mod for_in; pub(crate) mod init; pub(crate) mod iterator; +pub(crate) mod loop_ops; pub(crate) use for_await::*; pub(crate) use for_in::*; pub(crate) use init::*; pub(crate) use iterator::*; +pub(crate) use loop_ops::*; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct LoopStart; - -impl Operation for LoopStart { - const NAME: &'static str = "LoopStart"; - const INSTRUCTION: &'static str = "INST - LoopStart"; - - fn execute(context: &mut Context) -> JsResult { - context.vm.frame_mut().loop_env_stack.push(0); - context.vm.frame_mut().try_env_stack_loop_inc(); - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct LoopContinue; - -impl Operation for LoopContinue { - const NAME: &'static str = "LoopContinue"; - const INSTRUCTION: &'static str = "INST - LoopContinue"; - - fn execute(context: &mut Context) -> JsResult { - let env_num = context - .vm - .frame_mut() - .loop_env_stack - .last_mut() - .expect("loop env stack entry must exist"); - let env_num_copy = *env_num; - *env_num = 0; - for _ in 0..env_num_copy { - context.realm.environments.pop(); - } - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct LoopEnd; - -impl Operation for LoopEnd { - const NAME: &'static str = "LoopEnd"; - const INSTRUCTION: &'static str = "INST - LoopEnd"; - - fn execute(context: &mut Context) -> JsResult { - let env_num = context - .vm - .frame_mut() - .loop_env_stack - .pop() - .expect("loop env stack entry must exist"); - for _ in 0..env_num { - context.realm.environments.pop(); - context.vm.frame_mut().try_env_stack_dec(); - } - context.vm.frame_mut().try_env_stack_loop_dec(); - Ok(ShouldExit::False) - } -} diff --git a/boa_engine/src/vm/opcode/general/jump.rs b/boa_engine/src/vm/opcode/jump/mod.rs similarity index 100% rename from boa_engine/src/vm/opcode/general/jump.rs rename to boa_engine/src/vm/opcode/jump/mod.rs diff --git a/boa_engine/src/vm/opcode/mod.rs b/boa_engine/src/vm/opcode/mod.rs index ac482981848..12d8acfa6ae 100644 --- a/boa_engine/src/vm/opcode/mod.rs +++ b/boa_engine/src/vm/opcode/mod.rs @@ -5,13 +5,12 @@ use crate::{vm::ShouldExit, Context, JsResult}; pub(crate) mod await_stm; pub(crate) mod call; pub(crate) mod concat; -pub(crate) mod conversion; +pub(crate) mod to; pub(crate) mod copy; pub(crate) mod define; pub(crate) mod delete; pub(crate) mod dup; pub(crate) mod environment; -pub(crate) mod general; pub(crate) mod generator; pub(crate) mod get; pub(crate) mod iteration; @@ -28,18 +27,22 @@ pub(crate) mod switch; pub(crate) mod throw; pub(crate) mod try_catch; pub(crate) mod value; +pub(crate) mod jump; +pub(crate) mod binary_ops; +pub(crate) mod unary_ops; +pub(crate) mod nop; +pub(crate) mod void; // Operation structs pub(crate) use await_stm::*; pub(crate) use call::*; pub(crate) use concat::*; -pub(crate) use conversion::*; +pub(crate) use to::*; pub(crate) use copy::*; pub(crate) use define::*; pub(crate) use delete::*; pub(crate) use dup::*; pub(crate) use environment::*; -pub(crate) use general::*; pub(crate) use generator::*; pub(crate) use get::*; pub(crate) use iteration::*; @@ -56,6 +59,11 @@ pub(crate) use switch::*; pub(crate) use throw::*; pub(crate) use try_catch::*; pub(crate) use value::*; +pub(crate) use jump::*; +pub(crate) use binary_ops::*; +pub(crate) use unary_ops::*; +pub(crate) use nop::*; +pub(crate) use void::*; pub(crate) trait Operation { const NAME: &'static str; diff --git a/boa_engine/src/vm/opcode/nop/mod.rs b/boa_engine/src/vm/opcode/nop/mod.rs new file mode 100644 index 00000000000..e2f4c420c74 --- /dev/null +++ b/boa_engine/src/vm/opcode/nop/mod.rs @@ -0,0 +1,16 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsValue, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Nop; + +impl Operation for Nop { + const NAME: &'static str = "Nop"; + const INSTRUCTION: &'static str = "INST - Nop"; + + fn execute(_context: &mut Context) -> JsResult { + Ok(ShouldExit::False) + } +} \ No newline at end of file diff --git a/boa_engine/src/vm/opcode/pop/if_thrown.rs b/boa_engine/src/vm/opcode/pop/if_thrown.rs deleted file mode 100644 index 46ecac122b5..00000000000 --- a/boa_engine/src/vm/opcode/pop/if_thrown.rs +++ /dev/null @@ -1,21 +0,0 @@ -use crate::{ - vm::{opcode::Operation, ShouldExit}, - Context, JsResult, -}; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct PopIfThrown; - -impl Operation for PopIfThrown { - const NAME: &'static str = "PopIfThrown"; - const INSTRUCTION: &'static str = "INST - PopIfThrown"; - - fn execute(context: &mut Context) -> JsResult { - let frame = context.vm.frame_mut(); - if frame.thrown { - frame.thrown = false; - context.vm.pop(); - } - Ok(ShouldExit::False) - } -} diff --git a/boa_engine/src/vm/opcode/pop/mod.rs b/boa_engine/src/vm/opcode/pop/mod.rs index d3a58a4bbda..a75c5f0f13f 100644 --- a/boa_engine/src/vm/opcode/pop/mod.rs +++ b/boa_engine/src/vm/opcode/pop/mod.rs @@ -3,10 +3,6 @@ use crate::{ Context, JsResult, }; -pub(crate) mod if_thrown; - -pub(crate) use if_thrown::PopIfThrown; - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct Pop; @@ -20,6 +16,23 @@ impl Operation for Pop { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PopIfThrown; + +impl Operation for PopIfThrown { + const NAME: &'static str = "PopIfThrown"; + const INSTRUCTION: &'static str = "INST - PopIfThrown"; + + fn execute(context: &mut Context) -> JsResult { + let frame = context.vm.frame_mut(); + if frame.thrown { + frame.thrown = false; + context.vm.pop(); + } + Ok(ShouldExit::False) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct PopEnvironment; diff --git a/boa_engine/src/vm/opcode/push/class.rs b/boa_engine/src/vm/opcode/push/class.rs deleted file mode 100644 index d3d496333e0..00000000000 --- a/boa_engine/src/vm/opcode/push/class.rs +++ /dev/null @@ -1,207 +0,0 @@ -use crate::{ - builtins::function::{ConstructorKind, Function}, - object::{JsFunction, PrivateElement}, - vm::{opcode::Operation, ShouldExit}, - Context, JsResult, JsValue, -}; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct PushClassPrototype; - -impl Operation for PushClassPrototype { - const NAME: &'static str = "PushClassPrototype"; - const INSTRUCTION: &'static str = "INST - PushClassPrototype"; - - fn execute(context: &mut Context) -> JsResult { - let superclass = context.vm.pop(); - - 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"); - } - - let class = context.vm.pop(); - { - let class_object = class.as_object().expect("class must be object"); - class_object.set_prototype(Some(superclass.clone())); - - let mut class_object_mut = class_object.borrow_mut(); - let class_function = class_object_mut - .as_function_mut() - .expect("class must be function object"); - if let Function::Ordinary { - constructor_kind, .. - } = class_function - { - *constructor_kind = ConstructorKind::Derived; - } - } - - context.vm.push(class); - context.vm.push(proto); - Ok(ShouldExit::False) - } else if superclass.is_null() { - context.vm.push(JsValue::Null); - Ok(ShouldExit::False) - } else { - context.throw_type_error("superclass must be a constructor") - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct PushClassField; - -impl Operation for PushClassField { - const NAME: &'static str = "PushClassField"; - const INSTRUCTION: &'static str = "INST - PushClassField"; - - fn execute(context: &mut Context) -> JsResult { - let field_function_value = context.vm.pop(); - let field_name_value = context.vm.pop(); - let class_value = context.vm.pop(); - - let field_name_key = field_name_value.to_property_key(context)?; - let field_function_object = field_function_value - .as_object() - .expect("field value must be function object"); - let mut field_function_object_borrow = field_function_object.borrow_mut(); - let field_function = field_function_object_borrow - .as_function_mut() - .expect("field value must be function object"); - let class_object = class_value - .as_object() - .expect("class must be function object"); - field_function.set_home_object(class_object.clone()); - class_object - .borrow_mut() - .as_function_mut() - .expect("class must be function object") - .push_field( - field_name_key, - JsFunction::from_object_unchecked(field_function_object.clone()), - ); - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct PushClassFieldPrivate; - -impl Operation for PushClassFieldPrivate { - const NAME: &'static str = "PushClassFieldPrivate"; - const INSTRUCTION: &'static str = "INST - PushClassFieldPrivate"; - - fn execute(context: &mut Context) -> JsResult { - let index = context.vm.read::(); - let name = context.vm.frame().code.names[index as usize]; - let field_function_value = context.vm.pop(); - let class_value = context.vm.pop(); - - let field_function_object = field_function_value - .as_object() - .expect("field value must be function object"); - let mut field_function_object_borrow = field_function_object.borrow_mut(); - let field_function = field_function_object_borrow - .as_function_mut() - .expect("field value must be function object"); - let class_object = class_value - .as_object() - .expect("class must be function object"); - field_function.set_home_object(class_object.clone()); - class_object - .borrow_mut() - .as_function_mut() - .expect("class must be function object") - .push_field_private( - name, - JsFunction::from_object_unchecked(field_function_object.clone()), - ); - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct PushClassPrivateMethod; - -impl Operation for PushClassPrivateMethod { - const NAME: &'static str = "PushClassPrivateMethod"; - const INSTRUCTION: &'static str = "INST - PushClassPrivateMethod"; - - fn execute(context: &mut Context) -> JsResult { - let index = context.vm.read::(); - let name = context.vm.frame().code.names[index as usize]; - let method = context.vm.pop(); - let method_object = method.as_callable().expect("method must be callable"); - let class = context.vm.pop(); - class - .as_object() - .expect("class must be function object") - .borrow_mut() - .as_function_mut() - .expect("class must be function object") - .push_private_method(name, PrivateElement::Method(method_object.clone())); - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct PushClassPrivateGetter; - -impl Operation for PushClassPrivateGetter { - const NAME: &'static str = "PushClassPrivateGetter"; - const INSTRUCTION: &'static str = "INST - PushClassPrivateGetter"; - - fn execute(context: &mut Context) -> JsResult { - let index = context.vm.read::(); - let name = context.vm.frame().code.names[index as usize]; - let getter = context.vm.pop(); - let getter_object = getter.as_callable().expect("getter must be callable"); - let class = context.vm.pop(); - class - .as_object() - .expect("class must be function object") - .borrow_mut() - .as_function_mut() - .expect("class must be function object") - .push_private_method( - name, - PrivateElement::Accessor { - getter: Some(getter_object.clone()), - setter: None, - }, - ); - Ok(ShouldExit::False) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct PushClassPrivateSetter; - -impl Operation for PushClassPrivateSetter { - const NAME: &'static str = "PushClassPrivateSetter"; - const INSTRUCTION: &'static str = "INST - PushClassPrivateSetter"; - - fn execute(context: &mut Context) -> JsResult { - let index = context.vm.read::(); - let name = context.vm.frame().code.names[index as usize]; - let setter = context.vm.pop(); - let setter_object = setter.as_callable().expect("getter must be callable"); - let class = context.vm.pop(); - class - .as_object() - .expect("class must be function object") - .borrow_mut() - .as_function_mut() - .expect("class must be function object") - .push_private_method( - name, - PrivateElement::Accessor { - getter: None, - setter: Some(setter_object.clone()), - }, - ); - Ok(ShouldExit::False) - } -} diff --git a/boa_engine/src/vm/opcode/push/class/field.rs b/boa_engine/src/vm/opcode/push/class/field.rs new file mode 100644 index 00000000000..63329cafb0d --- /dev/null +++ b/boa_engine/src/vm/opcode/push/class/field.rs @@ -0,0 +1,78 @@ +use crate::{ + builtins::function::{ConstructorKind, Function}, + object::{JsFunction, PrivateElement}, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsValue, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PushClassField; + +impl Operation for PushClassField { + const NAME: &'static str = "PushClassField"; + const INSTRUCTION: &'static str = "INST - PushClassField"; + + fn execute(context: &mut Context) -> JsResult { + let field_function_value = context.vm.pop(); + let field_name_value = context.vm.pop(); + let class_value = context.vm.pop(); + + let field_name_key = field_name_value.to_property_key(context)?; + let field_function_object = field_function_value + .as_object() + .expect("field value must be function object"); + let mut field_function_object_borrow = field_function_object.borrow_mut(); + let field_function = field_function_object_borrow + .as_function_mut() + .expect("field value must be function object"); + let class_object = class_value + .as_object() + .expect("class must be function object"); + field_function.set_home_object(class_object.clone()); + class_object + .borrow_mut() + .as_function_mut() + .expect("class must be function object") + .push_field( + field_name_key, + JsFunction::from_object_unchecked(field_function_object.clone()), + ); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PushClassFieldPrivate; + +impl Operation for PushClassFieldPrivate { + const NAME: &'static str = "PushClassFieldPrivate"; + const INSTRUCTION: &'static str = "INST - PushClassFieldPrivate"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let name = context.vm.frame().code.names[index as usize]; + let field_function_value = context.vm.pop(); + let class_value = context.vm.pop(); + + let field_function_object = field_function_value + .as_object() + .expect("field value must be function object"); + let mut field_function_object_borrow = field_function_object.borrow_mut(); + let field_function = field_function_object_borrow + .as_function_mut() + .expect("field value must be function object"); + let class_object = class_value + .as_object() + .expect("class must be function object"); + field_function.set_home_object(class_object.clone()); + class_object + .borrow_mut() + .as_function_mut() + .expect("class must be function object") + .push_field_private( + name, + JsFunction::from_object_unchecked(field_function_object.clone()), + ); + Ok(ShouldExit::False) + } +} \ No newline at end of file diff --git a/boa_engine/src/vm/opcode/push/class/mod.rs b/boa_engine/src/vm/opcode/push/class/mod.rs new file mode 100644 index 00000000000..02aa4f0c7fe --- /dev/null +++ b/boa_engine/src/vm/opcode/push/class/mod.rs @@ -0,0 +1,58 @@ +use crate::{ + builtins::function::{ConstructorKind, Function}, + object::{JsFunction, PrivateElement}, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsValue, +}; + +pub(crate) mod field; +pub(crate) mod private; + +pub(crate) use private::*; +pub(crate) use field::*; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PushClassPrototype; + +impl Operation for PushClassPrototype { + const NAME: &'static str = "PushClassPrototype"; + const INSTRUCTION: &'static str = "INST - PushClassPrototype"; + + fn execute(context: &mut Context) -> JsResult { + let superclass = context.vm.pop(); + + 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"); + } + + let class = context.vm.pop(); + { + let class_object = class.as_object().expect("class must be object"); + class_object.set_prototype(Some(superclass.clone())); + + let mut class_object_mut = class_object.borrow_mut(); + let class_function = class_object_mut + .as_function_mut() + .expect("class must be function object"); + if let Function::Ordinary { + constructor_kind, .. + } = class_function + { + *constructor_kind = ConstructorKind::Derived; + } + } + + context.vm.push(class); + context.vm.push(proto); + Ok(ShouldExit::False) + } else if superclass.is_null() { + context.vm.push(JsValue::Null); + Ok(ShouldExit::False) + } else { + context.throw_type_error("superclass must be a constructor") + } + } +} + diff --git a/boa_engine/src/vm/opcode/push/class/private.rs b/boa_engine/src/vm/opcode/push/class/private.rs new file mode 100644 index 00000000000..13645e4a178 --- /dev/null +++ b/boa_engine/src/vm/opcode/push/class/private.rs @@ -0,0 +1,90 @@ +use crate::{ + builtins::function::{ConstructorKind, Function}, + object::{JsFunction, PrivateElement}, + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsValue, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PushClassPrivateMethod; + +impl Operation for PushClassPrivateMethod { + const NAME: &'static str = "PushClassPrivateMethod"; + const INSTRUCTION: &'static str = "INST - PushClassPrivateMethod"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let name = context.vm.frame().code.names[index as usize]; + let method = context.vm.pop(); + let method_object = method.as_callable().expect("method must be callable"); + let class = context.vm.pop(); + class + .as_object() + .expect("class must be function object") + .borrow_mut() + .as_function_mut() + .expect("class must be function object") + .push_private_method(name, PrivateElement::Method(method_object.clone())); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PushClassPrivateGetter; + +impl Operation for PushClassPrivateGetter { + const NAME: &'static str = "PushClassPrivateGetter"; + const INSTRUCTION: &'static str = "INST - PushClassPrivateGetter"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let name = context.vm.frame().code.names[index as usize]; + let getter = context.vm.pop(); + let getter_object = getter.as_callable().expect("getter must be callable"); + let class = context.vm.pop(); + class + .as_object() + .expect("class must be function object") + .borrow_mut() + .as_function_mut() + .expect("class must be function object") + .push_private_method( + name, + PrivateElement::Accessor { + getter: Some(getter_object.clone()), + setter: None, + }, + ); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct PushClassPrivateSetter; + +impl Operation for PushClassPrivateSetter { + const NAME: &'static str = "PushClassPrivateSetter"; + const INSTRUCTION: &'static str = "INST - PushClassPrivateSetter"; + + fn execute(context: &mut Context) -> JsResult { + let index = context.vm.read::(); + let name = context.vm.frame().code.names[index as usize]; + let setter = context.vm.pop(); + let setter_object = setter.as_callable().expect("getter must be callable"); + let class = context.vm.pop(); + class + .as_object() + .expect("class must be function object") + .borrow_mut() + .as_function_mut() + .expect("class must be function object") + .push_private_method( + name, + PrivateElement::Accessor { + getter: None, + setter: Some(setter_object.clone()), + }, + ); + Ok(ShouldExit::False) + } +} \ No newline at end of file diff --git a/boa_engine/src/vm/opcode/push/numbers.rs b/boa_engine/src/vm/opcode/push/numbers.rs index 1b8724d433d..9db5260a451 100644 --- a/boa_engine/src/vm/opcode/push/numbers.rs +++ b/boa_engine/src/vm/opcode/push/numbers.rs @@ -38,10 +38,9 @@ macro_rules! implement_push_numbers_no_conversion { } }; } -implement_push_numbers_with_conversion!(PushInt8, i8); +implement_push_numbers_with_conversion!(PushInt8, i8); implement_push_numbers_with_conversion!(PushInt16, i16); implement_push_numbers_no_conversion!(PushInt32, i32); - implement_push_numbers_no_conversion!(PushRational, f64); diff --git a/boa_engine/src/vm/opcode/conversion/mod.rs b/boa_engine/src/vm/opcode/to/mod.rs similarity index 100% rename from boa_engine/src/vm/opcode/conversion/mod.rs rename to boa_engine/src/vm/opcode/to/mod.rs diff --git a/boa_engine/src/vm/opcode/general/decrement.rs b/boa_engine/src/vm/opcode/unary_ops/decrement.rs similarity index 100% rename from boa_engine/src/vm/opcode/general/decrement.rs rename to boa_engine/src/vm/opcode/unary_ops/decrement.rs diff --git a/boa_engine/src/vm/opcode/general/increment.rs b/boa_engine/src/vm/opcode/unary_ops/increment.rs similarity index 100% rename from boa_engine/src/vm/opcode/general/increment.rs rename to boa_engine/src/vm/opcode/unary_ops/increment.rs diff --git a/boa_engine/src/vm/opcode/unary_ops/mod.rs b/boa_engine/src/vm/opcode/unary_ops/mod.rs new file mode 100644 index 00000000000..c52fb0ce062 --- /dev/null +++ b/boa_engine/src/vm/opcode/unary_ops/mod.rs @@ -0,0 +1,77 @@ +use crate::{ + builtins::Number, + value::Numeric, + vm::{opcode::Operation, ShouldExit}, + Context, JsBigInt, JsResult, +}; +use std::ops::Neg as StdNeg; + +pub(crate) mod increment; +pub(crate) mod decrement; + +pub(crate) use increment::*; +pub(crate) use decrement::*; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct TypeOf; + +impl Operation for TypeOf { + const NAME: &'static str = "TypeOf"; + const INSTRUCTION: &'static str = "INST - TypeOf"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + context.vm.push(value.type_of()); + Ok(ShouldExit::False) + } +} + + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Pos; + +impl Operation for Pos { + const NAME: &'static str = "Pos"; + const INSTRUCTION: &'static str = "INST - Pos"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + let value = value.to_number(context)?; + context.vm.push(value); + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Neg; + +impl Operation for Neg { + const NAME: &'static str = "Neg"; + const INSTRUCTION: &'static str = "INST - Neg"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + match value.to_numeric(context)? { + Numeric::Number(number) => context.vm.push(number.neg()), + Numeric::BigInt(bigint) => context.vm.push(JsBigInt::neg(&bigint)), + } + Ok(ShouldExit::False) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct BitNot; + +impl Operation for BitNot { + const NAME: &'static str = "BitNot"; + const INSTRUCTION: &'static str = "INST - BitNot"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + match value.to_numeric(context)? { + Numeric::Number(number) => context.vm.push(Number::not(number)), + Numeric::BigInt(bigint) => context.vm.push(JsBigInt::not(&bigint)), + } + Ok(ShouldExit::False) + } +} \ No newline at end of file diff --git a/boa_engine/src/vm/opcode/void/mod.rs b/boa_engine/src/vm/opcode/void/mod.rs new file mode 100644 index 00000000000..6e737a06bae --- /dev/null +++ b/boa_engine/src/vm/opcode/void/mod.rs @@ -0,0 +1,18 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, JsValue, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Void; + +impl Operation for Void { + const NAME: &'static str = "Void"; + const INSTRUCTION: &'static str = "INST - Void"; + + fn execute(context: &mut Context) -> JsResult { + let _old = context.vm.pop(); + context.vm.push(JsValue::undefined()); + Ok(ShouldExit::False) + } +} \ No newline at end of file From 8cb8146936ad06b527fdd3451fdd62f2f61b3e9b Mon Sep 17 00:00:00 2001 From: nekevss Date: Fri, 14 Oct 2022 09:46:06 -0400 Subject: [PATCH 07/12] Rustfmt and clippy fixes --- boa_engine/src/vm/opcode/binary_ops/mod.rs | 8 +++----- .../src/vm/opcode/define/class/getter.rs | 1 - .../src/vm/opcode/define/class/method.rs | 1 - boa_engine/src/vm/opcode/define/class/mod.rs | 7 +++---- .../src/vm/opcode/define/class/setter.rs | 2 +- .../src/vm/opcode/generator/yield_stm.rs | 3 +-- .../src/vm/opcode/iteration/loop_ops.rs | 2 +- boa_engine/src/vm/opcode/iteration/mod.rs | 3 --- boa_engine/src/vm/opcode/mod.rs | 20 +++++++++---------- boa_engine/src/vm/opcode/nop/mod.rs | 4 ++-- boa_engine/src/vm/opcode/push/class/field.rs | 7 +++---- boa_engine/src/vm/opcode/push/class/mod.rs | 4 +--- .../src/vm/opcode/push/class/private.rs | 7 +++---- boa_engine/src/vm/opcode/unary_ops/mod.rs | 9 ++++----- boa_engine/src/vm/opcode/void/mod.rs | 2 +- 15 files changed, 33 insertions(+), 47 deletions(-) diff --git a/boa_engine/src/vm/opcode/binary_ops/mod.rs b/boa_engine/src/vm/opcode/binary_ops/mod.rs index 507aa0244fc..181b3e9c55b 100644 --- a/boa_engine/src/vm/opcode/binary_ops/mod.rs +++ b/boa_engine/src/vm/opcode/binary_ops/mod.rs @@ -1,14 +1,13 @@ use crate::{ vm::{opcode::Operation, ShouldExit}, - Context, JsResult, JsValue, + Context, JsResult, }; -pub(crate) mod macro_defined; pub(crate) mod logical; +pub(crate) mod macro_defined; -pub(crate) use macro_defined::*; pub(crate) use logical::*; - +pub(crate) use macro_defined::*; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct NotEq; @@ -96,4 +95,3 @@ impl Operation for InstanceOf { Ok(ShouldExit::False) } } - diff --git a/boa_engine/src/vm/opcode/define/class/getter.rs b/boa_engine/src/vm/opcode/define/class/getter.rs index 786b4fdf127..745f3efc5ff 100644 --- a/boa_engine/src/vm/opcode/define/class/getter.rs +++ b/boa_engine/src/vm/opcode/define/class/getter.rs @@ -86,4 +86,3 @@ impl Operation for DefineClassGetterByValue { Ok(ShouldExit::False) } } - diff --git a/boa_engine/src/vm/opcode/define/class/method.rs b/boa_engine/src/vm/opcode/define/class/method.rs index c2ca26d991b..dd64efbbf0f 100644 --- a/boa_engine/src/vm/opcode/define/class/method.rs +++ b/boa_engine/src/vm/opcode/define/class/method.rs @@ -80,4 +80,3 @@ impl Operation for DefineClassMethodByValue { Ok(ShouldExit::False) } } - diff --git a/boa_engine/src/vm/opcode/define/class/mod.rs b/boa_engine/src/vm/opcode/define/class/mod.rs index c1affb1e2e3..7d461feee0d 100644 --- a/boa_engine/src/vm/opcode/define/class/mod.rs +++ b/boa_engine/src/vm/opcode/define/class/mod.rs @@ -1,8 +1,7 @@ - -pub(crate) mod method; pub(crate) mod getter; +pub(crate) mod method; pub(crate) mod setter; -pub(crate) use method::*; pub(crate) use getter::*; -pub(crate) use setter::*; \ No newline at end of file +pub(crate) use method::*; +pub(crate) use setter::*; diff --git a/boa_engine/src/vm/opcode/define/class/setter.rs b/boa_engine/src/vm/opcode/define/class/setter.rs index 5f00333c9bc..9db6d4040b0 100644 --- a/boa_engine/src/vm/opcode/define/class/setter.rs +++ b/boa_engine/src/vm/opcode/define/class/setter.rs @@ -85,4 +85,4 @@ impl Operation for DefineClassSetterByValue { )?; Ok(ShouldExit::False) } -} \ No newline at end of file +} diff --git a/boa_engine/src/vm/opcode/generator/yield_stm.rs b/boa_engine/src/vm/opcode/generator/yield_stm.rs index d60fc3854e7..10680b3aa2b 100644 --- a/boa_engine/src/vm/opcode/generator/yield_stm.rs +++ b/boa_engine/src/vm/opcode/generator/yield_stm.rs @@ -1,6 +1,6 @@ use crate::{ vm::{opcode::Operation, ShouldExit}, - Context, JsResult + Context, JsResult, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -14,4 +14,3 @@ impl Operation for Yield { Ok(ShouldExit::Yield) } } - diff --git a/boa_engine/src/vm/opcode/iteration/loop_ops.rs b/boa_engine/src/vm/opcode/iteration/loop_ops.rs index c88d9d0da44..f6600afdedd 100644 --- a/boa_engine/src/vm/opcode/iteration/loop_ops.rs +++ b/boa_engine/src/vm/opcode/iteration/loop_ops.rs @@ -61,4 +61,4 @@ impl Operation for LoopEnd { context.vm.frame_mut().try_env_stack_loop_dec(); Ok(ShouldExit::False) } -} \ No newline at end of file +} diff --git a/boa_engine/src/vm/opcode/iteration/mod.rs b/boa_engine/src/vm/opcode/iteration/mod.rs index c9a04731e0d..5e52baa2bd9 100644 --- a/boa_engine/src/vm/opcode/iteration/mod.rs +++ b/boa_engine/src/vm/opcode/iteration/mod.rs @@ -1,5 +1,3 @@ - - pub(crate) mod for_await; pub(crate) mod for_in; pub(crate) mod init; @@ -11,4 +9,3 @@ pub(crate) use for_in::*; pub(crate) use init::*; pub(crate) use iterator::*; pub(crate) use loop_ops::*; - diff --git a/boa_engine/src/vm/opcode/mod.rs b/boa_engine/src/vm/opcode/mod.rs index 12d8acfa6ae..62fb43f8a48 100644 --- a/boa_engine/src/vm/opcode/mod.rs +++ b/boa_engine/src/vm/opcode/mod.rs @@ -3,9 +3,9 @@ use crate::{vm::ShouldExit, Context, JsResult}; // Operation modules pub(crate) mod await_stm; +pub(crate) mod binary_ops; pub(crate) mod call; pub(crate) mod concat; -pub(crate) mod to; pub(crate) mod copy; pub(crate) mod define; pub(crate) mod delete; @@ -14,7 +14,9 @@ pub(crate) mod environment; pub(crate) mod generator; pub(crate) mod get; pub(crate) mod iteration; +pub(crate) mod jump; pub(crate) mod new; +pub(crate) mod nop; pub(crate) mod pop; pub(crate) mod promise; pub(crate) mod push; @@ -25,19 +27,17 @@ pub(crate) mod set; pub(crate) mod swap; pub(crate) mod switch; pub(crate) mod throw; +pub(crate) mod to; pub(crate) mod try_catch; -pub(crate) mod value; -pub(crate) mod jump; -pub(crate) mod binary_ops; pub(crate) mod unary_ops; -pub(crate) mod nop; +pub(crate) mod value; pub(crate) mod void; // Operation structs pub(crate) use await_stm::*; +pub(crate) use binary_ops::*; pub(crate) use call::*; pub(crate) use concat::*; -pub(crate) use to::*; pub(crate) use copy::*; pub(crate) use define::*; pub(crate) use delete::*; @@ -46,7 +46,9 @@ pub(crate) use environment::*; pub(crate) use generator::*; pub(crate) use get::*; pub(crate) use iteration::*; +pub(crate) use jump::*; pub(crate) use new::*; +pub(crate) use nop::*; pub(crate) use pop::*; pub(crate) use promise::*; pub(crate) use push::*; @@ -57,12 +59,10 @@ pub(crate) use set::*; pub(crate) use swap::*; pub(crate) use switch::*; pub(crate) use throw::*; +pub(crate) use to::*; pub(crate) use try_catch::*; -pub(crate) use value::*; -pub(crate) use jump::*; -pub(crate) use binary_ops::*; pub(crate) use unary_ops::*; -pub(crate) use nop::*; +pub(crate) use value::*; pub(crate) use void::*; pub(crate) trait Operation { diff --git a/boa_engine/src/vm/opcode/nop/mod.rs b/boa_engine/src/vm/opcode/nop/mod.rs index e2f4c420c74..9bd30dc4938 100644 --- a/boa_engine/src/vm/opcode/nop/mod.rs +++ b/boa_engine/src/vm/opcode/nop/mod.rs @@ -1,6 +1,6 @@ use crate::{ vm::{opcode::Operation, ShouldExit}, - Context, JsResult, JsValue, + Context, JsResult, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -13,4 +13,4 @@ impl Operation for Nop { fn execute(_context: &mut Context) -> JsResult { Ok(ShouldExit::False) } -} \ No newline at end of file +} diff --git a/boa_engine/src/vm/opcode/push/class/field.rs b/boa_engine/src/vm/opcode/push/class/field.rs index 63329cafb0d..7e371dab06d 100644 --- a/boa_engine/src/vm/opcode/push/class/field.rs +++ b/boa_engine/src/vm/opcode/push/class/field.rs @@ -1,8 +1,7 @@ use crate::{ - builtins::function::{ConstructorKind, Function}, - object::{JsFunction, PrivateElement}, + object::JsFunction, vm::{opcode::Operation, ShouldExit}, - Context, JsResult, JsValue, + Context, JsResult, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -75,4 +74,4 @@ impl Operation for PushClassFieldPrivate { ); Ok(ShouldExit::False) } -} \ No newline at end of file +} diff --git a/boa_engine/src/vm/opcode/push/class/mod.rs b/boa_engine/src/vm/opcode/push/class/mod.rs index 02aa4f0c7fe..b790660095e 100644 --- a/boa_engine/src/vm/opcode/push/class/mod.rs +++ b/boa_engine/src/vm/opcode/push/class/mod.rs @@ -1,6 +1,5 @@ use crate::{ builtins::function::{ConstructorKind, Function}, - object::{JsFunction, PrivateElement}, vm::{opcode::Operation, ShouldExit}, Context, JsResult, JsValue, }; @@ -8,8 +7,8 @@ use crate::{ pub(crate) mod field; pub(crate) mod private; -pub(crate) use private::*; pub(crate) use field::*; +pub(crate) use private::*; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct PushClassPrototype; @@ -55,4 +54,3 @@ impl Operation for PushClassPrototype { } } } - diff --git a/boa_engine/src/vm/opcode/push/class/private.rs b/boa_engine/src/vm/opcode/push/class/private.rs index 13645e4a178..5e574157344 100644 --- a/boa_engine/src/vm/opcode/push/class/private.rs +++ b/boa_engine/src/vm/opcode/push/class/private.rs @@ -1,8 +1,7 @@ use crate::{ - builtins::function::{ConstructorKind, Function}, - object::{JsFunction, PrivateElement}, + object::PrivateElement, vm::{opcode::Operation, ShouldExit}, - Context, JsResult, JsValue, + Context, JsResult, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -87,4 +86,4 @@ impl Operation for PushClassPrivateSetter { ); Ok(ShouldExit::False) } -} \ No newline at end of file +} diff --git a/boa_engine/src/vm/opcode/unary_ops/mod.rs b/boa_engine/src/vm/opcode/unary_ops/mod.rs index c52fb0ce062..186bd6fa45e 100644 --- a/boa_engine/src/vm/opcode/unary_ops/mod.rs +++ b/boa_engine/src/vm/opcode/unary_ops/mod.rs @@ -2,15 +2,15 @@ use crate::{ builtins::Number, value::Numeric, vm::{opcode::Operation, ShouldExit}, - Context, JsBigInt, JsResult, + Context, JsBigInt, JsResult, }; use std::ops::Neg as StdNeg; -pub(crate) mod increment; pub(crate) mod decrement; +pub(crate) mod increment; -pub(crate) use increment::*; pub(crate) use decrement::*; +pub(crate) use increment::*; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct TypeOf; @@ -26,7 +26,6 @@ impl Operation for TypeOf { } } - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct Pos; @@ -74,4 +73,4 @@ impl Operation for BitNot { } Ok(ShouldExit::False) } -} \ No newline at end of file +} diff --git a/boa_engine/src/vm/opcode/void/mod.rs b/boa_engine/src/vm/opcode/void/mod.rs index 6e737a06bae..2f305e35be9 100644 --- a/boa_engine/src/vm/opcode/void/mod.rs +++ b/boa_engine/src/vm/opcode/void/mod.rs @@ -15,4 +15,4 @@ impl Operation for Void { context.vm.push(JsValue::undefined()); Ok(ShouldExit::False) } -} \ No newline at end of file +} From fdbfe73a6e716e6b891fce06359dedd781ae1e8c Mon Sep 17 00:00:00 2001 From: nekevss Date: Tue, 18 Oct 2022 22:22:02 -0400 Subject: [PATCH 08/12] Fixes after rebase --- boa_engine/src/vm/opcode/define/class/getter.rs | 2 +- boa_engine/src/vm/opcode/define/class/method.rs | 2 +- boa_engine/src/vm/opcode/define/class/setter.rs | 2 +- boa_engine/src/vm/opcode/define/mod.rs | 4 ++-- boa_engine/src/vm/opcode/define/own_property.rs | 2 +- boa_engine/src/vm/opcode/delete/mod.rs | 2 +- boa_engine/src/vm/opcode/get/name.rs | 6 +++--- boa_engine/src/vm/opcode/get/private.rs | 2 +- boa_engine/src/vm/opcode/get/property.rs | 2 +- boa_engine/src/vm/opcode/push/class/field.rs | 2 +- boa_engine/src/vm/opcode/push/class/private.rs | 6 +++--- boa_engine/src/vm/opcode/set/name.rs | 4 ++-- boa_engine/src/vm/opcode/set/private.rs | 14 +++++++------- boa_engine/src/vm/opcode/set/property.rs | 6 +++--- 14 files changed, 28 insertions(+), 28 deletions(-) diff --git a/boa_engine/src/vm/opcode/define/class/getter.rs b/boa_engine/src/vm/opcode/define/class/getter.rs index 745f3efc5ff..16f76cbd115 100644 --- a/boa_engine/src/vm/opcode/define/class/getter.rs +++ b/boa_engine/src/vm/opcode/define/class/getter.rs @@ -26,7 +26,7 @@ impl Operation for DefineClassGetterByName { let name = context.vm.frame().code.names[index as usize]; let name = context .interner() - .resolve_expect(name) + .resolve_expect(name.sym()) .into_common::(false) .into(); let set = object diff --git a/boa_engine/src/vm/opcode/define/class/method.rs b/boa_engine/src/vm/opcode/define/class/method.rs index dd64efbbf0f..f9ca7ca57fb 100644 --- a/boa_engine/src/vm/opcode/define/class/method.rs +++ b/boa_engine/src/vm/opcode/define/class/method.rs @@ -28,7 +28,7 @@ impl Operation for DefineClassMethodByName { .expect("method must be function object") .set_home_object(object.clone()); let name = context.vm.frame().code.names[index as usize]; - let name = context.interner().resolve_expect(name); + let name = context.interner().resolve_expect(name.sym()); object.__define_own_property__( name.into_common::(false).into(), PropertyDescriptor::builder() diff --git a/boa_engine/src/vm/opcode/define/class/setter.rs b/boa_engine/src/vm/opcode/define/class/setter.rs index 9db6d4040b0..f9765f39cd2 100644 --- a/boa_engine/src/vm/opcode/define/class/setter.rs +++ b/boa_engine/src/vm/opcode/define/class/setter.rs @@ -26,7 +26,7 @@ impl Operation for DefineClassSetterByName { let name = context.vm.frame().code.names[index as usize]; let name = context .interner() - .resolve_expect(name) + .resolve_expect(name.sym()) .into_common::(false) .into(); let get = object diff --git a/boa_engine/src/vm/opcode/define/mod.rs b/boa_engine/src/vm/opcode/define/mod.rs index 1532f0e84f7..1174f9fcfa1 100644 --- a/boa_engine/src/vm/opcode/define/mod.rs +++ b/boa_engine/src/vm/opcode/define/mod.rs @@ -24,7 +24,7 @@ impl Operation for DefVar { if binding_locator.is_global() { let key = context .interner() - .resolve_expect(binding_locator.name()) + .resolve_expect(binding_locator.name().sym()) .into_common(false); context.global_bindings_mut().entry(key).or_insert( PropertyDescriptor::builder() @@ -61,7 +61,7 @@ impl Operation for DefInitVar { if binding_locator.is_global() { let key = context .interner() - .resolve_expect(binding_locator.name()) + .resolve_expect(binding_locator.name().sym()) .into_common::(false) .into(); crate::object::internal_methods::global::global_set_no_receiver(&key, value, context)?; diff --git a/boa_engine/src/vm/opcode/define/own_property.rs b/boa_engine/src/vm/opcode/define/own_property.rs index cf9a7e92753..c0f0962d9d8 100644 --- a/boa_engine/src/vm/opcode/define/own_property.rs +++ b/boa_engine/src/vm/opcode/define/own_property.rs @@ -23,7 +23,7 @@ impl Operation for DefineOwnPropertyByName { let name = context.vm.frame().code.names[index as usize]; let name = context .interner() - .resolve_expect(name) + .resolve_expect(name.sym()) .into_common::(false); object.__define_own_property__( name.into(), diff --git a/boa_engine/src/vm/opcode/delete/mod.rs b/boa_engine/src/vm/opcode/delete/mod.rs index 516a6ef0348..267d362c235 100644 --- a/boa_engine/src/vm/opcode/delete/mod.rs +++ b/boa_engine/src/vm/opcode/delete/mod.rs @@ -15,7 +15,7 @@ impl Operation for DeletePropertyByName { let key = context.vm.frame().code.names[index as usize]; let key = context .interner() - .resolve_expect(key) + .resolve_expect(key.sym()) .into_common::(false) .into(); let object = context.vm.pop(); diff --git a/boa_engine/src/vm/opcode/get/name.rs b/boa_engine/src/vm/opcode/get/name.rs index ba5f9039724..86f326edf73 100644 --- a/boa_engine/src/vm/opcode/get/name.rs +++ b/boa_engine/src/vm/opcode/get/name.rs @@ -26,7 +26,7 @@ impl Operation for GetName { } else { let key: JsString = context .interner() - .resolve_expect(binding_locator.name()) + .resolve_expect(binding_locator.name().sym()) .into_common(false); match context.global_bindings_mut().get(&key) { Some(desc) => match desc.kind() { @@ -61,7 +61,7 @@ impl Operation for GetName { } else { let name = context .interner() - .resolve_expect(binding_locator.name()) + .resolve_expect(binding_locator.name().sym()) .to_string(); return context.throw_reference_error(format!("{name} is not initialized")); }; @@ -92,7 +92,7 @@ impl Operation for GetNameOrUndefined { } else { let key: JsString = context .interner() - .resolve_expect(binding_locator.name()) + .resolve_expect(binding_locator.name().sym()) .into_common(false); match context.global_bindings_mut().get(&key) { Some(desc) => match desc.kind() { diff --git a/boa_engine/src/vm/opcode/get/private.rs b/boa_engine/src/vm/opcode/get/private.rs index 7c87f4878ee..b5a10e865f6 100644 --- a/boa_engine/src/vm/opcode/get/private.rs +++ b/boa_engine/src/vm/opcode/get/private.rs @@ -17,7 +17,7 @@ impl Operation for GetPrivateField { let value = context.vm.pop(); if let Some(object) = value.as_object() { let object_borrow_mut = object.borrow(); - if let Some(element) = object_borrow_mut.get_private_element(name) { + if let Some(element) = object_borrow_mut.get_private_element(name.sym()) { match element { PrivateElement::Field(value) => context.vm.push(value), PrivateElement::Method(method) => context.vm.push(method.clone()), diff --git a/boa_engine/src/vm/opcode/get/property.rs b/boa_engine/src/vm/opcode/get/property.rs index 6da99de02ff..a7e1eedce40 100644 --- a/boa_engine/src/vm/opcode/get/property.rs +++ b/boa_engine/src/vm/opcode/get/property.rs @@ -24,7 +24,7 @@ impl Operation for GetPropertyByName { let name = context.vm.frame().code.names[index as usize]; let name: PropertyKey = context .interner() - .resolve_expect(name) + .resolve_expect(name.sym()) .into_common::(false) .into(); let result = object.get(name, context)?; diff --git a/boa_engine/src/vm/opcode/push/class/field.rs b/boa_engine/src/vm/opcode/push/class/field.rs index 7e371dab06d..1c9b87fdda6 100644 --- a/boa_engine/src/vm/opcode/push/class/field.rs +++ b/boa_engine/src/vm/opcode/push/class/field.rs @@ -69,7 +69,7 @@ impl Operation for PushClassFieldPrivate { .as_function_mut() .expect("class must be function object") .push_field_private( - name, + name.sym(), JsFunction::from_object_unchecked(field_function_object.clone()), ); Ok(ShouldExit::False) diff --git a/boa_engine/src/vm/opcode/push/class/private.rs b/boa_engine/src/vm/opcode/push/class/private.rs index 5e574157344..49cd4cacc46 100644 --- a/boa_engine/src/vm/opcode/push/class/private.rs +++ b/boa_engine/src/vm/opcode/push/class/private.rs @@ -23,7 +23,7 @@ impl Operation for PushClassPrivateMethod { .borrow_mut() .as_function_mut() .expect("class must be function object") - .push_private_method(name, PrivateElement::Method(method_object.clone())); + .push_private_method(name.sym(), PrivateElement::Method(method_object.clone())); Ok(ShouldExit::False) } } @@ -48,7 +48,7 @@ impl Operation for PushClassPrivateGetter { .as_function_mut() .expect("class must be function object") .push_private_method( - name, + name.sym(), PrivateElement::Accessor { getter: Some(getter_object.clone()), setter: None, @@ -78,7 +78,7 @@ impl Operation for PushClassPrivateSetter { .as_function_mut() .expect("class must be function object") .push_private_method( - name, + name.sym(), PrivateElement::Accessor { getter: None, setter: Some(setter_object.clone()), diff --git a/boa_engine/src/vm/opcode/set/name.rs b/boa_engine/src/vm/opcode/set/name.rs index 7a3aac61b2f..80402425083 100644 --- a/boa_engine/src/vm/opcode/set/name.rs +++ b/boa_engine/src/vm/opcode/set/name.rs @@ -24,7 +24,7 @@ impl Operation for SetName { { let key: JsString = context .interner() - .resolve_expect(binding_locator.name()) + .resolve_expect(binding_locator.name().sym()) .into_common(false); let exists = context.global_bindings_mut().contains_key(&key); @@ -56,7 +56,7 @@ impl Operation for SetName { ) { context.throw_reference_error(format!( "cannot access '{}' before initialization", - context.interner().resolve_expect(binding_locator.name()) + context.interner().resolve_expect(binding_locator.name().sym()) ))?; } Ok(ShouldExit::False) diff --git a/boa_engine/src/vm/opcode/set/private.rs b/boa_engine/src/vm/opcode/set/private.rs index 910edc24555..e4aefb9f03b 100644 --- a/boa_engine/src/vm/opcode/set/private.rs +++ b/boa_engine/src/vm/opcode/set/private.rs @@ -18,9 +18,9 @@ impl Operation for AssignPrivateField { let object = context.vm.pop(); if let Some(object) = object.as_object() { let mut object_borrow_mut = object.borrow_mut(); - match object_borrow_mut.get_private_element(name) { + match object_borrow_mut.get_private_element(name.sym()) { Some(PrivateElement::Field(_)) => { - object_borrow_mut.set_private_element(name, PrivateElement::Field(value)); + object_borrow_mut.set_private_element(name.sym(), PrivateElement::Field(value)); } Some(PrivateElement::Method(_)) => { return context.throw_type_error("private method is not writable"); @@ -64,13 +64,13 @@ impl Operation for SetPrivateField { if let Some(PrivateElement::Accessor { getter: _, setter: Some(setter), - }) = object_borrow_mut.get_private_element(name) + }) = object_borrow_mut.get_private_element(name.sym()) { let setter = setter.clone(); drop(object_borrow_mut); setter.call(&object.clone().into(), &[value], context)?; } else { - object_borrow_mut.set_private_element(name, PrivateElement::Field(value)); + object_borrow_mut.set_private_element(name.sym(), PrivateElement::Field(value)); } } else { return context.throw_type_error("cannot set private property on non-object"); @@ -94,7 +94,7 @@ impl Operation for SetPrivateMethod { let object = context.vm.pop(); if let Some(object) = object.as_object() { let mut object_borrow_mut = object.borrow_mut(); - object_borrow_mut.set_private_element(name, PrivateElement::Method(value.clone())); + 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"); } @@ -117,7 +117,7 @@ impl Operation for SetPrivateSetter { let object = context.vm.pop(); if let Some(object) = object.as_object() { let mut object_borrow_mut = object.borrow_mut(); - object_borrow_mut.set_private_element_setter(name, value.clone()); + object_borrow_mut.set_private_element_setter(name.sym(), value.clone()); } else { return context.throw_type_error("cannot set private setter on non-object"); } @@ -140,7 +140,7 @@ impl Operation for SetPrivateGetter { let object = context.vm.pop(); if let Some(object) = object.as_object() { let mut object_borrow_mut = object.borrow_mut(); - object_borrow_mut.set_private_element_getter(name, value.clone()); + object_borrow_mut.set_private_element_getter(name.sym(), value.clone()); } else { return context.throw_type_error("cannot set private getter on non-object"); } diff --git a/boa_engine/src/vm/opcode/set/property.rs b/boa_engine/src/vm/opcode/set/property.rs index d90b3956270..97c043a030a 100644 --- a/boa_engine/src/vm/opcode/set/property.rs +++ b/boa_engine/src/vm/opcode/set/property.rs @@ -25,7 +25,7 @@ impl Operation for SetPropertyByName { let name = context.vm.frame().code.names[index as usize]; let name: PropertyKey = context .interner() - .resolve_expect(name) + .resolve_expect(name.sym()) .into_common::(false) .into(); @@ -72,7 +72,7 @@ impl Operation for SetPropertyGetterByName { let name = context.vm.frame().code.names[index as usize]; let name = context .interner() - .resolve_expect(name) + .resolve_expect(name.sym()) .into_common::(false) .into(); let set = object @@ -141,7 +141,7 @@ impl Operation for SetPropertySetterByName { let name = context.vm.frame().code.names[index as usize]; let name = context .interner() - .resolve_expect(name) + .resolve_expect(name.sym()) .into_common::(false) .into(); let get = object From 0243ca2c50be23d697bfd8ded9282f0046952122 Mon Sep 17 00:00:00 2001 From: nekevss Date: Tue, 18 Oct 2022 22:26:41 -0400 Subject: [PATCH 09/12] rustfmt --- boa_engine/src/vm/opcode/set/name.rs | 4 +++- boa_engine/src/vm/opcode/set/private.rs | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/boa_engine/src/vm/opcode/set/name.rs b/boa_engine/src/vm/opcode/set/name.rs index 80402425083..25accacc4ad 100644 --- a/boa_engine/src/vm/opcode/set/name.rs +++ b/boa_engine/src/vm/opcode/set/name.rs @@ -56,7 +56,9 @@ impl Operation for SetName { ) { context.throw_reference_error(format!( "cannot access '{}' before initialization", - context.interner().resolve_expect(binding_locator.name().sym()) + context + .interner() + .resolve_expect(binding_locator.name().sym()) ))?; } Ok(ShouldExit::False) diff --git a/boa_engine/src/vm/opcode/set/private.rs b/boa_engine/src/vm/opcode/set/private.rs index e4aefb9f03b..22c3241903d 100644 --- a/boa_engine/src/vm/opcode/set/private.rs +++ b/boa_engine/src/vm/opcode/set/private.rs @@ -94,7 +94,8 @@ impl Operation for SetPrivateMethod { let object = context.vm.pop(); if let Some(object) = object.as_object() { let mut object_borrow_mut = object.borrow_mut(); - object_borrow_mut.set_private_element(name.sym(), PrivateElement::Method(value.clone())); + 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"); } From a1647d8b7e7df83b38c8080a1e7750bb3e9c754b Mon Sep 17 00:00:00 2001 From: nekevss Date: Wed, 19 Oct 2022 20:03:35 -0400 Subject: [PATCH 10/12] 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) From df87f56677b5dedc627f714924d0e356e7d59556 Mon Sep 17 00:00:00 2001 From: nekevss Date: Fri, 21 Oct 2022 16:28:32 -0400 Subject: [PATCH 11/12] Review updates - private mods and initial doc buildout --- boa_engine/src/vm/opcode/await_stm/mod.rs | 4 + .../src/vm/opcode/binary_ops/logical.rs | 26 +++-- .../src/vm/opcode/binary_ops/macro_defined.rs | 40 ++++---- boa_engine/src/vm/opcode/binary_ops/mod.rs | 20 ++++ boa_engine/src/vm/opcode/call/mod.rs | 12 +++ boa_engine/src/vm/opcode/concat/mod.rs | 4 + boa_engine/src/vm/opcode/copy/mod.rs | 4 + .../src/vm/opcode/define/class/getter.rs | 8 ++ .../src/vm/opcode/define/class/method.rs | 8 ++ .../src/vm/opcode/define/class/setter.rs | 8 ++ boa_engine/src/vm/opcode/define/mod.rs | 24 ++++- .../src/vm/opcode/define/own_property.rs | 8 ++ boa_engine/src/vm/opcode/delete/mod.rs | 8 ++ boa_engine/src/vm/opcode/dup/mod.rs | 4 + boa_engine/src/vm/opcode/environment/mod.rs | 20 ++++ boa_engine/src/vm/opcode/generator/mod.rs | 13 +++ .../src/vm/opcode/generator/yield_stm.rs | 4 + boa_engine/src/vm/opcode/get/function.rs | 8 ++ boa_engine/src/vm/opcode/get/generator.rs | 8 ++ boa_engine/src/vm/opcode/get/name.rs | 8 ++ boa_engine/src/vm/opcode/get/private.rs | 4 + boa_engine/src/vm/opcode/get/property.rs | 12 +++ .../src/vm/opcode/iteration/for_await.rs | 8 ++ boa_engine/src/vm/opcode/iteration/for_in.rs | 8 ++ boa_engine/src/vm/opcode/iteration/init.rs | 8 ++ .../src/vm/opcode/iteration/iterator.rs | 12 +++ .../src/vm/opcode/iteration/loop_ops.rs | 12 +++ boa_engine/src/vm/opcode/jump/mod.rs | 12 +++ boa_engine/src/vm/opcode/mod.rs | 96 +++++++++++++------ boa_engine/src/vm/opcode/new/mod.rs | 8 ++ boa_engine/src/vm/opcode/nop/mod.rs | 4 + boa_engine/src/vm/opcode/pop/mod.rs | 20 ++++ boa_engine/src/vm/opcode/promise/mod.rs | 12 +++ boa_engine/src/vm/opcode/push/array.rs | 16 ++++ boa_engine/src/vm/opcode/push/class/field.rs | 8 ++ boa_engine/src/vm/opcode/push/class/mod.rs | 4 + .../src/vm/opcode/push/class/private.rs | 12 +++ boa_engine/src/vm/opcode/push/environment.rs | 8 ++ boa_engine/src/vm/opcode/push/literal.rs | 4 + boa_engine/src/vm/opcode/push/mod.rs | 40 ++++++-- boa_engine/src/vm/opcode/push/new_target.rs | 4 + boa_engine/src/vm/opcode/push/numbers.rs | 20 ++-- boa_engine/src/vm/opcode/push/object.rs | 4 + boa_engine/src/vm/opcode/require/mod.rs | 4 + .../src/vm/opcode/rest_parameter/mod.rs | 8 ++ boa_engine/src/vm/opcode/return_stm/mod.rs | 4 + .../src/vm/opcode/set/class_prototype.rs | 4 + boa_engine/src/vm/opcode/set/home_object.rs | 4 + boa_engine/src/vm/opcode/set/name.rs | 4 + boa_engine/src/vm/opcode/set/private.rs | 20 ++++ boa_engine/src/vm/opcode/set/property.rs | 24 +++++ boa_engine/src/vm/opcode/swap/mod.rs | 4 + boa_engine/src/vm/opcode/switch/mod.rs | 9 ++ boa_engine/src/vm/opcode/throw/mod.rs | 4 + boa_engine/src/vm/opcode/to/mod.rs | 8 ++ boa_engine/src/vm/opcode/try_catch/mod.rs | 20 ++++ .../src/vm/opcode/unary_ops/decrement.rs | 8 ++ .../src/vm/opcode/unary_ops/increment.rs | 8 ++ boa_engine/src/vm/opcode/unary_ops/logical.rs | 22 +++++ boa_engine/src/vm/opcode/unary_ops/mod.rs | 20 ++++ .../opcode/{void/mod.rs => unary_ops/void.rs} | 4 + boa_engine/src/vm/opcode/value/mod.rs | 4 + 62 files changed, 675 insertions(+), 83 deletions(-) create mode 100644 boa_engine/src/vm/opcode/unary_ops/logical.rs rename boa_engine/src/vm/opcode/{void/mod.rs => unary_ops/void.rs} (80%) diff --git a/boa_engine/src/vm/opcode/await_stm/mod.rs b/boa_engine/src/vm/opcode/await_stm/mod.rs index 68709626b42..fa5b2fd215a 100644 --- a/boa_engine/src/vm/opcode/await_stm/mod.rs +++ b/boa_engine/src/vm/opcode/await_stm/mod.rs @@ -5,6 +5,10 @@ use crate::{ Context, JsResult, JsValue, }; +/// `Await` implements the Opcode Operation for `Opcode::Await` +/// +/// Operation: +/// - Stops the current Async function and schedules it to resume later. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct Await; diff --git a/boa_engine/src/vm/opcode/binary_ops/logical.rs b/boa_engine/src/vm/opcode/binary_ops/logical.rs index 7654c1ffcd8..e498821dfed 100644 --- a/boa_engine/src/vm/opcode/binary_ops/logical.rs +++ b/boa_engine/src/vm/opcode/binary_ops/logical.rs @@ -3,20 +3,10 @@ use crate::{ Context, JsResult, }; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct LogicalNot; - -impl Operation for LogicalNot { - const NAME: &'static str = "LogicalNot"; - const INSTRUCTION: &'static str = "INST - LogicalNot"; - - fn execute(context: &mut Context) -> JsResult { - let value = context.vm.pop(); - context.vm.push(!value.to_boolean()); - Ok(ShouldExit::False) - } -} - +/// `LogicalAnd` implements the Opcode Operation for `Opcode::LogicalAnd` +/// +/// Operation: +/// - Binary logical `&&` operation #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct LogicalAnd; @@ -35,6 +25,10 @@ impl Operation for LogicalAnd { } } +/// `LogicalOr` implements the Opcode Operation for `Opcode::LogicalOr` +/// +/// Operation: +/// - Binary logical `||` operation #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct LogicalOr; @@ -53,6 +47,10 @@ impl Operation for LogicalOr { } } +/// `Coalesce` implements the Opcode Operation for `Opcode::Coalesce` +/// +/// Operation: +/// - Binary logical `||` operation #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct Coalesce; diff --git a/boa_engine/src/vm/opcode/binary_ops/macro_defined.rs b/boa_engine/src/vm/opcode/binary_ops/macro_defined.rs index 58cd11514fe..20fd7baf195 100644 --- a/boa_engine/src/vm/opcode/binary_ops/macro_defined.rs +++ b/boa_engine/src/vm/opcode/binary_ops/macro_defined.rs @@ -4,7 +4,11 @@ use crate::{ }; macro_rules! implement_bin_ops { - ($name:ident, $op:ident) => { + ($name:ident, $op:ident, $doc_string:literal) => { + #[doc= concat!("`", stringify!($name), "` implements the OpCode Operation for `Opcode::", stringify!($name), "`\n")] + #[doc= "\n"] + #[doc="Operation:\n"] + #[doc= concat!(" - ", $doc_string)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct $name; @@ -23,20 +27,20 @@ macro_rules! implement_bin_ops { }; } -implement_bin_ops!(Add, add); -implement_bin_ops!(Sub, sub); -implement_bin_ops!(Mul, mul); -implement_bin_ops!(Div, div); -implement_bin_ops!(Pow, pow); -implement_bin_ops!(Mod, rem); -implement_bin_ops!(BitAnd, bitand); -implement_bin_ops!(BitOr, bitor); -implement_bin_ops!(BitXor, bitxor); -implement_bin_ops!(ShiftLeft, shl); -implement_bin_ops!(ShiftRight, shr); -implement_bin_ops!(UnsignedShiftRight, ushr); -implement_bin_ops!(Eq, equals); -implement_bin_ops!(GreaterThan, gt); -implement_bin_ops!(GreaterThanOrEq, ge); -implement_bin_ops!(LessThan, lt); -implement_bin_ops!(LessThanOrEq, le); +implement_bin_ops!(Add, add, "Binary `+` operator."); +implement_bin_ops!(Sub, sub, "Binary `-` operator."); +implement_bin_ops!(Mul, mul, "Binary `*` operator."); +implement_bin_ops!(Div, div, "Binary `/` operator."); +implement_bin_ops!(Pow, pow, "Binary `**` operator."); +implement_bin_ops!(Mod, rem, "Binary `%` operator."); +implement_bin_ops!(BitAnd, bitand, "Binary `&` operator."); +implement_bin_ops!(BitOr, bitor, "Binary `|` operator."); +implement_bin_ops!(BitXor, bitxor, "Binary `^` operator."); +implement_bin_ops!(ShiftLeft, shl, "Binary `<<` operator."); +implement_bin_ops!(ShiftRight, shr, "Binary `>>` operator."); +implement_bin_ops!(UnsignedShiftRight, ushr, "Binary `>>>` operator."); +implement_bin_ops!(Eq, equals, "Binary `==` operator."); +implement_bin_ops!(GreaterThan, gt, "Binary `>` operator."); +implement_bin_ops!(GreaterThanOrEq, ge, "Binary `>=` operator."); +implement_bin_ops!(LessThan, lt, "Binary `<` operator."); +implement_bin_ops!(LessThanOrEq, le, "Binary `<=` operator."); diff --git a/boa_engine/src/vm/opcode/binary_ops/mod.rs b/boa_engine/src/vm/opcode/binary_ops/mod.rs index 704f6562bc5..fa8d9644d95 100644 --- a/boa_engine/src/vm/opcode/binary_ops/mod.rs +++ b/boa_engine/src/vm/opcode/binary_ops/mod.rs @@ -10,6 +10,10 @@ pub(crate) mod macro_defined; pub(crate) use logical::*; pub(crate) use macro_defined::*; +/// `NotEq` implements the Opcode Operation for `Opcode::NotEq` +/// +/// Operation: +/// - Binary `!=` operation #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct NotEq; @@ -26,6 +30,10 @@ impl Operation for NotEq { } } +/// `StrictEq` implements the Opcode Operation for `Opcode::StrictEq` +/// +/// Operation: +/// - Binary `===` operation #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct StrictEq; @@ -41,6 +49,10 @@ impl Operation for StrictEq { } } +/// `StrictNotEq` implements the Opcode Operation for `Opcode::StrictNotEq` +/// +/// Operation: +/// - Binary `!==` operation #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct StrictNotEq; @@ -56,6 +68,10 @@ impl Operation for StrictNotEq { } } +/// `In` implements the Opcode Operation for `Opcode::In` +/// +/// Operation: +/// - Binary `in` operation #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct In; @@ -82,6 +98,10 @@ impl Operation for In { } } +/// `InstanceOf` implements the Opcode Operation for `Opcode::InstanceOf` +/// +/// Operation: +/// - Binary `instanceof` operation #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct InstanceOf; diff --git a/boa_engine/src/vm/opcode/call/mod.rs b/boa_engine/src/vm/opcode/call/mod.rs index e76e9258a02..3f808ba666f 100644 --- a/boa_engine/src/vm/opcode/call/mod.rs +++ b/boa_engine/src/vm/opcode/call/mod.rs @@ -5,6 +5,10 @@ use crate::{ Context, JsResult, JsValue, }; +/// `CallEval` implements the Opcode Operation for `Opcode::CallEval` +/// +/// Operation: +/// - Call a function named "eval". #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct CallEval; @@ -57,6 +61,10 @@ impl Operation for CallEval { } } +/// `CallEvalSpread` implements the Opcode Operation for `Opcode::CallEvalSpread` +/// +/// Operation: +/// - Call a function named "eval" where the arguments contain spreads. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct CallEvalSpread; @@ -115,6 +123,10 @@ impl Operation for CallEvalSpread { } } +/// `Call` implements the Opcode Operation for `Opcode::Call` +/// +/// Operation: +/// - Call a function #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct Call; diff --git a/boa_engine/src/vm/opcode/concat/mod.rs b/boa_engine/src/vm/opcode/concat/mod.rs index 3a261f517d7..b2d3f1265c7 100644 --- a/boa_engine/src/vm/opcode/concat/mod.rs +++ b/boa_engine/src/vm/opcode/concat/mod.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsResult, JsString, }; +/// `ConcatToString` implements the Opcode Operation for `Opcode::ConcatToString` +/// +/// Operation: +/// - Concat multiple stack objects into a string. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct ConcatToString; diff --git a/boa_engine/src/vm/opcode/copy/mod.rs b/boa_engine/src/vm/opcode/copy/mod.rs index 4cabe63b204..9c27a207de6 100644 --- a/boa_engine/src/vm/opcode/copy/mod.rs +++ b/boa_engine/src/vm/opcode/copy/mod.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsResult, }; +/// `CopyDataProperties` implements the Opcode Operation for `Opcode::CopyDataProperties` +/// +/// Operation: +/// - Copy all properties of one object to another object. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct CopyDataProperties; diff --git a/boa_engine/src/vm/opcode/define/class/getter.rs b/boa_engine/src/vm/opcode/define/class/getter.rs index 16f76cbd115..52f75b87ed4 100644 --- a/boa_engine/src/vm/opcode/define/class/getter.rs +++ b/boa_engine/src/vm/opcode/define/class/getter.rs @@ -4,6 +4,10 @@ use crate::{ Context, JsResult, JsString, }; +/// `DefineClassGetterByName` implements the Opcode Operation for `Opcode::DefineClassGetterByName` +/// +/// Operation: +/// - Defines a class getter by name. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct DefineClassGetterByName; @@ -48,6 +52,10 @@ impl Operation for DefineClassGetterByName { } } +/// `DefineClassGetterByValue` implements the Opcode Operation for `Opcode::DefineClassGetterByValue` +/// +/// Operation: +/// - Defines a class getter by value. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct DefineClassGetterByValue; diff --git a/boa_engine/src/vm/opcode/define/class/method.rs b/boa_engine/src/vm/opcode/define/class/method.rs index f9ca7ca57fb..e9d2886240c 100644 --- a/boa_engine/src/vm/opcode/define/class/method.rs +++ b/boa_engine/src/vm/opcode/define/class/method.rs @@ -4,6 +4,10 @@ use crate::{ Context, JsResult, JsString, }; +/// `DefineClassMethodByName` implements the Opcode Operation for `Opcode::DefineClassMethodByName` +/// +/// Operation: +/// - Defines a class method by name. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct DefineClassMethodByName; @@ -43,6 +47,10 @@ impl Operation for DefineClassMethodByName { } } +/// `DefineClassMethodByValue` implements the Opcode Operation for `Opcode::DefineClassMethodByValue` +/// +/// Operation: +/// - Defines a class method by value. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct DefineClassMethodByValue; diff --git a/boa_engine/src/vm/opcode/define/class/setter.rs b/boa_engine/src/vm/opcode/define/class/setter.rs index f9765f39cd2..bd76ba87c06 100644 --- a/boa_engine/src/vm/opcode/define/class/setter.rs +++ b/boa_engine/src/vm/opcode/define/class/setter.rs @@ -4,6 +4,10 @@ use crate::{ Context, JsResult, JsString, }; +/// `DefineClassSetterByName` implements the Opcode Operation for `Opcode::DefineClassSetterByName` +/// +/// Operation: +/// - Defines a class setter by name. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct DefineClassSetterByName; @@ -48,6 +52,10 @@ impl Operation for DefineClassSetterByName { } } +/// `DefineClassSetterByValue` implements the Opcode Operation for `Opcode::DefineClassSetterByValue` +/// +/// Operation: +/// - Defines a class setter by value. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct DefineClassSetterByValue; diff --git a/boa_engine/src/vm/opcode/define/mod.rs b/boa_engine/src/vm/opcode/define/mod.rs index 1174f9fcfa1..65fc6182a83 100644 --- a/boa_engine/src/vm/opcode/define/mod.rs +++ b/boa_engine/src/vm/opcode/define/mod.rs @@ -10,6 +10,10 @@ pub(crate) mod own_property; pub(crate) use class::*; pub(crate) use own_property::*; +/// `DefVar` implements the Opcode Operation for `Opcode::DefVar` +/// +/// Operation: +/// - Declare `var` type variable. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct DefVar; @@ -45,6 +49,10 @@ impl Operation for DefVar { } } +/// `DefInitVar` implements the Opcode Operation for `Opcode::DefInitVar` +/// +/// Operation: +/// - Declare and initialize a function argument. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct DefInitVar; @@ -76,6 +84,10 @@ impl Operation for DefInitVar { } } +/// `DefLet` implements the Opcode Operation for `Opcode::DefLet` +/// +/// Operation: +/// - Declare `let` type variable. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct DefLet; @@ -96,7 +108,11 @@ impl Operation for DefLet { } macro_rules! implement_declaritives { - ($name:ident) => { + ($name:ident, $doc_string:literal) => { + #[doc= concat!("`", stringify!($name), "` implements the OpCode Operation for `Opcode::", stringify!($name), "`\n")] + #[doc= "\n"] + #[doc="Operation:\n"] + #[doc= concat!(" - ", $doc_string)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct $name; @@ -119,6 +135,6 @@ macro_rules! implement_declaritives { }; } -implement_declaritives!(DefInitLet); -implement_declaritives!(DefInitConst); -implement_declaritives!(DefInitArg); +implement_declaritives!(DefInitLet, "Declare and initialize `let` type variable"); +implement_declaritives!(DefInitConst, "Declare and initialize `const` type variable"); +implement_declaritives!(DefInitArg, "Declare and initialize function arguments"); diff --git a/boa_engine/src/vm/opcode/define/own_property.rs b/boa_engine/src/vm/opcode/define/own_property.rs index c0f0962d9d8..c89c063b757 100644 --- a/boa_engine/src/vm/opcode/define/own_property.rs +++ b/boa_engine/src/vm/opcode/define/own_property.rs @@ -4,6 +4,10 @@ use crate::{ Context, JsResult, JsString, }; +/// `DefineOwnPropertyByName` implements the Opcode Operation for `Opcode::DefineOwnPropertyByName` +/// +/// Operation: +/// - Defines a own property of an object by name. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct DefineOwnPropertyByName; @@ -39,6 +43,10 @@ impl Operation for DefineOwnPropertyByName { } } +/// `DefineOwnPropertyByValue` implements the Opcode Operation for `Opcode::DefineOwnPropertyByValue` +/// +/// Operation: +/// - Defines a own property of an object by value. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct DefineOwnPropertyByValue; diff --git a/boa_engine/src/vm/opcode/delete/mod.rs b/boa_engine/src/vm/opcode/delete/mod.rs index 1f64759e2fc..6b0d5f3d793 100644 --- a/boa_engine/src/vm/opcode/delete/mod.rs +++ b/boa_engine/src/vm/opcode/delete/mod.rs @@ -4,6 +4,10 @@ use crate::{ Context, JsResult, JsString, }; +/// `DeletePropertyByName` implements the Opcode Operation for `Opcode::DeletePropertyByName` +/// +/// Operation: +/// - Deletes a property by name of an object #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct DeletePropertyByName; @@ -31,6 +35,10 @@ impl Operation for DeletePropertyByName { } } +/// `DeletePropertyByValue` implements the Opcode Operation for `Opcode::DeletePropertyByValue` +/// +/// Operation: +/// - Deletes a property by value of an object #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct DeletePropertyByValue; diff --git a/boa_engine/src/vm/opcode/dup/mod.rs b/boa_engine/src/vm/opcode/dup/mod.rs index 6e562f6e937..c2f5f641a97 100644 --- a/boa_engine/src/vm/opcode/dup/mod.rs +++ b/boa_engine/src/vm/opcode/dup/mod.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsResult, }; +/// `Dup` implements the Opcode Operation for `Opcode::Dup` +/// +/// Operation: +/// - Push a copy of the top value on the stack. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct Dup; diff --git a/boa_engine/src/vm/opcode/environment/mod.rs b/boa_engine/src/vm/opcode/environment/mod.rs index 4e6ddc29cb1..de7ef7b209d 100644 --- a/boa_engine/src/vm/opcode/environment/mod.rs +++ b/boa_engine/src/vm/opcode/environment/mod.rs @@ -5,6 +5,10 @@ use crate::{ Context, JsResult, JsValue, }; +/// `This` implements the Opcode Operation for `Opcode::This` +/// +/// Operation: +/// - Pushes `this` value. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct This; @@ -25,6 +29,10 @@ impl Operation for This { } } +/// `Super` implements the Opcode Operation for `Opcode::Super` +/// +/// Operation: +/// - Pushes the current `super` value to the stack. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct Super; @@ -63,6 +71,10 @@ impl Operation for Super { } } +/// `SuperCall` implements the Opcode Operation for `Opcode::SuperCall` +/// +/// Operation: +/// - Execute the `super()` method. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct SuperCall; @@ -125,6 +137,10 @@ impl Operation for SuperCall { } } +/// `SuperCallSpread` implements the Opcode Operation for `Opcode::SuperCallSpread` +/// +/// Operation: +/// - Execute the `super()` method where the arguments contain spreads. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct SuperCallSpread; @@ -192,6 +208,10 @@ impl Operation for SuperCallSpread { } } +/// `SuperCallDerived` implements the Opcode Operation for `Opcode::SuperCallDerived` +/// +/// Operation: +/// - Execute the `super()` method when no constructor of the class is defined. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct SuperCallDerived; diff --git a/boa_engine/src/vm/opcode/generator/mod.rs b/boa_engine/src/vm/opcode/generator/mod.rs index fd9a13468fe..91ffb206eb7 100644 --- a/boa_engine/src/vm/opcode/generator/mod.rs +++ b/boa_engine/src/vm/opcode/generator/mod.rs @@ -15,6 +15,11 @@ use crate::{ pub(crate) mod yield_stm; pub(crate) use yield_stm::*; + +/// `GeneratorNext` implements the Opcode Operation for `Opcode::GeneratorNext` +/// +/// Operation: +/// - Resumes the current generator function. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct GeneratorNext; @@ -53,6 +58,10 @@ impl Operation for GeneratorNext { } } +/// `AsyncGeneratorNext` implements the Opcode Operation for `Opcode::AsyncGeneratorNext` +/// +/// Operation: +/// - Resumes the current generator function. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct AsyncGeneratorNext; @@ -113,6 +122,10 @@ impl Operation for AsyncGeneratorNext { } } +/// `GeneratorNextDelegate` implements the Opcode Operation for `Opcode::GeneratorNextDelegate` +/// +/// Operation: +/// - Delegates the current generator function another generator. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct GeneratorNextDelegate; diff --git a/boa_engine/src/vm/opcode/generator/yield_stm.rs b/boa_engine/src/vm/opcode/generator/yield_stm.rs index 10680b3aa2b..1f8fd0543ab 100644 --- a/boa_engine/src/vm/opcode/generator/yield_stm.rs +++ b/boa_engine/src/vm/opcode/generator/yield_stm.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsResult, }; +/// `Yield` implements the Opcode Operation for `Opcode::Yield` +/// +/// Operation: +/// - Yield from the current execution. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct Yield; diff --git a/boa_engine/src/vm/opcode/get/function.rs b/boa_engine/src/vm/opcode/get/function.rs index ea104d417c5..ce9dfe99e2e 100644 --- a/boa_engine/src/vm/opcode/get/function.rs +++ b/boa_engine/src/vm/opcode/get/function.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsResult, }; +/// `GetFunction` implements the Opcode Operation for `Opcode::GetFunction` +/// +/// Operation: +/// - Get function from the pre-compiled inner functions. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct GetFunction; @@ -19,6 +23,10 @@ impl Operation for GetFunction { } } +/// `GetFunctionAsync` implements the Opcode Operation for `Opcode::GetFunctionAsync` +/// +/// Operation: +/// - Get async function from the pre-compiled inner functions. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct GetFunctionAsync; diff --git a/boa_engine/src/vm/opcode/get/generator.rs b/boa_engine/src/vm/opcode/get/generator.rs index ce345c25000..c63662e4223 100644 --- a/boa_engine/src/vm/opcode/get/generator.rs +++ b/boa_engine/src/vm/opcode/get/generator.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsResult, }; +/// `GetGenerator` implements the Opcode Operation for `Opcode::GetGenerator` +/// +/// Operation: +/// - Get generator function from the pre-compiled inner functions. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct GetGenerator; @@ -19,6 +23,10 @@ impl Operation for GetGenerator { } } +/// `GetGeneratorAsync` implements the Opcode Operation for `Opcode::GetGeneratorAsync` +/// +/// Operation: +/// - Get async generator function from the pre-compiled inner functions. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct GetGeneratorAsync; diff --git a/boa_engine/src/vm/opcode/get/name.rs b/boa_engine/src/vm/opcode/get/name.rs index aeae0d2470c..6b11a004191 100644 --- a/boa_engine/src/vm/opcode/get/name.rs +++ b/boa_engine/src/vm/opcode/get/name.rs @@ -5,6 +5,10 @@ use crate::{ Context, JsResult, JsString, JsValue, }; +/// `GetName` implements the Opcode Operation for `Opcode::GetName` +/// +/// Operation: +/// - Find a binding on the environment chain and push its value. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct GetName; @@ -75,6 +79,10 @@ impl Operation for GetName { } } +/// `GetNameOrUndefined` implements the Opcode Operation for `Opcode::GetNameOrUndefined` +/// +/// Operation: +/// - Find a binding on the environment chain and push its value. If the binding does not exist push undefined. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct GetNameOrUndefined; diff --git a/boa_engine/src/vm/opcode/get/private.rs b/boa_engine/src/vm/opcode/get/private.rs index a39f255fd99..ea611079162 100644 --- a/boa_engine/src/vm/opcode/get/private.rs +++ b/boa_engine/src/vm/opcode/get/private.rs @@ -5,6 +5,10 @@ use crate::{ Context, JsResult, }; +/// `GetPrivateField` implements the Opcode Operation for `Opcode::GetPrivateField` +/// +/// Operation: +/// - Get a private property by name from an object an push it on the stack. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct GetPrivateField; diff --git a/boa_engine/src/vm/opcode/get/property.rs b/boa_engine/src/vm/opcode/get/property.rs index a7e1eedce40..87c01c4a72d 100644 --- a/boa_engine/src/vm/opcode/get/property.rs +++ b/boa_engine/src/vm/opcode/get/property.rs @@ -4,6 +4,10 @@ use crate::{ Context, JsResult, JsString, }; +/// `GetPropertyByName` implements the Opcode Operation for `Opcode::GetPropertyByName` +/// +/// Operation: +/// - Get a property by name from an object an push it on the stack. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct GetPropertyByName; @@ -34,6 +38,10 @@ impl Operation for GetPropertyByName { } } +/// `GetPropertyByValue` implements the Opcode Operation for `Opcode::GetPropertyByValue` +/// +/// Operation: +/// - Get a property by value from an object an push it on the stack. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct GetPropertyByValue; @@ -58,6 +66,10 @@ impl Operation for GetPropertyByValue { } } +/// `GetPropertyByValuePush` implements the Opcode Operation for `Opcode::GetPropertyByValuePush` +/// +/// Operation: +/// - Get a property by value from an object an push the key and value on the stack. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct GetPropertyByValuePush; diff --git a/boa_engine/src/vm/opcode/iteration/for_await.rs b/boa_engine/src/vm/opcode/iteration/for_await.rs index ca7ec103721..afa1253de56 100644 --- a/boa_engine/src/vm/opcode/iteration/for_await.rs +++ b/boa_engine/src/vm/opcode/iteration/for_await.rs @@ -5,6 +5,10 @@ use crate::{ Context, JsResult, }; +/// `ForAwaitOfLoopIterate` implements the Opcode Operation for `Opcode::ForAwaitOfLoopIterator` +/// +/// Operation: +/// - Move to the next value in a for await..of loop. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct ForAwaitOfLoopIterate; @@ -35,6 +39,10 @@ impl Operation for ForAwaitOfLoopIterate { } } +/// `ForAwaitOfLoopNext` implements the Opcode Operation for `Opcode::ForAwaitOfLoopNext` +/// +/// Operation: +/// - Get the value from a for await..of loop next result. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct ForAwaitOfLoopNext; diff --git a/boa_engine/src/vm/opcode/iteration/for_in.rs b/boa_engine/src/vm/opcode/iteration/for_in.rs index ec3bd144dcb..b7c9582918b 100644 --- a/boa_engine/src/vm/opcode/iteration/for_in.rs +++ b/boa_engine/src/vm/opcode/iteration/for_in.rs @@ -6,6 +6,10 @@ use crate::{ Context, JsResult, JsValue, }; +/// `ForInLoopInitIterator` implements the Opcode Operation for `Opcode::ForInLoopInitIterator` +/// +/// Operation: +/// - Initialize the iterator for a for..in loop or jump to after the loop if object is null or undefined. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct ForInLoopInitIterator; @@ -38,6 +42,10 @@ impl Operation for ForInLoopInitIterator { } } +/// `ForInLoopNext` implements the Opcode Operation for `Opcode::ForInLoopNext` +/// +/// Operation: +/// - Move to the next value in a for..in loop or jump to exit of the loop if done. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct ForInLoopNext; diff --git a/boa_engine/src/vm/opcode/iteration/init.rs b/boa_engine/src/vm/opcode/iteration/init.rs index 9ecdbf6ffa2..955ce793769 100644 --- a/boa_engine/src/vm/opcode/iteration/init.rs +++ b/boa_engine/src/vm/opcode/iteration/init.rs @@ -4,6 +4,10 @@ use crate::{ Context, JsResult, }; +/// `InitIterator` implements the Opcode Operation for `Opcode::InitIterator` +/// +/// Operation: +/// - Initialize an iterator #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct InitIterator; @@ -21,6 +25,10 @@ impl Operation for InitIterator { } } +/// `InitIteratorAsync` implements the Opcode Operation for `Opcode::InitIteratorAsync` +/// +/// Operation: +/// - Initialize an async iterator. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct InitIteratorAsync; diff --git a/boa_engine/src/vm/opcode/iteration/iterator.rs b/boa_engine/src/vm/opcode/iteration/iterator.rs index 896d296a312..38bf5e4d991 100644 --- a/boa_engine/src/vm/opcode/iteration/iterator.rs +++ b/boa_engine/src/vm/opcode/iteration/iterator.rs @@ -4,6 +4,10 @@ use crate::{ Context, JsResult, JsValue, }; +/// `IteratorNext` implements the Opcode Operation for `Opcode::IteratorNext` +/// +/// Operation: +/// - Advance the iterator by one and put the value on the stack. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct IteratorNext; @@ -38,6 +42,10 @@ impl Operation for IteratorNext { } } +/// `IteratorClose` implements the Opcode Operation for `Opcode::IteratorClose` +/// +/// Operation: +/// - Close an iterator #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct IteratorClose; @@ -62,6 +70,10 @@ impl Operation for IteratorClose { } } +/// `IteratorToArray` implements the Opcode Operation for `Opcode::IteratorToArray` +/// +/// Operation: +/// - Consume the iterator and construct and array with all the values. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct IteratorToArray; diff --git a/boa_engine/src/vm/opcode/iteration/loop_ops.rs b/boa_engine/src/vm/opcode/iteration/loop_ops.rs index f6600afdedd..e28a19c18e6 100644 --- a/boa_engine/src/vm/opcode/iteration/loop_ops.rs +++ b/boa_engine/src/vm/opcode/iteration/loop_ops.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsResult, }; +/// `LoopStart` implements the Opcode Operation for `Opcode::LoopStart` +/// +/// Operation: +/// - Push loop start marker. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct LoopStart; @@ -17,6 +21,10 @@ impl Operation for LoopStart { } } +/// `LoopContinue` implements the Opcode Operation for `Opcode::LoopContinue` +/// +/// Operation: +/// - Clean up environments when a loop continues. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct LoopContinue; @@ -40,6 +48,10 @@ impl Operation for LoopContinue { } } +/// `LoopEnd` implements the Opcode Operation for `Opcode::LoopEnd` +/// +/// Operation: +/// - Clean up enviroments at the end of a lopp. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct LoopEnd; diff --git a/boa_engine/src/vm/opcode/jump/mod.rs b/boa_engine/src/vm/opcode/jump/mod.rs index 6dea7045b16..f509a59c972 100644 --- a/boa_engine/src/vm/opcode/jump/mod.rs +++ b/boa_engine/src/vm/opcode/jump/mod.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsResult, }; +/// `Jump` implements the Opcode Operation for `Opcode::Jump` +/// +/// Operation: +/// - Unconditional jump to address. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct Jump; @@ -17,6 +21,10 @@ impl Operation for Jump { } } +/// `JumpIfFalse` implements the Opcode Operation for `Opcode::JumpIfFalse` +/// +/// Operation: +/// - Conditional jump to address. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct JumpIfFalse; @@ -33,6 +41,10 @@ impl Operation for JumpIfFalse { } } +/// `JumpIfNotUndefined` implements the Opcode Operation for `Opcode::JumpIfNotUndefined` +/// +/// Operation: +/// - Conditional jump to address. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct JumpIfNotUndefined; diff --git a/boa_engine/src/vm/opcode/mod.rs b/boa_engine/src/vm/opcode/mod.rs index 62fb43f8a48..9fed4fe1b85 100644 --- a/boa_engine/src/vm/opcode/mod.rs +++ b/boa_engine/src/vm/opcode/mod.rs @@ -2,69 +2,103 @@ use crate::{vm::ShouldExit, Context, JsResult}; // Operation modules -pub(crate) mod await_stm; -pub(crate) mod binary_ops; -pub(crate) mod call; -pub(crate) mod concat; -pub(crate) mod copy; -pub(crate) mod define; -pub(crate) mod delete; -pub(crate) mod dup; -pub(crate) mod environment; -pub(crate) mod generator; -pub(crate) mod get; -pub(crate) mod iteration; -pub(crate) mod jump; -pub(crate) mod new; -pub(crate) mod nop; -pub(crate) mod pop; -pub(crate) mod promise; -pub(crate) mod push; -pub(crate) mod require; -pub(crate) mod rest_parameter; -pub(crate) mod return_stm; -pub(crate) mod set; -pub(crate) mod swap; -pub(crate) mod switch; -pub(crate) mod throw; -pub(crate) mod to; -pub(crate) mod try_catch; -pub(crate) mod unary_ops; -pub(crate) mod value; -pub(crate) mod void; +mod await_stm; +mod binary_ops; +mod call; +mod concat; +mod copy; +mod define; +mod delete; +mod dup; +mod environment; +mod generator; +mod get; +mod iteration; +mod jump; +mod new; +mod nop; +mod pop; +mod promise; +mod push; +mod require; +mod rest_parameter; +mod return_stm; +mod set; +mod swap; +mod switch; +mod throw; +mod to; +mod try_catch; +mod unary_ops; +mod value; // Operation structs +#[doc(inline)] pub(crate) use await_stm::*; +#[doc(inline)] pub(crate) use binary_ops::*; +#[doc(inline)] pub(crate) use call::*; +#[doc(inline)] pub(crate) use concat::*; +#[doc(inline)] pub(crate) use copy::*; +#[doc(inline)] pub(crate) use define::*; +#[doc(inline)] pub(crate) use delete::*; +#[doc(inline)] pub(crate) use dup::*; +#[doc(inline)] pub(crate) use environment::*; +#[doc(inline)] pub(crate) use generator::*; +#[doc(inline)] pub(crate) use get::*; +#[doc(inline)] pub(crate) use iteration::*; +#[doc(inline)] pub(crate) use jump::*; +#[doc(inline)] pub(crate) use new::*; +#[doc(inline)] pub(crate) use nop::*; +#[doc(inline)] pub(crate) use pop::*; +#[doc(inline)] pub(crate) use promise::*; +#[doc(inline)] pub(crate) use push::*; +#[doc(inline)] pub(crate) use require::*; +#[doc(inline)] pub(crate) use rest_parameter::*; +#[doc(inline)] pub(crate) use return_stm::*; +#[doc(inline)] pub(crate) use set::*; +#[doc(inline)] pub(crate) use swap::*; +#[doc(inline)] pub(crate) use switch::*; +#[doc(inline)] pub(crate) use throw::*; +#[doc(inline)] pub(crate) use to::*; +#[doc(inline)] pub(crate) use try_catch::*; +#[doc(inline)] pub(crate) use unary_ops::*; +#[doc(inline)] pub(crate) use value::*; -pub(crate) use void::*; +/// The `Operation` trait implements the execution code along with the +/// identifying Name and Instruction value for an Boa Opcode +/// +/// +/// This trait should be implemented for a struct that corresponds with +/// any arm of the `OpCode` enum. +/// pub(crate) trait Operation { const NAME: &'static str; const INSTRUCTION: &'static str; diff --git a/boa_engine/src/vm/opcode/new/mod.rs b/boa_engine/src/vm/opcode/new/mod.rs index 4134954d105..65aa75ae6cb 100644 --- a/boa_engine/src/vm/opcode/new/mod.rs +++ b/boa_engine/src/vm/opcode/new/mod.rs @@ -4,6 +4,10 @@ use crate::{ Context, JsResult, }; +/// `New` implements the Opcode Operation for `Opcode::New` +/// +/// Operation: +/// - Call construct on a function. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct New; @@ -39,6 +43,10 @@ impl Operation for New { } } +/// `NewSpread` implements the Opcode Operation for `Opcode::NewSpread` +/// +/// Operation: +/// - Call construct on a function where the arguments contain spreads. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct NewSpread; diff --git a/boa_engine/src/vm/opcode/nop/mod.rs b/boa_engine/src/vm/opcode/nop/mod.rs index 9bd30dc4938..0ed775f2c51 100644 --- a/boa_engine/src/vm/opcode/nop/mod.rs +++ b/boa_engine/src/vm/opcode/nop/mod.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsResult, }; +/// `Nop` implements the Opcode Operation for `Opcode::Nop` +/// +/// Operation: +/// - No-operation instruction, does nothing #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct Nop; diff --git a/boa_engine/src/vm/opcode/pop/mod.rs b/boa_engine/src/vm/opcode/pop/mod.rs index a75c5f0f13f..ce276188982 100644 --- a/boa_engine/src/vm/opcode/pop/mod.rs +++ b/boa_engine/src/vm/opcode/pop/mod.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsResult, }; +/// `Pop` implements the Opcode Operation for `Opcode::Pop` +/// +/// Operation: +/// - Pop the top value from the stack. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct Pop; @@ -16,6 +20,10 @@ impl Operation for Pop { } } +/// `PopIfThrown` implements the Opcode Operation for `Opcode::PopIfThrown` +/// +/// Operation: +/// - Pop the top value from the stack if the last try block has thrown a value. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct PopIfThrown; @@ -33,6 +41,10 @@ impl Operation for PopIfThrown { } } +/// `PopEnvironment` implements the Opcode Operation for `Opcode::PopEnvironment` +/// +/// Operation: +/// - Pop the current environment. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct PopEnvironment; @@ -48,6 +60,10 @@ impl Operation for PopEnvironment { } } +/// `PopReturnAdd` implements the Opcode Operation for `Opcode::PopReturnAdd` +/// +/// Operation: +/// - Add one to the pop on return count. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct PopOnReturnAdd; @@ -61,6 +77,10 @@ impl Operation for PopOnReturnAdd { } } +/// `PopOnReturnSub` implements the Opcode Operation for `Opcode::PopOnReturnSub` +/// +/// Operation: +/// - Subtract one from the pop on return count. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct PopOnReturnSub; diff --git a/boa_engine/src/vm/opcode/promise/mod.rs b/boa_engine/src/vm/opcode/promise/mod.rs index c7e563fc262..1f3f1342667 100644 --- a/boa_engine/src/vm/opcode/promise/mod.rs +++ b/boa_engine/src/vm/opcode/promise/mod.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsError, JsResult, }; +/// `FinallyStart` implements the Opcode Operation for `Opcode::FinallyStart` +/// +/// Operation: +/// - Start of a finally block. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct FinallyStart; @@ -21,6 +25,10 @@ impl Operation for FinallyStart { } } +/// `FinallyEnd` implements the Opcode Operation for `Opcode::FinallyEnd` +/// +/// Operation: +/// - End of a finally block. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct FinallyEnd; @@ -48,6 +56,10 @@ impl Operation for FinallyEnd { } } +/// `FinallySetJump` implements the Opcode Operation for `Opcode::FinallySetJump` +/// +/// Operation: +/// - Set the address for a finally jump. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct FinallySetJump; diff --git a/boa_engine/src/vm/opcode/push/array.rs b/boa_engine/src/vm/opcode/push/array.rs index f0cbe4ae8fa..56e5065ff24 100644 --- a/boa_engine/src/vm/opcode/push/array.rs +++ b/boa_engine/src/vm/opcode/push/array.rs @@ -4,6 +4,10 @@ use crate::{ Context, JsResult, }; +/// `PushNewArray` implements the Opcode Operation for `Opcode::PushNewArray` +/// +/// Operation: +/// - Push an empty array value on the stack. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct PushNewArray; @@ -19,6 +23,10 @@ impl Operation for PushNewArray { } } +/// `PushValueToArray` implements the Opcode Operation for `Opcode::PushValueToArray` +/// +/// Operation: +/// - Push a value to an array. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct PushValueToArray; @@ -40,6 +48,10 @@ impl Operation for PushValueToArray { } } +/// `PushEllisionToArray` implements the Opcode Operation for `Opcode::PushEllisionToArray` +/// +/// Operation: +/// - Push an empty element/hole to an array. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct PushElisionToArray; @@ -61,6 +73,10 @@ impl Operation for PushElisionToArray { } } +/// `PushIteratorToArray` implements the Opcode Operation for `Opcode::PushIteratorToArray` +/// +/// Operation: +/// - Push all iterator values to an array. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct PushIteratorToArray; diff --git a/boa_engine/src/vm/opcode/push/class/field.rs b/boa_engine/src/vm/opcode/push/class/field.rs index 1c9b87fdda6..210244dd9e0 100644 --- a/boa_engine/src/vm/opcode/push/class/field.rs +++ b/boa_engine/src/vm/opcode/push/class/field.rs @@ -4,6 +4,10 @@ use crate::{ Context, JsResult, }; +/// `PushClassField` implements the Opcode Operation for `Opcode::PushClassField` +/// +/// Operation: +/// - Push a field to a class. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct PushClassField; @@ -40,6 +44,10 @@ impl Operation for PushClassField { } } +/// `PushClassFieldPrivate` implements the Opcode Operation for `Opcode::PushClassFieldPrivate` +/// +/// Operation: +/// - Push a private field to the class. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct PushClassFieldPrivate; diff --git a/boa_engine/src/vm/opcode/push/class/mod.rs b/boa_engine/src/vm/opcode/push/class/mod.rs index 450bf77c9ec..e76cbef32cb 100644 --- a/boa_engine/src/vm/opcode/push/class/mod.rs +++ b/boa_engine/src/vm/opcode/push/class/mod.rs @@ -11,6 +11,10 @@ pub(crate) mod private; pub(crate) use field::*; pub(crate) use private::*; +/// `PushClassPrototype` implements the Opcode Operation for `Opcode::PushClassPrototype` +/// +/// Operation: +/// - Get the prototype of a superclass and push it on the stack. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct PushClassPrototype; diff --git a/boa_engine/src/vm/opcode/push/class/private.rs b/boa_engine/src/vm/opcode/push/class/private.rs index 49cd4cacc46..4d77b4e1789 100644 --- a/boa_engine/src/vm/opcode/push/class/private.rs +++ b/boa_engine/src/vm/opcode/push/class/private.rs @@ -4,6 +4,10 @@ use crate::{ Context, JsResult, }; +/// `PushClassPrivateMethod` implements the Opcode Operation for `Opcode::PushClassPrivateMethod` +/// +/// Operation: +/// - Push a private method to the class. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct PushClassPrivateMethod; @@ -28,6 +32,10 @@ impl Operation for PushClassPrivateMethod { } } +/// `PushClassPrivateGetter` implements the Opcode Operation for `Opcode::PushClassPrivateGetter` +/// +/// Operation: +/// - Push a private getter to the class. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct PushClassPrivateGetter; @@ -58,6 +66,10 @@ impl Operation for PushClassPrivateGetter { } } +/// `PushClassPrivateSetter` implements the Opcode Operation for `Opcode::PushClassPrivateSetter` +/// +/// Operation: +/// - Push a private setter to the class. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct PushClassPrivateSetter; diff --git a/boa_engine/src/vm/opcode/push/environment.rs b/boa_engine/src/vm/opcode/push/environment.rs index 998d92f63c0..bc0c7840941 100644 --- a/boa_engine/src/vm/opcode/push/environment.rs +++ b/boa_engine/src/vm/opcode/push/environment.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsResult, }; +/// `PushDeclarativeEnvironment` implements the Opcode Operation for `Opcode::PushDeclarativeEnvironment` +/// +/// Operation: +/// - Push a declarative environment #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct PushDeclarativeEnvironment; @@ -26,6 +30,10 @@ impl Operation for PushDeclarativeEnvironment { } } +/// `PushFunctionEnvironment` implements the Opcode Operation for `Opcode::PushFunctionEnvironment` +/// +/// Operation: +/// - Push a function environment. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct PushFunctionEnvironment; diff --git a/boa_engine/src/vm/opcode/push/literal.rs b/boa_engine/src/vm/opcode/push/literal.rs index 09640f8e4f1..d0cc937564f 100644 --- a/boa_engine/src/vm/opcode/push/literal.rs +++ b/boa_engine/src/vm/opcode/push/literal.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsResult, }; +/// `PushLiteral` implements the Opcode Operation for `Opcode::PushLiteral` +/// +/// Operation: +/// - Push literal value on the stack. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct PushLiteral; diff --git a/boa_engine/src/vm/opcode/push/mod.rs b/boa_engine/src/vm/opcode/push/mod.rs index cae0d14c115..e029837735d 100644 --- a/boa_engine/src/vm/opcode/push/mod.rs +++ b/boa_engine/src/vm/opcode/push/mod.rs @@ -20,7 +20,11 @@ pub(crate) use numbers::*; pub(crate) use object::*; macro_rules! implement_push_generics { - ($name:ident, $push_value:expr) => { + ($name:ident, $push_value:expr, $doc_string:literal) => { + #[doc= concat!("`", stringify!($name), "` implements the OpCode Operation for `Opcode::", stringify!($name), "`\n")] + #[doc= "\n"] + #[doc="Operation:\n"] + #[doc= concat!(" - ", $doc_string)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct $name; @@ -36,12 +40,28 @@ macro_rules! implement_push_generics { }; } -implement_push_generics!(PushUndefined, JsValue::undefined()); -implement_push_generics!(PushNull, JsValue::null()); -implement_push_generics!(PushTrue, true); -implement_push_generics!(PushFalse, false); -implement_push_generics!(PushZero, 0); -implement_push_generics!(PushOne, 1); -implement_push_generics!(PushNaN, JsValue::nan()); -implement_push_generics!(PushPositiveInfinity, JsValue::positive_infinity()); -implement_push_generics!(PushNegativeInfinity, JsValue::negative_infinity()); +implement_push_generics!( + PushUndefined, + JsValue::undefined(), + "Push integer `undefined` on the stack." +); +implement_push_generics!( + PushNull, + JsValue::null(), + "Push integer `null` on the stack." +); +implement_push_generics!(PushTrue, true, "Push integer `true` on the stack."); +implement_push_generics!(PushFalse, false, "Push integer `false` on the stack."); +implement_push_generics!(PushZero, 0, "Push integer `0` on the stack."); +implement_push_generics!(PushOne, 1, "Push integer `1` on the stack."); +implement_push_generics!(PushNaN, JsValue::nan(), "Push integer `NaN` on the stack."); +implement_push_generics!( + PushPositiveInfinity, + JsValue::positive_infinity(), + "Push integer `Infinity` on the stack." +); +implement_push_generics!( + PushNegativeInfinity, + JsValue::negative_infinity(), + "Push integer `-Infinity` on the stack." +); diff --git a/boa_engine/src/vm/opcode/push/new_target.rs b/boa_engine/src/vm/opcode/push/new_target.rs index 7eb61993a44..85ef0f8eaf2 100644 --- a/boa_engine/src/vm/opcode/push/new_target.rs +++ b/boa_engine/src/vm/opcode/push/new_target.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsResult, JsValue, }; +/// `PushNewTarget` implements the Opcode Operation for `Opcode::PushNewTarget` +/// +/// Operation: +/// - Push the current new target to the stack. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct PushNewTarget; diff --git a/boa_engine/src/vm/opcode/push/numbers.rs b/boa_engine/src/vm/opcode/push/numbers.rs index 9db5260a451..3f0b3a6a599 100644 --- a/boa_engine/src/vm/opcode/push/numbers.rs +++ b/boa_engine/src/vm/opcode/push/numbers.rs @@ -4,7 +4,11 @@ use crate::{ }; macro_rules! implement_push_numbers_with_conversion { - ($name:ident, $num_type:ty) => { + ($name:ident, $num_type:ty, $doc_string:literal) => { + #[doc= concat!("`", stringify!($name), "` implements the OpCode Operation for `Opcode::", stringify!($name), "`\n")] + #[doc= "\n"] + #[doc="Operation:\n"] + #[doc= concat!(" - ", $doc_string)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct $name; @@ -22,7 +26,11 @@ macro_rules! implement_push_numbers_with_conversion { } macro_rules! implement_push_numbers_no_conversion { - ($name:ident, $num_type:ty) => { + ($name:ident, $num_type:ty, $doc_string:literal) => { + #[doc= concat!("`", stringify!($name), "` implements the OpCode Operation for `Opcode::", stringify!($name), "`\n")] + #[doc= "\n"] + #[doc="Operation:\n"] + #[doc= concat!(" - ", $doc_string)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct $name; @@ -39,8 +47,8 @@ macro_rules! implement_push_numbers_no_conversion { }; } -implement_push_numbers_with_conversion!(PushInt8, i8); -implement_push_numbers_with_conversion!(PushInt16, i16); +implement_push_numbers_with_conversion!(PushInt8, i8, "Push `i8` value on the stack"); +implement_push_numbers_with_conversion!(PushInt16, i16, "Push `i16` value on the stack"); -implement_push_numbers_no_conversion!(PushInt32, i32); -implement_push_numbers_no_conversion!(PushRational, f64); +implement_push_numbers_no_conversion!(PushInt32, i32, "Push `i32` value on the stack"); +implement_push_numbers_no_conversion!(PushRational, f64, "Push `f64` value on the stack"); diff --git a/boa_engine/src/vm/opcode/push/object.rs b/boa_engine/src/vm/opcode/push/object.rs index 98770100562..7819e97511b 100644 --- a/boa_engine/src/vm/opcode/push/object.rs +++ b/boa_engine/src/vm/opcode/push/object.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsResult, }; +/// `PushEmptyObject` implements the Opcode Operation for `Opcode::PushEmptyObject` +/// +/// Operation: +/// - Push empty object `{}` value on the stack. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct PushEmptyObject; diff --git a/boa_engine/src/vm/opcode/require/mod.rs b/boa_engine/src/vm/opcode/require/mod.rs index 07362bec716..308591ea906 100644 --- a/boa_engine/src/vm/opcode/require/mod.rs +++ b/boa_engine/src/vm/opcode/require/mod.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsResult, }; +/// `RequireObjectCoercible` implements the Opcode Operation for `Opcode::RequireObjectCoercible` +/// +/// Operation: +/// - Call `RequireObjectCoercible` on the stack value. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct RequireObjectCoercible; diff --git a/boa_engine/src/vm/opcode/rest_parameter/mod.rs b/boa_engine/src/vm/opcode/rest_parameter/mod.rs index 307d71fd31b..18d950a224e 100644 --- a/boa_engine/src/vm/opcode/rest_parameter/mod.rs +++ b/boa_engine/src/vm/opcode/rest_parameter/mod.rs @@ -4,6 +4,10 @@ use crate::{ Context, JsResult, }; +/// `RestParameterInit` implements the Opcode Operation for `Opcode::RestParameterInit` +/// +/// Operation: +/// - Initialize the rest parameter value of a function from the remaining arguments. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct RestParameterInit; @@ -34,6 +38,10 @@ impl Operation for RestParameterInit { } } +/// `RestParameterPop` implements the Opcode Operation for `Opcode::RestParameterPop` +/// +/// Operation: +/// - Pop the remaining arguments of a function. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct RestParameterPop; diff --git a/boa_engine/src/vm/opcode/return_stm/mod.rs b/boa_engine/src/vm/opcode/return_stm/mod.rs index fb10beb8a5b..ee08121de66 100644 --- a/boa_engine/src/vm/opcode/return_stm/mod.rs +++ b/boa_engine/src/vm/opcode/return_stm/mod.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsResult, }; +/// `Return` implements the Opcode Operation for `Opcode::Return` +/// +/// Operation: +/// - Return from a function. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct Return; diff --git a/boa_engine/src/vm/opcode/set/class_prototype.rs b/boa_engine/src/vm/opcode/set/class_prototype.rs index c19a7b40199..b47c58ec7a4 100644 --- a/boa_engine/src/vm/opcode/set/class_prototype.rs +++ b/boa_engine/src/vm/opcode/set/class_prototype.rs @@ -5,6 +5,10 @@ use crate::{ Context, JsResult, JsValue, }; +/// `SetClassProtoType` implements the Opcode Operation for `Opcode::SetClassPrototype` +/// +/// Operation: +/// - Set the prototype of a class object. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct SetClassPrototype; diff --git a/boa_engine/src/vm/opcode/set/home_object.rs b/boa_engine/src/vm/opcode/set/home_object.rs index 91750746ddc..a587f90ec0c 100644 --- a/boa_engine/src/vm/opcode/set/home_object.rs +++ b/boa_engine/src/vm/opcode/set/home_object.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsResult, }; +/// `SetHomeObject` implements the Opcode Operation for `Opcode::SetHomeObject` +/// +/// Operation: +/// - Set home object internal slot of a function object. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct SetHomeObject; diff --git a/boa_engine/src/vm/opcode/set/name.rs b/boa_engine/src/vm/opcode/set/name.rs index 8c096245488..d23313162f0 100644 --- a/boa_engine/src/vm/opcode/set/name.rs +++ b/boa_engine/src/vm/opcode/set/name.rs @@ -4,6 +4,10 @@ use crate::{ Context, JsResult, JsString, }; +/// `SetName` implements the Opcode Operation for `Opcode::SetName` +/// +/// Operation: +/// - Find a binding on the environment chain and assign its value. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct SetName; diff --git a/boa_engine/src/vm/opcode/set/private.rs b/boa_engine/src/vm/opcode/set/private.rs index 75267cbb819..5c46de0e4f9 100644 --- a/boa_engine/src/vm/opcode/set/private.rs +++ b/boa_engine/src/vm/opcode/set/private.rs @@ -5,6 +5,10 @@ use crate::{ Context, JsResult, }; +/// `AssignPrivateField` implements the Opcode Operation for `Opcode::AssignPrivateField` +/// +/// Operation: +/// - Assign the value of a private property of an object by it's name. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct AssignPrivateField; @@ -56,6 +60,10 @@ impl Operation for AssignPrivateField { } } +/// `SetPrivateField` implements the Opcode Operation for `Opcode::SetPrivateField` +/// +/// Operation: +/// - Set a private property of a class constructor by it's name. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct SetPrivateField; @@ -90,6 +98,10 @@ impl Operation for SetPrivateField { } } +/// `SetPrivateMethod` implements the Opcode Operation for `Opcode::SetPrivateMethod` +/// +/// Operation: +/// - Set a private method of a class constructor by it's name. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct SetPrivateMethod; @@ -116,6 +128,10 @@ impl Operation for SetPrivateMethod { } } +/// `SetPrivateSetter` implements the Opcode Operation for `Opcode::SetPrivateSetter` +/// +/// Operation: +/// - Set a private setter property of a class constructor by it's name. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct SetPrivateSetter; @@ -141,6 +157,10 @@ impl Operation for SetPrivateSetter { } } +/// `SetPrivateGetter` implements the Opcode Operation for `Opcode::SetPrivateGetter` +/// +/// Operation: +/// - Set a private getter property of a class constructor by it's name. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct SetPrivateGetter; diff --git a/boa_engine/src/vm/opcode/set/property.rs b/boa_engine/src/vm/opcode/set/property.rs index 97c043a030a..f1f88551843 100644 --- a/boa_engine/src/vm/opcode/set/property.rs +++ b/boa_engine/src/vm/opcode/set/property.rs @@ -4,6 +4,10 @@ use crate::{ Context, JsResult, JsString, }; +/// `SetPropertyByName` implements the Opcode Operation for `Opcode::SetPropertyByName` +/// +/// Operation: +/// - Sets a property by name of an object. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct SetPropertyByName; @@ -34,6 +38,10 @@ impl Operation for SetPropertyByName { } } +/// `SetPropertyByValue` implements the Opcode Operation for `Opcode::SetPropertyByValue` +/// +/// Operation: +/// - Sets a property by value of an object. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct SetPropertyByValue; @@ -57,6 +65,10 @@ impl Operation for SetPropertyByValue { } } +/// `SetPropertyGetterByName` implements the Opcode Operation for `Opcode::SetPropertyGetterByName` +/// +/// Operation: +/// - Sets a getter property by name of an object. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct SetPropertyGetterByName; @@ -94,6 +106,10 @@ impl Operation for SetPropertyGetterByName { } } +/// `SetPropertyGetterByValue` implements the Opcode Operation for `Opcode::SetPropertyGetterByValue` +/// +/// Operation: +/// - Sets a getter property by value of an object. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct SetPropertyGetterByValue; @@ -126,6 +142,10 @@ impl Operation for SetPropertyGetterByValue { } } +/// `SetPropertySetterByName` implements the Opcode Operation for `Opcode::SetPropertySetterByName` +/// +/// Operation: +/// - Sets a setter property by name of an object. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct SetPropertySetterByName; @@ -163,6 +183,10 @@ impl Operation for SetPropertySetterByName { } } +/// `SetPropertySetterByValue` implements the Opcode Operation for `Opcode::SetPropertySetterByValue` +/// +/// Operation: +/// - Sets a setter property by value of an object. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct SetPropertySetterByValue; diff --git a/boa_engine/src/vm/opcode/swap/mod.rs b/boa_engine/src/vm/opcode/swap/mod.rs index 03048e6c59e..fa74ca5edec 100644 --- a/boa_engine/src/vm/opcode/swap/mod.rs +++ b/boa_engine/src/vm/opcode/swap/mod.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsResult, }; +/// `Swap` implements the Opcode Operation for `Opcode::Swap` +/// +/// Operation: +/// - Swap the top two values on the stack. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct Swap; diff --git a/boa_engine/src/vm/opcode/switch/mod.rs b/boa_engine/src/vm/opcode/switch/mod.rs index 7e0d4cdf857..385cd9c58ce 100644 --- a/boa_engine/src/vm/opcode/switch/mod.rs +++ b/boa_engine/src/vm/opcode/switch/mod.rs @@ -3,6 +3,11 @@ use crate::{ Context, JsResult, }; +/// `Case` implements the Opcode Operation for `Opcode::Case` +/// +/// Operation: +/// - Pop the two values of the stack, strict equal compares the two values, +/// if true jumps to address, otherwise push the second pop'ed value. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct Case; @@ -24,6 +29,10 @@ impl Operation for Case { } } +/// `Default` implements the Opcode Operation for `Opcode::Default` +/// +/// Operation: +/// - Pops the top of stack and jump to address. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct Default; diff --git a/boa_engine/src/vm/opcode/throw/mod.rs b/boa_engine/src/vm/opcode/throw/mod.rs index 1d46ae04216..efa05ea3751 100644 --- a/boa_engine/src/vm/opcode/throw/mod.rs +++ b/boa_engine/src/vm/opcode/throw/mod.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsError, JsResult, }; +/// `Throw` implements the Opcode Operation for `Opcode::Throw` +/// +/// Operation: +/// - Throw exception. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct Throw; diff --git a/boa_engine/src/vm/opcode/to/mod.rs b/boa_engine/src/vm/opcode/to/mod.rs index a021a6d48f7..20b7d6883d9 100644 --- a/boa_engine/src/vm/opcode/to/mod.rs +++ b/boa_engine/src/vm/opcode/to/mod.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsResult, }; +/// `ToBoolean` implements the Opcode Operation for `Opcode::ToBoolean` +/// +/// Operation: +/// - Pops value converts it to boolean and pushes it back. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct ToBoolean; @@ -17,6 +21,10 @@ impl Operation for ToBoolean { } } +/// `ToPropertyKey` implements the Opcode Operation for `Opcode::ToPropertyKey` +/// +/// Operation: +/// - Call `ToPropertyKey` on the value on the stack. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct ToPropertyKey; diff --git a/boa_engine/src/vm/opcode/try_catch/mod.rs b/boa_engine/src/vm/opcode/try_catch/mod.rs index 6671556e554..c19fd2b75d1 100644 --- a/boa_engine/src/vm/opcode/try_catch/mod.rs +++ b/boa_engine/src/vm/opcode/try_catch/mod.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsResult, }; +/// `TryStart` implements the Opcode Operation for `Opcode::TryStart` +/// +/// Operation: +/// - Start of a try block. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct TryStart; @@ -29,6 +33,10 @@ impl Operation for TryStart { } } +/// `TryEnd` implements the Opcode Operation for `Opcode::TryEnd` +/// +/// Operation: +/// - End of a try block #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct TryEnd; @@ -67,6 +75,10 @@ impl Operation for TryEnd { } } +/// `CatchStart` implements the Opcode Operation for `Opcode::CatchStart` +/// +/// Operation: +/// - Start of a catch block. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct CatchStart; @@ -89,6 +101,10 @@ impl Operation for CatchStart { } } +/// `CatchEnd` implements the Opcode Operation for `Opcode::CatchEnd` +/// +/// Operation: +/// - End of a catch block. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct CatchEnd; @@ -127,6 +143,10 @@ impl Operation for CatchEnd { } } +/// `CatchEnd2` implements the Opcode Operation for `Opcode::CatchEnd2` +/// +/// Operation: +/// - End of a catch block #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct CatchEnd2; diff --git a/boa_engine/src/vm/opcode/unary_ops/decrement.rs b/boa_engine/src/vm/opcode/unary_ops/decrement.rs index 0574056b996..a09396eb09d 100644 --- a/boa_engine/src/vm/opcode/unary_ops/decrement.rs +++ b/boa_engine/src/vm/opcode/unary_ops/decrement.rs @@ -4,6 +4,10 @@ use crate::{ Context, JsBigInt, JsResult, }; +/// `Dec` implements the Opcode Operation for `Opcode::Dec` +/// +/// Operation: +/// - Unary `--` operator. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct Dec; @@ -23,6 +27,10 @@ impl Operation for Dec { } } +/// `DecPost` implements the Opcode Operation for `Opcode::DecPost` +/// +/// Operation: +/// - Unary postfix `--` operator. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct DecPost; diff --git a/boa_engine/src/vm/opcode/unary_ops/increment.rs b/boa_engine/src/vm/opcode/unary_ops/increment.rs index 039d585fb84..f9771206915 100644 --- a/boa_engine/src/vm/opcode/unary_ops/increment.rs +++ b/boa_engine/src/vm/opcode/unary_ops/increment.rs @@ -4,6 +4,10 @@ use crate::{ Context, JsBigInt, JsResult, }; +/// `Inc` implements the Opcode Operation for `Opcode::Inc` +/// +/// Operation: +/// - Unary `++` operator. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct Inc; @@ -23,6 +27,10 @@ impl Operation for Inc { } } +/// `Inc` implements the Opcode Operation for `Opcode::Inc` +/// +/// Operation: +/// - Unary postfix `++` operator. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct IncPost; diff --git a/boa_engine/src/vm/opcode/unary_ops/logical.rs b/boa_engine/src/vm/opcode/unary_ops/logical.rs new file mode 100644 index 00000000000..363a8dd444a --- /dev/null +++ b/boa_engine/src/vm/opcode/unary_ops/logical.rs @@ -0,0 +1,22 @@ +use crate::{ + vm::{opcode::Operation, ShouldExit}, + Context, JsResult, +}; + +/// `LogicalNot` implements the Opcode Operation for `Opcode::LogicalNot` +/// +/// Operation: +/// - Unary logical `!` operator. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct LogicalNot; + +impl Operation for LogicalNot { + const NAME: &'static str = "LogicalNot"; + const INSTRUCTION: &'static str = "INST - LogicalNot"; + + fn execute(context: &mut Context) -> JsResult { + let value = context.vm.pop(); + context.vm.push(!value.to_boolean()); + Ok(ShouldExit::False) + } +} diff --git a/boa_engine/src/vm/opcode/unary_ops/mod.rs b/boa_engine/src/vm/opcode/unary_ops/mod.rs index 186bd6fa45e..daea12d340b 100644 --- a/boa_engine/src/vm/opcode/unary_ops/mod.rs +++ b/boa_engine/src/vm/opcode/unary_ops/mod.rs @@ -8,10 +8,18 @@ use std::ops::Neg as StdNeg; pub(crate) mod decrement; pub(crate) mod increment; +pub(crate) mod logical; +pub(crate) mod void; pub(crate) use decrement::*; pub(crate) use increment::*; +pub(crate) use logical::*; +pub(crate) use void::*; +/// `TypeOf` implements the Opcode Operation for `Opcode::TypeOf` +/// +/// Operation: +/// - Unary `typeof` operator. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct TypeOf; @@ -26,6 +34,10 @@ impl Operation for TypeOf { } } +/// `Pos` implements the Opcode Operation for `Opcode::Pos` +/// +/// Operation: +/// - Unary `+` operator. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct Pos; @@ -41,6 +53,10 @@ impl Operation for Pos { } } +/// `Neg` implements the Opcode Operation for `Opcode::Neg` +/// +/// Operation: +/// - Unary `-` operator. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct Neg; @@ -58,6 +74,10 @@ impl Operation for Neg { } } +/// `BitNot` implements the Opcode Operation for `Opcode::BitNot` +/// +/// Operation: +/// - Unary bitwise `~` operator. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct BitNot; diff --git a/boa_engine/src/vm/opcode/void/mod.rs b/boa_engine/src/vm/opcode/unary_ops/void.rs similarity index 80% rename from boa_engine/src/vm/opcode/void/mod.rs rename to boa_engine/src/vm/opcode/unary_ops/void.rs index 2f305e35be9..19da829fddd 100644 --- a/boa_engine/src/vm/opcode/void/mod.rs +++ b/boa_engine/src/vm/opcode/unary_ops/void.rs @@ -3,6 +3,10 @@ use crate::{ Context, JsResult, JsValue, }; +/// `Void` implements the Opcode Operation for `Opcode::Void` +/// +/// Operation: +/// - Unary `void` operator. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct Void; diff --git a/boa_engine/src/vm/opcode/value/mod.rs b/boa_engine/src/vm/opcode/value/mod.rs index 876e5ff6d42..e9813f645d9 100644 --- a/boa_engine/src/vm/opcode/value/mod.rs +++ b/boa_engine/src/vm/opcode/value/mod.rs @@ -4,6 +4,10 @@ use crate::{ Context, JsResult, }; +/// `ValueNotNullOrUndefined` implements the Opcode Operation for `Opcode::ValueNotNullOrUndefined` +/// +/// Operation: +/// - Require the stack value to be neither null nor undefined. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct ValueNotNullOrUndefined; From 5698bde552b74e1c7388816196fc3fe6f1b4b525 Mon Sep 17 00:00:00 2001 From: raskad <32105367+raskad@users.noreply.github.com> Date: Sat, 22 Oct 2022 15:38:47 +0200 Subject: [PATCH 12/12] Trigger Benchmark CI