#![allow(clippy::inline_always)]
#![allow(clippy::doc_markdown)]
use crate::{
Context,
vm::{completion_record::CompletionRecord, completion_record::IntoCompletionRecord},
};
use args::{Argument, read};
use std::ops::ControlFlow;
use thin_vec::ThinVec;
mod args;
mod arguments;
mod r#await;
mod binary_ops;
mod call;
mod concat;
mod control_flow;
mod copy;
mod define;
mod delete;
mod environment;
mod function;
mod generator;
mod get;
mod iteration;
mod meta;
mod new;
mod nop;
mod object;
mod pop;
mod push;
mod rest_parameter;
mod set;
mod switch;
mod templates;
mod to;
mod unary_ops;
mod value;
#[doc(inline)]
pub(crate) use arguments::*;
#[doc(inline)]
pub(crate) use r#await::*;
#[doc(inline)]
pub(crate) use binary_ops::*;
#[doc(inline)]
pub(crate) use call::*;
#[doc(inline)]
pub(crate) use concat::*;
#[doc(inline)]
pub(crate) use control_flow::*;
#[doc(inline)]
pub(crate) use copy::*;
#[doc(inline)]
pub(crate) use define::*;
#[doc(inline)]
pub(crate) use delete::*;
#[doc(inline)]
pub(crate) use environment::*;
#[doc(inline)]
pub(crate) use function::*;
#[doc(inline)]
pub(crate) use generator::*;
#[doc(inline)]
pub(crate) use get::*;
#[doc(inline)]
pub(crate) use iteration::*;
#[doc(inline)]
pub(crate) use meta::*;
#[doc(inline)]
pub(crate) use new::*;
#[doc(inline)]
pub(crate) use nop::*;
#[doc(inline)]
pub(crate) use object::*;
#[doc(inline)]
pub(crate) use pop::*;
#[doc(inline)]
pub(crate) use push::*;
#[doc(inline)]
pub(crate) use rest_parameter::*;
#[doc(inline)]
pub(crate) use set::*;
#[doc(inline)]
pub(crate) use switch::*;
#[doc(inline)]
pub(crate) use templates::*;
#[doc(inline)]
pub(crate) use to::*;
#[doc(inline)]
pub(crate) use unary_ops::*;
#[doc(inline)]
pub(crate) use value::*;
#[derive(Clone, Copy, Debug)]
pub(crate) enum BindingOpcode {
Var,
InitVar,
InitLexical,
SetName,
}
pub(crate) trait Operation {
const NAME: &'static str;
#[allow(unused)] const INSTRUCTION: &'static str;
const COST: u8;
}
#[derive(Debug)]
pub(crate) struct BytecodeEmitter {
bytes: Vec<u8>,
}
impl BytecodeEmitter {
pub(crate) fn new() -> Self {
Self { bytes: Vec::new() }
}
pub(crate) fn into_bytecode(self) -> Bytecode {
Bytecode {
bytes: self.bytes.into_boxed_slice(),
}
}
pub(crate) fn next_opcode_location(&self) -> Address {
Address::new(self.bytes.len() as u32)
}
pub(crate) fn patch_jump(&mut self, label: Address, patch: Address) {
let pos = u32::from(label) as usize;
let bytes = u32::from(patch).to_le_bytes();
self.bytes[pos + 1] = bytes[0];
self.bytes[pos + 2] = bytes[1];
self.bytes[pos + 3] = bytes[2];
self.bytes[pos + 4] = bytes[3];
}
pub(crate) fn patch_jump_table(&mut self, label: Address, patch: &[Address]) {
let length_offset = u32::from(label) as usize + 1;
let (length, first_offset) = read::<u32>(&self.bytes, length_offset);
assert_eq!(length as usize, patch.len());
for (i, value) in patch.iter().enumerate() {
let offset = first_offset + i * size_of::<u32>();
self.bytes[offset..offset + size_of::<u32>()]
.copy_from_slice(&u32::from(*value).to_le_bytes());
}
}
}
#[derive(Clone, Debug, Default)]
pub(crate) struct Bytecode {
pub(crate) bytes: Box<[u8]>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) struct Address(u32);
impl Address {
pub(crate) const fn new(value: u32) -> Self {
Self(value)
}
pub(crate) const fn as_u32(self) -> u32 {
self.0
}
}
impl From<Address> for u32 {
fn from(addr: Address) -> Self {
addr.0
}
}
impl From<u32> for Address {
fn from(value: u32) -> Self {
Self::new(value)
}
}
impl std::ops::Add<u32> for Address {
type Output = Self;
fn add(self, rhs: u32) -> Self {
Self::new(self.0 + rhs)
}
}
impl std::fmt::Display for Address {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:06x}", self.0)
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct RegisterOperand(u32);
impl RegisterOperand {
pub(crate) fn new(value: u32) -> Self {
Self(value)
}
}
impl From<RegisterOperand> for u32 {
fn from(value: RegisterOperand) -> Self {
value.0
}
}
impl From<RegisterOperand> for usize {
fn from(value: RegisterOperand) -> Self {
value.0 as usize
}
}
impl From<u8> for RegisterOperand {
fn from(value: u8) -> Self {
Self::new(value.into())
}
}
impl From<u16> for RegisterOperand {
fn from(value: u16) -> Self {
Self::new(value.into())
}
}
impl From<u32> for RegisterOperand {
fn from(value: u32) -> Self {
Self::new(value)
}
}
impl std::fmt::Display for RegisterOperand {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "r{:02}", self.0)
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct IndexOperand(u32);
impl IndexOperand {
pub(crate) fn new(value: u32) -> Self {
Self(value)
}
}
impl From<IndexOperand> for u32 {
fn from(value: IndexOperand) -> Self {
value.0
}
}
impl From<IndexOperand> for usize {
fn from(value: IndexOperand) -> Self {
value.0 as usize
}
}
impl From<bool> for IndexOperand {
fn from(value: bool) -> Self {
Self::new(value.into())
}
}
impl From<u8> for IndexOperand {
fn from(value: u8) -> Self {
Self::new(value.into())
}
}
impl From<u16> for IndexOperand {
fn from(value: u16) -> Self {
Self::new(value.into())
}
}
impl From<u32> for IndexOperand {
fn from(value: u32) -> Self {
Self::new(value)
}
}
impl std::fmt::Display for IndexOperand {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl Opcode {
fn encode(self) -> u8 {
self as u8
}
pub(crate) fn decode(instruction: u8) -> Self {
Self::from(instruction)
}
}
fn encode_instruction<A: Argument>(opcode: Opcode, args: A, bytes: &mut Vec<u8>) {
bytes.push(opcode.encode());
args.encode(bytes);
}
macro_rules! generate_opcodes {
(
$(
$(#[$comment:ident $($args:tt)*])*
$Variant:ident $({
$(
$(#[$fieldinner:ident $($fieldargs:tt)*])*
$FieldName:ident : $FieldType:ty
),*
$(,)?
})? $(=> $mapping:ident)?
),*
$(,)?
) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub(crate) enum Opcode {
$(
$(#[$comment $($args)*])*
$Variant
),*
}
impl From<u8> for Opcode {
#[inline]
#[allow(non_upper_case_globals)]
fn from(value: u8) -> Self {
$(
const $Variant: u8 = Opcode::$Variant as u8;
)*
match value {
$($Variant => Self::$Variant),*
}
}
}
impl Opcode {
pub(crate) fn as_str(&self) -> &'static str {
match self {
$(Self::$Variant => $Variant::NAME),*
}
}
}
impl BytecodeEmitter {
$(
pastey::paste! {
#[allow(unused)]
pub(crate) fn [<emit_ $Variant:snake>](&mut self $( $(, $FieldName: $FieldType)* )? ) {
encode_instruction(
Opcode::$Variant,
($($($FieldName),*)?),
&mut self.bytes,
);
}
}
)*
}
type OpcodeHandler = fn(&mut Context, usize) -> ControlFlow<CompletionRecord>;
pub(crate) const OPCODE_HANDLERS: [OpcodeHandler; 256] = {
[
$(
pastey::paste! { [<handle_ $Variant:snake>] },
)*
]
};
type OpcodeHandlerBudget = fn(&mut Context, usize, &mut u32) -> ControlFlow<CompletionRecord>;
pub(crate) const OPCODE_HANDLERS_BUDGET: [OpcodeHandlerBudget; 256] = {
[
$(
pastey::paste! { [<handle_ $Variant:snake _budget>] },
)*
]
};
$(
pastey::paste! {
#[inline(always)]
#[allow(unused_parens)]
fn [<handle_ $Variant:snake>](context: &mut Context, pc: usize) -> ControlFlow<CompletionRecord> {
let bytes = &context.vm.frame().code_block.bytecode.bytes;
let (args, next_pc) = <($($($FieldType),*)?)>::decode(bytes, pc + 1);
context.vm.frame_mut().pc = next_pc as u32;
let result = $Variant::operation(args, context);
IntoCompletionRecord::into_completion_record(result, context)
}
}
)*
$(
pastey::paste! {
#[inline(always)]
#[allow(unused_parens)]
fn [<handle_ $Variant:snake _budget>](context: &mut Context, pc: usize, budget: &mut u32) -> ControlFlow<CompletionRecord> {
*budget = budget.saturating_sub(u32::from($Variant::COST));
let bytes = &context.vm.frame().code_block.bytecode.bytes;
let (args, next_pc) = <($($($FieldType),*)?)>::decode(bytes, pc + 1);
context.vm.frame_mut().pc = next_pc as u32;
let result = $Variant::operation(args, context);
IntoCompletionRecord::into_completion_record(result, context)
}
}
)*
$(
$(
struct $Variant {}
impl $Variant {
#[allow(unused_parens)]
#[allow(unused_variables)]
#[inline(always)]
fn operation(args: (), context: &mut Context) {
$mapping::operation(args, context)
}
}
impl Operation for $Variant {
const NAME: &'static str = "Reserved";
const INSTRUCTION: &'static str = "INST - Reserved";
const COST: u8 = 0;
}
)?
)*
pub(crate) enum Instruction {
$(
$Variant $({
$(
$(#[$fieldinner $($fieldargs)*])*
$FieldName : $FieldType
),*
})?
),*
}
impl Bytecode {
#[allow(unused_parens)]
pub(crate) fn next_instruction(&self, pc: usize) -> (Instruction, usize) {
let bytes = &self.bytes;
let opcode = Opcode::decode(bytes[pc]);
match opcode {
$(
Opcode::$Variant => {
let (($($($FieldName),*)?), read_size) = <($($($FieldType),*)?)>::decode(bytes, pc + 1);
(Instruction::$Variant $({
$(
$FieldName: $FieldName
),*
})?, read_size)
}
),*
}
}
}
}
}
pub(crate) struct InstructionIterator<'bytecode> {
bytes: &'bytecode Bytecode,
pc: usize,
}
impl<'bytecode> InstructionIterator<'bytecode> {
#[inline]
#[must_use]
pub(crate) const fn new(bytes: &'bytecode Bytecode) -> Self {
Self { bytes, pc: 0 }
}
#[inline]
#[must_use]
pub(crate) const fn pc(&self) -> usize {
self.pc
}
}
impl Iterator for InstructionIterator<'_> {
type Item = (usize, Opcode, Instruction);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let start_pc = self.pc;
if self.pc >= self.bytes.bytes.len() {
return None;
}
let bytes = &self.bytes.bytes;
let opcode = Opcode::decode(bytes[self.pc]);
let (instruction, read_size) = self.bytes.next_instruction(self.pc);
self.pc = read_size;
Some((start_pc, opcode, instruction))
}
}
generate_opcodes! {
Pop,
StoreZero { dst: RegisterOperand },
StoreOne { dst: RegisterOperand },
StoreInt8 { dst: RegisterOperand, value: i8 },
StoreInt16 { dst: RegisterOperand, value: i16 },
StoreInt32 { dst: RegisterOperand, value: i32 },
StoreFloat { dst: RegisterOperand, value: f32 },
StoreDouble { dst: RegisterOperand, value: f64 },
StoreNan { dst: RegisterOperand },
StorePositiveInfinity { dst: RegisterOperand },
StoreNegativeInfinity { dst: RegisterOperand },
StoreNull { dst: RegisterOperand },
StoreTrue { dst: RegisterOperand },
StoreFalse { dst: RegisterOperand },
StoreUndefined { dst: RegisterOperand },
StoreLiteral { dst: RegisterOperand, index: IndexOperand },
StoreRegexp { dst: RegisterOperand, pattern_index: IndexOperand, flags_index: IndexOperand },
StoreEmptyObject { dst: RegisterOperand },
StoreClassPrototype {
dst: RegisterOperand,
class: RegisterOperand,
superclass: RegisterOperand
},
SetClassPrototype {
dst: RegisterOperand,
prototype: RegisterOperand,
class: RegisterOperand
},
SetHomeObject {
function: RegisterOperand,
home: RegisterOperand
},
GetHomeObject {
function: RegisterOperand,
},
SetPrototype {
object: RegisterOperand,
prototype: RegisterOperand
},
GetPrototype {
object: RegisterOperand,
},
StoreNewArray { dst: RegisterOperand },
PushValueToArray { value: RegisterOperand, array: RegisterOperand },
PushElisionToArray { array: RegisterOperand },
PushIteratorToArray { array: RegisterOperand },
Add { dst: RegisterOperand, lhs: RegisterOperand, rhs: RegisterOperand },
Sub { dst: RegisterOperand, lhs: RegisterOperand, rhs: RegisterOperand },
Div { dst: RegisterOperand, lhs: RegisterOperand, rhs: RegisterOperand },
Mul { dst: RegisterOperand, lhs: RegisterOperand, rhs: RegisterOperand },
Mod { dst: RegisterOperand, lhs: RegisterOperand, rhs: RegisterOperand },
Pow { dst: RegisterOperand, lhs: RegisterOperand, rhs: RegisterOperand },
ShiftRight { dst: RegisterOperand, lhs: RegisterOperand, rhs: RegisterOperand },
ShiftLeft { dst: RegisterOperand, lhs: RegisterOperand, rhs: RegisterOperand },
UnsignedShiftRight { dst: RegisterOperand, lhs: RegisterOperand, rhs: RegisterOperand },
BitOr { dst: RegisterOperand, lhs: RegisterOperand, rhs: RegisterOperand },
BitAnd { dst: RegisterOperand, lhs: RegisterOperand, rhs: RegisterOperand },
BitXor { dst: RegisterOperand, lhs: RegisterOperand, rhs: RegisterOperand },
BitNot { value: RegisterOperand },
In { dst: RegisterOperand, lhs: RegisterOperand, rhs: RegisterOperand },
InPrivate { dst: RegisterOperand, index: IndexOperand, rhs: RegisterOperand },
Eq { dst: RegisterOperand, lhs: RegisterOperand, rhs: RegisterOperand },
StrictEq { dst: RegisterOperand, lhs: RegisterOperand, rhs: RegisterOperand },
NotEq { dst: RegisterOperand, lhs: RegisterOperand, rhs: RegisterOperand },
StrictNotEq { dst: RegisterOperand, lhs: RegisterOperand, rhs: RegisterOperand },
GreaterThan { dst: RegisterOperand, lhs: RegisterOperand, rhs: RegisterOperand },
GreaterThanOrEq { dst: RegisterOperand, lhs: RegisterOperand, rhs: RegisterOperand },
LessThan { dst: RegisterOperand, lhs: RegisterOperand, rhs: RegisterOperand },
LessThanOrEq { dst: RegisterOperand, lhs: RegisterOperand, rhs: RegisterOperand },
InstanceOf { dst: RegisterOperand, lhs: RegisterOperand, rhs: RegisterOperand },
LogicalAnd { address: Address, value: RegisterOperand },
LogicalOr { address: Address, value: RegisterOperand },
Coalesce { address: Address, value: RegisterOperand },
TypeOf { value: RegisterOperand },
LogicalNot { value: RegisterOperand },
Pos { value: RegisterOperand },
Neg { value: RegisterOperand },
Inc { dst: RegisterOperand, src: RegisterOperand },
Dec { dst: RegisterOperand, src: RegisterOperand },
DefVar { binding_index: IndexOperand },
DefInitVar { src: RegisterOperand, binding_index: IndexOperand },
PutLexicalValue { src: RegisterOperand, binding_index: IndexOperand },
ThrowMutateImmutable { index: IndexOperand },
GetArgument { index: IndexOperand, dst: RegisterOperand },
GetName { dst: RegisterOperand, binding_index: IndexOperand },
GetNameGlobal { dst: RegisterOperand, binding_index: IndexOperand, ic_index: IndexOperand },
GetLocator { binding_index: IndexOperand },
GetNameAndLocator { dst: RegisterOperand, binding_index: IndexOperand },
GetNameOrUndefined { dst: RegisterOperand, binding_index: IndexOperand },
SetName { src: RegisterOperand, binding_index: IndexOperand },
SetNameByLocator { src: RegisterOperand },
DeleteName { dst: RegisterOperand, binding_index: IndexOperand },
GetMethod { object: RegisterOperand, name_index: IndexOperand },
GetLengthProperty {
dst: RegisterOperand,
value: RegisterOperand,
ic_index: IndexOperand
},
GetPropertyByName {
dst: RegisterOperand,
value: RegisterOperand,
ic_index: IndexOperand
},
GetPropertyByNameWithThis {
dst: RegisterOperand,
receiver: RegisterOperand,
value: RegisterOperand,
ic_index: IndexOperand
},
GetPropertyByValue {
dst: RegisterOperand,
key: RegisterOperand,
receiver: RegisterOperand,
object: RegisterOperand
},
GetPropertyByValuePush {
dst: RegisterOperand,
key: RegisterOperand,
receiver: RegisterOperand,
object: RegisterOperand
},
SetPropertyByName {
value: RegisterOperand,
object: RegisterOperand,
ic_index: IndexOperand
},
SetPropertyByNameWithThis {
value: RegisterOperand,
receiver: RegisterOperand,
object: RegisterOperand,
ic_index: IndexOperand
},
SetFunctionName { function: RegisterOperand, name: RegisterOperand, prefix: IndexOperand },
DefineOwnPropertyByName { object: RegisterOperand, value: RegisterOperand, name_index: IndexOperand },
DefineClassStaticMethodByName {
value: RegisterOperand,
object: RegisterOperand,
name_index: IndexOperand
},
DefineClassMethodByName {
value: RegisterOperand,
object: RegisterOperand,
name_index: IndexOperand
},
SetPropertyByValue {
value: RegisterOperand,
key: RegisterOperand,
receiver: RegisterOperand,
object: RegisterOperand
},
DefineOwnPropertyByValue {
value: RegisterOperand,
key: RegisterOperand,
object: RegisterOperand
},
DefineClassStaticMethodByValue {
value: RegisterOperand,
key: RegisterOperand,
object: RegisterOperand
},
DefineClassMethodByValue {
value: RegisterOperand,
key: RegisterOperand,
object: RegisterOperand
},
SetPropertyGetterByName { object: RegisterOperand, value: RegisterOperand, name_index: IndexOperand },
DefineClassStaticGetterByName {
value: RegisterOperand,
object: RegisterOperand,
name_index: IndexOperand
},
DefineClassGetterByName {
value: RegisterOperand,
object: RegisterOperand,
name_index: IndexOperand
},
SetPropertyGetterByValue {
value: RegisterOperand,
key: RegisterOperand,
object: RegisterOperand
},
DefineClassStaticGetterByValue {
value: RegisterOperand,
key: RegisterOperand,
object: RegisterOperand
},
DefineClassGetterByValue {
value: RegisterOperand,
key: RegisterOperand,
object: RegisterOperand
},
SetPropertySetterByName { object: RegisterOperand, value: RegisterOperand, name_index: IndexOperand },
DefineClassStaticSetterByName {
value: RegisterOperand,
object: RegisterOperand,
name_index: IndexOperand
},
DefineClassSetterByName {
value: RegisterOperand,
object: RegisterOperand,
name_index: IndexOperand
},
SetPropertySetterByValue {
value: RegisterOperand,
key: RegisterOperand,
object: RegisterOperand
},
DefineClassStaticSetterByValue {
value: RegisterOperand,
key: RegisterOperand,
object: RegisterOperand
},
DefineClassSetterByValue {
value: RegisterOperand,
key: RegisterOperand,
object: RegisterOperand
},
SetPrivateField { value: RegisterOperand, object: RegisterOperand, name_index: IndexOperand },
DefinePrivateField { object: RegisterOperand, value: RegisterOperand, name_index: IndexOperand },
SetPrivateMethod { object: RegisterOperand, value: RegisterOperand, name_index: IndexOperand },
SetPrivateSetter { object: RegisterOperand, value: RegisterOperand, name_index: IndexOperand },
SetPrivateGetter { object: RegisterOperand, value: RegisterOperand, name_index: IndexOperand },
GetPrivateField { dst: RegisterOperand, object: RegisterOperand, name_index: IndexOperand },
PushClassField { object: RegisterOperand, name: RegisterOperand, value: RegisterOperand, is_anonymous_function: IndexOperand },
PushClassFieldPrivate { object: RegisterOperand, value: RegisterOperand, name_index: IndexOperand },
PushClassPrivateGetter { object: RegisterOperand, value: RegisterOperand, name_index: IndexOperand },
PushClassPrivateSetter { object: RegisterOperand, value: RegisterOperand, name_index: IndexOperand },
PushClassPrivateMethod { object: RegisterOperand, proto: RegisterOperand, value: RegisterOperand, name_index: IndexOperand },
DeletePropertyByName { object: RegisterOperand, name_index: IndexOperand },
DeletePropertyByValue { object: RegisterOperand, key: RegisterOperand },
DeleteSuperThrow,
CopyDataProperties { object: RegisterOperand, source: RegisterOperand, excluded_keys: ThinVec<RegisterOperand> },
ToPropertyKey { src: RegisterOperand, dst: RegisterOperand },
Jump { address: Address },
JumpIfTrue { address: Address, value: RegisterOperand },
JumpIfFalse { address: Address, value: RegisterOperand },
JumpIfNotUndefined { address: Address, value: RegisterOperand },
JumpIfNullOrUndefined { address: Address, value: RegisterOperand },
JumpIfNotLessThan { address: Address, lhs: RegisterOperand, rhs: RegisterOperand },
JumpIfNotLessThanOrEqual { address: Address, lhs: RegisterOperand, rhs: RegisterOperand },
JumpIfNotGreaterThan { address: Address, lhs: RegisterOperand, rhs: RegisterOperand },
JumpIfNotGreaterThanOrEqual { address: Address, lhs: RegisterOperand, rhs: RegisterOperand },
JumpIfNotEqual { address: Address, lhs: RegisterOperand, rhs: RegisterOperand },
JumpTable { index: u32, addresses: ThinVec<Address> },
Throw { src: RegisterOperand },
ReThrow,
Exception { dst: RegisterOperand },
MaybeException { has_exception: RegisterOperand, exception: RegisterOperand },
ThrowNewTypeError { message: IndexOperand },
ThrowNewReferenceError { message: IndexOperand },
GetFunctionObject { function_object: RegisterOperand },
This { dst: RegisterOperand },
ThisForObjectEnvironmentName { dst: RegisterOperand, index: IndexOperand },
SuperCall { argument_count: IndexOperand },
SuperCallSpread,
SuperCallDerived,
BindThisValue { value: RegisterOperand },
ImportCall { specifier: RegisterOperand, options: RegisterOperand, phase: IndexOperand },
Case { address: Address, value: RegisterOperand, condition: RegisterOperand },
GetFunction { dst: RegisterOperand, index: IndexOperand },
CallEval { argument_count: IndexOperand, scope_index: IndexOperand },
CallEvalSpread { scope_index: IndexOperand },
Call { argument_count: IndexOperand },
CallSpread,
New { argument_count: IndexOperand },
NewSpread,
CheckReturn,
Return,
AsyncGeneratorClose,
Generator,
AsyncGenerator,
SetAccumulator { src: RegisterOperand },
SetRegisterFromAccumulator { dst: RegisterOperand },
Move { dst: RegisterOperand, src: RegisterOperand },
PopIntoRegister { dst: RegisterOperand },
PushFromRegister { src: RegisterOperand },
PushScope { scope_index: IndexOperand },
PushObjectEnvironment { src: RegisterOperand },
PopEnvironment,
IncrementLoopIteration,
CreateForInIterator { src: RegisterOperand },
GetIterator { src: RegisterOperand },
GetAsyncIterator { src: RegisterOperand },
IteratorPop { iterator: RegisterOperand, next: RegisterOperand },
IteratorPush { iterator: RegisterOperand, next: RegisterOperand },
IteratorNext,
IteratorUpdateResult { result: RegisterOperand },
IteratorDone { dst: RegisterOperand },
IteratorFinishAsyncNext { resume_kind: RegisterOperand, value: RegisterOperand },
IteratorValue { dst: RegisterOperand },
IteratorResult { dst: RegisterOperand },
IteratorToArray { dst: RegisterOperand },
IteratorStackEmpty { dst: RegisterOperand },
CreateIteratorResult { value: RegisterOperand, done: IndexOperand },
IteratorReturn { value: RegisterOperand, called: RegisterOperand },
ConcatToString { dst: RegisterOperand, values: ThinVec<RegisterOperand> },
ValueNotNullOrUndefined { src: RegisterOperand },
RestParameterInit { dst: RegisterOperand },
GeneratorYield { src: RegisterOperand },
AsyncGeneratorYield { src: RegisterOperand },
CreatePromiseCapability,
Await { src: RegisterOperand },
NewTarget { dst: RegisterOperand },
ImportMeta { dst: RegisterOperand },
IsObject { value: RegisterOperand },
TemplateLookup { address: Address, site: u64, dst: RegisterOperand },
TemplateCreate { site: u64, dst: RegisterOperand, values: ThinVec<u32> },
PushPrivateEnvironment { class: RegisterOperand, name_indices: ThinVec<u32> },
PopPrivateEnvironment,
CreateMappedArgumentsObject { dst: RegisterOperand },
CreateUnmappedArgumentsObject { dst: RegisterOperand },
Reserved1 => Reserved,
Reserved2 => Reserved,
Reserved3 => Reserved,
Reserved4 => Reserved,
Reserved5 => Reserved,
Reserved6 => Reserved,
Reserved7 => Reserved,
Reserved8 => Reserved,
Reserved9 => Reserved,
Reserved10 => Reserved,
Reserved11 => Reserved,
Reserved12 => Reserved,
Reserved13 => Reserved,
Reserved14 => Reserved,
Reserved15 => Reserved,
Reserved16 => Reserved,
Reserved17 => Reserved,
Reserved18 => Reserved,
Reserved19 => Reserved,
Reserved20 => Reserved,
Reserved21 => Reserved,
Reserved22 => Reserved,
Reserved23 => Reserved,
Reserved24 => Reserved,
Reserved25 => Reserved,
Reserved26 => Reserved,
Reserved27 => Reserved,
Reserved28 => Reserved,
Reserved29 => Reserved,
Reserved30 => Reserved,
Reserved31 => Reserved,
Reserved32 => Reserved,
Reserved33 => Reserved,
Reserved34 => Reserved,
Reserved35 => Reserved,
Reserved36 => Reserved,
Reserved37 => Reserved,
Reserved38 => Reserved,
Reserved39 => Reserved,
Reserved40 => Reserved,
Reserved41 => Reserved,
Reserved42 => Reserved,
Reserved43 => Reserved,
Reserved44 => Reserved,
Reserved45 => Reserved,
Reserved46 => Reserved,
Reserved47 => Reserved,
Reserved48 => Reserved,
Reserved49 => Reserved,
Reserved50 => Reserved,
Reserved51 => Reserved,
Reserved52 => Reserved,
Reserved53 => Reserved,
Reserved54 => Reserved,
Reserved55 => Reserved,
Reserved56 => Reserved,
Reserved57 => Reserved,
Reserved58 => Reserved,
Reserved59 => Reserved,
DefEvalVar { binding_index: IndexOperand },
}