introduce instruction virtual table

This commit is contained in:
TcMits
2025-09-13 16:35:17 +07:00
parent b1420904bb
commit 01da48fde9
5 changed files with 213 additions and 160 deletions

View File

@@ -412,7 +412,8 @@ impl CompiledExpression {
// Execute the program
let mut pc = 0usize;
while pc < program.insns.len() {
let (insn, insn_fn) = &program.insns[pc];
let (insn, _) = &program.insns[pc];
let insn_fn = insn.to_function_fast();
state.pc = pc as u32;
// Execute the instruction

View File

@@ -64,7 +64,7 @@ impl CheckpointResult {
}
}
#[derive(Debug, Copy, Clone, EnumString)]
#[derive(Debug, Copy, Clone, Default, EnumString)]
#[strum(ascii_case_insensitive)]
pub enum CheckpointMode {
/// Checkpoint as many frames as possible without waiting for any database readers or writers to finish, then sync the database file if all frames in the log were checkpointed.
@@ -73,6 +73,7 @@ pub enum CheckpointMode {
/// Optional upper_bound_inclusive parameter can be set in order to checkpoint frames with number no larger than the parameter
Passive { upper_bound_inclusive: Option<u64> },
/// This mode blocks until there is no database writer and all readers are reading from the most recent database snapshot. It then checkpoints all frames in the log file and syncs the database file. This mode blocks new database writers while it is pending, but new database readers are allowed to continue unimpeded.
#[default]
Full,
/// This mode works the same way as `Full` with the addition that after checkpointing the log file it blocks (calls the busy-handler callback) until all readers are reading from the database file only. This ensures that the next writer will restart the log file from the beginning. Like `Full`, this mode blocks new database writer attempts while it is pending, but does not impede readers.
Restart,

View File

@@ -34,7 +34,7 @@ impl TableRefIdCounter {
}
}
use super::{BranchOffset, CursorID, Insn, InsnFunction, InsnReference, JumpTarget, Program};
use super::{BranchOffset, CursorID, Insn, InsnReference, JumpTarget, Program};
/// A key that uniquely identifies a cursor.
/// The key is a pair of table reference id and index.
@@ -85,7 +85,7 @@ pub struct ProgramBuilder {
next_free_register: usize,
next_free_cursor_id: usize,
/// Instruction, the function to execute it with, and its original index in the vector.
insns: Vec<(Insn, InsnFunction, usize)>,
insns: Vec<(Insn, usize)>,
/// A span of instructions from (offset_start_inclusive, offset_end_exclusive),
/// that are deemed to be compile-time constant and can be hoisted out of loops
/// so that they get evaluated only once at the start of the program.
@@ -328,10 +328,9 @@ impl ProgramBuilder {
#[instrument(skip(self), level = Level::DEBUG)]
pub fn emit_insn(&mut self, insn: Insn) {
let function = insn.to_function();
// This seemingly empty trace here is needed so that a function span is emmited with it
tracing::trace!("");
self.insns.push((insn, function, self.insns.len()));
self.insns.push((insn, self.insns.len()));
}
pub fn close_cursors(&mut self, cursors: &[CursorID]) {
@@ -419,7 +418,7 @@ impl ProgramBuilder {
pub fn pop_current_parent_explain(&mut self) {
if let QueryMode::ExplainQueryPlan = self.query_mode {
if let Some(current) = self.current_parent_explain_idx {
let (Insn::Explain { p2, .. }, _, _) = &self.insns[current] else {
let (Insn::Explain { p2, .. }, _) = &self.insns[current] else {
unreachable!("current_parent_explain_idx must point to an Explain insn");
};
self.current_parent_explain_idx = *p2;
@@ -447,7 +446,7 @@ impl ProgramBuilder {
// 1. if insn not in any constant span, it stays where it is
// 2. if insn is in a constant span, it is after other insns, except those that are in a later constant span
// 3. within a single constant span the order is preserver
self.insns.sort_by(|(_, _, index_a), (_, _, index_b)| {
self.insns.sort_by(|(_, index_a), (_, index_b)| {
let a_span = self
.constant_spans
.iter()
@@ -471,7 +470,7 @@ impl ProgramBuilder {
let new_offset = self
.insns
.iter()
.position(|(_, _, index)| *old_offset == *index as u32)
.position(|(_, index)| *old_offset == *index as u32)
.unwrap() as u32;
*resolved_offset = Some((new_offset, *target));
}
@@ -482,7 +481,7 @@ impl ProgramBuilder {
let new_offset = self
.insns
.iter()
.position(|(_, _, index)| *old_offset == *index as u32)
.position(|(_, index)| *old_offset == *index as u32)
.expect("comment must exist") as u32;
*old_offset = new_offset;
}
@@ -492,25 +491,23 @@ impl ProgramBuilder {
if let Some(old_parent) = self.current_parent_explain_idx {
self.insns
.iter()
.position(|(_, _, index)| old_parent == *index)
.position(|(_, index)| old_parent == *index)
} else {
None
};
for i in 0..self.insns.len() {
let (Insn::Explain { p2, .. }, _, _) = &self.insns[i] else {
let (Insn::Explain { p2, .. }, _) = &self.insns[i] else {
continue;
};
let new_p2 = if p2.is_some() {
self.insns
.iter()
.position(|(_, _, index)| *p2 == Some(*index))
self.insns.iter().position(|(_, index)| *p2 == Some(*index))
} else {
None
};
let (Insn::Explain { p1, p2, .. }, _, _) = &mut self.insns[i] else {
let (Insn::Explain { p1, p2, .. }, _) = &mut self.insns[i] else {
unreachable!();
};
@@ -591,7 +588,7 @@ impl ProgramBuilder {
);
}
};
for (insn, _, _) in self.insns.iter_mut() {
for (insn, _) in self.insns.iter_mut() {
match insn {
Insn::Init { target_pc } => {
resolve(target_pc, "Init");
@@ -997,11 +994,7 @@ impl ProgramBuilder {
self.parameters.list.dedup();
Program {
max_registers: self.next_free_register,
insns: self
.insns
.into_iter()
.map(|(insn, function, _)| (insn, function))
.collect(),
insns: self.insns,
cursor_ref: self.cursor_ref,
comments: self.comments,
connection,

View File

@@ -10,6 +10,10 @@ use crate::{
translate::{collate::CollationSeq, emitter::TransactionMode},
Value,
};
use std::sync::LazyLock;
use strum::EnumCount;
use strum::VariantArray as _;
use strum_macros::{EnumDiscriminants, VariantArray};
use turso_macros::Description;
use turso_parser::ast::SortOrder;
@@ -150,7 +154,11 @@ impl<T: Copy + std::fmt::Display> std::fmt::Display for RegisterOrLiteral<T> {
}
}
#[derive(Description, Debug)]
#[derive(Description, Debug, EnumDiscriminants)]
#[strum_discriminants(vis(pub(crate)))]
#[strum_discriminants(derive(VariantArray, EnumCount))]
#[strum_discriminants(repr(u8))]
#[strum_discriminants(name(InsnVariants))]
pub enum Insn {
/// Initialize the program state and jump to the given PC.
Init {
@@ -1095,147 +1103,175 @@ pub enum Insn {
},
}
impl Insn {
pub fn to_function(&self) -> InsnFunction {
static INSN_VIRTUAL_TABLE: LazyLock<[InsnFunction; InsnVariants::COUNT]> = LazyLock::new(|| {
let mut result: [InsnFunction; InsnVariants::COUNT] = [execute::op_null; InsnVariants::COUNT];
for variant in InsnVariants::VARIANTS {
result[*variant as u8 as usize] = variant.to_function();
}
result
});
impl InsnVariants {
pub(crate) fn to_function_fast(&self) -> InsnFunction {
INSN_VIRTUAL_TABLE[*self as u8 as usize]
}
pub(crate) fn to_function(&self) -> InsnFunction {
match self {
Insn::Init { .. } => execute::op_init,
Insn::Null { .. } => execute::op_null,
Insn::BeginSubrtn { .. } => execute::op_null,
Insn::NullRow { .. } => execute::op_null_row,
Insn::Add { .. } => execute::op_add,
Insn::Subtract { .. } => execute::op_subtract,
Insn::Multiply { .. } => execute::op_multiply,
Insn::Divide { .. } => execute::op_divide,
Insn::DropIndex { .. } => execute::op_drop_index,
Insn::Compare { .. } => execute::op_compare,
Insn::BitAnd { .. } => execute::op_bit_and,
Insn::BitOr { .. } => execute::op_bit_or,
Insn::BitNot { .. } => execute::op_bit_not,
Insn::Checkpoint { .. } => execute::op_checkpoint,
Insn::Remainder { .. } => execute::op_remainder,
Insn::Jump { .. } => execute::op_jump,
Insn::Move { .. } => execute::op_move,
Insn::IfPos { .. } => execute::op_if_pos,
Insn::NotNull { .. } => execute::op_not_null,
Insn::Eq { .. }
| Insn::Ne { .. }
| Insn::Lt { .. }
| Insn::Le { .. }
| Insn::Gt { .. }
| Insn::Ge { .. } => execute::op_comparison,
Insn::If { .. } => execute::op_if,
Insn::IfNot { .. } => execute::op_if_not,
Insn::OpenRead { .. } => execute::op_open_read,
Insn::VOpen { .. } => execute::op_vopen,
Insn::VCreate { .. } => execute::op_vcreate,
Insn::VFilter { .. } => execute::op_vfilter,
Insn::VColumn { .. } => execute::op_vcolumn,
Insn::VUpdate { .. } => execute::op_vupdate,
Insn::VNext { .. } => execute::op_vnext,
Insn::VDestroy { .. } => execute::op_vdestroy,
InsnVariants::Init { .. } => execute::op_init,
InsnVariants::Null { .. } => execute::op_null,
InsnVariants::BeginSubrtn { .. } => execute::op_null,
InsnVariants::NullRow { .. } => execute::op_null_row,
InsnVariants::Add { .. } => execute::op_add,
InsnVariants::Subtract { .. } => execute::op_subtract,
InsnVariants::Multiply { .. } => execute::op_multiply,
InsnVariants::Divide { .. } => execute::op_divide,
InsnVariants::DropIndex { .. } => execute::op_drop_index,
InsnVariants::Compare { .. } => execute::op_compare,
InsnVariants::BitAnd { .. } => execute::op_bit_and,
InsnVariants::BitOr { .. } => execute::op_bit_or,
InsnVariants::BitNot { .. } => execute::op_bit_not,
InsnVariants::Checkpoint { .. } => execute::op_checkpoint,
InsnVariants::Remainder { .. } => execute::op_remainder,
InsnVariants::Jump { .. } => execute::op_jump,
InsnVariants::Move { .. } => execute::op_move,
InsnVariants::IfPos { .. } => execute::op_if_pos,
InsnVariants::NotNull { .. } => execute::op_not_null,
InsnVariants::Eq { .. }
| InsnVariants::Ne { .. }
| InsnVariants::Lt { .. }
| InsnVariants::Le { .. }
| InsnVariants::Gt { .. }
| InsnVariants::Ge { .. } => execute::op_comparison,
InsnVariants::If { .. } => execute::op_if,
InsnVariants::IfNot { .. } => execute::op_if_not,
InsnVariants::OpenRead { .. } => execute::op_open_read,
InsnVariants::VOpen { .. } => execute::op_vopen,
InsnVariants::VCreate { .. } => execute::op_vcreate,
InsnVariants::VFilter { .. } => execute::op_vfilter,
InsnVariants::VColumn { .. } => execute::op_vcolumn,
InsnVariants::VUpdate { .. } => execute::op_vupdate,
InsnVariants::VNext { .. } => execute::op_vnext,
InsnVariants::VDestroy { .. } => execute::op_vdestroy,
Insn::OpenPseudo { .. } => execute::op_open_pseudo,
Insn::Rewind { .. } => execute::op_rewind,
Insn::Last { .. } => execute::op_last,
Insn::Column { .. } => execute::op_column,
Insn::TypeCheck { .. } => execute::op_type_check,
Insn::MakeRecord { .. } => execute::op_make_record,
Insn::ResultRow { .. } => execute::op_result_row,
Insn::Next { .. } => execute::op_next,
Insn::Prev { .. } => execute::op_prev,
Insn::Halt { .. } => execute::op_halt,
Insn::HaltIfNull { .. } => execute::op_halt_if_null,
Insn::Transaction { .. } => execute::op_transaction,
Insn::AutoCommit { .. } => execute::op_auto_commit,
Insn::Goto { .. } => execute::op_goto,
Insn::Gosub { .. } => execute::op_gosub,
Insn::Return { .. } => execute::op_return,
Insn::Integer { .. } => execute::op_integer,
Insn::Real { .. } => execute::op_real,
Insn::RealAffinity { .. } => execute::op_real_affinity,
Insn::String8 { .. } => execute::op_string8,
Insn::Blob { .. } => execute::op_blob,
Insn::RowData { .. } => execute::op_row_data,
Insn::RowId { .. } => execute::op_row_id,
Insn::IdxRowId { .. } => execute::op_idx_row_id,
Insn::SeekRowid { .. } => execute::op_seek_rowid,
Insn::DeferredSeek { .. } => execute::op_deferred_seek,
Insn::SeekGE { .. }
| Insn::SeekGT { .. }
| Insn::SeekLE { .. }
| Insn::SeekLT { .. } => execute::op_seek,
Insn::SeekEnd { .. } => execute::op_seek_end,
Insn::IdxGE { .. } => execute::op_idx_ge,
Insn::IdxGT { .. } => execute::op_idx_gt,
Insn::IdxLE { .. } => execute::op_idx_le,
Insn::IdxLT { .. } => execute::op_idx_lt,
Insn::DecrJumpZero { .. } => execute::op_decr_jump_zero,
Insn::AggStep { .. } => execute::op_agg_step,
Insn::AggFinal { .. } => execute::op_agg_final,
Insn::SorterOpen { .. } => execute::op_sorter_open,
Insn::SorterInsert { .. } => execute::op_sorter_insert,
Insn::SorterSort { .. } => execute::op_sorter_sort,
Insn::SorterData { .. } => execute::op_sorter_data,
Insn::SorterNext { .. } => execute::op_sorter_next,
Insn::Function { .. } => execute::op_function,
Insn::Cast { .. } => execute::op_cast,
Insn::InitCoroutine { .. } => execute::op_init_coroutine,
Insn::EndCoroutine { .. } => execute::op_end_coroutine,
Insn::Yield { .. } => execute::op_yield,
Insn::Insert { .. } => execute::op_insert,
Insn::Int64 { .. } => execute::op_int_64,
Insn::IdxInsert { .. } => execute::op_idx_insert,
Insn::Delete { .. } => execute::op_delete,
Insn::NewRowid { .. } => execute::op_new_rowid,
Insn::MustBeInt { .. } => execute::op_must_be_int,
Insn::SoftNull { .. } => execute::op_soft_null,
Insn::NoConflict { .. } => execute::op_no_conflict,
Insn::NotExists { .. } => execute::op_not_exists,
Insn::OffsetLimit { .. } => execute::op_offset_limit,
Insn::OpenWrite { .. } => execute::op_open_write,
Insn::Copy { .. } => execute::op_copy,
Insn::CreateBtree { .. } => execute::op_create_btree,
Insn::Destroy { .. } => execute::op_destroy,
InsnVariants::OpenPseudo { .. } => execute::op_open_pseudo,
InsnVariants::Rewind { .. } => execute::op_rewind,
InsnVariants::Last { .. } => execute::op_last,
InsnVariants::Column { .. } => execute::op_column,
InsnVariants::TypeCheck { .. } => execute::op_type_check,
InsnVariants::MakeRecord { .. } => execute::op_make_record,
InsnVariants::ResultRow { .. } => execute::op_result_row,
InsnVariants::Next { .. } => execute::op_next,
InsnVariants::Prev { .. } => execute::op_prev,
InsnVariants::Halt { .. } => execute::op_halt,
InsnVariants::HaltIfNull { .. } => execute::op_halt_if_null,
InsnVariants::Transaction { .. } => execute::op_transaction,
InsnVariants::AutoCommit { .. } => execute::op_auto_commit,
InsnVariants::Goto { .. } => execute::op_goto,
InsnVariants::Gosub { .. } => execute::op_gosub,
InsnVariants::Return { .. } => execute::op_return,
InsnVariants::Integer { .. } => execute::op_integer,
InsnVariants::Real { .. } => execute::op_real,
InsnVariants::RealAffinity { .. } => execute::op_real_affinity,
InsnVariants::String8 { .. } => execute::op_string8,
InsnVariants::Blob { .. } => execute::op_blob,
InsnVariants::RowData { .. } => execute::op_row_data,
InsnVariants::RowId { .. } => execute::op_row_id,
InsnVariants::IdxRowId { .. } => execute::op_idx_row_id,
InsnVariants::SeekRowid { .. } => execute::op_seek_rowid,
InsnVariants::DeferredSeek { .. } => execute::op_deferred_seek,
InsnVariants::SeekGE { .. }
| InsnVariants::SeekGT { .. }
| InsnVariants::SeekLE { .. }
| InsnVariants::SeekLT { .. } => execute::op_seek,
InsnVariants::SeekEnd { .. } => execute::op_seek_end,
InsnVariants::IdxGE { .. } => execute::op_idx_ge,
InsnVariants::IdxGT { .. } => execute::op_idx_gt,
InsnVariants::IdxLE { .. } => execute::op_idx_le,
InsnVariants::IdxLT { .. } => execute::op_idx_lt,
InsnVariants::DecrJumpZero { .. } => execute::op_decr_jump_zero,
InsnVariants::AggStep { .. } => execute::op_agg_step,
InsnVariants::AggFinal { .. } => execute::op_agg_final,
InsnVariants::SorterOpen { .. } => execute::op_sorter_open,
InsnVariants::SorterInsert { .. } => execute::op_sorter_insert,
InsnVariants::SorterSort { .. } => execute::op_sorter_sort,
InsnVariants::SorterData { .. } => execute::op_sorter_data,
InsnVariants::SorterNext { .. } => execute::op_sorter_next,
InsnVariants::Function { .. } => execute::op_function,
InsnVariants::Cast { .. } => execute::op_cast,
InsnVariants::InitCoroutine { .. } => execute::op_init_coroutine,
InsnVariants::EndCoroutine { .. } => execute::op_end_coroutine,
InsnVariants::Yield { .. } => execute::op_yield,
InsnVariants::Insert { .. } => execute::op_insert,
InsnVariants::Int64 { .. } => execute::op_int_64,
InsnVariants::IdxInsert { .. } => execute::op_idx_insert,
InsnVariants::Delete { .. } => execute::op_delete,
InsnVariants::NewRowid { .. } => execute::op_new_rowid,
InsnVariants::MustBeInt { .. } => execute::op_must_be_int,
InsnVariants::SoftNull { .. } => execute::op_soft_null,
InsnVariants::NoConflict { .. } => execute::op_no_conflict,
InsnVariants::NotExists { .. } => execute::op_not_exists,
InsnVariants::OffsetLimit { .. } => execute::op_offset_limit,
InsnVariants::OpenWrite { .. } => execute::op_open_write,
InsnVariants::Copy { .. } => execute::op_copy,
InsnVariants::CreateBtree { .. } => execute::op_create_btree,
InsnVariants::Destroy { .. } => execute::op_destroy,
Insn::DropTable { .. } => execute::op_drop_table,
Insn::DropView { .. } => execute::op_drop_view,
Insn::Close { .. } => execute::op_close,
Insn::IsNull { .. } => execute::op_is_null,
Insn::CollSeq { .. } => execute::op_coll_seq,
Insn::ParseSchema { .. } => execute::op_parse_schema,
Insn::PopulateMaterializedViews { .. } => execute::op_populate_materialized_views,
Insn::ShiftRight { .. } => execute::op_shift_right,
Insn::ShiftLeft { .. } => execute::op_shift_left,
Insn::AddImm { .. } => execute::op_add_imm,
Insn::Variable { .. } => execute::op_variable,
Insn::ZeroOrNull { .. } => execute::op_zero_or_null,
Insn::Not { .. } => execute::op_not,
Insn::Concat { .. } => execute::op_concat,
Insn::And { .. } => execute::op_and,
Insn::Or { .. } => execute::op_or,
Insn::Noop => execute::op_noop,
Insn::PageCount { .. } => execute::op_page_count,
Insn::ReadCookie { .. } => execute::op_read_cookie,
Insn::SetCookie { .. } => execute::op_set_cookie,
Insn::OpenEphemeral { .. } | Insn::OpenAutoindex { .. } => execute::op_open_ephemeral,
Insn::Once { .. } => execute::op_once,
Insn::Found { .. } | Insn::NotFound { .. } => execute::op_found,
Insn::Affinity { .. } => execute::op_affinity,
Insn::IdxDelete { .. } => execute::op_idx_delete,
Insn::Count { .. } => execute::op_count,
Insn::IntegrityCk { .. } => execute::op_integrity_check,
Insn::RenameTable { .. } => execute::op_rename_table,
Insn::DropColumn { .. } => execute::op_drop_column,
Insn::AddColumn { .. } => execute::op_add_column,
Insn::AlterColumn { .. } => execute::op_alter_column,
Insn::MaxPgcnt { .. } => execute::op_max_pgcnt,
Insn::JournalMode { .. } => execute::op_journal_mode,
Insn::IfNeg { .. } => execute::op_if_neg,
Insn::Explain { .. } => execute::op_noop,
InsnVariants::DropTable { .. } => execute::op_drop_table,
InsnVariants::DropView { .. } => execute::op_drop_view,
InsnVariants::Close { .. } => execute::op_close,
InsnVariants::IsNull { .. } => execute::op_is_null,
InsnVariants::CollSeq { .. } => execute::op_coll_seq,
InsnVariants::ParseSchema { .. } => execute::op_parse_schema,
InsnVariants::PopulateMaterializedViews { .. } => {
execute::op_populate_materialized_views
}
InsnVariants::ShiftRight { .. } => execute::op_shift_right,
InsnVariants::ShiftLeft { .. } => execute::op_shift_left,
InsnVariants::AddImm { .. } => execute::op_add_imm,
InsnVariants::Variable { .. } => execute::op_variable,
InsnVariants::ZeroOrNull { .. } => execute::op_zero_or_null,
InsnVariants::Not { .. } => execute::op_not,
InsnVariants::Concat { .. } => execute::op_concat,
InsnVariants::And { .. } => execute::op_and,
InsnVariants::Or { .. } => execute::op_or,
InsnVariants::Noop => execute::op_noop,
InsnVariants::PageCount { .. } => execute::op_page_count,
InsnVariants::ReadCookie { .. } => execute::op_read_cookie,
InsnVariants::SetCookie { .. } => execute::op_set_cookie,
InsnVariants::OpenEphemeral { .. } | InsnVariants::OpenAutoindex { .. } => {
execute::op_open_ephemeral
}
InsnVariants::Once { .. } => execute::op_once,
InsnVariants::Found { .. } | InsnVariants::NotFound { .. } => execute::op_found,
InsnVariants::Affinity { .. } => execute::op_affinity,
InsnVariants::IdxDelete { .. } => execute::op_idx_delete,
InsnVariants::Count { .. } => execute::op_count,
InsnVariants::IntegrityCk { .. } => execute::op_integrity_check,
InsnVariants::RenameTable { .. } => execute::op_rename_table,
InsnVariants::DropColumn { .. } => execute::op_drop_column,
InsnVariants::AddColumn { .. } => execute::op_add_column,
InsnVariants::AlterColumn { .. } => execute::op_alter_column,
InsnVariants::MaxPgcnt { .. } => execute::op_max_pgcnt,
InsnVariants::JournalMode { .. } => execute::op_journal_mode,
InsnVariants::IfNeg { .. } => execute::op_if_neg,
InsnVariants::Explain { .. } => execute::op_noop,
}
}
}
impl Insn {
pub fn to_function_fast(&self) -> InsnFunction {
InsnVariants::from(self).to_function_fast()
}
pub fn to_function(&self) -> InsnFunction {
InsnVariants::from(self).to_function()
}
}
// TODO: Add remaining cookies.
#[derive(Description, Debug, Clone, Copy)]
pub enum Cookie {
@@ -1256,3 +1292,21 @@ pub enum Cookie {
/// The application ID as set by the application_id pragma.
ApplicationId = 8,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_make_sure_correct_insn_table() {
for variant in super::InsnVariants::VARIANTS {
let func1 = variant.to_function();
let func2 = variant.to_function_fast();
assert_eq!(
func1 as usize, func2 as usize,
"Variant {:?} does not match in fast table",
variant
);
}
}
}

View File

@@ -96,7 +96,7 @@ pub enum JumpTarget {
AfterThisInsn,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
/// Represents a target for a jump instruction.
/// Stores 32-bit ints to keep the enum word-sized.
pub enum BranchOffset {
@@ -108,6 +108,7 @@ pub enum BranchOffset {
Offset(InsnReference),
/// A placeholder is a temporary value to satisfy the compiler.
/// It must be set later.
#[default]
Placeholder,
}
@@ -475,7 +476,9 @@ macro_rules! get_cursor {
pub struct Program {
pub max_registers: usize,
pub insns: Vec<(Insn, InsnFunction)>,
// we store original indices because we don't want to create new vec from
// ProgramBuilder
pub insns: Vec<(Insn, usize)>,
pub cursor_ref: Vec<(Option<CursorKey>, CursorType)>,
pub comments: Vec<(InsnReference, &'static str)>,
pub parameters: crate::parameters::Parameters,
@@ -644,7 +647,8 @@ impl Program {
}
// invalidate row
let _ = state.result_row.take();
let (insn, insn_function) = &self.insns[state.pc as usize];
let (insn, _) = &self.insns[state.pc as usize];
let insn_function = insn.to_function_fast();
if enable_tracing {
trace_insn(self, state.pc as InsnReference, insn);
}