143 lines
4.0 KiB
Rust
143 lines
4.0 KiB
Rust
use fix_codegen::OperandType;
|
|
use fix_common::StringId;
|
|
use num_enum::TryFromPrimitive;
|
|
use string_interner::Symbol as _;
|
|
|
|
use crate::{OperandData, VmRuntimeCtx};
|
|
|
|
pub(crate) struct BytecodeReader<'a> {
|
|
bytecode: &'a [u8],
|
|
pc: usize,
|
|
inst_start_pc: usize,
|
|
}
|
|
|
|
impl<'a> BytecodeReader<'a> {
|
|
#[cfg_attr(feature = "tailcall", allow(dead_code))]
|
|
pub(crate) fn new(bytecode: &'a [u8], pc: usize) -> Self {
|
|
Self {
|
|
bytecode,
|
|
pc,
|
|
inst_start_pc: pc,
|
|
}
|
|
}
|
|
|
|
#[inline(always)]
|
|
#[cfg_attr(not(feature = "tailcall"), allow(dead_code))]
|
|
pub(crate) fn from_after_op(bytecode: &'a [u8], inst_start_pc: usize) -> Self {
|
|
Self {
|
|
bytecode,
|
|
pc: inst_start_pc + 1,
|
|
inst_start_pc,
|
|
}
|
|
}
|
|
|
|
#[inline(always)]
|
|
#[cfg_attr(debug_assertions, track_caller)]
|
|
fn read_array<const N: usize>(&mut self) -> [u8; N] {
|
|
let ret = self.bytecode[self.pc..self.pc + N]
|
|
.try_into()
|
|
.expect("read_array failed");
|
|
self.pc += N;
|
|
ret
|
|
}
|
|
|
|
#[inline(always)]
|
|
#[cfg_attr(feature = "tailcall", allow(dead_code))]
|
|
pub(crate) fn read_op(&mut self) -> fix_codegen::Op {
|
|
use fix_codegen::Op;
|
|
self.inst_start_pc = self.pc;
|
|
let byte = self.bytecode[self.pc];
|
|
if !likely_stable::likely((0..Op::Illegal as u8).contains(&byte)) {
|
|
panic!("unknown opcode: {byte:#04x}")
|
|
}
|
|
self.pc += 1;
|
|
unsafe { std::mem::transmute::<u8, Op>(byte) }
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn read_u8(&mut self) -> u8 {
|
|
let val = self.bytecode[self.pc];
|
|
self.pc += 1;
|
|
val
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn read_u16(&mut self) -> u16 {
|
|
u16::from_le_bytes(self.read_array())
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn read_u32(&mut self) -> u32 {
|
|
u32::from_le_bytes(self.read_array())
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn read_i32(&mut self) -> i32 {
|
|
i32::from_le_bytes(self.read_array())
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn read_i64(&mut self) -> i64 {
|
|
i64::from_le_bytes(self.read_array())
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn read_f64(&mut self) -> f64 {
|
|
f64::from_le_bytes(self.read_array())
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn read_string_id(&mut self) -> StringId {
|
|
let raw = self.read_u32();
|
|
#[allow(clippy::unwrap_used)]
|
|
StringId(string_interner::symbol::SymbolU32::try_from_usize(raw as usize).unwrap())
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn read_operand_data<C: VmRuntimeCtx>(&mut self, ctx: &C) -> OperandData {
|
|
let tag = self.read_u8();
|
|
let Ok(ty) = OperandType::try_from_primitive(tag)
|
|
.map_err(|err| panic!("unknown operand tag: {:#04x}", err.number));
|
|
match ty {
|
|
OperandType::Const => {
|
|
let id = self.read_u32();
|
|
OperandData::Const(ctx.get_const(id))
|
|
}
|
|
OperandType::BigInt => {
|
|
let val = self.read_i64();
|
|
OperandData::BigInt(val)
|
|
}
|
|
OperandType::Local => {
|
|
let layer = self.read_u8();
|
|
let idx = self.read_u32();
|
|
OperandData::Local { layer, idx }
|
|
}
|
|
OperandType::BuiltinConst => {
|
|
let id = self.read_string_id();
|
|
OperandData::BuiltinConst(id)
|
|
}
|
|
OperandType::Builtins => OperandData::Builtins,
|
|
OperandType::ReplBinding => {
|
|
let id = self.read_string_id();
|
|
OperandData::ReplBinding(id)
|
|
}
|
|
OperandType::ScopedImportBinding => {
|
|
let id = self.read_string_id();
|
|
OperandData::ScopedImportBinding(id)
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(crate) fn pc(&self) -> usize {
|
|
self.pc
|
|
}
|
|
|
|
pub(crate) fn set_pc(&mut self, pc: usize) {
|
|
self.pc = pc;
|
|
}
|
|
|
|
pub(crate) fn inst_start_pc(&self) -> usize {
|
|
self.inst_start_pc
|
|
}
|
|
}
|