#![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 generator;
mod get;
mod global;
mod iteration;
mod meta;
mod new;
mod nop;
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 generator::*;
#[doc(inline)]
pub(crate) use get::*;
#[doc(inline)]
pub(crate) use global::*;
#[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 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 {
bytecode: Vec<u8>,
}
impl ByteCodeEmitter {
pub(crate) fn new() -> Self {
Self {
bytecode: Vec::new(),
}
}
pub(crate) fn into_bytecode(self) -> ByteCode {
ByteCode {
bytecode: self.bytecode.into_boxed_slice(),
}
}
pub(crate) fn next_opcode_location(&self) -> u32 {
self.bytecode.len() as u32
}
pub(crate) fn patch_jump(&mut self, label: u32, patch: u32) {
let pos = label as usize;
let bytes = patch.to_le_bytes();
self.bytecode[pos + 1] = bytes[0];
self.bytecode[pos + 2] = bytes[1];
self.bytecode[pos + 3] = bytes[2];
self.bytecode[pos + 4] = bytes[3];
}
pub(crate) fn patch_jump_two_addresses(&mut self, label: u32, patch: (u32, u32)) {
let pos = label as usize;
let bytes = patch.0.to_le_bytes();
self.bytecode[pos + 1] = bytes[0];
self.bytecode[pos + 2] = bytes[1];
self.bytecode[pos + 3] = bytes[2];
self.bytecode[pos + 4] = bytes[3];
let bytes = patch.1.to_le_bytes();
self.bytecode[pos + 5] = bytes[0];
self.bytecode[pos + 6] = bytes[1];
self.bytecode[pos + 7] = bytes[2];
self.bytecode[pos + 8] = bytes[3];
}
pub(crate) fn patch_jump_table(&mut self, label: u32, patch: (u32, &[u32])) {
let pos = label as usize;
let (total_len, pos) = read::<u16>(&self.bytecode, pos + 1);
let arg_count = total_len as usize;
assert_eq!(arg_count, patch.1.len());
let bytes = patch.0.to_le_bytes();
self.bytecode[pos] = bytes[0];
self.bytecode[pos + 1] = bytes[1];
self.bytecode[pos + 2] = bytes[2];
self.bytecode[pos + 3] = bytes[3];
for (i, value) in patch.1.iter().enumerate() {
let offset = pos + 4 + (i) * 4;
let bytes = value.to_le_bytes();
self.bytecode[offset] = bytes[0];
self.bytecode[offset + 1] = bytes[1];
self.bytecode[offset + 2] = bytes[2];
self.bytecode[offset + 3] = bytes[3];
}
}
}
#[derive(Clone, Debug, Default)]
pub(crate) struct ByteCode {
pub(crate) bytecode: Box<[u8]>,
}
enum VaryingOperandVariant {
U8(u8),
U16(u16),
U32(u32),
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct VaryingOperand {
value: u32,
}
impl VaryingOperand {
pub(crate) fn new(value: u32) -> Self {
Self { value }
}
fn variant(self) -> VaryingOperandVariant {
if let Ok(value) = u8::try_from(self.value) {
VaryingOperandVariant::U8(value)
} else if let Ok(value) = u16::try_from(self.value) {
VaryingOperandVariant::U16(value)
} else {
VaryingOperandVariant::U32(self.value)
}
}
}
impl From<VaryingOperand> for u32 {
fn from(value: VaryingOperand) -> Self {
value.value
}
}
impl From<VaryingOperand> for usize {
fn from(value: VaryingOperand) -> Self {
value.value as usize
}
}
impl From<bool> for VaryingOperand {
fn from(value: bool) -> Self {
Self::new(value.into())
}
}
impl From<u8> for VaryingOperand {
fn from(value: u8) -> Self {
Self::new(value.into())
}
}
impl From<u16> for VaryingOperand {
fn from(value: u16) -> Self {
Self::new(value.into())
}
}
impl From<u32> for VaryingOperand {
fn from(value: u32) -> Self {
Self::new(value)
}
}
impl std::fmt::Display for VaryingOperand {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.value)
}
}
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 {
$(
paste::paste! {
#[allow(unused)]
pub(crate) fn [<emit_ $Variant:snake>](&mut self $( $(, $FieldName: $FieldType)* )? ) {
encode_instruction(
Opcode::$Variant,
($($($FieldName),*)?),
&mut self.bytecode,
);
}
}
)*
}
type OpcodeHandler = fn(&mut Context, usize) -> ControlFlow<CompletionRecord>;
const OPCODE_HANDLERS: [OpcodeHandler; 256] = {
[
$(
paste::paste! { [<handle_ $Variant:snake>] },
)*
]
};
type OpcodeHandlerBudget = fn(&mut Context, usize, &mut u32) -> ControlFlow<CompletionRecord>;
const OPCODE_HANDLERS_BUDGET: [OpcodeHandlerBudget; 256] = {
[
$(
paste::paste! { [<handle_ $Variant:snake _budget>] },
)*
]
};
$(
paste::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.bytecode;
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)
}
}
)*
$(
paste::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.bytecode;
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.bytecode;
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)
}
),*
}
}
}
}
}
impl Context {
pub(crate) fn execute_bytecode_instruction(
&mut self,
opcode: Opcode,
) -> ControlFlow<CompletionRecord> {
let frame = self.vm.frame_mut();
let pc = frame.pc as usize;
OPCODE_HANDLERS[opcode as usize](self, pc)
}
pub(crate) fn execute_bytecode_instruction_with_budget(
&mut self,
budget: &mut u32,
opcode: Opcode,
) -> ControlFlow<CompletionRecord> {
let frame = self.vm.frame_mut();
let pc = frame.pc as usize;
OPCODE_HANDLERS_BUDGET[opcode as usize](self, pc, budget)
}
}
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.bytecode.len() {
return None;
}
let bytes = &self.bytes.bytecode;
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,
PushZero { dst: VaryingOperand },
PushOne { dst: VaryingOperand },
PushInt8 { dst: VaryingOperand, value: i8 },
PushInt16 { dst: VaryingOperand, value: i16 },
PushInt32 { dst: VaryingOperand, value: i32 },
PushFloat { dst: VaryingOperand, value: f32 },
PushDouble { dst: VaryingOperand, value: f64 },
PushNan { dst: VaryingOperand },
PushPositiveInfinity { dst: VaryingOperand },
PushNegativeInfinity { dst: VaryingOperand },
PushNull { dst: VaryingOperand },
PushTrue { dst: VaryingOperand },
PushFalse { dst: VaryingOperand },
PushUndefined { dst: VaryingOperand },
PushLiteral { dst: VaryingOperand, index: VaryingOperand },
PushRegexp { dst: VaryingOperand, pattern_index: VaryingOperand, flags_index: VaryingOperand },
PushEmptyObject { dst: VaryingOperand },
PushClassPrototype {
dst: VaryingOperand,
class: VaryingOperand,
superclass: VaryingOperand
},
SetClassPrototype {
dst: VaryingOperand,
prototype: VaryingOperand,
class: VaryingOperand
},
SetHomeObject {
function: VaryingOperand,
home: VaryingOperand
},
SetPrototype {
object: VaryingOperand,
prototype: VaryingOperand
},
PushNewArray { dst: VaryingOperand },
PushValueToArray { value: VaryingOperand, array: VaryingOperand },
PushElisionToArray { array: VaryingOperand },
PushIteratorToArray { array: VaryingOperand },
Add { dst: VaryingOperand, lhs: VaryingOperand, rhs: VaryingOperand },
Sub { dst: VaryingOperand, lhs: VaryingOperand, rhs: VaryingOperand },
Div { dst: VaryingOperand, lhs: VaryingOperand, rhs: VaryingOperand },
Mul { dst: VaryingOperand, lhs: VaryingOperand, rhs: VaryingOperand },
Mod { dst: VaryingOperand, lhs: VaryingOperand, rhs: VaryingOperand },
Pow { dst: VaryingOperand, lhs: VaryingOperand, rhs: VaryingOperand },
ShiftRight { dst: VaryingOperand, lhs: VaryingOperand, rhs: VaryingOperand },
ShiftLeft { dst: VaryingOperand, lhs: VaryingOperand, rhs: VaryingOperand },
UnsignedShiftRight { dst: VaryingOperand, lhs: VaryingOperand, rhs: VaryingOperand },
BitOr { dst: VaryingOperand, lhs: VaryingOperand, rhs: VaryingOperand },
BitAnd { dst: VaryingOperand, lhs: VaryingOperand, rhs: VaryingOperand },
BitXor { dst: VaryingOperand, lhs: VaryingOperand, rhs: VaryingOperand },
BitNot { value: VaryingOperand },
In { dst: VaryingOperand, lhs: VaryingOperand, rhs: VaryingOperand },
InPrivate { dst: VaryingOperand, index: VaryingOperand, rhs: VaryingOperand },
Eq { dst: VaryingOperand, lhs: VaryingOperand, rhs: VaryingOperand },
StrictEq { dst: VaryingOperand, lhs: VaryingOperand, rhs: VaryingOperand },
NotEq { dst: VaryingOperand, lhs: VaryingOperand, rhs: VaryingOperand },
StrictNotEq { dst: VaryingOperand, lhs: VaryingOperand, rhs: VaryingOperand },
GreaterThan { dst: VaryingOperand, lhs: VaryingOperand, rhs: VaryingOperand },
GreaterThanOrEq { dst: VaryingOperand, lhs: VaryingOperand, rhs: VaryingOperand },
LessThan { dst: VaryingOperand, lhs: VaryingOperand, rhs: VaryingOperand },
LessThanOrEq { dst: VaryingOperand, lhs: VaryingOperand, rhs: VaryingOperand },
InstanceOf { dst: VaryingOperand, lhs: VaryingOperand, rhs: VaryingOperand },
LogicalAnd { address: u32, value: VaryingOperand },
LogicalOr { address: u32, value: VaryingOperand },
Coalesce { address: u32, value: VaryingOperand },
TypeOf { value: VaryingOperand },
LogicalNot { value: VaryingOperand },
Pos { value: VaryingOperand },
Neg { value: VaryingOperand },
Inc { dst: VaryingOperand, src: VaryingOperand },
Dec { dst: VaryingOperand, src: VaryingOperand },
DefVar { binding_index: VaryingOperand },
DefInitVar { src: VaryingOperand, binding_index: VaryingOperand },
PutLexicalValue { src: VaryingOperand, binding_index: VaryingOperand },
ThrowMutateImmutable { index: VaryingOperand },
GetArgument { index: VaryingOperand, dst: VaryingOperand },
GetName { dst: VaryingOperand, binding_index: VaryingOperand },
GetNameGlobal { dst: VaryingOperand, binding_index: VaryingOperand, ic_index: VaryingOperand },
GetLocator { binding_index: VaryingOperand },
GetNameAndLocator { dst: VaryingOperand, binding_index: VaryingOperand },
GetNameOrUndefined { dst: VaryingOperand, binding_index: VaryingOperand },
SetName { src: VaryingOperand, binding_index: VaryingOperand },
SetNameByLocator { src: VaryingOperand },
DeleteName { dst: VaryingOperand, binding_index: VaryingOperand },
GetPropertyByName {
dst: VaryingOperand,
receiver: VaryingOperand,
value: VaryingOperand,
ic_index: VaryingOperand
},
GetPropertyByValue {
dst: VaryingOperand,
key: VaryingOperand,
receiver: VaryingOperand,
object: VaryingOperand
},
GetPropertyByValuePush {
dst: VaryingOperand,
key: VaryingOperand,
receiver: VaryingOperand,
object: VaryingOperand
},
SetPropertyByName {
value: VaryingOperand,
receiver: VaryingOperand,
object: VaryingOperand,
ic_index: VaryingOperand
},
SetFunctionName { function: VaryingOperand, name: VaryingOperand, prefix: VaryingOperand },
DefineOwnPropertyByName { object: VaryingOperand, value: VaryingOperand, name_index: VaryingOperand },
DefineClassStaticMethodByName {
value: VaryingOperand,
object: VaryingOperand,
name_index: VaryingOperand
},
DefineClassMethodByName {
value: VaryingOperand,
object: VaryingOperand,
name_index: VaryingOperand
},
SetPropertyByValue {
value: VaryingOperand,
key: VaryingOperand,
receiver: VaryingOperand,
object: VaryingOperand
},
DefineOwnPropertyByValue {
value: VaryingOperand,
key: VaryingOperand,
object: VaryingOperand
},
DefineClassStaticMethodByValue {
value: VaryingOperand,
key: VaryingOperand,
object: VaryingOperand
},
DefineClassMethodByValue {
value: VaryingOperand,
key: VaryingOperand,
object: VaryingOperand
},
SetPropertyGetterByName { object: VaryingOperand, value: VaryingOperand, name_index: VaryingOperand },
DefineClassStaticGetterByName {
value: VaryingOperand,
object: VaryingOperand,
name_index: VaryingOperand
},
DefineClassGetterByName {
value: VaryingOperand,
object: VaryingOperand,
name_index: VaryingOperand
},
SetPropertyGetterByValue {
value: VaryingOperand,
key: VaryingOperand,
object: VaryingOperand
},
DefineClassStaticGetterByValue {
value: VaryingOperand,
key: VaryingOperand,
object: VaryingOperand
},
DefineClassGetterByValue {
value: VaryingOperand,
key: VaryingOperand,
object: VaryingOperand
},
SetPropertySetterByName { object: VaryingOperand, value: VaryingOperand, name_index: VaryingOperand },
DefineClassStaticSetterByName {
value: VaryingOperand,
object: VaryingOperand,
name_index: VaryingOperand
},
DefineClassSetterByName {
value: VaryingOperand,
object: VaryingOperand,
name_index: VaryingOperand
},
SetPropertySetterByValue {
value: VaryingOperand,
key: VaryingOperand,
object: VaryingOperand
},
DefineClassStaticSetterByValue {
value: VaryingOperand,
key: VaryingOperand,
object: VaryingOperand
},
DefineClassSetterByValue {
value: VaryingOperand,
key: VaryingOperand,
object: VaryingOperand
},
SetPrivateField { value: VaryingOperand, object: VaryingOperand, name_index: VaryingOperand },
DefinePrivateField { object: VaryingOperand, value: VaryingOperand, name_index: VaryingOperand },
SetPrivateMethod { object: VaryingOperand, value: VaryingOperand, name_index: VaryingOperand },
SetPrivateSetter { object: VaryingOperand, value: VaryingOperand, name_index: VaryingOperand },
SetPrivateGetter { object: VaryingOperand, value: VaryingOperand, name_index: VaryingOperand },
GetPrivateField { dst: VaryingOperand, object: VaryingOperand, name_index: VaryingOperand },
PushClassField { object: VaryingOperand, name_index: VaryingOperand, value: VaryingOperand, is_anonymous_function: VaryingOperand },
PushClassFieldPrivate { object: VaryingOperand, value: VaryingOperand, name_index: VaryingOperand },
PushClassPrivateGetter { object: VaryingOperand, value: VaryingOperand, name_index: VaryingOperand },
PushClassPrivateSetter { object: VaryingOperand, value: VaryingOperand, name_index: VaryingOperand },
PushClassPrivateMethod { object: VaryingOperand, proto: VaryingOperand, value: VaryingOperand, name_index: VaryingOperand },
DeletePropertyByName { object: VaryingOperand, name_index: VaryingOperand },
DeletePropertyByValue { object: VaryingOperand, key: VaryingOperand },
DeleteSuperThrow,
CopyDataProperties { object: VaryingOperand, source: VaryingOperand, excluded_keys: ThinVec<VaryingOperand> },
ToPropertyKey { src: VaryingOperand, dst: VaryingOperand },
Jump { address: u32 },
JumpIfTrue { address: u32, value: VaryingOperand },
JumpIfFalse { address: u32, value: VaryingOperand },
JumpIfNotUndefined { address: u32, value: VaryingOperand },
JumpIfNullOrUndefined { address: u32, value: VaryingOperand },
JumpTable { index: u32, default: u32, addresses: ThinVec<u32> },
Throw { src: VaryingOperand },
ReThrow,
Exception { dst: VaryingOperand },
MaybeException { has_exception: VaryingOperand, exception: VaryingOperand },
ThrowNewTypeError { message: VaryingOperand },
ThrowNewSyntaxError { message: VaryingOperand },
ThrowNewReferenceError { message: VaryingOperand },
This { dst: VaryingOperand },
ThisForObjectEnvironmentName { dst: VaryingOperand, index: VaryingOperand },
Super { dst: VaryingOperand },
SuperCallPrepare { dst: VaryingOperand },
SuperCall { argument_count: VaryingOperand },
SuperCallSpread,
SuperCallDerived,
BindThisValue { value: VaryingOperand },
ImportCall { value: VaryingOperand },
Case { address: u32, value: VaryingOperand, condition: VaryingOperand },
GetFunction { dst: VaryingOperand, index: VaryingOperand },
CallEval { argument_count: VaryingOperand, scope_index: VaryingOperand },
CallEvalSpread { scope_index: VaryingOperand },
Call { argument_count: VaryingOperand },
CallSpread,
New { argument_count: VaryingOperand },
NewSpread,
CheckReturn,
Return,
AsyncGeneratorClose,
Generator { r#async: VaryingOperand },
SetAccumulator { src: VaryingOperand },
SetRegisterFromAccumulator { dst: VaryingOperand },
Move { dst: VaryingOperand, src: VaryingOperand },
PopIntoRegister { dst: VaryingOperand },
PushFromRegister { src: VaryingOperand },
PushScope { scope_index: VaryingOperand },
PushObjectEnvironment { src: VaryingOperand },
PopEnvironment,
IncrementLoopIteration,
CreateForInIterator { src: VaryingOperand },
GetIterator { src: VaryingOperand },
GetAsyncIterator { src: VaryingOperand },
IteratorNext,
IteratorDone { dst: VaryingOperand },
IteratorFinishAsyncNext { resume_kind: VaryingOperand, value: VaryingOperand },
IteratorValue { dst: VaryingOperand },
IteratorResult { dst: VaryingOperand },
IteratorToArray { dst: VaryingOperand },
IteratorStackEmpty { dst: VaryingOperand },
CreateIteratorResult { value: VaryingOperand, done: VaryingOperand },
IteratorReturn { value: VaryingOperand, called: VaryingOperand },
ConcatToString { dst: VaryingOperand, values: ThinVec<VaryingOperand> },
ValueNotNullOrUndefined { src: VaryingOperand },
RestParameterInit { dst: VaryingOperand },
GeneratorYield { src: VaryingOperand },
GeneratorNext { resume_kind: VaryingOperand, value: VaryingOperand },
AsyncGeneratorYield { src: VaryingOperand },
CreatePromiseCapability,
CompletePromiseCapability,
JumpIfNotResumeKind { address: u32, resume_kind: VaryingOperand, src: VaryingOperand },
GeneratorDelegateNext {
throw_method_undefined: u32,
return_method_undefined: u32,
value: VaryingOperand,
resume_kind: VaryingOperand,
is_return: VaryingOperand
},
GeneratorDelegateResume {
r#return: u32,
exit: u32,
value: VaryingOperand,
resume_kind: VaryingOperand,
is_return: VaryingOperand
},
Await { src: VaryingOperand },
NewTarget { dst: VaryingOperand },
ImportMeta { dst: VaryingOperand },
IsObject { value: VaryingOperand },
TemplateLookup { address: u32, site: u64, dst: VaryingOperand },
TemplateCreate { site: u64, dst: VaryingOperand, values: ThinVec<u32> },
PushPrivateEnvironment { class: VaryingOperand, name_indices: ThinVec<u32> },
PopPrivateEnvironment,
CreateMappedArgumentsObject { dst: VaryingOperand },
CreateUnmappedArgumentsObject { dst: VaryingOperand },
HasRestrictedGlobalProperty { dst: VaryingOperand, index: VaryingOperand },
CanDeclareGlobalFunction { dst: VaryingOperand, index: VaryingOperand },
CanDeclareGlobalVar { dst: VaryingOperand, index: VaryingOperand },
CreateGlobalFunctionBinding { src: VaryingOperand, configurable: VaryingOperand, name_index: VaryingOperand },
CreateGlobalVarBinding { configurable: VaryingOperand, name_index: VaryingOperand },
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,
Reserved60 => Reserved,
Reserved61 => Reserved,
Reserved62 => Reserved,
Reserved63 => Reserved,
}