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}