Skip to main content

bytecode_lang/
builder.rs

1//! Building modules: [`ModuleBuilder`] and [`FunctionBuilder`].
2//!
3//! The builders own every structural guarantee a code generator should not
4//! have to think about: strings, structural types, and constants are
5//! deduplicated; registers are numbered and typed as they are declared;
6//! branches are written against [`Label`]s and resolved when the function is
7//! added, so **a built function never contains an unresolved or out-of-range
8//! branch target**; and [`FunctionBuilder::parallel_move`] turns a set of
9//! simultaneous moves (block arguments, the bytecode stand-in for SSA phis)
10//! into a correct sequence, breaking cycles through a temporary (the defect
11//! class of family issue H01, where `jump H(b, a)` was emitted as two plain
12//! moves and lost a value).
13//!
14//! Builder methods that cannot fail on their own (declaring a register,
15//! emitting an instruction) never return `Result`. When one of them does
16//! hit a limit, or is handed a label from another function, the builder
17//! records the first such error and reports it from
18//! [`ModuleBuilder::add_function`] or [`ModuleBuilder::finish`], so a
19//! code generator can emit straight-line code and check once.
20
21use alloc::boxed::Box;
22use alloc::collections::{BTreeMap, BTreeSet};
23use alloc::vec::Vec;
24use core::fmt;
25
26use crate::encode::section_sizes;
27use crate::ids::{
28    ConstId, FuncId, GlobalId, ImportId, NameRef, Reg, StrId, TableId, Target, TypeId, TypeRef,
29    UpvalIdx,
30};
31use crate::inst::Inst;
32use crate::module::{
33    Callee, Const, Export, ExportItem, Function, Global, Handler, Hook, HookBinding, Import,
34    JumpTable, LineRow, LocalVar, Module, Strings,
35};
36use crate::policy::IntTy;
37use crate::types::{FuncType, TypeDef, ValType};
38
39/// Why a function or module could not be built.
40///
41/// # Examples
42///
43/// ```
44/// use bytecode_lang::{BuildError, ModuleBuilder};
45///
46/// let mut m = ModuleBuilder::new();
47/// let mut f = m.function("f", &[], &[]);
48/// let nowhere = f.label();
49/// f.jmp(nowhere); // never bound
50/// let err = m.add_function(f).unwrap_err();
51/// assert!(matches!(err, BuildError::UnboundLabel { .. }));
52/// ```
53#[derive(Clone, Copy, PartialEq, Eq, Debug)]
54#[non_exhaustive]
55pub enum BuildError {
56    /// A branch, table, handler, or local uses a label that was never bound.
57    UnboundLabel {
58        /// The function.
59        func: FuncId,
60        /// The label's number within the function.
61        label: u32,
62    },
63    /// A label was bound twice.
64    LabelRebound {
65        /// The function.
66        func: FuncId,
67        /// The label's number within the function.
68        label: u32,
69    },
70    /// A label made by another function's builder was used.
71    ForeignLabel {
72        /// The function whose builder saw the label.
73        func: FuncId,
74    },
75    /// A branch target is not an instruction of the function: an emitted
76    /// instruction names a target past the end, or a label used by a branch
77    /// is bound after the last instruction.
78    TargetOutOfRange {
79        /// The function.
80        func: FuncId,
81        /// The target.
82        target: u32,
83    },
84    /// A try region or local range ends before it starts.
85    InvalidRange {
86        /// The function.
87        func: FuncId,
88    },
89    /// A per-function table is full: registers, captures, name refs, or
90    /// type refs (65,536 each), parameters (255), or instructions, jump
91    /// tables, handlers (`u32::MAX`).
92    TooMany {
93        /// The function.
94        func: FuncId,
95        /// Which table: `"registers"`, `"captures"`, ...
96        what: &'static str,
97    },
98    /// A register was named that the function never declared.
99    UnknownRegister {
100        /// The function.
101        func: FuncId,
102        /// The register.
103        reg: Reg,
104    },
105    /// An instruction with `overflow = promote` writes a register declared
106    /// with a static type. `promote` produces an `f64` where an integer does
107    /// not fit, so its result must be `dyn` (OPS §2).
108    PromoteNotDynamic {
109        /// The function.
110        func: FuncId,
111        /// The instruction's pc.
112        pc: u32,
113    },
114    /// Two moves of one parallel move write the same register.
115    ConflictingMoves {
116        /// The function.
117        func: FuncId,
118        /// The register written twice.
119        dst: Reg,
120    },
121    /// A function builder does not belong to this module builder, or was
122    /// already added.
123    ForeignFunction(FuncId),
124    /// A declared function was never added.
125    UndefinedFunction(FuncId),
126    /// A reserved type was never defined.
127    UndefinedType(TypeId),
128    /// An aggregate constant refers to itself or a later constant.
129    ConstForwardRef(ConstId),
130    /// A module-level table would pass `u32::MAX` entries or bytes
131    /// (`what` names it).
132    ModuleFull(&'static str),
133    /// An encoded section would exceed 4 GiB, which its length field cannot
134    /// express.
135    TooLarge {
136        /// The section id (see `specs/LSB.md` §6).
137        section: u32,
138    },
139}
140
141impl fmt::Display for BuildError {
142    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143        match self {
144            BuildError::UnboundLabel { func, label } => {
145                write!(f, "label {label} of {func} is used but never bound")
146            }
147            BuildError::LabelRebound { func, label } => {
148                write!(f, "label {label} of {func} is bound twice")
149            }
150            BuildError::ForeignLabel { func } => {
151                write!(f, "{func} was given a label from another function")
152            }
153            BuildError::TargetOutOfRange { func, target } => {
154                write!(f, "branch target @{target} is past the end of {func}")
155            }
156            BuildError::InvalidRange { func } => {
157                write!(
158                    f,
159                    "a try region or local range of {func} ends before it starts"
160                )
161            }
162            BuildError::TooMany { func, what } => write!(f, "{func} has too many {what}"),
163            BuildError::UnknownRegister { func, reg } => {
164                write!(f, "{func} names undeclared register {reg}")
165            }
166            BuildError::PromoteNotDynamic { func, pc } => write!(
167                f,
168                "instruction {pc} of {func} uses overflow = promote but its destination is not dyn"
169            ),
170            BuildError::ConflictingMoves { func, dst } => {
171                write!(f, "a parallel move in {func} writes {dst} twice")
172            }
173            BuildError::ForeignFunction(func) => {
174                write!(
175                    f,
176                    "{func} does not belong to this module builder or was added twice"
177                )
178            }
179            BuildError::UndefinedFunction(func) => {
180                write!(f, "{func} was declared but never added")
181            }
182            BuildError::UndefinedType(ty) => write!(f, "{ty} was reserved but never defined"),
183            BuildError::ConstForwardRef(id) => write!(
184                f,
185                "an aggregate constant refers to {id}, which is not an earlier constant"
186            ),
187            BuildError::ModuleFull(what) => write!(f, "the module's {what} table is full"),
188            BuildError::TooLarge { section } => {
189                write!(f, "section {section} would exceed 4 GiB")
190            }
191        }
192    }
193}
194
195impl core::error::Error for BuildError {}
196
197/// A position in a function's code, named before it is known.
198///
199/// Make one with [`FunctionBuilder::label`], use it in branches, tables,
200/// handlers, and local ranges, and [`bind`](FunctionBuilder::bind) it to the
201/// next instruction's position exactly once. A label belongs to the builder
202/// that made it.
203///
204/// # Examples
205///
206/// ```
207/// use bytecode_lang::{Inst, ModuleBuilder, Target};
208///
209/// let mut m = ModuleBuilder::new();
210/// let mut f = m.function("f", &[], &[]);
211/// let end = f.label();
212/// f.jmp(end);
213/// f.emit(Inst::Nop {});
214/// f.bind(end);
215/// f.ret_void();
216/// let id = m.add_function(f).unwrap();
217/// let module = m.finish().unwrap();
218/// assert_eq!(module.function(id).unwrap().code()[0], Inst::Jmp { target: Target(2) });
219/// ```
220#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
221pub struct Label {
222    func: FuncId,
223    index: u32,
224}
225
226/// Builds one function. Created by [`ModuleBuilder::function`], added back
227/// with [`ModuleBuilder::add_function`].
228///
229/// The parameters are registers `r0..rN` with the declared parameter types;
230/// [`reg`](FunctionBuilder::reg) declares more, in order, so consecutive
231/// calls return consecutive registers (what call windows need).
232///
233/// # Examples
234///
235/// ```
236/// use bytecode_lang::{Inst, IntOp, IntTy, ModuleBuilder, ValType};
237///
238/// // fn count(n: i64) -> i64 { let i = 0; while i < n { i = i + 1 } i }
239/// let mut m = ModuleBuilder::new();
240/// let mut f = m.function("count", &[ValType::I64], &[ValType::I64]);
241/// let n = f.param(0);
242/// let (i, one, more) = (f.reg(ValType::I64), f.reg(ValType::I64), f.reg(ValType::Bool));
243/// let i64op = IntOp::new(IntTy::I64);
244/// f.emit(Inst::LoadInt { dst: i, val: 0, ty: IntTy::I64 });
245/// f.emit(Inst::LoadInt { dst: one, val: 1, ty: IntTy::I64 });
246/// let (head, done) = (f.label(), f.label());
247/// f.bind(head);
248/// f.emit(Inst::ILt { dst: more, lhs: i, rhs: n, ty: IntTy::I64 });
249/// f.jmp_if_not(more, done);
250/// f.emit(Inst::IAdd { dst: i, lhs: i, rhs: one, op: i64op });
251/// f.emit(Inst::Safepoint {});
252/// f.jmp(head);
253/// f.bind(done);
254/// f.ret(i);
255/// m.add_function(f).unwrap();
256/// let module = m.finish().unwrap();
257/// assert_eq!(module.functions()[0].code().len(), 8);
258/// ```
259#[derive(Clone, Debug)]
260pub struct FunctionBuilder {
261    id: FuncId,
262    name: StrId,
263    sig: TypeId,
264    regs: Vec<ValType>,
265    params: u16,
266    captures: Vec<ValType>,
267    names: Vec<StrId>,
268    name_index: BTreeMap<StrId, NameRef>,
269    type_refs: Vec<TypeId>,
270    type_index: BTreeMap<TypeId, TypeRef>,
271    code: Vec<Inst>,
272    labels: Vec<Option<u32>>,
273    /// Branches emitted against a label: (pc, label).
274    fixups: Vec<(u32, Label)>,
275    tables: Vec<(Vec<Label>, Label)>,
276    handlers: Vec<(Label, Label, Label, Reg)>,
277    locals: Vec<(Reg, StrId, Label, Label)>,
278    lines: Vec<LineRow>,
279    location: Option<(StrId, u32, u32)>,
280    temps: BTreeMap<ValType, Reg>,
281    error: Option<BuildError>,
282}
283
284/// The placeholder target of a branch awaiting its label; never valid, so
285/// an unpatched branch could not slip through the final range check.
286const UNRESOLVED: Target = Target(u32::MAX);
287
288impl FunctionBuilder {
289    fn new(id: FuncId, name: StrId, sig: TypeId, params: &[ValType]) -> Self {
290        let mut f = FunctionBuilder {
291            id,
292            name,
293            sig,
294            regs: Vec::with_capacity(params.len()),
295            params: 0,
296            captures: Vec::new(),
297            names: Vec::new(),
298            name_index: BTreeMap::new(),
299            type_refs: Vec::new(),
300            type_index: BTreeMap::new(),
301            code: Vec::new(),
302            labels: Vec::new(),
303            fixups: Vec::new(),
304            tables: Vec::new(),
305            handlers: Vec::new(),
306            locals: Vec::new(),
307            lines: Vec::new(),
308            location: None,
309            temps: BTreeMap::new(),
310            error: None,
311        };
312        if params.len() > usize::from(u8::MAX) {
313            f.fail(BuildError::TooMany {
314                func: id,
315                what: "parameters",
316            });
317        }
318        for &ty in params {
319            let _param = f.reg(ty);
320        }
321        f.params = u16::try_from(params.len()).unwrap_or(u16::MAX);
322        f
323    }
324
325    /// Records the first error; later ones are consequences of it.
326    fn fail(&mut self, error: BuildError) {
327        if self.error.is_none() {
328            self.error = Some(error);
329        }
330    }
331
332    fn too_many(&mut self, what: &'static str) {
333        self.fail(BuildError::TooMany {
334            func: self.id,
335            what,
336        });
337    }
338
339    /// The id this function will have in the module.
340    ///
341    /// # Examples
342    ///
343    /// ```
344    /// use bytecode_lang::{FuncId, ModuleBuilder};
345    ///
346    /// let mut m = ModuleBuilder::new();
347    /// let f = m.function("f", &[], &[]);
348    /// assert_eq!(f.id(), FuncId(0));
349    /// ```
350    #[must_use]
351    pub fn id(&self) -> FuncId {
352        self.id
353    }
354
355    /// The register holding parameter `index`: parameters occupy the first
356    /// registers, in order, so this is `Reg(index)`.
357    ///
358    /// # Examples
359    ///
360    /// ```
361    /// use bytecode_lang::{ModuleBuilder, Reg, ValType};
362    ///
363    /// let mut m = ModuleBuilder::new();
364    /// let f = m.function("f", &[ValType::I64, ValType::F64], &[]);
365    /// assert_eq!(f.param(1), Reg(1));
366    /// assert_eq!(f.param_count(), 2);
367    /// ```
368    #[must_use]
369    pub fn param(&self, index: u16) -> Reg {
370        Reg(index)
371    }
372
373    /// The number of parameters.
374    ///
375    /// # Examples
376    ///
377    /// ```
378    /// use bytecode_lang::{ModuleBuilder, ValType};
379    ///
380    /// let mut m = ModuleBuilder::new();
381    /// assert_eq!(m.function("f", &[ValType::Dyn], &[]).param_count(), 1);
382    /// ```
383    #[must_use]
384    pub fn param_count(&self) -> u16 {
385        self.params
386    }
387
388    /// Declares a register of type `ty` and returns it. Registers are
389    /// numbered in declaration order.
390    ///
391    /// # Examples
392    ///
393    /// ```
394    /// use bytecode_lang::{ModuleBuilder, Reg, ValType};
395    ///
396    /// let mut m = ModuleBuilder::new();
397    /// let mut f = m.function("f", &[ValType::I64], &[]);
398    /// assert_eq!(f.reg(ValType::Dyn), Reg(1));
399    /// assert_eq!(f.reg(ValType::Dyn), Reg(2));
400    /// ```
401    pub fn reg(&mut self, ty: ValType) -> Reg {
402        match u16::try_from(self.regs.len()) {
403            Ok(index) => {
404                self.regs.push(ty);
405                Reg(index)
406            }
407            Err(_) => {
408                self.too_many("registers");
409                Reg(u16::MAX)
410            }
411        }
412    }
413
414    /// Declares one register per type, consecutively, and returns the
415    /// first: a call window (`dst` then the arguments) in one step.
416    ///
417    /// # Examples
418    ///
419    /// ```
420    /// use bytecode_lang::{ModuleBuilder, Reg, ValType};
421    ///
422    /// let mut m = ModuleBuilder::new();
423    /// let mut f = m.function("f", &[], &[]);
424    /// let window = f.regs(&[ValType::I64, ValType::I64, ValType::I64]);
425    /// assert_eq!(window, Reg(0));
426    /// assert_eq!(f.reg(ValType::Bool), Reg(3));
427    /// ```
428    pub fn regs(&mut self, types: &[ValType]) -> Reg {
429        let first = Reg(u16::try_from(self.regs.len()).unwrap_or(u16::MAX));
430        for &ty in types {
431            let _reg = self.reg(ty);
432        }
433        first
434    }
435
436    /// Declares a captured value of type `ty` (read with
437    /// [`Inst::GetUpval`]) and returns its index.
438    ///
439    /// # Examples
440    ///
441    /// ```
442    /// use bytecode_lang::{ModuleBuilder, UpvalIdx, ValType};
443    ///
444    /// let mut m = ModuleBuilder::new();
445    /// let mut f = m.function("f", &[], &[]);
446    /// assert_eq!(f.capture(ValType::I64), UpvalIdx(0));
447    /// assert_eq!(f.capture(ValType::Dyn), UpvalIdx(1));
448    /// ```
449    pub fn capture(&mut self, ty: ValType) -> UpvalIdx {
450        match u16::try_from(self.captures.len()) {
451            Ok(index) => {
452                self.captures.push(ty);
453                UpvalIdx(index)
454            }
455            Err(_) => {
456                self.too_many("captures");
457                UpvalIdx(u16::MAX)
458            }
459        }
460    }
461
462    /// The function-local [`NameRef`] for the string `name`, adding it to
463    /// the function's name list on first use.
464    ///
465    /// # Examples
466    ///
467    /// ```
468    /// use bytecode_lang::{ModuleBuilder, NameRef};
469    ///
470    /// let mut m = ModuleBuilder::new();
471    /// let (x, y) = (m.string("x"), m.string("y"));
472    /// let mut f = m.function("f", &[], &[]);
473    /// assert_eq!(f.name_ref(y), NameRef(0));
474    /// assert_eq!(f.name_ref(x), NameRef(1));
475    /// assert_eq!(f.name_ref(y), NameRef(0));
476    /// ```
477    pub fn name_ref(&mut self, name: StrId) -> NameRef {
478        if let Some(&r) = self.name_index.get(&name) {
479            return r;
480        }
481        match u16::try_from(self.names.len()) {
482            Ok(index) => {
483                self.names.push(name);
484                let r = NameRef(index);
485                let _previous = self.name_index.insert(name, r);
486                r
487            }
488            Err(_) => {
489                self.too_many("name refs");
490                NameRef(u16::MAX)
491            }
492        }
493    }
494
495    /// The function-local [`TypeRef`] for the type `ty`, adding it to the
496    /// function's type list on first use.
497    ///
498    /// # Examples
499    ///
500    /// ```
501    /// use bytecode_lang::{ModuleBuilder, TypeDef, TypeRef, ValType};
502    ///
503    /// let mut m = ModuleBuilder::new();
504    /// let arr = m.add_type(TypeDef::Array(ValType::Dyn));
505    /// let mut f = m.function("f", &[], &[]);
506    /// assert_eq!(f.type_ref(arr), TypeRef(0));
507    /// assert_eq!(f.type_ref(arr), TypeRef(0));
508    /// ```
509    pub fn type_ref(&mut self, ty: TypeId) -> TypeRef {
510        if let Some(&r) = self.type_index.get(&ty) {
511            return r;
512        }
513        match u16::try_from(self.type_refs.len()) {
514            Ok(index) => {
515                self.type_refs.push(ty);
516                let r = TypeRef(index);
517                let _previous = self.type_index.insert(ty, r);
518                r
519            }
520            Err(_) => {
521                self.too_many("type refs");
522                TypeRef(u16::MAX)
523            }
524        }
525    }
526
527    /// Sets the source position of the instructions emitted from now on.
528    /// A line-table row is added at the next instruction only if the
529    /// position changed.
530    ///
531    /// # Examples
532    ///
533    /// ```
534    /// use bytecode_lang::{Inst, ModuleBuilder};
535    ///
536    /// let mut m = ModuleBuilder::new();
537    /// let file = m.string("a.mox");
538    /// let mut f = m.function("f", &[], &[]);
539    /// f.set_location(file, 1, 1);
540    /// f.emit(Inst::Nop {});
541    /// f.emit(Inst::Nop {}); // same position: no new row
542    /// f.set_location(file, 2, 1);
543    /// f.ret_void();
544    /// let id = m.add_function(f).unwrap();
545    /// let module = m.finish().unwrap();
546    /// let pcs: Vec<u32> = module.function(id).unwrap().lines().iter().map(|r| r.pc).collect();
547    /// assert_eq!(pcs, [0, 2]);
548    /// ```
549    pub fn set_location(&mut self, file: StrId, line: u32, column: u32) {
550        self.location = Some((file, line, column));
551    }
552
553    /// The position the next instruction will have.
554    ///
555    /// # Examples
556    ///
557    /// ```
558    /// use bytecode_lang::{Inst, ModuleBuilder};
559    ///
560    /// let mut m = ModuleBuilder::new();
561    /// let mut f = m.function("f", &[], &[]);
562    /// assert_eq!(f.pc(), 0);
563    /// f.emit(Inst::Nop {});
564    /// assert_eq!(f.pc(), 1);
565    /// ```
566    #[must_use]
567    pub fn pc(&self) -> u32 {
568        u32::try_from(self.code.len()).unwrap_or(u32::MAX)
569    }
570
571    /// Appends `inst` and returns its pc.
572    ///
573    /// A `jmp`, `jmp_if`, or `jmp_if_not` emitted this way carries a raw
574    /// [`Target`]; it is checked against the final code length when the
575    /// function is added. Prefer [`jmp`](Self::jmp) and friends, which take
576    /// labels.
577    ///
578    /// # Examples
579    ///
580    /// ```
581    /// use bytecode_lang::{Inst, ModuleBuilder};
582    ///
583    /// let mut m = ModuleBuilder::new();
584    /// let mut f = m.function("f", &[], &[]);
585    /// assert_eq!(f.emit(Inst::Safepoint {}), 0);
586    /// assert_eq!(f.emit(Inst::RetVoid {}), 1);
587    /// ```
588    pub fn emit(&mut self, inst: Inst) -> u32 {
589        let pc = self.pc();
590        if pc == u32::MAX {
591            self.too_many("instructions");
592            return pc;
593        }
594        if let Some((file, line, column)) = self.location {
595            let same = self
596                .lines
597                .last()
598                .is_some_and(|r| (r.file, r.line, r.column) == (file, line, column));
599            if !same {
600                self.lines.push(LineRow {
601                    pc,
602                    file,
603                    line,
604                    column,
605                });
606            }
607        }
608        self.code.push(inst);
609        pc
610    }
611
612    /// Emits `mov dst, src`.
613    ///
614    /// # Examples
615    ///
616    /// ```
617    /// use bytecode_lang::{Inst, ModuleBuilder, Reg, ValType};
618    ///
619    /// let mut m = ModuleBuilder::new();
620    /// let mut f = m.function("f", &[ValType::I64], &[]);
621    /// let copy = f.reg(ValType::I64);
622    /// f.mov(copy, Reg(0));
623    /// f.ret_void();
624    /// let id = m.add_function(f).unwrap();
625    /// let module = m.finish().unwrap();
626    /// assert_eq!(module.function(id).unwrap().code()[0], Inst::Mov { dst: copy, src: Reg(0) });
627    /// ```
628    pub fn mov(&mut self, dst: Reg, src: Reg) -> u32 {
629        self.emit(Inst::Mov { dst, src })
630    }
631
632    /// Emits `ret src`.
633    ///
634    /// # Examples
635    ///
636    /// ```
637    /// use bytecode_lang::{Inst, ModuleBuilder, ValType};
638    ///
639    /// let mut m = ModuleBuilder::new();
640    /// let mut f = m.function("f", &[ValType::Dyn], &[ValType::Dyn]);
641    /// let x = f.param(0);
642    /// assert_eq!(f.ret(x), 0);
643    /// ```
644    pub fn ret(&mut self, src: Reg) -> u32 {
645        self.emit(Inst::Ret { src })
646    }
647
648    /// Emits `ret_void`.
649    ///
650    /// # Examples
651    ///
652    /// ```
653    /// use bytecode_lang::ModuleBuilder;
654    ///
655    /// let mut m = ModuleBuilder::new();
656    /// let mut f = m.function("f", &[], &[]);
657    /// assert_eq!(f.ret_void(), 0);
658    /// ```
659    pub fn ret_void(&mut self) -> u32 {
660        self.emit(Inst::RetVoid {})
661    }
662
663    /// A new, unbound label.
664    ///
665    /// # Examples
666    ///
667    /// ```
668    /// use bytecode_lang::ModuleBuilder;
669    ///
670    /// let mut m = ModuleBuilder::new();
671    /// let mut f = m.function("f", &[], &[]);
672    /// let (a, b) = (f.label(), f.label());
673    /// assert_ne!(a, b);
674    /// ```
675    pub fn label(&mut self) -> Label {
676        let index = match u32::try_from(self.labels.len()) {
677            Ok(index) => index,
678            Err(_) => {
679                self.too_many("labels");
680                u32::MAX
681            }
682        };
683        self.labels.push(None);
684        Label {
685            func: self.id,
686            index,
687        }
688    }
689
690    /// Whether `label` was made by this builder; records an error if not.
691    fn owns(&mut self, label: Label) -> bool {
692        let ok = label.func == self.id && (label.index as usize) < self.labels.len();
693        if !ok {
694            self.fail(BuildError::ForeignLabel { func: self.id });
695        }
696        ok
697    }
698
699    /// Binds `label` to the position of the next instruction emitted.
700    /// Binding a label twice is an error.
701    ///
702    /// # Examples
703    ///
704    /// ```
705    /// use bytecode_lang::{BuildError, ModuleBuilder};
706    ///
707    /// let mut m = ModuleBuilder::new();
708    /// let mut f = m.function("f", &[], &[]);
709    /// let l = f.label();
710    /// f.bind(l);
711    /// f.bind(l);
712    /// f.ret_void();
713    /// assert!(matches!(m.add_function(f), Err(BuildError::LabelRebound { .. })));
714    /// ```
715    pub fn bind(&mut self, label: Label) {
716        if !self.owns(label) {
717            return;
718        }
719        let pc = self.pc();
720        match self.labels.get_mut(label.index as usize) {
721            Some(slot @ None) => *slot = Some(pc),
722            _ => self.fail(BuildError::LabelRebound {
723                func: self.id,
724                label: label.index,
725            }),
726        }
727    }
728
729    fn branch(&mut self, inst: Inst, label: Label) -> u32 {
730        let owned = self.owns(label);
731        let pc = self.emit(inst);
732        if owned {
733            self.fixups.push((pc, label));
734        }
735        pc
736    }
737
738    /// Emits `jmp label`.
739    ///
740    /// # Examples
741    ///
742    /// ```
743    /// use bytecode_lang::{Inst, ModuleBuilder, Target};
744    ///
745    /// let mut m = ModuleBuilder::new();
746    /// let mut f = m.function("f", &[], &[]);
747    /// let top = f.label();
748    /// f.bind(top);
749    /// f.emit(Inst::Safepoint {});
750    /// f.jmp(top);
751    /// let id = m.add_function(f).unwrap();
752    /// let module = m.finish().unwrap();
753    /// assert_eq!(module.function(id).unwrap().code()[1], Inst::Jmp { target: Target(0) });
754    /// ```
755    pub fn jmp(&mut self, label: Label) -> u32 {
756        self.branch(Inst::Jmp { target: UNRESOLVED }, label)
757    }
758
759    /// Emits `jmp_if cond, label`.
760    ///
761    /// # Examples
762    ///
763    /// ```
764    /// use bytecode_lang::{Inst, ModuleBuilder, Target, ValType};
765    ///
766    /// let mut m = ModuleBuilder::new();
767    /// let mut f = m.function("f", &[ValType::Bool], &[]);
768    /// let c = f.param(0);
769    /// let out = f.label();
770    /// f.jmp_if(c, out);
771    /// f.bind(out);
772    /// f.ret_void();
773    /// let id = m.add_function(f).unwrap();
774    /// let module = m.finish().unwrap();
775    /// assert_eq!(module.function(id).unwrap().code()[0], Inst::JmpIf { cond: c, target: Target(1) });
776    /// ```
777    pub fn jmp_if(&mut self, cond: Reg, label: Label) -> u32 {
778        self.branch(
779            Inst::JmpIf {
780                cond,
781                target: UNRESOLVED,
782            },
783            label,
784        )
785    }
786
787    /// Emits `jmp_if_not cond, label`.
788    ///
789    /// # Examples
790    ///
791    /// ```
792    /// use bytecode_lang::{Inst, ModuleBuilder, Target, ValType};
793    ///
794    /// let mut m = ModuleBuilder::new();
795    /// let mut f = m.function("f", &[ValType::Bool], &[]);
796    /// let c = f.param(0);
797    /// let out = f.label();
798    /// f.jmp_if_not(c, out);
799    /// f.bind(out);
800    /// f.ret_void();
801    /// let id = m.add_function(f).unwrap();
802    /// let module = m.finish().unwrap();
803    /// assert_eq!(module.function(id).unwrap().code()[0], Inst::JmpIfNot { cond: c, target: Target(1) });
804    /// ```
805    pub fn jmp_if_not(&mut self, cond: Reg, label: Label) -> u32 {
806        self.branch(
807            Inst::JmpIfNot {
808                cond,
809                target: UNRESOLVED,
810            },
811            label,
812        )
813    }
814
815    /// Emits `switch.ty src, jtN` with a new jump table: `targets[v]` for a
816    /// selector `v` in range, `default` otherwise. Returns the table's id.
817    ///
818    /// # Examples
819    ///
820    /// ```
821    /// use bytecode_lang::{IntTy, ModuleBuilder, TableId, ValType};
822    ///
823    /// let mut m = ModuleBuilder::new();
824    /// let mut f = m.function("f", &[ValType::U8], &[]);
825    /// let sel = f.param(0);
826    /// let (zero, other) = (f.label(), f.label());
827    /// assert_eq!(f.switch(IntTy::U8, sel, &[zero], other), TableId(0));
828    /// f.bind(zero);
829    /// f.bind(other);
830    /// f.ret_void();
831    /// assert!(m.add_function(f).is_ok());
832    /// ```
833    pub fn switch(&mut self, ty: IntTy, src: Reg, targets: &[Label], default: Label) -> TableId {
834        let all_owned = targets.iter().all(|&l| self.owns(l)) & self.owns(default);
835        let table = match u32::try_from(self.tables.len()) {
836            Ok(index) => TableId(index),
837            Err(_) => {
838                self.too_many("jump tables");
839                TableId(u32::MAX)
840            }
841        };
842        if all_owned {
843            self.tables.push((targets.to_vec(), default));
844        }
845        let _pc = self.emit(Inst::Switch { src, table, ty });
846        table
847    }
848
849    /// Declares a try region: an error raised at a pc in `start..end`
850    /// continues at `handler` with the error value in `catch` (a `dyn`
851    /// register). Declare inner regions before the regions that enclose
852    /// them; the first matching region wins.
853    ///
854    /// # Examples
855    ///
856    /// ```
857    /// use bytecode_lang::{Inst, ModuleBuilder, Reg, ValType};
858    ///
859    /// let mut m = ModuleBuilder::new();
860    /// let mut f = m.function("f", &[ValType::Dyn], &[]);
861    /// let err = f.reg(ValType::Dyn);
862    /// let (start, end, handler) = (f.label(), f.label(), f.label());
863    /// f.bind(start);
864    /// f.emit(Inst::Throw { src: Reg(0) });
865    /// f.bind(end);
866    /// f.bind(handler);
867    /// f.ret_void();
868    /// f.try_region(start, end, handler, err);
869    /// let id = m.add_function(f).unwrap();
870    /// let module = m.finish().unwrap();
871    /// assert_eq!(module.function(id).unwrap().handlers()[0].catch, err);
872    /// ```
873    pub fn try_region(&mut self, start: Label, end: Label, handler: Label, catch: Reg) {
874        if self.owns(start) & self.owns(end) & self.owns(handler) {
875            self.handlers.push((start, end, handler, catch));
876        }
877    }
878
879    /// Names the register `reg` as the source variable `name` over the
880    /// range `start..end`, for debuggers.
881    ///
882    /// # Examples
883    ///
884    /// ```
885    /// use bytecode_lang::{ModuleBuilder, ValType};
886    ///
887    /// let mut m = ModuleBuilder::new();
888    /// let name = m.string("count");
889    /// let mut f = m.function("f", &[ValType::I64], &[]);
890    /// let (s, e) = (f.label(), f.label());
891    /// f.bind(s);
892    /// f.ret_void();
893    /// f.bind(e);
894    /// f.local(f.param(0), name, s, e);
895    /// let id = m.add_function(f).unwrap();
896    /// let module = m.finish().unwrap();
897    /// assert_eq!(module.function(id).unwrap().locals()[0].name, name);
898    /// ```
899    pub fn local(&mut self, reg: Reg, name: StrId, start: Label, end: Label) {
900        if self.owns(start) & self.owns(end) {
901            self.locals.push((reg, name, start, end));
902        }
903    }
904
905    /// A temporary of type `ty` for breaking move cycles, guaranteed not to
906    /// be any register in `named` (the registers the current move set
907    /// mentions). One temporary per type is cached and reused, since it is
908    /// only live inside one move sequence; if a move set names the cached
909    /// one (or names undeclared registers a fresh one would collide with),
910    /// fresh registers are declared until one is free. That terminates
911    /// within `named.len() + 1` declarations.
912    fn temp(&mut self, ty: ValType, named: &BTreeSet<Reg>) -> Reg {
913        if let Some(&r) = self.temps.get(&ty) {
914            if !named.contains(&r) {
915                return r;
916            }
917        }
918        loop {
919            let r = self.reg(ty);
920            if self.error.is_some() || !named.contains(&r) {
921                let _previous = self.temps.insert(ty, r);
922                return r;
923            }
924        }
925    }
926
927    /// Emits moves that copy every `src` to its `dst` **simultaneously**:
928    /// each destination ends up with the value its source held before any
929    /// move ran, even when sources and destinations overlap or form cycles
930    /// (`(a, b), (b, a)` swaps). Moves whose source is their destination
931    /// are dropped. Cycles are broken through a temporary register of the
932    /// saved register's type. Two moves writing one register are an error.
933    ///
934    /// This is the correct lowering of block arguments (the bytecode form of
935    /// SSA phis): a back edge that permutes its own parameters must not be
936    /// emitted as plain sequential moves.
937    ///
938    /// # Examples
939    ///
940    /// ```
941    /// use bytecode_lang::{Inst, ModuleBuilder, Reg, ValType};
942    ///
943    /// let mut m = ModuleBuilder::new();
944    /// let mut f = m.function("swap", &[ValType::I64, ValType::I64], &[]);
945    /// let (a, b) = (f.param(0), f.param(1));
946    /// f.parallel_move(&[(a, b), (b, a)]);
947    /// f.ret_void();
948    /// let id = m.add_function(f).unwrap();
949    /// let module = m.finish().unwrap();
950    /// let tmp = Reg(2); // allocated to break the cycle
951    /// assert_eq!(
952    ///     &module.function(id).unwrap().code()[..3],
953    ///     &[
954    ///         Inst::Mov { dst: tmp, src: a },
955    ///         Inst::Mov { dst: a, src: b },
956    ///         Inst::Mov { dst: b, src: tmp },
957    ///     ],
958    /// );
959    /// ```
960    pub fn parallel_move(&mut self, moves: &[(Reg, Reg)]) {
961        // Pending moves (dst, src), self-moves dropped.
962        let mut pending: Vec<(Reg, Reg)> = moves.iter().copied().filter(|(d, s)| d != s).collect();
963        // Every register the move set mentions: a temporary must be none of them.
964        let named: BTreeSet<Reg> = moves.iter().flat_map(|&(d, s)| [d, s]).collect();
965        let n = pending.len();
966        // dst -> index of the move writing it (destinations are unique).
967        let mut writer: BTreeMap<Reg, usize> = BTreeMap::new();
968        for (i, &(dst, _)) in pending.iter().enumerate() {
969            if writer.insert(dst, i).is_some() {
970                self.fail(BuildError::ConflictingMoves { func: self.id, dst });
971                return;
972            }
973        }
974        // src -> moves reading it, and how many of those are still pending.
975        let mut readers: BTreeMap<Reg, Vec<usize>> = BTreeMap::new();
976        for (i, &(_, src)) in pending.iter().enumerate() {
977            readers.entry(src).or_default().push(i);
978        }
979        let mut live_readers: BTreeMap<Reg, usize> =
980            readers.iter().map(|(&r, v)| (r, v.len())).collect();
981        let mut done = alloc::vec![false; n];
982        // A move is ready when nothing pending still needs its destination.
983        let mut ready: Vec<usize> = (0..n)
984            .filter(|&i| {
985                pending
986                    .get(i)
987                    .is_some_and(|&(d, _)| !live_readers.contains_key(&d))
988            })
989            .collect();
990        let mut remaining = n;
991        let mut scan = 0usize;
992        while remaining > 0 {
993            while let Some(i) = ready.pop() {
994                let Some(&(dst, src)) = pending.get(i) else {
995                    continue;
996                };
997                let _pc = self.emit(Inst::Mov { dst, src });
998                if let Some(flag) = done.get_mut(i) {
999                    *flag = true;
1000                }
1001                remaining -= 1;
1002                // `src` lost a reader; if none are left and `src` is itself
1003                // a pending destination, that move may now run.
1004                if let Some(count) = live_readers.get_mut(&src) {
1005                    *count -= 1;
1006                    if *count == 0 {
1007                        let _gone = live_readers.remove(&src);
1008                        if let Some(&w) = writer.get(&src) {
1009                            if !done.get(w).copied().unwrap_or(true) {
1010                                ready.push(w);
1011                            }
1012                        }
1013                    }
1014                }
1015            }
1016            if remaining == 0 {
1017                break;
1018            }
1019            // Every pending move now lies on a cycle (each destination still
1020            // has exactly one pending reader). Save one destination in a
1021            // temporary and point its reader at the temporary; the cycle
1022            // becomes a chain and drains through `ready`.
1023            while done.get(scan).copied().unwrap_or(false) {
1024                scan += 1;
1025            }
1026            let Some(&(saved, _)) = pending.get(scan) else {
1027                return;
1028            };
1029            let Some(&ty) = self.regs.get(saved.index()) else {
1030                self.fail(BuildError::UnknownRegister {
1031                    func: self.id,
1032                    reg: saved,
1033                });
1034                return;
1035            };
1036            let tmp = self.temp(ty, &named);
1037            let _pc = self.emit(Inst::Mov {
1038                dst: tmp,
1039                src: saved,
1040            });
1041            if let Some(list) = readers.get(&saved) {
1042                for &j in list {
1043                    if !done.get(j).copied().unwrap_or(true) {
1044                        if let Some(m) = pending.get_mut(j) {
1045                            m.1 = tmp;
1046                        }
1047                    }
1048                }
1049            }
1050            let _gone = live_readers.remove(&saved);
1051            ready.push(scan);
1052        }
1053    }
1054
1055    /// Resolves labels and produces the function.
1056    fn finish(mut self) -> Result<(FuncId, Function), BuildError> {
1057        if let Some(error) = self.error {
1058            return Err(error);
1059        }
1060        let func = self.id;
1061        let len = self.pc();
1062        let labels = core::mem::take(&mut self.labels);
1063        let resolve =
1064            |label: Label| -> Result<u32, BuildError> {
1065                labels.get(label.index as usize).copied().flatten().ok_or(
1066                    BuildError::UnboundLabel {
1067                        func,
1068                        label: label.index,
1069                    },
1070                )
1071            };
1072        let in_code = |pc: u32| -> Result<Target, BuildError> {
1073            if pc < len {
1074                Ok(Target(pc))
1075            } else {
1076                Err(BuildError::TargetOutOfRange { func, target: pc })
1077            }
1078        };
1079
1080        for &(pc, label) in &self.fixups {
1081            let target = in_code(resolve(label)?)?;
1082            if let Some(inst) = self.code.get_mut(pc as usize) {
1083                *inst = match *inst {
1084                    Inst::Jmp { .. } => Inst::Jmp { target },
1085                    Inst::JmpIf { cond, .. } => Inst::JmpIf { cond, target },
1086                    Inst::JmpIfNot { cond, .. } => Inst::JmpIfNot { cond, target },
1087                    other => other,
1088                };
1089            }
1090        }
1091        // One pass over the code, one dispatch per instruction:
1092        // - every branch, label-built or emitted raw, must land on an
1093        //   instruction (this is the guarantee; the fix-ups above only fill
1094        //   the placeholders);
1095        // - `overflow = promote` yields an f64 where an integer does not fit,
1096        //   so it is only valid with a `dyn` destination. Where the
1097        //   destination's declared type is known here, enforce that; an
1098        //   undeclared register is left to the verifier.
1099        for (pc, inst) in self.code.iter().enumerate() {
1100            let (target, promote) = inst.build_checks();
1101            if let Some(target) = target {
1102                let _target = in_code(target.0)?;
1103            }
1104            if promote {
1105                let declared = inst.dst().and_then(|d| self.regs.get(d.index()));
1106                if declared.is_some_and(|&ty| ty != ValType::Dyn) {
1107                    let pc = u32::try_from(pc).unwrap_or(u32::MAX);
1108                    return Err(BuildError::PromoteNotDynamic { func, pc });
1109                }
1110            }
1111        }
1112
1113        let mut tables = Vec::with_capacity(self.tables.len());
1114        for (targets, default) in &self.tables {
1115            let mut resolved = Vec::with_capacity(targets.len());
1116            for &l in targets {
1117                resolved.push(in_code(resolve(l)?)?);
1118            }
1119            tables.push(JumpTable {
1120                targets: resolved,
1121                default: in_code(resolve(*default)?)?,
1122            });
1123        }
1124
1125        let mut handlers = Vec::with_capacity(self.handlers.len());
1126        for &(start, end, handler, catch) in &self.handlers {
1127            let (start, end) = (resolve(start)?, resolve(end)?);
1128            if start > end {
1129                return Err(BuildError::InvalidRange { func });
1130            }
1131            let target = in_code(resolve(handler)?)?;
1132            handlers.push(Handler {
1133                start,
1134                end,
1135                target,
1136                catch,
1137            });
1138        }
1139
1140        let mut locals = Vec::with_capacity(self.locals.len());
1141        for &(reg, name, start, end) in &self.locals {
1142            let (start, end) = (resolve(start)?, resolve(end)?);
1143            if start > end {
1144                return Err(BuildError::InvalidRange { func });
1145            }
1146            locals.push(LocalVar {
1147                reg,
1148                name,
1149                start,
1150                end,
1151            });
1152        }
1153
1154        Ok((
1155            func,
1156            Function {
1157                name: self.name,
1158                sig: self.sig,
1159                regs: self.regs,
1160                captures: self.captures,
1161                names: self.names,
1162                type_refs: self.type_refs,
1163                tables,
1164                handlers,
1165                code: self.code,
1166                lines: self.lines,
1167                locals,
1168            },
1169        ))
1170    }
1171}
1172
1173/// Builds a [`Module`].
1174///
1175/// Strings, structural types (everything but structs), and constants are
1176/// deduplicated. Ids are dense and assigned in creation order. Functions are
1177/// declared with [`function`](Self::function), which fixes their
1178/// [`FuncId`] up front so they can call each other in any order, and are
1179/// added with [`add_function`](Self::add_function).
1180///
1181/// # Examples
1182///
1183/// ```
1184/// use bytecode_lang::{Const, ExportItem, Inst, ModuleBuilder, ValType};
1185///
1186/// let mut m = ModuleBuilder::new();
1187/// let greeting = m.string("hello");
1188/// let k = m.constant(Const::Str(greeting));
1189/// let mut f = m.function("greet", &[], &[ValType::Str]);
1190/// let s = f.reg(ValType::Str);
1191/// f.emit(Inst::LoadConst { dst: s, k });
1192/// f.ret(s);
1193/// let greet = m.add_function(f).unwrap();
1194/// m.export("greet", ExportItem::Func(greet));
1195/// let module = m.finish().unwrap();
1196/// assert_eq!(module.string(greeting), Some("hello"));
1197/// ```
1198#[derive(Clone, Debug, Default)]
1199pub struct ModuleBuilder {
1200    strings: Strings,
1201    string_index: BTreeMap<Box<str>, StrId>,
1202    types: Vec<Option<TypeDef>>,
1203    type_index: BTreeMap<TypeDef, TypeId>,
1204    consts: Vec<Const>,
1205    const_index: BTreeMap<Const, ConstId>,
1206    imports: Vec<Import>,
1207    globals: Vec<Global>,
1208    functions: Vec<Option<Function>>,
1209    /// The (name, signature) each declared function slot was created with.
1210    declared: Vec<(StrId, TypeId)>,
1211    exports: Vec<Export>,
1212    hooks: BTreeMap<Hook, Callee>,
1213    name: Option<StrId>,
1214    start: Option<FuncId>,
1215    error: Option<BuildError>,
1216}
1217
1218/// The next dense id for a table of `len` entries, or `None` when the
1219/// table is full.
1220fn next_id(len: usize) -> Option<u32> {
1221    u32::try_from(len).ok().filter(|&id| id != u32::MAX)
1222}
1223
1224impl ModuleBuilder {
1225    /// An empty module builder.
1226    ///
1227    /// # Examples
1228    ///
1229    /// ```
1230    /// use bytecode_lang::ModuleBuilder;
1231    ///
1232    /// let module = ModuleBuilder::new().finish().unwrap();
1233    /// assert!(module.functions().is_empty());
1234    /// ```
1235    #[must_use]
1236    pub fn new() -> Self {
1237        Self::default()
1238    }
1239
1240    fn fail(&mut self, error: BuildError) {
1241        if self.error.is_none() {
1242            self.error = Some(error);
1243        }
1244    }
1245
1246    /// The id of the string `s`, adding it on first use.
1247    ///
1248    /// # Examples
1249    ///
1250    /// ```
1251    /// use bytecode_lang::{ModuleBuilder, StrId};
1252    ///
1253    /// let mut m = ModuleBuilder::new();
1254    /// assert_eq!(m.string("a"), StrId(0));
1255    /// assert_eq!(m.string("b"), StrId(1));
1256    /// assert_eq!(m.string("a"), StrId(0));
1257    /// ```
1258    pub fn string(&mut self, s: &str) -> StrId {
1259        if let Some(&id) = self.string_index.get(s) {
1260            return id;
1261        }
1262        let Some(id) = next_id(self.strings.len()) else {
1263            self.fail(BuildError::ModuleFull("string"));
1264            return StrId(u32::MAX);
1265        };
1266        if !self.strings.push(s) {
1267            self.fail(BuildError::ModuleFull("string"));
1268            return StrId(u32::MAX);
1269        }
1270        let _previous = self.string_index.insert(Box::from(s), StrId(id));
1271        StrId(id)
1272    }
1273
1274    /// Adds a type and returns its id. Structural types (functions, arrays,
1275    /// maps, cells, iterators) are deduplicated; every struct is a new type.
1276    ///
1277    /// # Examples
1278    ///
1279    /// ```
1280    /// use bytecode_lang::{ModuleBuilder, StructDef, TypeDef, ValType};
1281    ///
1282    /// let mut m = ModuleBuilder::new();
1283    /// let a = m.add_type(TypeDef::Array(ValType::I64));
1284    /// assert_eq!(m.add_type(TypeDef::Array(ValType::I64)), a);
1285    /// let s1 = m.add_type(TypeDef::Struct(StructDef::default()));
1286    /// let s2 = m.add_type(TypeDef::Struct(StructDef::default()));
1287    /// assert_ne!(s1, s2);
1288    /// ```
1289    pub fn add_type(&mut self, def: TypeDef) -> TypeId {
1290        if def.is_structural() {
1291            if let Some(&id) = self.type_index.get(&def) {
1292                return id;
1293            }
1294        }
1295        let Some(id) = next_id(self.types.len()) else {
1296            self.fail(BuildError::ModuleFull("type"));
1297            return TypeId(u32::MAX);
1298        };
1299        if def.is_structural() {
1300            let _previous = self.type_index.insert(def.clone(), TypeId(id));
1301        }
1302        self.types.push(Some(def));
1303        TypeId(id)
1304    }
1305
1306    /// Reserves a type id to be defined later with
1307    /// [`define_type`](Self::define_type): how a struct refers to itself
1308    /// (a list node's `next` field) or two structs refer to each other.
1309    ///
1310    /// # Examples
1311    ///
1312    /// ```
1313    /// use bytecode_lang::{Field, ModuleBuilder, StructDef, TypeDef, ValType};
1314    ///
1315    /// let mut m = ModuleBuilder::new();
1316    /// let node = m.reserve_type();
1317    /// let (name, next) = (m.string("Node"), m.string("next"));
1318    /// m.define_type(node, TypeDef::Struct(StructDef {
1319    ///     name,
1320    ///     parent: None,
1321    ///     fields: vec![Field { name: next, ty: ValType::Ref(node) }],
1322    ///     methods: vec![],
1323    /// }));
1324    /// assert!(m.finish().is_ok());
1325    /// ```
1326    pub fn reserve_type(&mut self) -> TypeId {
1327        let Some(id) = next_id(self.types.len()) else {
1328            self.fail(BuildError::ModuleFull("type"));
1329            return TypeId(u32::MAX);
1330        };
1331        self.types.push(None);
1332        TypeId(id)
1333    }
1334
1335    /// Defines a type reserved with [`reserve_type`](Self::reserve_type).
1336    /// Defining an id that was not reserved, or defining it twice, is
1337    /// recorded as [`UndefinedType`](BuildError::UndefinedType).
1338    ///
1339    /// # Examples
1340    ///
1341    /// ```
1342    /// use bytecode_lang::{ModuleBuilder, TypeDef, ValType};
1343    ///
1344    /// let mut m = ModuleBuilder::new();
1345    /// let t = m.reserve_type();
1346    /// m.define_type(t, TypeDef::Cell(ValType::Dyn));
1347    /// assert_eq!(m.finish().unwrap().type_def(t), Some(&TypeDef::Cell(ValType::Dyn)));
1348    /// ```
1349    pub fn define_type(&mut self, id: TypeId, def: TypeDef) {
1350        match self.types.get_mut(id.index()) {
1351            Some(slot @ None) => *slot = Some(def),
1352            _ => self.fail(BuildError::UndefinedType(id)),
1353        }
1354    }
1355
1356    /// The id of the function type `(params) -> (results)`.
1357    ///
1358    /// # Examples
1359    ///
1360    /// ```
1361    /// use bytecode_lang::{ModuleBuilder, ValType};
1362    ///
1363    /// let mut m = ModuleBuilder::new();
1364    /// let a = m.func_type(&[ValType::Dyn], &[ValType::Dyn]);
1365    /// assert_eq!(m.func_type(&[ValType::Dyn], &[ValType::Dyn]), a);
1366    /// ```
1367    pub fn func_type(&mut self, params: &[ValType], results: &[ValType]) -> TypeId {
1368        self.add_type(TypeDef::Func(FuncType {
1369            params: params.to_vec(),
1370            results: results.to_vec(),
1371        }))
1372    }
1373
1374    /// Adds a constant and returns its id; equal constants share one id.
1375    /// An aggregate may only refer to constants that already exist
1376    /// (otherwise [`ConstForwardRef`](BuildError::ConstForwardRef)).
1377    ///
1378    /// # Examples
1379    ///
1380    /// ```
1381    /// use bytecode_lang::{Const, ModuleBuilder};
1382    ///
1383    /// let mut m = ModuleBuilder::new();
1384    /// let one = m.constant(Const::Int(1));
1385    /// let two = m.constant(Const::Int(2));
1386    /// let list = m.constant(Const::Array(vec![one, two, one]));
1387    /// assert_eq!(m.constant(Const::Int(1)), one);
1388    /// assert_eq!(m.finish().unwrap().consts().len(), 3);
1389    /// # let _ = list;
1390    /// ```
1391    pub fn constant(&mut self, c: Const) -> ConstId {
1392        if let Some(&id) = self.const_index.get(&c) {
1393            return id;
1394        }
1395        let len = self.consts.len();
1396        if let Some(bad) = c.children().find(|child| child.index() >= len) {
1397            self.fail(BuildError::ConstForwardRef(bad));
1398            return ConstId(u32::MAX);
1399        }
1400        let Some(id) = next_id(len) else {
1401            self.fail(BuildError::ModuleFull("constant"));
1402            return ConstId(u32::MAX);
1403        };
1404        let _previous = self.const_index.insert(c.clone(), ConstId(id));
1405        self.consts.push(c);
1406        ConstId(id)
1407    }
1408
1409    /// Adds a host-function import.
1410    ///
1411    /// # Examples
1412    ///
1413    /// ```
1414    /// use bytecode_lang::{ImportId, ModuleBuilder, ValType};
1415    ///
1416    /// let mut m = ModuleBuilder::new();
1417    /// let sig = m.func_type(&[ValType::Str], &[]);
1418    /// assert_eq!(m.import("ls.io", "print", sig), ImportId(0));
1419    /// ```
1420    pub fn import(&mut self, module: &str, name: &str, sig: TypeId) -> ImportId {
1421        let (module, name) = (self.string(module), self.string(name));
1422        let Some(id) = next_id(self.imports.len()) else {
1423            self.fail(BuildError::ModuleFull("import"));
1424            return ImportId(u32::MAX);
1425        };
1426        self.imports.push(Import { module, name, sig });
1427        ImportId(id)
1428    }
1429
1430    /// Adds a global.
1431    ///
1432    /// # Examples
1433    ///
1434    /// ```
1435    /// use bytecode_lang::{Const, GlobalId, ModuleBuilder, ValType};
1436    ///
1437    /// let mut m = ModuleBuilder::new();
1438    /// let zero = m.constant(Const::Int(0));
1439    /// assert_eq!(m.global("hits", ValType::I64, true, Some(zero)), GlobalId(0));
1440    /// ```
1441    pub fn global(
1442        &mut self,
1443        name: &str,
1444        ty: ValType,
1445        mutable: bool,
1446        init: Option<ConstId>,
1447    ) -> GlobalId {
1448        let name = self.string(name);
1449        let Some(id) = next_id(self.globals.len()) else {
1450            self.fail(BuildError::ModuleFull("global"));
1451            return GlobalId(u32::MAX);
1452        };
1453        self.globals.push(Global {
1454            name,
1455            ty,
1456            mutable,
1457            init,
1458        });
1459        GlobalId(id)
1460    }
1461
1462    /// Declares a function and returns its builder. The function's id is
1463    /// fixed now ([`FunctionBuilder::id`]), so other functions can call it
1464    /// before it is added.
1465    ///
1466    /// # Examples
1467    ///
1468    /// ```
1469    /// use bytecode_lang::{FuncId, ModuleBuilder, ValType};
1470    ///
1471    /// let mut m = ModuleBuilder::new();
1472    /// let even = m.function("even", &[ValType::I64], &[ValType::Bool]);
1473    /// let odd = m.function("odd", &[ValType::I64], &[ValType::Bool]);
1474    /// assert_eq!((even.id(), odd.id()), (FuncId(0), FuncId(1)));
1475    /// ```
1476    pub fn function(
1477        &mut self,
1478        name: &str,
1479        params: &[ValType],
1480        results: &[ValType],
1481    ) -> FunctionBuilder {
1482        let name = self.string(name);
1483        let sig = self.func_type(params, results);
1484        let id = match next_id(self.functions.len()) {
1485            Some(id) => {
1486                self.functions.push(None);
1487                self.declared.push((name, sig));
1488                FuncId(id)
1489            }
1490            None => {
1491                self.fail(BuildError::ModuleFull("function"));
1492                FuncId(u32::MAX)
1493            }
1494        };
1495        FunctionBuilder::new(id, name, sig, params)
1496    }
1497
1498    /// Resolves the function's labels and places it in its slot.
1499    ///
1500    /// # Errors
1501    ///
1502    /// The first error the function builder recorded, an unbound label, a
1503    /// branch target past the end, an inverted range, or
1504    /// [`ForeignFunction`](BuildError::ForeignFunction) if the builder was
1505    /// not declared by this module builder or was already added.
1506    ///
1507    /// # Examples
1508    ///
1509    /// ```
1510    /// use bytecode_lang::{BuildError, Inst, ModuleBuilder, Target};
1511    ///
1512    /// let mut m = ModuleBuilder::new();
1513    /// let mut f = m.function("f", &[], &[]);
1514    /// f.emit(Inst::Jmp { target: Target(5) }); // raw target past the end
1515    /// assert_eq!(
1516    ///     m.add_function(f),
1517    ///     Err(BuildError::TargetOutOfRange { func: bytecode_lang::FuncId(0), target: 5 }),
1518    /// );
1519    /// ```
1520    pub fn add_function(&mut self, f: FunctionBuilder) -> Result<FuncId, BuildError> {
1521        let id = f.id;
1522        let declared = self.declared.get(id.index()) == Some(&(f.name, f.sig));
1523        let empty = matches!(self.functions.get(id.index()), Some(None));
1524        if !declared || !empty {
1525            return Err(BuildError::ForeignFunction(id));
1526        }
1527        let (id, function) = f.finish()?;
1528        if let Some(slot) = self.functions.get_mut(id.index()) {
1529            *slot = Some(function);
1530        }
1531        Ok(id)
1532    }
1533
1534    /// Exports `item` under `name`.
1535    ///
1536    /// # Examples
1537    ///
1538    /// ```
1539    /// use bytecode_lang::{ExportItem, ModuleBuilder, ValType};
1540    ///
1541    /// let mut m = ModuleBuilder::new();
1542    /// let g = m.global("version", ValType::I32, false, None);
1543    /// m.export("version", ExportItem::Global(g));
1544    /// assert_eq!(m.finish().unwrap().exports().len(), 1);
1545    /// ```
1546    pub fn export(&mut self, name: &str, item: ExportItem) {
1547        let name = self.string(name);
1548        if next_id(self.exports.len()).is_none() {
1549            self.fail(BuildError::ModuleFull("export"));
1550            return;
1551        }
1552        self.exports.push(Export { name, item });
1553    }
1554
1555    /// Binds a dynamic-operation hook, replacing any earlier binding.
1556    ///
1557    /// # Examples
1558    ///
1559    /// ```
1560    /// use bytecode_lang::{Callee, Hook, ModuleBuilder, ValType};
1561    ///
1562    /// let mut m = ModuleBuilder::new();
1563    /// let sig = m.func_type(&[ValType::Dyn, ValType::Dyn], &[ValType::Dyn]);
1564    /// let loose_eq = m.import("mox.rt", "loose_eq", sig);
1565    /// m.hook(Hook::Eq, Callee::Import(loose_eq));
1566    /// let module = m.finish().unwrap();
1567    /// assert_eq!(module.hook(Hook::Eq), Some(Callee::Import(loose_eq)));
1568    /// ```
1569    pub fn hook(&mut self, hook: Hook, callee: Callee) {
1570        let _previous = self.hooks.insert(hook, callee);
1571    }
1572
1573    /// Names the module (the name the loader links imports against).
1574    ///
1575    /// # Examples
1576    ///
1577    /// ```
1578    /// use bytecode_lang::ModuleBuilder;
1579    ///
1580    /// let mut m = ModuleBuilder::new();
1581    /// m.set_name("app");
1582    /// assert!(m.finish().unwrap().name().is_some());
1583    /// ```
1584    pub fn set_name(&mut self, name: &str) {
1585        self.name = Some(self.string(name));
1586    }
1587
1588    /// Sets the initializer the loader runs after binding imports.
1589    ///
1590    /// # Examples
1591    ///
1592    /// ```
1593    /// use bytecode_lang::{FuncId, ModuleBuilder};
1594    ///
1595    /// let mut m = ModuleBuilder::new();
1596    /// let mut f = m.function("init", &[], &[]);
1597    /// f.ret_void();
1598    /// let init = m.add_function(f).unwrap();
1599    /// m.set_start(init);
1600    /// assert_eq!(m.finish().unwrap().start(), Some(FuncId(0)));
1601    /// ```
1602    pub fn set_start(&mut self, func: FuncId) {
1603        self.start = Some(func);
1604    }
1605
1606    /// Produces the module.
1607    ///
1608    /// # Errors
1609    ///
1610    /// The first error recorded while building, a declared function never
1611    /// added ([`UndefinedFunction`](BuildError::UndefinedFunction)), a
1612    /// reserved type never defined ([`UndefinedType`](BuildError::UndefinedType)),
1613    /// or a section too large to encode ([`TooLarge`](BuildError::TooLarge)).
1614    ///
1615    /// # Examples
1616    ///
1617    /// ```
1618    /// use bytecode_lang::{BuildError, FuncId, ModuleBuilder};
1619    ///
1620    /// let mut m = ModuleBuilder::new();
1621    /// let _forgotten = m.function("f", &[], &[]);
1622    /// assert_eq!(m.finish().unwrap_err(), BuildError::UndefinedFunction(FuncId(0)));
1623    /// ```
1624    pub fn finish(self) -> Result<Module, BuildError> {
1625        if let Some(error) = self.error {
1626            return Err(error);
1627        }
1628        let mut functions = Vec::with_capacity(self.functions.len());
1629        for (i, f) in self.functions.into_iter().enumerate() {
1630            let id = FuncId(u32::try_from(i).unwrap_or(u32::MAX));
1631            functions.push(f.ok_or(BuildError::UndefinedFunction(id))?);
1632        }
1633        let mut types = Vec::with_capacity(self.types.len());
1634        for (i, t) in self.types.into_iter().enumerate() {
1635            let id = TypeId(u32::try_from(i).unwrap_or(u32::MAX));
1636            types.push(t.ok_or(BuildError::UndefinedType(id))?);
1637        }
1638        let module = Module {
1639            strings: self.strings,
1640            types,
1641            consts: self.consts,
1642            imports: self.imports,
1643            globals: self.globals,
1644            functions,
1645            exports: self.exports,
1646            hooks: self
1647                .hooks
1648                .into_iter()
1649                .map(|(hook, callee)| HookBinding { hook, callee })
1650                .collect(),
1651            name: self.name,
1652            start: self.start,
1653        };
1654        for (section, size) in (1u32..).zip(section_sizes(&module)) {
1655            if size > u64::from(u32::MAX) {
1656                return Err(BuildError::TooLarge { section });
1657            }
1658        }
1659        Ok(module)
1660    }
1661}