From 8b1f0ea23c92ad1ea91b9e7cbbc1fa2391ff8141 Mon Sep 17 00:00:00 2001 From: Jussi Saurio Date: Mon, 3 Feb 2025 10:28:51 +0200 Subject: [PATCH] Use vec for label resolution, not hashmap --- core/vdbe/builder.rs | 36 +++++++++++++++++++++++------------- core/vdbe/mod.rs | 6 +++--- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/core/vdbe/builder.rs b/core/vdbe/builder.rs index 1752e9dd3..a029a0161 100644 --- a/core/vdbe/builder.rs +++ b/core/vdbe/builder.rs @@ -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, // 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, CursorType)>, // Hashmap of label to insn reference. Resolved in build(). - label_to_resolved_offset: HashMap, + label_to_resolved_offset: Vec>, // 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 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() { diff --git a/core/vdbe/mod.rs b/core/vdbe/mod.rs index 16156347a..3f70dab45 100644 --- a/core/vdbe/mod.rs +++ b/core/vdbe/mod.rs @@ -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, }