mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-11 11:14:21 +01:00
Use vec for label resolution, not hashmap
This commit is contained in:
@@ -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() {
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user