Browse Source

Implement asynchronous evaluation of scripts (#3044)

* Implement asynchronous evaluation of scripts

* cargo fmt

* FIx fuzz build

* Reduce execution table size

---------

Co-authored-by: Haled Odat <8566042+HalidOdat@users.noreply.github.com>
pull/3403/head
José Julián Espina 1 year ago committed by GitHub
parent
commit
9ef368f170
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 52
      boa_engine/src/script.rs
  2. 123
      boa_engine/src/vm/mod.rs
  3. 3
      boa_engine/src/vm/opcode/await/mod.rs
  4. 3
      boa_engine/src/vm/opcode/binary_ops/logical.rs
  5. 1
      boa_engine/src/vm/opcode/binary_ops/macro_defined.rs
  6. 6
      boa_engine/src/vm/opcode/binary_ops/mod.rs
  7. 9
      boa_engine/src/vm/opcode/call/mod.rs
  8. 1
      boa_engine/src/vm/opcode/concat/mod.rs
  9. 6
      boa_engine/src/vm/opcode/control_flow/jump.rs
  10. 4
      boa_engine/src/vm/opcode/control_flow/return.rs
  11. 5
      boa_engine/src/vm/opcode/control_flow/throw.rs
  12. 1
      boa_engine/src/vm/opcode/copy/mod.rs
  13. 4
      boa_engine/src/vm/opcode/define/class/getter.rs
  14. 4
      boa_engine/src/vm/opcode/define/class/method.rs
  15. 4
      boa_engine/src/vm/opcode/define/class/setter.rs
  16. 3
      boa_engine/src/vm/opcode/define/mod.rs
  17. 2
      boa_engine/src/vm/opcode/define/own_property.rs
  18. 4
      boa_engine/src/vm/opcode/delete/mod.rs
  19. 1
      boa_engine/src/vm/opcode/dup/mod.rs
  20. 7
      boa_engine/src/vm/opcode/environment/mod.rs
  21. 6
      boa_engine/src/vm/opcode/generator/mod.rs
  22. 2
      boa_engine/src/vm/opcode/generator/yield_stm.rs
  23. 1
      boa_engine/src/vm/opcode/get/argument.rs
  24. 4
      boa_engine/src/vm/opcode/get/function.rs
  25. 2
      boa_engine/src/vm/opcode/get/generator.rs
  26. 4
      boa_engine/src/vm/opcode/get/name.rs
  27. 1
      boa_engine/src/vm/opcode/get/private.rs
  28. 3
      boa_engine/src/vm/opcode/get/property.rs
  29. 1
      boa_engine/src/vm/opcode/iteration/for_in.rs
  30. 2
      boa_engine/src/vm/opcode/iteration/get.rs
  31. 12
      boa_engine/src/vm/opcode/iteration/iterator.rs
  32. 1
      boa_engine/src/vm/opcode/iteration/loop_ops.rs
  33. 2
      boa_engine/src/vm/opcode/meta/mod.rs
  34. 42
      boa_engine/src/vm/opcode/mod.rs
  35. 26
      boa_engine/src/vm/opcode/modifier.rs
  36. 2
      boa_engine/src/vm/opcode/new/mod.rs
  37. 2
      boa_engine/src/vm/opcode/nop/mod.rs
  38. 2
      boa_engine/src/vm/opcode/pop/mod.rs
  39. 4
      boa_engine/src/vm/opcode/push/array.rs
  40. 2
      boa_engine/src/vm/opcode/push/class/field.rs
  41. 1
      boa_engine/src/vm/opcode/push/class/mod.rs
  42. 3
      boa_engine/src/vm/opcode/push/class/private.rs
  43. 4
      boa_engine/src/vm/opcode/push/environment.rs
  44. 2
      boa_engine/src/vm/opcode/push/literal.rs
  45. 1
      boa_engine/src/vm/opcode/push/mod.rs
  46. 2
      boa_engine/src/vm/opcode/push/numbers.rs
  47. 1
      boa_engine/src/vm/opcode/push/object.rs
  48. 1
      boa_engine/src/vm/opcode/require/mod.rs
  49. 1
      boa_engine/src/vm/opcode/rest_parameter/mod.rs
  50. 1
      boa_engine/src/vm/opcode/set/class_prototype.rs
  51. 1
      boa_engine/src/vm/opcode/set/home_object.rs
  52. 3
      boa_engine/src/vm/opcode/set/name.rs
  53. 5
      boa_engine/src/vm/opcode/set/private.rs
  54. 7
      boa_engine/src/vm/opcode/set/property.rs
  55. 1
      boa_engine/src/vm/opcode/set/prototype.rs
  56. 3
      boa_engine/src/vm/opcode/swap/mod.rs
  57. 2
      boa_engine/src/vm/opcode/switch/mod.rs
  58. 2
      boa_engine/src/vm/opcode/templates/mod.rs
  59. 2
      boa_engine/src/vm/opcode/to/mod.rs
  60. 2
      boa_engine/src/vm/opcode/unary_ops/decrement.rs
  61. 2
      boa_engine/src/vm/opcode/unary_ops/increment.rs
  62. 1
      boa_engine/src/vm/opcode/unary_ops/logical.rs
  63. 4
      boa_engine/src/vm/opcode/unary_ops/mod.rs
  64. 1
      boa_engine/src/vm/opcode/unary_ops/void.rs
  65. 2
      boa_engine/src/vm/opcode/value/mod.rs

52
boa_engine/src/script.rs

@ -146,6 +146,52 @@ impl Script {
pub fn evaluate(&self, context: &mut Context<'_>) -> JsResult<JsValue> {
let _timer = Profiler::global().start_event("Execution", "Main");
self.prepare_run(context)?;
let record = context.run();
context.vm.pop_frame();
context.clear_kept_objects();
record.consume()
}
/// Evaluates this script and returns its result, periodically yielding to the executor
/// in order to avoid blocking the current thread.
///
/// This uses an implementation defined amount of "clock cycles" that need to pass before
/// execution is suspended. See [`Script::evaluate_async_with_budget`] if you want to also
/// customize this parameter.
#[allow(clippy::future_not_send)]
pub async fn evaluate_async(&self, context: &mut Context<'_>) -> JsResult<JsValue> {
self.evaluate_async_with_budget(context, 256).await
}
/// Evaluates this script and returns its result, yielding to the executor each time `budget`
/// number of "clock cycles" pass.
///
/// Note that "clock cycle" is in quotation marks because we can't determine exactly how many
/// CPU clock cycles a VM instruction will take, but all instructions have a "cost" associated
/// with them that depends on their individual complexity. We'd recommend benchmarking with
/// different budget sizes in order to find the ideal yielding time for your application.
#[allow(clippy::future_not_send)]
pub async fn evaluate_async_with_budget(
&self,
context: &mut Context<'_>,
budget: u32,
) -> JsResult<JsValue> {
let _timer = Profiler::global().start_event("Async Execution", "Main");
self.prepare_run(context)?;
let record = context.run_async_with_budget(budget).await;
context.vm.pop_frame();
context.clear_kept_objects();
record.consume()
}
fn prepare_run(&self, context: &mut Context<'_>) -> JsResult<()> {
let codeblock = self.codeblock(context)?;
let env_fp = context.vm.environments.len() as u32;
@ -165,11 +211,7 @@ impl Script {
// TODO: Here should be https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
self.realm().resize_global_env();
let record = context.run();
context.vm.pop_frame();
context.clear_kept_objects();
record.consume()
Ok(())
}
}

123
boa_engine/src/vm/mod.rs

@ -11,7 +11,7 @@ use crate::{
use boa_gc::{custom_trace, Finalize, Trace};
use boa_profiler::Profiler;
use std::mem::size_of;
use std::{future::Future, mem::size_of, ops::ControlFlow, pin::Pin, task};
#[cfg(feature = "trace")]
use boa_interner::ToInternedString;
@ -292,7 +292,10 @@ impl Context<'_> {
);
}
fn trace_execute_instruction(&mut self) -> JsResult<CompletionType> {
fn trace_execute_instruction<F>(&mut self, f: F) -> JsResult<CompletionType>
where
F: FnOnce(Opcode, &mut Context<'_>) -> JsResult<CompletionType>,
{
let bytecodes = &self.vm.frame().code_block.bytecode;
let pc = self.vm.frame().pc as usize;
let (_, varying_operand_kind, instruction) = InstructionIterator::with_pc(bytecodes, pc)
@ -322,7 +325,7 @@ impl Context<'_> {
}
let instant = Instant::now();
let result = self.execute_instruction();
let result = self.execute_instruction(f);
let duration = instant.elapsed();
let fp = self.vm.frames.last().map(|frame| frame.fp as usize);
@ -370,7 +373,10 @@ impl Context<'_> {
}
impl Context<'_> {
fn execute_instruction(&mut self) -> JsResult<CompletionType> {
fn execute_instruction<F>(&mut self, f: F) -> JsResult<CompletionType>
where
F: FnOnce(Opcode, &mut Context<'_>) -> JsResult<CompletionType>,
{
let opcode: Opcode = {
let _timer = Profiler::global().start_event("Opcode retrieval", "vm");
@ -384,37 +390,32 @@ impl Context<'_> {
let _timer = Profiler::global().start_event(opcode.as_instruction_str(), "vm");
opcode.execute(self)
}
pub(crate) fn run(&mut self) -> CompletionRecord {
let _timer = Profiler::global().start_event("run", "vm");
#[cfg(feature = "trace")]
if self.vm.trace {
self.trace_call_frame();
f(opcode, self)
}
'instruction: loop {
fn execute_one<F>(&mut self, f: F) -> ControlFlow<CompletionRecord>
where
F: FnOnce(Opcode, &mut Context<'_>) -> JsResult<CompletionType>,
{
#[cfg(feature = "fuzz")]
{
if self.instructions_remaining == 0 {
return CompletionRecord::Throw(JsError::from_native(
return ControlFlow::Break(CompletionRecord::Throw(JsError::from_native(
JsNativeError::no_instructions_remain(),
));
)));
}
self.instructions_remaining -= 1;
}
#[cfg(feature = "trace")]
let result = if self.vm.trace || self.vm.frame().code_block.traceable() {
self.trace_execute_instruction()
self.trace_execute_instruction(f)
} else {
self.execute_instruction()
self.execute_instruction(f)
};
#[cfg(not(feature = "trace"))]
let result = self.execute_instruction();
let result = self.execute_instruction(f);
let result = match result {
Ok(result) => result,
@ -435,14 +436,14 @@ impl Context<'_> {
}
self.vm.environments.truncate(env_fp);
self.vm.stack.truncate(fp);
return CompletionRecord::Throw(err);
return ControlFlow::Break(CompletionRecord::Throw(err));
}
// Note: -1 because we increment after fetching the opcode.
let pc = self.vm.frame().pc.saturating_sub(1);
if self.vm.handle_exception_at(pc) {
self.vm.pending_exception = Some(err);
continue;
return ControlFlow::Continue(());
}
// Inject realm before crossing the function boundry
@ -460,7 +461,7 @@ impl Context<'_> {
let result = self.vm.take_return_value();
if self.vm.frame().exit_early() {
return CompletionRecord::Normal(result);
return ControlFlow::Break(CompletionRecord::Normal(result));
}
self.vm.push(result);
@ -472,12 +473,12 @@ impl Context<'_> {
if self.vm.frame().exit_early() {
self.vm.environments.truncate(env_fp as usize);
self.vm.stack.truncate(fp as usize);
return CompletionRecord::Throw(
return ControlFlow::Break(CompletionRecord::Throw(
self.vm
.pending_exception
.take()
.expect("Err must exist for a CompletionType::Throw"),
);
));
}
self.vm.pop_frame();
@ -489,16 +490,16 @@ impl Context<'_> {
let exit_early = frame.exit_early();
if self.vm.handle_exception_at(pc) {
continue 'instruction;
return ControlFlow::Continue(());
}
if exit_early {
return CompletionRecord::Throw(
return ControlFlow::Break(CompletionRecord::Throw(
self.vm
.pending_exception
.take()
.expect("Err must exist for a CompletionType::Throw"),
);
));
}
self.vm.pop_frame();
@ -510,13 +511,58 @@ impl Context<'_> {
CompletionType::Yield => {
let result = self.vm.take_return_value();
if self.vm.frame().exit_early() {
return CompletionRecord::Return(result);
return ControlFlow::Break(CompletionRecord::Return(result));
}
self.vm.push(result);
self.vm.pop_frame();
}
}
ControlFlow::Continue(())
}
/// Runs the current frame to completion, yielding to the caller each time `budget`
/// "clock cycles" have passed.
#[allow(clippy::future_not_send)]
pub(crate) async fn run_async_with_budget(&mut self, budget: u32) -> CompletionRecord {
let _timer = Profiler::global().start_event("run_async_with_budget", "vm");
#[cfg(feature = "trace")]
if self.vm.trace {
self.trace_call_frame();
}
let mut runtime_budget: u32 = budget;
loop {
match self.execute_one(|opcode, context| {
opcode.spend_budget_and_execute(context, &mut runtime_budget)
}) {
ControlFlow::Continue(()) => {}
ControlFlow::Break(record) => return record,
}
if runtime_budget == 0 {
runtime_budget = budget;
yield_now().await;
}
}
}
pub(crate) fn run(&mut self) -> CompletionRecord {
let _timer = Profiler::global().start_event("run", "vm");
#[cfg(feature = "trace")]
if self.vm.trace {
self.trace_call_frame();
}
loop {
match self.execute_one(Opcode::execute) {
ControlFlow::Continue(()) => {}
ControlFlow::Break(value) => return value,
}
}
}
@ -538,3 +584,24 @@ impl Context<'_> {
Ok(())
}
}
/// Yields once to the executor.
fn yield_now() -> impl Future<Output = ()> {
struct YieldNow(bool);
impl Future for YieldNow {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
if self.0 {
task::Poll::Ready(())
} else {
self.0 = true;
cx.waker().wake_by_ref();
task::Poll::Pending
}
}
}
YieldNow(false)
}

3
boa_engine/src/vm/opcode/await/mod.rs

@ -18,6 +18,7 @@ pub(crate) struct Await;
impl Operation for Await {
const NAME: &'static str = "Await";
const INSTRUCTION: &'static str = "INST - Await";
const COST: u8 = 5;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();
@ -150,6 +151,7 @@ pub(crate) struct CreatePromiseCapability;
impl Operation for CreatePromiseCapability {
const NAME: &'static str = "CreatePromiseCapability";
const INSTRUCTION: &'static str = "INST - CreatePromiseCapability";
const COST: u8 = 8;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
if context.vm.frame().promise_capability.is_some() {
@ -177,6 +179,7 @@ pub(crate) struct CompletePromiseCapability;
impl Operation for CompletePromiseCapability {
const NAME: &'static str = "CompletePromiseCapability";
const INSTRUCTION: &'static str = "INST - CompletePromiseCapability";
const COST: u8 = 8;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
// If the current executing function is an async function we have to resolve/reject it's promise at the end.

3
boa_engine/src/vm/opcode/binary_ops/logical.rs

@ -13,6 +13,7 @@ pub(crate) struct LogicalAnd;
impl Operation for LogicalAnd {
const NAME: &'static str = "LogicalAnd";
const INSTRUCTION: &'static str = "INST - LogicalAnd";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let exit = context.vm.read::<u32>();
@ -35,6 +36,7 @@ pub(crate) struct LogicalOr;
impl Operation for LogicalOr {
const NAME: &'static str = "LogicalOr";
const INSTRUCTION: &'static str = "INST - LogicalOr";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let exit = context.vm.read::<u32>();
@ -57,6 +59,7 @@ pub(crate) struct Coalesce;
impl Operation for Coalesce {
const NAME: &'static str = "Coalesce";
const INSTRUCTION: &'static str = "INST - Coalesce";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let exit = context.vm.read::<u32>();

1
boa_engine/src/vm/opcode/binary_ops/macro_defined.rs

@ -15,6 +15,7 @@ macro_rules! implement_bin_ops {
impl Operation for $name {
const NAME: &'static str = stringify!($name);
const INSTRUCTION: &'static str = stringify!("INST - " + $name);
const COST: u8 = 2;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let rhs = context.vm.pop();

6
boa_engine/src/vm/opcode/binary_ops/mod.rs

@ -20,6 +20,7 @@ pub(crate) struct NotEq;
impl Operation for NotEq {
const NAME: &'static str = "NotEq";
const INSTRUCTION: &'static str = "INST - NotEq";
const COST: u8 = 2;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let rhs = context.vm.pop();
@ -40,6 +41,7 @@ pub(crate) struct StrictEq;
impl Operation for StrictEq {
const NAME: &'static str = "StrictEq";
const INSTRUCTION: &'static str = "INST - StrictEq";
const COST: u8 = 2;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let rhs = context.vm.pop();
@ -59,6 +61,7 @@ pub(crate) struct StrictNotEq;
impl Operation for StrictNotEq {
const NAME: &'static str = "StrictNotEq";
const INSTRUCTION: &'static str = "INST - StrictNotEq";
const COST: u8 = 2;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let rhs = context.vm.pop();
@ -78,6 +81,7 @@ pub(crate) struct In;
impl Operation for In {
const NAME: &'static str = "In";
const INSTRUCTION: &'static str = "INST - In";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let rhs = context.vm.pop();
@ -137,6 +141,7 @@ impl InPrivate {
impl Operation for InPrivate {
const NAME: &'static str = "InPrivate";
const INSTRUCTION: &'static str = "INST - InPrivate";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
@ -164,6 +169,7 @@ pub(crate) struct InstanceOf;
impl Operation for InstanceOf {
const NAME: &'static str = "InstanceOf";
const INSTRUCTION: &'static str = "INST - InstanceOf";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let target = context.vm.pop();

9
boa_engine/src/vm/opcode/call/mod.rs

@ -63,6 +63,9 @@ impl CallEval {
impl Operation for CallEval {
const NAME: &'static str = "CallEval";
const INSTRUCTION: &'static str = "INST - CallEval";
// TODO: Calls will require a big refactor in order to track
// the cost of the call.
const COST: u8 = 5;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let argument_count = context.vm.read::<u8>();
@ -90,6 +93,9 @@ pub(crate) struct CallEvalSpread;
impl Operation for CallEvalSpread {
const NAME: &'static str = "CallEvalSpread";
const INSTRUCTION: &'static str = "INST - CallEvalSpread";
// TODO: Calls will require a big refactor in order to track
// the cost of the call.
const COST: u8 = 5;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
// Get the arguments that are stored as an array object on the stack.
@ -176,6 +182,7 @@ impl Call {
impl Operation for Call {
const NAME: &'static str = "Call";
const INSTRUCTION: &'static str = "INST - Call";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let argument_count = context.vm.read::<u8>();
@ -199,6 +206,7 @@ pub(crate) struct CallSpread;
impl Operation for CallSpread {
const NAME: &'static str = "CallSpread";
const INSTRUCTION: &'static str = "INST - CallSpread";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
// Get the arguments that are stored as an array object on the stack.
@ -240,6 +248,7 @@ pub(crate) struct ImportCall;
impl Operation for ImportCall {
const NAME: &'static str = "ImportCall";
const INSTRUCTION: &'static str = "INST - ImportCall";
const COST: u8 = 15;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
// Import Calls

1
boa_engine/src/vm/opcode/concat/mod.rs

@ -31,6 +31,7 @@ impl ConcatToString {
impl Operation for ConcatToString {
const NAME: &'static str = "ConcatToString";
const INSTRUCTION: &'static str = "INST - ConcatToString";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value_count = context.vm.read::<u8>() as usize;

6
boa_engine/src/vm/opcode/control_flow/jump.rs

@ -13,6 +13,7 @@ pub(crate) struct Jump;
impl Operation for Jump {
const NAME: &'static str = "Jump";
const INSTRUCTION: &'static str = "INST - Jump";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let address = context.vm.read::<u32>();
@ -31,6 +32,7 @@ pub(crate) struct JumpIfTrue;
impl Operation for JumpIfTrue {
const NAME: &'static str = "JumpIfTrue";
const INSTRUCTION: &'static str = "INST - JumpIfTrue";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let address = context.vm.read::<u32>();
@ -51,6 +53,7 @@ pub(crate) struct JumpIfFalse;
impl Operation for JumpIfFalse {
const NAME: &'static str = "JumpIfFalse";
const INSTRUCTION: &'static str = "INST - JumpIfFalse";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let address = context.vm.read::<u32>();
@ -71,6 +74,7 @@ pub(crate) struct JumpIfNotUndefined;
impl Operation for JumpIfNotUndefined {
const NAME: &'static str = "JumpIfNotUndefined";
const INSTRUCTION: &'static str = "INST - JumpIfNotUndefined";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let address = context.vm.read::<u32>();
@ -93,6 +97,7 @@ pub(crate) struct JumpIfNullOrUndefined;
impl Operation for JumpIfNullOrUndefined {
const NAME: &'static str = "JumpIfNullOrUndefined";
const INSTRUCTION: &'static str = "INST - JumpIfNullOrUndefined";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let address = context.vm.read::<u32>();
@ -116,6 +121,7 @@ pub(crate) struct JumpTable;
impl Operation for JumpTable {
const NAME: &'static str = "JumpTable";
const INSTRUCTION: &'static str = "INST - JumpTable";
const COST: u8 = 5;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let default = context.vm.read::<u32>();

4
boa_engine/src/vm/opcode/control_flow/return.rs

@ -13,6 +13,7 @@ pub(crate) struct Return;
impl Operation for Return {
const NAME: &'static str = "Return";
const INSTRUCTION: &'static str = "INST - Return";
const COST: u8 = 4;
fn execute(_context: &mut Context<'_>) -> JsResult<CompletionType> {
Ok(CompletionType::Return)
@ -29,6 +30,7 @@ pub(crate) struct CheckReturn;
impl Operation for CheckReturn {
const NAME: &'static str = "CheckReturn";
const INSTRUCTION: &'static str = "INST - CheckReturn";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
if !context.vm.frame().construct() {
@ -80,6 +82,7 @@ pub(crate) struct GetReturnValue;
impl Operation for GetReturnValue {
const NAME: &'static str = "GetReturnValue";
const INSTRUCTION: &'static str = "INST - GetReturnValue";
const COST: u8 = 2;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.get_return_value();
@ -98,6 +101,7 @@ pub(crate) struct SetReturnValue;
impl Operation for SetReturnValue {
const NAME: &'static str = "SetReturnValue";
const INSTRUCTION: &'static str = "INST - SetReturnValue";
const COST: u8 = 2;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();

5
boa_engine/src/vm/opcode/control_flow/throw.rs

@ -13,6 +13,7 @@ pub(crate) struct Throw;
impl Operation for Throw {
const NAME: &'static str = "Throw";
const INSTRUCTION: &'static str = "INST - Throw";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let error = JsError::from_opaque(context.vm.pop());
@ -38,6 +39,7 @@ pub(crate) struct ReThrow;
impl Operation for ReThrow {
const NAME: &'static str = "ReThrow";
const INSTRUCTION: &'static str = "INST - ReThrow";
const COST: u8 = 2;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
// Note: -1 because we increment after fetching the opcode.
@ -69,6 +71,7 @@ pub(crate) struct Exception;
impl Operation for Exception {
const NAME: &'static str = "Exception";
const INSTRUCTION: &'static str = "INST - Exception";
const COST: u8 = 2;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
if let Some(error) = context.vm.pending_exception.take() {
@ -96,6 +99,7 @@ pub(crate) struct MaybeException;
impl Operation for MaybeException {
const NAME: &'static str = "MaybeException";
const INSTRUCTION: &'static str = "INST - MaybeException";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
if let Some(error) = context.vm.pending_exception.take() {
@ -133,6 +137,7 @@ impl ThrowNewTypeError {
impl Operation for ThrowNewTypeError {
const NAME: &'static str = "ThrowNewTypeError";
const INSTRUCTION: &'static str = "INST - ThrowNewTypeError";
const COST: u8 = 2;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;

1
boa_engine/src/vm/opcode/copy/mod.rs

@ -43,6 +43,7 @@ impl CopyDataProperties {
impl Operation for CopyDataProperties {
const NAME: &'static str = "CopyDataProperties";
const INSTRUCTION: &'static str = "INST - CopyDataProperties";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let excluded_key_count = context.vm.read::<u8>() as usize;

4
boa_engine/src/vm/opcode/define/class/getter.rs

@ -51,6 +51,7 @@ impl DefineClassStaticGetterByName {
impl Operation for DefineClassStaticGetterByName {
const NAME: &'static str = "DefineClassStaticGetterByName";
const INSTRUCTION: &'static str = "INST - DefineClassStaticGetterByName";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
@ -114,6 +115,7 @@ impl DefineClassGetterByName {
impl Operation for DefineClassGetterByName {
const NAME: &'static str = "DefineClassGetterByName";
const INSTRUCTION: &'static str = "INST - DefineClassGetterByName";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
@ -141,6 +143,7 @@ pub(crate) struct DefineClassStaticGetterByValue;
impl Operation for DefineClassStaticGetterByValue {
const NAME: &'static str = "DefineClassStaticGetterByValue";
const INSTRUCTION: &'static str = "INST - DefineClassStaticGetterByValue";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let function = context.vm.pop();
@ -190,6 +193,7 @@ pub(crate) struct DefineClassGetterByValue;
impl Operation for DefineClassGetterByValue {
const NAME: &'static str = "DefineClassGetterByValue";
const INSTRUCTION: &'static str = "INST - DefineClassGetterByValue";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let function = context.vm.pop();

4
boa_engine/src/vm/opcode/define/class/method.rs

@ -47,6 +47,7 @@ impl DefineClassStaticMethodByName {
impl Operation for DefineClassStaticMethodByName {
const NAME: &'static str = "DefineClassStaticMethodByName";
const INSTRUCTION: &'static str = "INST - DefineClassStaticMethodByName";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
@ -106,6 +107,7 @@ impl DefineClassMethodByName {
impl Operation for DefineClassMethodByName {
const NAME: &'static str = "DefineClassMethodByName";
const INSTRUCTION: &'static str = "INST - DefineClassMethodByName";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
@ -133,6 +135,7 @@ pub(crate) struct DefineClassStaticMethodByValue;
impl Operation for DefineClassStaticMethodByValue {
const NAME: &'static str = "DefineClassStaticMethodByValue";
const INSTRUCTION: &'static str = "INST - DefineClassStaticMethodByValue";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let function = context.vm.pop();
@ -178,6 +181,7 @@ pub(crate) struct DefineClassMethodByValue;
impl Operation for DefineClassMethodByValue {
const NAME: &'static str = "DefineClassMethodByValue";
const INSTRUCTION: &'static str = "INST - DefineClassMethodByValue";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let function = context.vm.pop();

4
boa_engine/src/vm/opcode/define/class/setter.rs

@ -52,6 +52,7 @@ impl DefineClassStaticSetterByName {
impl Operation for DefineClassStaticSetterByName {
const NAME: &'static str = "DefineClassStaticSetterByName";
const INSTRUCTION: &'static str = "INST - DefineClassStaticSetterByName";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
@ -117,6 +118,7 @@ impl DefineClassSetterByName {
impl Operation for DefineClassSetterByName {
const NAME: &'static str = "DefineClassSetterByName";
const INSTRUCTION: &'static str = "INST - DefineClassSetterByName";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
@ -144,6 +146,7 @@ pub(crate) struct DefineClassStaticSetterByValue;
impl Operation for DefineClassStaticSetterByValue {
const NAME: &'static str = "DefineClassStaticSetterByValue";
const INSTRUCTION: &'static str = "INST - DefineClassStaticSetterByValue";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let function = context.vm.pop();
@ -195,6 +198,7 @@ pub(crate) struct DefineClassSetterByValue;
impl Operation for DefineClassSetterByValue {
const NAME: &'static str = "DefineClassSetterByValue";
const INSTRUCTION: &'static str = "INST - DefineClassSetterByValue";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let function = context.vm.pop();

3
boa_engine/src/vm/opcode/define/mod.rs

@ -38,6 +38,7 @@ impl DefVar {
impl Operation for DefVar {
const NAME: &'static str = "DefVar";
const INSTRUCTION: &'static str = "INST - DefVar";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();
@ -80,6 +81,7 @@ impl DefInitVar {
impl Operation for DefInitVar {
const NAME: &'static str = "DefInitVar";
const INSTRUCTION: &'static str = "INST - DefInitVar";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();
@ -122,6 +124,7 @@ impl PutLexicalValue {
impl Operation for PutLexicalValue {
const NAME: &'static str = "PutLexicalValue";
const INSTRUCTION: &'static str = "INST - PutLexicalValue";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();

2
boa_engine/src/vm/opcode/define/own_property.rs

@ -38,6 +38,7 @@ impl DefineOwnPropertyByName {
impl Operation for DefineOwnPropertyByName {
const NAME: &'static str = "DefineOwnPropertyByName";
const INSTRUCTION: &'static str = "INST - DefineOwnPropertyByName";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
@ -65,6 +66,7 @@ pub(crate) struct DefineOwnPropertyByValue;
impl Operation for DefineOwnPropertyByValue {
const NAME: &'static str = "DefineOwnPropertyByValue";
const INSTRUCTION: &'static str = "INST - DefineOwnPropertyByValue";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();

4
boa_engine/src/vm/opcode/delete/mod.rs

@ -30,6 +30,7 @@ impl DeletePropertyByName {
impl Operation for DeletePropertyByName {
const NAME: &'static str = "DeletePropertyByName";
const INSTRUCTION: &'static str = "INST - DeletePropertyByName";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
@ -57,6 +58,7 @@ pub(crate) struct DeletePropertyByValue;
impl Operation for DeletePropertyByValue {
const NAME: &'static str = "DeletePropertyByValue";
const INSTRUCTION: &'static str = "INST - DeletePropertyByValue";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let key_value = context.vm.pop();
@ -97,6 +99,7 @@ impl DeleteName {
impl Operation for DeleteName {
const NAME: &'static str = "DeleteName";
const INSTRUCTION: &'static str = "INST - DeleteName";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();
@ -124,6 +127,7 @@ pub(crate) struct DeleteSuperThrow;
impl Operation for DeleteSuperThrow {
const NAME: &'static str = "DeleteSuperThrow";
const INSTRUCTION: &'static str = "INST - DeleteSuperThrow";
const COST: u8 = 2;
fn execute(_: &mut Context<'_>) -> JsResult<CompletionType> {
Err(JsNativeError::reference()

1
boa_engine/src/vm/opcode/dup/mod.rs

@ -13,6 +13,7 @@ pub(crate) struct Dup;
impl Operation for Dup {
const NAME: &'static str = "Dup";
const INSTRUCTION: &'static str = "INST - Dup";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();

7
boa_engine/src/vm/opcode/environment/mod.rs

@ -14,6 +14,7 @@ pub(crate) struct This;
impl Operation for This {
const NAME: &'static str = "This";
const INSTRUCTION: &'static str = "INST - This";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let this = context.vm.environments.get_this_binding()?;
@ -32,6 +33,7 @@ pub(crate) struct Super;
impl Operation for Super {
const NAME: &'static str = "Super";
const INSTRUCTION: &'static str = "INST - Super";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let home_object = {
@ -72,6 +74,7 @@ pub(crate) struct SuperCallPrepare;
impl Operation for SuperCallPrepare {
const NAME: &'static str = "SuperCallPrepare";
const INSTRUCTION: &'static str = "INST - SuperCallPrepare";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let this_env = context
@ -134,6 +137,7 @@ impl SuperCall {
impl Operation for SuperCall {
const NAME: &'static str = "SuperCall";
const INSTRUCTION: &'static str = "INST - SuperCall";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value_count = context.vm.read::<u8>() as usize;
@ -161,6 +165,7 @@ pub(crate) struct SuperCallSpread;
impl Operation for SuperCallSpread {
const NAME: &'static str = "SuperCallSpread";
const INSTRUCTION: &'static str = "INST - SuperCallSpread";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
// Get the arguments that are stored as an array object on the stack.
@ -219,6 +224,7 @@ pub(crate) struct SuperCallDerived;
impl Operation for SuperCallDerived {
const NAME: &'static str = "SuperCallDerived";
const INSTRUCTION: &'static str = "INST - SuperCallDerived";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let argument_count = context.vm.frame().argument_count as usize;
@ -271,6 +277,7 @@ pub(crate) struct BindThisValue;
impl Operation for BindThisValue {
const NAME: &'static str = "BindThisValue";
const INSTRUCTION: &'static str = "INST - BindThisValue";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
// Taken from `SuperCall : super Arguments` steps 7-12.

6
boa_engine/src/vm/opcode/generator/mod.rs

@ -32,6 +32,7 @@ pub(crate) struct Generator;
impl Operation for Generator {
const NAME: &'static str = "Generator";
const INSTRUCTION: &'static str = "INST - Generator";
const COST: u8 = 8;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let r#async = context.vm.read::<u8>() != 0;
@ -128,6 +129,7 @@ pub(crate) struct AsyncGeneratorClose;
impl Operation for AsyncGeneratorClose {
const NAME: &'static str = "AsyncGeneratorClose";
const INSTRUCTION: &'static str = "INST - AsyncGeneratorClose";
const COST: u8 = 8;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
// Step 3.e-g in [AsyncGeneratorStart](https://tc39.es/ecma262/#sec-asyncgeneratorstart)
@ -176,6 +178,7 @@ pub(crate) struct GeneratorNext;
impl Operation for GeneratorNext {
const NAME: &'static str = "GeneratorNext";
const INSTRUCTION: &'static str = "INST - GeneratorNext";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let generator_resume_kind = context.vm.pop().to_generator_resume_kind();
@ -202,6 +205,7 @@ pub(crate) struct JumpIfNotResumeKind;
impl Operation for JumpIfNotResumeKind {
const NAME: &'static str = "JumpIfNotResumeKind";
const INSTRUCTION: &'static str = "INST - JumpIfNotResumeKind";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let exit = context.vm.read::<u32>();
@ -228,6 +232,7 @@ pub(crate) struct GeneratorDelegateNext;
impl Operation for GeneratorDelegateNext {
const NAME: &'static str = "GeneratorDelegateNext";
const INSTRUCTION: &'static str = "INST - GeneratorDelegateNext";
const COST: u8 = 18;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let throw_method_undefined = context.vm.read::<u32>();
@ -317,6 +322,7 @@ pub(crate) struct GeneratorDelegateResume;
impl Operation for GeneratorDelegateResume {
const NAME: &'static str = "GeneratorDelegateResume";
const INSTRUCTION: &'static str = "INST - GeneratorDelegateResume";
const COST: u8 = 7;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let return_gen = context.vm.read::<u32>();

2
boa_engine/src/vm/opcode/generator/yield_stm.rs

@ -14,6 +14,7 @@ pub(crate) struct GeneratorYield;
impl Operation for GeneratorYield {
const NAME: &'static str = "GeneratorYield";
const INSTRUCTION: &'static str = "INST - GeneratorYield";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();
@ -32,6 +33,7 @@ pub(crate) struct AsyncGeneratorYield;
impl Operation for AsyncGeneratorYield {
const NAME: &'static str = "AsyncGeneratorYield";
const INSTRUCTION: &'static str = "INST - AsyncGeneratorYield";
const COST: u8 = 8;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();

1
boa_engine/src/vm/opcode/get/argument.rs

@ -29,6 +29,7 @@ impl GetArgument {
impl Operation for GetArgument {
const NAME: &'static str = "GetArgument";
const INSTRUCTION: &'static str = "INST - GetArgument";
const COST: u8 = 2;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;

4
boa_engine/src/vm/opcode/get/function.rs

@ -23,6 +23,7 @@ impl GetArrowFunction {
impl Operation for GetArrowFunction {
const NAME: &'static str = "GetArrowFunction";
const INSTRUCTION: &'static str = "INST - GetArrowFunction";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
@ -60,6 +61,7 @@ impl GetAsyncArrowFunction {
impl Operation for GetAsyncArrowFunction {
const NAME: &'static str = "GetAsyncArrowFunction";
const INSTRUCTION: &'static str = "INST - GetAsyncArrowFunction";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
@ -101,6 +103,7 @@ impl GetFunction {
impl Operation for GetFunction {
const NAME: &'static str = "GetFunction";
const INSTRUCTION: &'static str = "INST - GetFunction";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
@ -145,6 +148,7 @@ impl GetFunctionAsync {
impl Operation for GetFunctionAsync {
const NAME: &'static str = "GetFunctionAsync";
const INSTRUCTION: &'static str = "INST - GetFunctionAsync";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;

2
boa_engine/src/vm/opcode/get/generator.rs

@ -23,6 +23,7 @@ impl GetGenerator {
impl Operation for GetGenerator {
const NAME: &'static str = "GetGenerator";
const INSTRUCTION: &'static str = "INST - GetGenerator";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
@ -60,6 +61,7 @@ impl GetGeneratorAsync {
impl Operation for GetGeneratorAsync {
const NAME: &'static str = "GetGeneratorAsync";
const INSTRUCTION: &'static str = "INST - GetGeneratorAsync";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;

4
boa_engine/src/vm/opcode/get/name.rs

@ -31,6 +31,7 @@ impl GetName {
impl Operation for GetName {
const NAME: &'static str = "GetName";
const INSTRUCTION: &'static str = "INST - GetName";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();
@ -69,6 +70,7 @@ impl GetLocator {
impl Operation for GetLocator {
const NAME: &'static str = "GetLocator";
const INSTRUCTION: &'static str = "INST - GetLocator";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();
@ -115,6 +117,7 @@ impl GetNameAndLocator {
impl Operation for GetNameAndLocator {
const NAME: &'static str = "GetNameAndLocator";
const INSTRUCTION: &'static str = "INST - GetNameAndLocator";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();
@ -169,6 +172,7 @@ impl GetNameOrUndefined {
impl Operation for GetNameOrUndefined {
const NAME: &'static str = "GetNameOrUndefined";
const INSTRUCTION: &'static str = "INST - GetNameOrUndefined";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();

1
boa_engine/src/vm/opcode/get/private.rs

@ -31,6 +31,7 @@ impl GetPrivateField {
impl Operation for GetPrivateField {
const NAME: &'static str = "GetPrivateField";
const INSTRUCTION: &'static str = "INST - GetPrivateField";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;

3
boa_engine/src/vm/opcode/get/property.rs

@ -32,6 +32,7 @@ impl GetPropertyByName {
impl Operation for GetPropertyByName {
const NAME: &'static str = "GetPropertyByName";
const INSTRUCTION: &'static str = "INST - GetPropertyByName";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();
@ -59,6 +60,7 @@ pub(crate) struct GetPropertyByValue;
impl Operation for GetPropertyByValue {
const NAME: &'static str = "GetPropertyByValue";
const INSTRUCTION: &'static str = "INST - GetPropertyByValue";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let key = context.vm.pop();
@ -105,6 +107,7 @@ pub(crate) struct GetPropertyByValuePush;
impl Operation for GetPropertyByValuePush {
const NAME: &'static str = "GetPropertyByValuePush";
const INSTRUCTION: &'static str = "INST - GetPropertyByValuePush";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let key = context.vm.pop();

1
boa_engine/src/vm/opcode/iteration/for_in.rs

@ -15,6 +15,7 @@ pub(crate) struct CreateForInIterator;
impl Operation for CreateForInIterator {
const NAME: &'static str = "CreateForInIterator";
const INSTRUCTION: &'static str = "INST - CreateForInIterator";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let object = context.vm.pop();

2
boa_engine/src/vm/opcode/iteration/get.rs

@ -14,6 +14,7 @@ pub(crate) struct GetIterator;
impl Operation for GetIterator {
const NAME: &'static str = "GetIterator";
const INSTRUCTION: &'static str = "INST - GetIterator";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let object = context.vm.pop();
@ -33,6 +34,7 @@ pub(crate) struct GetAsyncIterator;
impl Operation for GetAsyncIterator {
const NAME: &'static str = "GetAsyncIterator";
const INSTRUCTION: &'static str = "INST - GetAsyncIterator";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let object = context.vm.pop();

12
boa_engine/src/vm/opcode/iteration/iterator.rs

@ -17,6 +17,7 @@ pub(crate) struct IteratorNext;
impl Operation for IteratorNext {
const NAME: &'static str = "IteratorNext";
const INSTRUCTION: &'static str = "INST - IteratorNext";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let mut iterator = context
@ -44,6 +45,7 @@ pub(crate) struct IteratorNextWithoutPop;
impl Operation for IteratorNextWithoutPop {
const NAME: &'static str = "IteratorNextWithoutPop";
const INSTRUCTION: &'static str = "INST - IteratorNextWithoutPop";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let mut iterator = context
@ -74,6 +76,7 @@ pub(crate) struct IteratorFinishAsyncNext;
impl Operation for IteratorFinishAsyncNext {
const NAME: &'static str = "IteratorFinishAsyncNext";
const INSTRUCTION: &'static str = "INST - IteratorFinishAsyncNext";
const COST: u8 = 5;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let mut iterator = context
@ -115,6 +118,7 @@ pub(crate) struct IteratorResult;
impl Operation for IteratorResult {
const NAME: &'static str = "IteratorResult";
const INSTRUCTION: &'static str = "INST - IteratorResult";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let last_result = context
@ -143,6 +147,7 @@ pub(crate) struct IteratorValue;
impl Operation for IteratorValue {
const NAME: &'static str = "IteratorValue";
const INSTRUCTION: &'static str = "INST - IteratorValue";
const COST: u8 = 5;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let mut iterator = context
@ -171,6 +176,7 @@ pub(crate) struct IteratorValueWithoutPop;
impl Operation for IteratorValueWithoutPop {
const NAME: &'static str = "IteratorValueWithoutPop";
const INSTRUCTION: &'static str = "INST - IteratorValueWithoutPop";
const COST: u8 = 5;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let mut iterator = context
@ -199,6 +205,7 @@ pub(crate) struct IteratorDone;
impl Operation for IteratorDone {
const NAME: &'static str = "IteratorDone";
const INSTRUCTION: &'static str = "INST - IteratorDone";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let done = context
@ -225,6 +232,7 @@ pub(crate) struct IteratorReturn;
impl Operation for IteratorReturn {
const NAME: &'static str = "IteratorReturn";
const INSTRUCTION: &'static str = "INST - IteratorReturn";
const COST: u8 = 8;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let record = context
@ -261,6 +269,7 @@ pub(crate) struct IteratorToArray;
impl Operation for IteratorToArray {
const NAME: &'static str = "IteratorToArray";
const INSTRUCTION: &'static str = "INST - IteratorToArray";
const COST: u8 = 8;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let mut iterator = context
@ -314,6 +323,7 @@ pub(crate) struct IteratorPop;
impl Operation for IteratorPop {
const NAME: &'static str = "IteratorPop";
const INSTRUCTION: &'static str = "INST - IteratorPop";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
context.vm.frame_mut().iterators.pop();
@ -331,6 +341,7 @@ pub(crate) struct IteratorStackEmpty;
impl Operation for IteratorStackEmpty {
const NAME: &'static str = "IteratorStackEmpty";
const INSTRUCTION: &'static str = "INST - IteratorStackEmpty";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let is_empty = context.vm.frame().iterators.is_empty();
@ -349,6 +360,7 @@ pub(crate) struct CreateIteratorResult;
impl Operation for CreateIteratorResult {
const NAME: &'static str = "CreateIteratorResult";
const INSTRUCTION: &'static str = "INST - CreateIteratorResult";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();

1
boa_engine/src/vm/opcode/iteration/loop_ops.rs

@ -14,6 +14,7 @@ pub(crate) struct IncrementLoopIteration;
impl Operation for IncrementLoopIteration {
const NAME: &'static str = "IncrementLoopIteration";
const INSTRUCTION: &'static str = "INST - IncrementLoopIteration";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let previous_iteration_count = context.vm.frame_mut().loop_iteration_count;

2
boa_engine/src/vm/opcode/meta/mod.rs

@ -16,6 +16,7 @@ pub(crate) struct NewTarget;
impl Operation for NewTarget {
const NAME: &'static str = "NewTarget";
const INSTRUCTION: &'static str = "INST - NewTarget";
const COST: u8 = 2;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let new_target = if let Some(new_target) = context
@ -44,6 +45,7 @@ pub(crate) struct ImportMeta;
impl Operation for ImportMeta {
const NAME: &'static str = "ImportMeta";
const INSTRUCTION: &'static str = "INST - ImportMeta";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
// Meta Properties

42
boa_engine/src/vm/opcode/mod.rs

@ -396,11 +396,11 @@ macro_rules! generate_opcodes {
}
impl Opcode {
const MAX: usize = 2usize.pow(8) * 3;
const MAX: usize = 2usize.pow(8);
// TODO: see if this can be exposed on all features.
#[allow(unused)]
const NAMES: [&'static str; Self::MAX] = [
const NAMES: [&'static str; Self::MAX * 3] = [
$(<generate_opcodes!(name $Variant $(=> $mapping)?)>::NAME),*,
$(<generate_opcodes!(name $Variant $(=> $mapping)?)>::NAME),*,
$(<generate_opcodes!(name $Variant $(=> $mapping)?)>::NAME),*
@ -414,7 +414,7 @@ macro_rules! generate_opcodes {
Self::NAMES[self as usize]
}
const INSTRUCTIONS: [&'static str; Self::MAX] = [
const INSTRUCTIONS: [&'static str; Self::MAX * 3] = [
$(<generate_opcodes!(name $Variant $(=> $mapping)?)>::INSTRUCTION),*,
$(<generate_opcodes!(name $Variant $(=> $mapping)?)>::INSTRUCTION),*,
$(<generate_opcodes!(name $Variant $(=> $mapping)?)>::INSTRUCTION),*
@ -426,7 +426,29 @@ macro_rules! generate_opcodes {
Self::INSTRUCTIONS[self as usize]
}
const EXECUTE_FNS: [fn(&mut Context<'_>) -> JsResult<CompletionType>; Self::MAX] = [
const SPEND_FNS: [fn(&mut Context<'_>, &mut u32) -> JsResult<CompletionType>; Self::MAX] = [
$(<generate_opcodes!(name $Variant $(=> $mapping)?)>::spend_budget_and_execute),*,
];
/// Spends the cost of this opcode into the provided budget and executes it.
pub(super) fn spend_budget_and_execute(
self,
context: &mut Context<'_>,
budget: &mut u32
) -> JsResult<CompletionType> {
Self::SPEND_FNS[self as usize](context, budget)
}
const COSTS: [u8; Self::MAX] = [
$(<generate_opcodes!(name $Variant $(=> $mapping)?)>::COST),*,
];
/// Return the cost of this opcode.
pub(super) const fn cost(self) -> u8 {
Self::COSTS[self as usize]
}
const EXECUTE_FNS: [fn(&mut Context<'_>) -> JsResult<CompletionType>; Self::MAX * 3] = [
$(<generate_opcodes!(name $Variant $(=> $mapping)?)>::execute),*,
$(<generate_opcodes!(name $Variant $(=> $mapping)?)>::execute_with_u16_operands),*,
$(<generate_opcodes!(name $Variant $(=> $mapping)?)>::execute_with_u32_operands),*
@ -440,7 +462,7 @@ macro_rules! generate_opcodes {
/// This represents a VM instruction, it contains both opcode and operands.
///
// TODO: An instruction should be a representation of a valid executable instruction (opcode + operands),
// so variants like `ResevedN`, or operand width prefix modifiers, idealy shouldn't
// so variants like `ReservedN`, or operand width prefix modifiers, idealy shouldn't
// be a part of `Instruction`.
#[derive(Debug, Clone, PartialEq)]
#[repr(u8)]
@ -530,6 +552,7 @@ macro_rules! generate_opcodes {
pub(crate) trait Operation {
const NAME: &'static str;
const INSTRUCTION: &'static str;
const COST: u8;
/// Execute opcode with [`VaryingOperandKind::U8`] sized [`VaryingOperand`]s.
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType>;
@ -547,6 +570,15 @@ pub(crate) trait Operation {
fn execute_with_u32_operands(context: &mut Context<'_>) -> JsResult<CompletionType> {
Reserved::execute_with_u32_operands(context)
}
/// Spends the cost of this operation into `budget` and runs `execute`.
fn spend_budget_and_execute(
context: &mut Context<'_>,
budget: &mut u32,
) -> JsResult<CompletionType> {
*budget = budget.saturating_sub(u32::from(Self::COST));
Self::execute(context)
}
}
generate_opcodes! {

26
boa_engine/src/vm/opcode/modifier.rs

@ -12,11 +12,22 @@ pub(crate) struct U16Operands;
impl Operation for U16Operands {
const NAME: &'static str = "U16Operands";
const INSTRUCTION: &'static str = "INST - U16Operands";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let opcode = context.vm.read::<u8>() as usize;
Opcode::EXECUTE_FNS[256 + opcode](context)
Opcode::EXECUTE_FNS[Opcode::MAX + opcode](context)
}
fn spend_budget_and_execute(
context: &mut Context<'_>,
budget: &mut u32,
) -> JsResult<CompletionType> {
let opcode: Opcode = context.vm.read::<u8>().into();
*budget = budget.saturating_sub(u32::from(opcode.cost()) + u32::from(Self::COST));
Opcode::EXECUTE_FNS[Opcode::MAX + opcode as usize](context)
}
}
@ -30,10 +41,21 @@ pub(crate) struct U32Operands;
impl Operation for U32Operands {
const NAME: &'static str = "U32Operands";
const INSTRUCTION: &'static str = "INST - U32Operands";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let opcode = context.vm.read::<u8>() as usize;
Opcode::EXECUTE_FNS[256 * 2 + opcode](context)
Opcode::EXECUTE_FNS[Opcode::MAX * 2 + opcode](context)
}
fn spend_budget_and_execute(
context: &mut Context<'_>,
budget: &mut u32,
) -> JsResult<CompletionType> {
let opcode: Opcode = context.vm.read::<u8>().into();
*budget = budget.saturating_sub(u32::from(opcode.cost()) + u32::from(Self::COST));
Opcode::EXECUTE_FNS[Opcode::MAX * 2 + opcode as usize](context)
}
}

2
boa_engine/src/vm/opcode/new/mod.rs

@ -31,6 +31,7 @@ impl New {
impl Operation for New {
const NAME: &'static str = "New";
const INSTRUCTION: &'static str = "INST - New";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let argument_count = context.vm.read::<u8>() as usize;
@ -58,6 +59,7 @@ pub(crate) struct NewSpread;
impl Operation for NewSpread {
const NAME: &'static str = "NewSpread";
const INSTRUCTION: &'static str = "INST - NewSpread";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
// Get the arguments that are stored as an array object on the stack.

2
boa_engine/src/vm/opcode/nop/mod.rs

@ -13,6 +13,7 @@ pub(crate) struct Nop;
impl Operation for Nop {
const NAME: &'static str = "Nop";
const INSTRUCTION: &'static str = "INST - Nop";
const COST: u8 = 1;
fn execute(_: &mut Context<'_>) -> JsResult<CompletionType> {
Ok(CompletionType::Normal)
@ -29,6 +30,7 @@ pub(crate) struct Reserved;
impl Operation for Reserved {
const NAME: &'static str = "Reserved";
const INSTRUCTION: &'static str = "INST - Reserved";
const COST: u8 = 0;
fn execute(_: &mut Context<'_>) -> JsResult<CompletionType> {
unreachable!("Reserved opcodes are unreachable!")

2
boa_engine/src/vm/opcode/pop/mod.rs

@ -13,6 +13,7 @@ pub(crate) struct Pop;
impl Operation for Pop {
const NAME: &'static str = "Pop";
const INSTRUCTION: &'static str = "INST - Pop";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let _val = context.vm.pop();
@ -30,6 +31,7 @@ pub(crate) struct PopEnvironment;
impl Operation for PopEnvironment {
const NAME: &'static str = "PopEnvironment";
const INSTRUCTION: &'static str = "INST - PopEnvironment";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
context.vm.environments.pop();

4
boa_engine/src/vm/opcode/push/array.rs

@ -16,6 +16,7 @@ pub(crate) struct PushNewArray;
impl Operation for PushNewArray {
const NAME: &'static str = "PushNewArray";
const INSTRUCTION: &'static str = "INST - PushNewArray";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let array = context
@ -38,6 +39,7 @@ pub(crate) struct PushValueToArray;
impl Operation for PushValueToArray {
const NAME: &'static str = "PushValueToArray";
const INSTRUCTION: &'static str = "INST - PushValueToArray";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();
@ -63,6 +65,7 @@ pub(crate) struct PushElisionToArray;
impl Operation for PushElisionToArray {
const NAME: &'static str = "PushElisionToArray";
const INSTRUCTION: &'static str = "INST - PushElisionToArray";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let array = context.vm.pop();
@ -88,6 +91,7 @@ pub(crate) struct PushIteratorToArray;
impl Operation for PushIteratorToArray {
const NAME: &'static str = "PushIteratorToArray";
const INSTRUCTION: &'static str = "INST - PushIteratorToArray";
const COST: u8 = 8;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let mut iterator = context

2
boa_engine/src/vm/opcode/push/class/field.rs

@ -14,6 +14,7 @@ pub(crate) struct PushClassField;
impl Operation for PushClassField {
const NAME: &'static str = "PushClassField";
const INSTRUCTION: &'static str = "INST - PushClassField";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let field_function_value = context.vm.pop();
@ -85,6 +86,7 @@ impl PushClassFieldPrivate {
impl Operation for PushClassFieldPrivate {
const NAME: &'static str = "PushClassFieldPrivate";
const INSTRUCTION: &'static str = "INST - PushClassFieldPrivate";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;

1
boa_engine/src/vm/opcode/push/class/mod.rs

@ -22,6 +22,7 @@ pub(crate) struct PushClassPrototype;
impl Operation for PushClassPrototype {
const NAME: &'static str = "PushClassPrototype";
const INSTRUCTION: &'static str = "INST - PushClassPrototype";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let superclass = context.vm.pop();

3
boa_engine/src/vm/opcode/push/class/private.rs

@ -51,6 +51,7 @@ impl PushClassPrivateMethod {
impl Operation for PushClassPrivateMethod {
const NAME: &'static str = "PushClassPrivateMethod";
const INSTRUCTION: &'static str = "INST - PushClassPrivateMethod";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
@ -103,6 +104,7 @@ impl PushClassPrivateGetter {
impl Operation for PushClassPrivateGetter {
const NAME: &'static str = "PushClassPrivateGetter";
const INSTRUCTION: &'static str = "INST - PushClassPrivateGetter";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
@ -155,6 +157,7 @@ impl PushClassPrivateSetter {
impl Operation for PushClassPrivateSetter {
const NAME: &'static str = "PushClassPrivateSetter";
const INSTRUCTION: &'static str = "INST - PushClassPrivateSetter";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;

4
boa_engine/src/vm/opcode/push/environment.rs

@ -28,6 +28,7 @@ impl PushDeclarativeEnvironment {
impl Operation for PushDeclarativeEnvironment {
const NAME: &'static str = "PushDeclarativeEnvironment";
const INSTRUCTION: &'static str = "INST - PushDeclarativeEnvironment";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let compile_environments_index = context.vm.read::<u8>() as usize;
@ -55,6 +56,7 @@ pub(crate) struct PushObjectEnvironment;
impl Operation for PushObjectEnvironment {
const NAME: &'static str = "PushObjectEnvironment";
const INSTRUCTION: &'static str = "INST - PushObjectEnvironment";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let object = context.vm.pop();
@ -75,6 +77,7 @@ pub(crate) struct PushPrivateEnvironment;
impl Operation for PushPrivateEnvironment {
const NAME: &'static str = "PushPrivateEnvironment";
const INSTRUCTION: &'static str = "INST - PushPrivateEnvironment";
const COST: u8 = 5;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let class_value = context.vm.pop();
@ -114,6 +117,7 @@ pub(crate) struct PopPrivateEnvironment;
impl Operation for PopPrivateEnvironment {
const NAME: &'static str = "PopPrivateEnvironment";
const INSTRUCTION: &'static str = "INST - PopPrivateEnvironment";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
context.vm.environments.pop_private();

2
boa_engine/src/vm/opcode/push/literal.rs

@ -23,6 +23,7 @@ impl PushLiteral {
impl Operation for PushLiteral {
const NAME: &'static str = "PushLiteral";
const INSTRUCTION: &'static str = "INST - PushLiteral";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
@ -65,6 +66,7 @@ impl PushRegExp {
impl Operation for PushRegExp {
const NAME: &'static str = "PushRegExp";
const INSTRUCTION: &'static str = "INST - PushRegExp";
const COST: u8 = 5;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let pattern_index = context.vm.read::<u8>() as usize;

1
boa_engine/src/vm/opcode/push/mod.rs

@ -29,6 +29,7 @@ macro_rules! implement_push_generics {
impl Operation for $name {
const NAME: &'static str = stringify!($name);
const INSTRUCTION: &'static str = stringify!("INST - " + $name);
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
context.vm.push($push_value);

2
boa_engine/src/vm/opcode/push/numbers.rs

@ -15,6 +15,7 @@ macro_rules! implement_push_numbers_with_conversion {
impl Operation for $name {
const NAME: &'static str = stringify!($name);
const INSTRUCTION: &'static str = stringify!("INST - " + $name);
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.read::<$num_type>();
@ -37,6 +38,7 @@ macro_rules! implement_push_numbers_no_conversion {
impl Operation for $name {
const NAME: &'static str = stringify!($name);
const INSTRUCTION: &'static str = stringify!("INST - " + $name);
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.read::<$num_type>();

1
boa_engine/src/vm/opcode/push/object.rs

@ -14,6 +14,7 @@ pub(crate) struct PushEmptyObject;
impl Operation for PushEmptyObject {
const NAME: &'static str = "PushEmptyObject";
const INSTRUCTION: &'static str = "INST - PushEmptyObject";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let o = context

1
boa_engine/src/vm/opcode/require/mod.rs

@ -13,6 +13,7 @@ pub(crate) struct RequireObjectCoercible;
impl Operation for RequireObjectCoercible {
const NAME: &'static str = "RequireObjectCoercible";
const INSTRUCTION: &'static str = "INST - RequireObjectCoercible";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();

1
boa_engine/src/vm/opcode/rest_parameter/mod.rs

@ -14,6 +14,7 @@ pub(crate) struct RestParameterInit;
impl Operation for RestParameterInit {
const NAME: &'static str = "RestParameterInit";
const INSTRUCTION: &'static str = "INST - RestParameterInit";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let arg_count = context.vm.frame().argument_count as usize;

1
boa_engine/src/vm/opcode/set/class_prototype.rs

@ -15,6 +15,7 @@ pub(crate) struct SetClassPrototype;
impl Operation for SetClassPrototype {
const NAME: &'static str = "SetClassPrototype";
const INSTRUCTION: &'static str = "INST - SetClassPrototype";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let prototype_value = context.vm.pop();

1
boa_engine/src/vm/opcode/set/home_object.rs

@ -13,6 +13,7 @@ pub(crate) struct SetHomeObject;
impl Operation for SetHomeObject {
const NAME: &'static str = "SetHomeObject";
const INSTRUCTION: &'static str = "INST - SetHomeObject";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let function = context.vm.pop();

3
boa_engine/src/vm/opcode/set/name.rs

@ -27,6 +27,7 @@ impl ThrowMutateImmutable {
impl Operation for ThrowMutateImmutable {
const NAME: &'static str = "ThrowMutateImmutable";
const INSTRUCTION: &'static str = "INST - ThrowMutateImmutable";
const COST: u8 = 2;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();
@ -73,6 +74,7 @@ impl SetName {
impl Operation for SetName {
const NAME: &'static str = "SetName";
const INSTRUCTION: &'static str = "INST - SetName";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();
@ -100,6 +102,7 @@ pub(crate) struct SetNameByLocator;
impl Operation for SetNameByLocator {
const NAME: &'static str = "SetNameByLocator";
const INSTRUCTION: &'static str = "INST - SetNameByLocator";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let binding_locator = context

5
boa_engine/src/vm/opcode/set/private.rs

@ -36,6 +36,7 @@ impl SetPrivateField {
impl Operation for SetPrivateField {
const NAME: &'static str = "SetPrivateField";
const INSTRUCTION: &'static str = "INST - SetPrivateField";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
@ -81,6 +82,7 @@ impl DefinePrivateField {
impl Operation for DefinePrivateField {
const NAME: &'static str = "DefinePrivateField";
const INSTRUCTION: &'static str = "INST - DefinePrivateField";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
@ -140,6 +142,7 @@ impl SetPrivateMethod {
impl Operation for SetPrivateMethod {
const NAME: &'static str = "SetPrivateMethod";
const INSTRUCTION: &'static str = "INST - SetPrivateMethod";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
@ -190,6 +193,7 @@ impl SetPrivateSetter {
impl Operation for SetPrivateSetter {
const NAME: &'static str = "SetPrivateSetter";
const INSTRUCTION: &'static str = "INST - SetPrivateSetter";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
@ -240,6 +244,7 @@ impl SetPrivateGetter {
impl Operation for SetPrivateGetter {
const NAME: &'static str = "SetPrivateGetter";
const INSTRUCTION: &'static str = "INST - SetPrivateGetter";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;

7
boa_engine/src/vm/opcode/set/property.rs

@ -41,6 +41,7 @@ impl SetPropertyByName {
impl Operation for SetPropertyByName {
const NAME: &'static str = "SetPropertyByName";
const INSTRUCTION: &'static str = "INST - SetPropertyByName";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>();
@ -68,6 +69,7 @@ pub(crate) struct SetPropertyByValue;
impl Operation for SetPropertyByValue {
const NAME: &'static str = "SetPropertyByValue";
const INSTRUCTION: &'static str = "INST - SetPropertyByValue";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();
@ -197,6 +199,7 @@ impl SetPropertyGetterByName {
impl Operation for SetPropertyGetterByName {
const NAME: &'static str = "SetPropertyGetterByName";
const INSTRUCTION: &'static str = "INST - SetPropertyGetterByName";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
@ -224,6 +227,7 @@ pub(crate) struct SetPropertyGetterByValue;
impl Operation for SetPropertyGetterByValue {
const NAME: &'static str = "SetPropertyGetterByValue";
const INSTRUCTION: &'static str = "INST - SetPropertyGetterByValue";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();
@ -285,6 +289,7 @@ impl SetPropertySetterByName {
impl Operation for SetPropertySetterByName {
const NAME: &'static str = "SetPropertySetterByName";
const INSTRUCTION: &'static str = "INST - SetPropertySetterByName";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let index = context.vm.read::<u8>() as usize;
@ -312,6 +317,7 @@ pub(crate) struct SetPropertySetterByValue;
impl Operation for SetPropertySetterByValue {
const NAME: &'static str = "SetPropertySetterByValue";
const INSTRUCTION: &'static str = "INST - SetPropertySetterByValue";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();
@ -348,6 +354,7 @@ pub(crate) struct SetFunctionName;
impl Operation for SetFunctionName {
const NAME: &'static str = "SetFunctionName";
const INSTRUCTION: &'static str = "INST - SetFunctionName";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let prefix = context.vm.read::<u8>();

1
boa_engine/src/vm/opcode/set/prototype.rs

@ -13,6 +13,7 @@ pub(crate) struct SetPrototype;
impl Operation for SetPrototype {
const NAME: &'static str = "SetPrototype";
const INSTRUCTION: &'static str = "INST - SetPrototype";
const COST: u8 = 4;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();

3
boa_engine/src/vm/opcode/swap/mod.rs

@ -13,6 +13,7 @@ pub(crate) struct Swap;
impl Operation for Swap {
const NAME: &'static str = "Swap";
const INSTRUCTION: &'static str = "INST - Swap";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let len = context.vm.stack.len();
@ -32,6 +33,7 @@ pub(crate) struct RotateLeft;
impl Operation for RotateLeft {
const NAME: &'static str = "RotateLeft";
const INSTRUCTION: &'static str = "INST - RotateLeft";
const COST: u8 = 2;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let n = context.vm.read::<u8>() as usize;
@ -51,6 +53,7 @@ pub(crate) struct RotateRight;
impl Operation for RotateRight {
const NAME: &'static str = "RotateRight";
const INSTRUCTION: &'static str = "INST - RotateRight";
const COST: u8 = 2;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let n = context.vm.read::<u8>() as usize;

2
boa_engine/src/vm/opcode/switch/mod.rs

@ -14,6 +14,7 @@ pub(crate) struct Case;
impl Operation for Case {
const NAME: &'static str = "Case";
const INSTRUCTION: &'static str = "INST - Case";
const COST: u8 = 2;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let address = context.vm.read::<u32>();
@ -39,6 +40,7 @@ pub(crate) struct Default;
impl Operation for Default {
const NAME: &'static str = "Default";
const INSTRUCTION: &'static str = "INST - Default";
const COST: u8 = 2;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let exit = context.vm.read::<u32>();

2
boa_engine/src/vm/opcode/templates/mod.rs

@ -17,6 +17,7 @@ pub(crate) struct TemplateLookup;
impl Operation for TemplateLookup {
const NAME: &'static str = "TemplateLookup";
const INSTRUCTION: &'static str = "INST - TemplateLookup";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let jump = context.vm.read::<u32>();
@ -101,6 +102,7 @@ impl TemplateCreate {
impl Operation for TemplateCreate {
const NAME: &'static str = "TemplateCreate";
const INSTRUCTION: &'static str = "INST - TemplateCreate";
const COST: u8 = 6;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let count = u32::from(context.vm.read::<u8>());

2
boa_engine/src/vm/opcode/to/mod.rs

@ -13,6 +13,7 @@ pub(crate) struct ToBoolean;
impl Operation for ToBoolean {
const NAME: &'static str = "ToBoolean";
const INSTRUCTION: &'static str = "INST - ToBoolean";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();
@ -31,6 +32,7 @@ pub(crate) struct ToPropertyKey;
impl Operation for ToPropertyKey {
const NAME: &'static str = "ToPropertyKey";
const INSTRUCTION: &'static str = "INST - ToPropertyKey";
const COST: u8 = 2;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();

2
boa_engine/src/vm/opcode/unary_ops/decrement.rs

@ -14,6 +14,7 @@ pub(crate) struct Dec;
impl Operation for Dec {
const NAME: &'static str = "Dec";
const INSTRUCTION: &'static str = "INST - Dec";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();
@ -42,6 +43,7 @@ pub(crate) struct DecPost;
impl Operation for DecPost {
const NAME: &'static str = "DecPost";
const INSTRUCTION: &'static str = "INST - DecPost";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();

2
boa_engine/src/vm/opcode/unary_ops/increment.rs

@ -14,6 +14,7 @@ pub(crate) struct Inc;
impl Operation for Inc {
const NAME: &'static str = "Inc";
const INSTRUCTION: &'static str = "INST - Inc";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();
@ -42,6 +43,7 @@ pub(crate) struct IncPost;
impl Operation for IncPost {
const NAME: &'static str = "IncPost";
const INSTRUCTION: &'static str = "INST - IncPost";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();

1
boa_engine/src/vm/opcode/unary_ops/logical.rs

@ -13,6 +13,7 @@ pub(crate) struct LogicalNot;
impl Operation for LogicalNot {
const NAME: &'static str = "LogicalNot";
const INSTRUCTION: &'static str = "INST - LogicalNot";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();

4
boa_engine/src/vm/opcode/unary_ops/mod.rs

@ -26,6 +26,7 @@ pub(crate) struct TypeOf;
impl Operation for TypeOf {
const NAME: &'static str = "TypeOf";
const INSTRUCTION: &'static str = "INST - TypeOf";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();
@ -44,6 +45,7 @@ pub(crate) struct Pos;
impl Operation for Pos {
const NAME: &'static str = "Pos";
const INSTRUCTION: &'static str = "INST - Pos";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();
@ -63,6 +65,7 @@ pub(crate) struct Neg;
impl Operation for Neg {
const NAME: &'static str = "Neg";
const INSTRUCTION: &'static str = "INST - Neg";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();
@ -84,6 +87,7 @@ pub(crate) struct BitNot;
impl Operation for BitNot {
const NAME: &'static str = "BitNot";
const INSTRUCTION: &'static str = "INST - BitNot";
const COST: u8 = 3;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();

1
boa_engine/src/vm/opcode/unary_ops/void.rs

@ -13,6 +13,7 @@ pub(crate) struct Void;
impl Operation for Void {
const NAME: &'static str = "Void";
const INSTRUCTION: &'static str = "INST - Void";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let _old = context.vm.pop();

2
boa_engine/src/vm/opcode/value/mod.rs

@ -14,6 +14,7 @@ pub(crate) struct ValueNotNullOrUndefined;
impl Operation for ValueNotNullOrUndefined {
const NAME: &'static str = "ValueNotNullOrUndefined";
const INSTRUCTION: &'static str = "INST - ValueNotNullOrUndefined";
const COST: u8 = 2;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();
@ -42,6 +43,7 @@ pub(crate) struct IsObject;
impl Operation for IsObject {
const NAME: &'static str = "IsObject";
const INSTRUCTION: &'static str = "INST - IsObject";
const COST: u8 = 1;
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();

Loading…
Cancel
Save