Use vec for label resolution, not hashmap

This commit is contained in:
Jussi Saurio
2025-02-03 10:28:51 +02:00
parent 40f536fabb
commit 8b1f0ea23c
2 changed files with 26 additions and 16 deletions

View File

@@ -15,7 +15,7 @@ use super::{BranchOffset, CursorID, Insn, InsnReference, Program};
#[allow(dead_code)]
pub struct ProgramBuilder {
next_free_register: usize,
next_free_label: i32,
next_free_label: u32,
next_free_cursor_id: usize,
insns: Vec<Insn>,
// for temporarily storing instructions that will be put after Transaction opcode
@@ -24,7 +24,7 @@ pub struct ProgramBuilder {
// Cursors that are referenced by the program. Indexed by CursorID.
pub cursor_ref: Vec<(Option<String>, CursorType)>,
// Hashmap of label to insn reference. Resolved in build().
label_to_resolved_offset: HashMap<i32, u32>,
label_to_resolved_offset: Vec<Option<InsnReference>>,
// Bitmask of cursors that have emitted a SeekRowid instruction.
seekrowid_emitted_bitmask: u64,
// map of instruction index to manual comment (used in EXPLAIN)
@@ -57,7 +57,7 @@ impl ProgramBuilder {
next_insn_label: None,
cursor_ref: Vec::new(),
constant_insns: Vec::new(),
label_to_resolved_offset: HashMap::new(),
label_to_resolved_offset: Vec::with_capacity(4), // 4 is arbitrary, we guess to assign at least this much
seekrowid_emitted_bitmask: 0,
comments: HashMap::new(),
parameters: Parameters::new(),
@@ -91,8 +91,10 @@ impl ProgramBuilder {
pub fn emit_insn(&mut self, insn: Insn) {
if let Some(label) = self.next_insn_label {
self.label_to_resolved_offset
.insert(label.to_label_value(), self.insns.len() as InsnReference);
self.label_to_resolved_offset.insert(
label.to_label_value() as usize,
Some(self.insns.len() as InsnReference),
);
self.next_insn_label = None;
}
self.insns.push(insn);
@@ -183,8 +185,10 @@ impl ProgramBuilder {
}
pub fn allocate_label(&mut self) -> BranchOffset {
self.next_free_label -= 1;
BranchOffset::Label(self.next_free_label)
let label_n = self.next_free_label;
self.next_free_label += 1;
self.label_to_resolved_offset.push(None);
BranchOffset::Label(label_n)
}
// Effectively a GOTO <next insn> without the need to emit an explicit GOTO instruction.
@@ -197,8 +201,8 @@ impl ProgramBuilder {
pub fn resolve_label(&mut self, label: BranchOffset, to_offset: BranchOffset) {
assert!(matches!(label, BranchOffset::Label(_)));
assert!(matches!(to_offset, BranchOffset::Offset(_)));
self.label_to_resolved_offset
.insert(label.to_label_value(), to_offset.to_offset_int());
self.label_to_resolved_offset[label.to_label_value() as usize] =
Some(to_offset.to_offset_int());
}
/// Resolve unresolved labels to a specific offset in the instruction list.
@@ -209,10 +213,16 @@ impl ProgramBuilder {
pub fn resolve_labels(&mut self) {
let resolve = |pc: &mut BranchOffset, insn_name: &str| {
if let BranchOffset::Label(label) = pc {
let to_offset = *self.label_to_resolved_offset.get(label).unwrap_or_else(|| {
panic!("Reference to undefined label in {}: {}", insn_name, label)
});
*pc = BranchOffset::Offset(to_offset);
let to_offset = self
.label_to_resolved_offset
.get(*label as usize)
.unwrap_or_else(|| {
panic!("Reference to undefined label in {}: {}", insn_name, label)
});
*pc = BranchOffset::Offset(
to_offset
.unwrap_or_else(|| panic!("Unresolved label in {}: {}", insn_name, label)),
);
}
};
for insn in self.insns.iter_mut() {

View File

@@ -74,7 +74,7 @@ pub enum BranchOffset {
/// A label is a named location in the program.
/// If there are references to it, it must always be resolved to an Offset
/// via program.resolve_label().
Label(i32),
Label(u32),
/// An offset is a direct index into the instruction list.
Offset(InsnReference),
/// A placeholder is a temporary value to satisfy the compiler.
@@ -103,7 +103,7 @@ impl BranchOffset {
}
/// Returns the label value. Panics if the branch offset is an offset or placeholder.
pub fn to_label_value(&self) -> i32 {
pub fn to_label_value(&self) -> u32 {
match self {
BranchOffset::Label(v) => *v,
BranchOffset::Offset(_) => unreachable!("Offset cannot be converted to label value"),
@@ -116,7 +116,7 @@ impl BranchOffset {
/// label or placeholder.
pub fn to_debug_int(&self) -> i32 {
match self {
BranchOffset::Label(v) => *v,
BranchOffset::Label(v) => *v as i32,
BranchOffset::Offset(v) => *v as i32,
BranchOffset::Placeholder => i32::MAX,
}