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