Skip to main content

wit_dylib/
metadata.rs

1use indexmap::IndexMap;
2use std::mem;
3use wasm_encoder::{Function, MemArg};
4use wit_parser::TypeId;
5
6const VERSION: u32 = 3;
7
8#[derive(Default)]
9pub struct Metadata {
10    pub import_funcs: Vec<ImportFunc>,
11    pub export_funcs: Vec<ExportFunc>,
12    pub resources: Vec<Resource>,
13    pub records: Vec<Record>,
14    pub flags: Vec<Flags>,
15    pub tuples: Vec<Tuple>,
16    pub variants: Vec<Variant>,
17    pub enums: Vec<Enum>,
18    pub options: Vec<WitOption>,
19    pub results: Vec<WitResult>,
20    pub lists: Vec<List>,
21    pub maps: Vec<Map>,
22    pub fixed_length_lists: Vec<FixedLengthList>,
23    pub futures: Vec<Future>,
24    pub streams: Vec<Stream>,
25    pub aliases: Vec<Alias>,
26}
27
28pub struct ImportFunc {
29    pub interface: Option<String>,
30    pub name: String,
31    pub sync_import_elem_index: Option<u32>,
32    pub async_import_elem_index: Option<u32>,
33    pub async_import_lift_results_elem_index: Option<u32>,
34    pub args: Vec<Type>,
35    pub result: Option<Type>,
36    pub async_abi_area: Option<(usize, usize)>,
37}
38
39pub struct ExportFunc {
40    pub interface: Option<String>,
41    pub name: String,
42    pub async_export_task_return_elem_index: Option<u32>,
43    pub args: Vec<Type>,
44    pub result: Option<Type>,
45}
46
47pub struct Resource {
48    pub id: TypeId,
49    pub interface: Option<String>,
50    pub name: String,
51    pub drop_elem_index: u32,
52    pub new_elem_index: Option<u32>,
53    pub rep_elem_index: Option<u32>,
54}
55
56pub struct Record {
57    pub id: TypeId,
58    pub interface: Option<String>,
59    pub name: String,
60    pub fields: Vec<(String, Type)>,
61}
62
63pub struct Flags {
64    pub id: TypeId,
65    pub interface: Option<String>,
66    pub name: String,
67    pub names: Vec<String>,
68}
69
70pub struct Tuple {
71    pub id: TypeId,
72    pub interface: Option<String>,
73    pub name: Option<String>,
74    pub types: Vec<Type>,
75}
76
77pub struct Variant {
78    pub id: TypeId,
79    pub interface: Option<String>,
80    pub name: String,
81    pub cases: Vec<(String, Option<Type>)>,
82}
83
84pub struct Enum {
85    pub id: TypeId,
86    pub interface: Option<String>,
87    pub name: String,
88    pub names: Vec<String>,
89}
90
91pub struct WitOption {
92    pub id: TypeId,
93    pub interface: Option<String>,
94    pub name: Option<String>,
95    pub ty: Type,
96}
97
98pub struct WitResult {
99    pub id: TypeId,
100    pub interface: Option<String>,
101    pub name: Option<String>,
102    pub ok: Option<Type>,
103    pub err: Option<Type>,
104}
105
106pub struct List {
107    pub id: TypeId,
108    pub interface: Option<String>,
109    pub name: Option<String>,
110    pub ty: Type,
111}
112
113pub struct FixedLengthList {
114    pub id: TypeId,
115    pub interface: Option<String>,
116    pub name: Option<String>,
117    pub len: u32,
118    pub ty: Type,
119}
120
121pub struct Map {
122    pub id: TypeId,
123    pub interface: Option<String>,
124    pub name: Option<String>,
125    pub key_type: Type,
126    pub value_type: Type,
127}
128
129pub struct Future {
130    pub id: TypeId,
131    pub interface: Option<String>,
132    pub name: Option<String>,
133    pub ty: Option<Type>,
134    pub new_elem_index: u32,
135    pub read_elem_index: u32,
136    pub write_elem_index: u32,
137    pub cancel_read_elem_index: u32,
138    pub cancel_write_elem_index: u32,
139    pub drop_readable_elem_index: u32,
140    pub drop_writable_elem_index: u32,
141    pub lift_elem_index: Option<u32>,
142    pub lower_elem_index: Option<u32>,
143    pub abi_payload_size: usize,
144    pub abi_payload_align: usize,
145}
146
147pub struct Stream {
148    pub id: TypeId,
149    pub interface: Option<String>,
150    pub name: Option<String>,
151    pub ty: Option<Type>,
152    pub new_elem_index: u32,
153    pub read_elem_index: u32,
154    pub write_elem_index: u32,
155    pub cancel_read_elem_index: u32,
156    pub cancel_write_elem_index: u32,
157    pub drop_readable_elem_index: u32,
158    pub drop_writable_elem_index: u32,
159    pub lift_elem_index: Option<u32>,
160    pub lower_elem_index: Option<u32>,
161    pub abi_payload_size: usize,
162    pub abi_payload_align: usize,
163}
164
165pub struct Alias {
166    pub id: TypeId,
167    pub interface: Option<String>,
168    pub name: String,
169    pub ty: Type,
170}
171
172#[derive(Copy, Clone)]
173pub enum Type {
174    U8,
175    U16,
176    U32,
177    U64,
178    S8,
179    S16,
180    S32,
181    S64,
182    Bool,
183    Char,
184    F32,
185    F64,
186    String,
187    ErrorContext,
188    Record(usize),
189    Own(usize),
190    Borrow(usize),
191    Flags(usize),
192    Tuple(usize),
193    Variant(usize),
194    Enum(usize),
195    Option(usize),
196    Result(usize),
197    List(usize),
198    FixedLengthList(usize),
199    Map(usize),
200    Future(usize),
201    Stream(usize),
202    Alias(usize),
203}
204
205struct Encoder {
206    data: Vec<u8>,
207    table_base: u32,
208    memory_base: u32,
209    relocs: Vec<Reloc>,
210    strings: IndexMap<String, SymbolId>,
211    symbol_offsets: Vec<usize>,
212}
213
214struct Reloc {
215    sym: SymbolId,
216    offset: usize,
217    addend: usize,
218    kind: RelocKind,
219}
220
221enum RelocKind {
222    Data,
223    Table,
224}
225
226#[derive(Debug, PartialEq, Copy, Clone)]
227struct SymbolId(usize);
228
229impl SymbolId {
230    const TABLE: SymbolId = SymbolId(usize::MAX);
231}
232
233impl Metadata {
234    pub fn encode(&self, table_base: u32, memory_base: u32) -> (u32, Vec<u8>, Option<Function>) {
235        let mut encoder = Encoder {
236            data: Vec::new(),
237            table_base,
238            memory_base,
239            relocs: Vec::new(),
240            strings: IndexMap::new(),
241            symbol_offsets: Vec::new(),
242        };
243
244        let import_funcs = encoder.encode_list(&self.import_funcs, Encoder::encode_import_funcs);
245        let export_funcs = encoder.encode_list(&self.export_funcs, Encoder::encode_export_funcs);
246        let resources = encoder.encode_list(&self.resources, Encoder::encode_resources);
247        let records = encoder.encode_list(&self.records, Encoder::encode_records);
248        let flags = encoder.encode_list(&self.flags, Encoder::encode_flags);
249        let tuples = encoder.encode_list(&self.tuples, Encoder::encode_tuples);
250        let variants = encoder.encode_list(&self.variants, Encoder::encode_variants);
251        let enums = encoder.encode_list(&self.enums, Encoder::encode_enums);
252        let options = encoder.encode_list(&self.options, Encoder::encode_options);
253        let results = encoder.encode_list(&self.results, Encoder::encode_results);
254        let lists = encoder.encode_list(&self.lists, Encoder::encode_lists);
255        let maps = encoder.encode_list(&self.maps, Encoder::encode_maps);
256        let fixed_length_lists =
257            encoder.encode_list(&self.fixed_length_lists, Encoder::encode_fixed_length_lists);
258        let futures = encoder.encode_list(&self.futures, Encoder::encode_futures);
259        let streams = encoder.encode_list(&self.streams, Encoder::encode_streams);
260        let aliases = encoder.encode_list(&self.aliases, Encoder::encode_aliases);
261
262        let sym_metadata = encoder.symbol();
263        encoder.bind(sym_metadata);
264        encoder.put_u32(VERSION);
265        for (sym, len) in [
266            import_funcs,
267            export_funcs,
268            resources,
269            records,
270            flags,
271            tuples,
272            variants,
273            enums,
274            options,
275            results,
276            lists,
277            maps,
278            fixed_length_lists,
279            futures,
280            streams,
281            aliases,
282        ] {
283            encoder.put_usize(len);
284            if len > 0 {
285                encoder.memory_ptr(sym);
286            } else {
287                encoder.put_usize(0);
288            }
289        }
290
291        encoder.encode_strings();
292
293        let apply_relocs = encoder.generate_apply_relocs();
294        (
295            u32::try_from(encoder.symbol_offsets[sym_metadata.0]).unwrap(),
296            encoder.finish(),
297            apply_relocs,
298        )
299    }
300}
301
302impl Encoder {
303    fn encode_list<T>(
304        &mut self,
305        list: &[T],
306        encode: impl Fn(&mut Self, &[T]),
307    ) -> (SymbolId, usize) {
308        let ret = self.symbol();
309        self.bind(ret);
310        encode(self, list);
311        (ret, list.len())
312    }
313
314    fn encode_import_funcs(&mut self, funcs: &[ImportFunc]) {
315        let mut deferred_args = Vec::new();
316        for func in funcs {
317            let ImportFunc {
318                interface,
319                name,
320                sync_import_elem_index,
321                async_import_elem_index,
322                async_import_lift_results_elem_index,
323                args,
324                result,
325                async_abi_area,
326            } = func;
327            self.opt_string_ptr(interface.as_deref());
328            self.string_ptr(name);
329            self.opt_elem_index(*sync_import_elem_index);
330            self.opt_elem_index(*async_import_elem_index);
331            self.opt_elem_index(*async_import_lift_results_elem_index);
332            self.list(args, &mut deferred_args);
333            self.opt_ty(result.as_ref());
334            match async_abi_area {
335                Some((size, align)) => {
336                    self.put_usize(*size);
337                    self.put_usize(*align);
338                }
339                None => {
340                    self.put_usize(0);
341                    self.put_usize(0);
342                }
343            }
344        }
345
346        for (sym, args) in deferred_args {
347            self.bind(sym);
348            for arg in args {
349                self.ty(arg);
350            }
351        }
352    }
353
354    fn encode_export_funcs(&mut self, funcs: &[ExportFunc]) {
355        let mut deferred_args = Vec::new();
356        for func in funcs {
357            let ExportFunc {
358                interface,
359                name,
360                async_export_task_return_elem_index,
361                args,
362                result,
363            } = func;
364            self.opt_string_ptr(interface.as_deref());
365            self.string_ptr(name);
366            self.opt_elem_index(*async_export_task_return_elem_index);
367            self.list(args, &mut deferred_args);
368            self.opt_ty(result.as_ref());
369        }
370
371        for (sym, args) in deferred_args {
372            self.bind(sym);
373            for arg in args {
374                self.ty(arg);
375            }
376        }
377    }
378
379    fn encode_resources(&mut self, resources: &[Resource]) {
380        for resource in resources {
381            let Resource {
382                id: _,
383                interface,
384                name,
385                drop_elem_index,
386                new_elem_index,
387                rep_elem_index,
388            } = resource;
389            self.opt_string_ptr(interface.as_deref());
390            self.string_ptr(name);
391            self.elem_index(*drop_elem_index);
392            self.opt_elem_index(*new_elem_index);
393            self.opt_elem_index(*rep_elem_index);
394        }
395    }
396
397    fn encode_records(&mut self, records: &[Record]) {
398        let mut deferred_fields = Vec::new();
399        for record in records {
400            let Record {
401                id: _,
402                interface,
403                name,
404                fields,
405            } = record;
406            self.opt_string_ptr(interface.as_deref());
407            self.string_ptr(name);
408            self.list(fields, &mut deferred_fields);
409        }
410
411        for (sym, fields) in deferred_fields {
412            self.bind(sym);
413            for (name, ty) in fields {
414                self.string_ptr(name);
415                self.ty(ty);
416            }
417        }
418    }
419
420    fn encode_flags(&mut self, flags: &[Flags]) {
421        let mut deferred = Vec::new();
422        for flags in flags {
423            let Flags {
424                id: _,
425                interface,
426                name,
427                names,
428            } = flags;
429            self.opt_string_ptr(interface.as_deref());
430            self.string_ptr(name);
431            self.list(names, &mut deferred);
432        }
433
434        for (sym, names) in deferred {
435            self.bind(sym);
436            for name in names {
437                self.string_ptr(name);
438            }
439        }
440    }
441
442    fn encode_tuples(&mut self, tuples: &[Tuple]) {
443        let mut deferred = Vec::new();
444        for tuple in tuples {
445            let Tuple {
446                id: _,
447                interface,
448                name,
449                types,
450            } = tuple;
451            self.opt_string_ptr(interface.as_deref());
452            self.opt_string_ptr(name.as_deref());
453            self.list(types, &mut deferred);
454        }
455
456        for (sym, types) in deferred {
457            self.bind(sym);
458            for ty in types {
459                self.ty(ty);
460            }
461        }
462    }
463
464    fn encode_variants(&mut self, variants: &[Variant]) {
465        let mut deferred = Vec::new();
466        for variant in variants {
467            let Variant {
468                id: _,
469                interface,
470                name,
471                cases,
472            } = variant;
473            self.opt_string_ptr(interface.as_deref());
474            self.string_ptr(name);
475            self.list(cases, &mut deferred);
476        }
477
478        for (sym, cases) in deferred {
479            self.bind(sym);
480            for (name, ty) in cases {
481                self.string_ptr(name);
482                self.opt_ty(ty.as_ref());
483            }
484        }
485    }
486
487    fn encode_enums(&mut self, enums: &[Enum]) {
488        let mut deferred = Vec::new();
489        for e in enums {
490            let Enum {
491                id: _,
492                interface,
493                name,
494                names,
495            } = e;
496            self.opt_string_ptr(interface.as_deref());
497            self.string_ptr(name);
498            self.list(names, &mut deferred);
499        }
500
501        for (sym, names) in deferred {
502            self.bind(sym);
503            for name in names {
504                self.string_ptr(name);
505            }
506        }
507    }
508
509    fn encode_options(&mut self, options: &[WitOption]) {
510        for option in options {
511            let WitOption {
512                id: _,
513                interface,
514                name,
515                ty,
516            } = option;
517            self.opt_string_ptr(interface.as_deref());
518            self.opt_string_ptr(name.as_deref());
519            self.ty(ty);
520        }
521    }
522
523    fn encode_results(&mut self, results: &[WitResult]) {
524        for result in results {
525            let WitResult {
526                id: _,
527                interface,
528                name,
529                ok,
530                err,
531            } = result;
532            self.opt_string_ptr(interface.as_deref());
533            self.opt_string_ptr(name.as_deref());
534            self.opt_ty(ok.as_ref());
535            self.opt_ty(err.as_ref());
536        }
537    }
538
539    fn encode_lists(&mut self, lists: &[List]) {
540        for list in lists {
541            let List {
542                id: _,
543                interface,
544                name,
545                ty,
546            } = list;
547            self.opt_string_ptr(interface.as_deref());
548            self.opt_string_ptr(name.as_deref());
549            self.ty(ty);
550        }
551    }
552
553    fn encode_maps(&mut self, maps: &[Map]) {
554        for map in maps {
555            let Map {
556                id: _,
557                interface,
558                name,
559                key_type,
560                value_type,
561            } = map;
562            self.opt_string_ptr(interface.as_deref());
563            self.opt_string_ptr(name.as_deref());
564            self.ty(key_type);
565            self.ty(value_type);
566        }
567    }
568
569    fn encode_fixed_length_lists(&mut self, lists: &[FixedLengthList]) {
570        for list in lists {
571            let FixedLengthList {
572                id: _,
573                interface,
574                name,
575                len,
576                ty,
577            } = list;
578            self.opt_string_ptr(interface.as_deref());
579            self.opt_string_ptr(name.as_deref());
580            self.put_u32(*len);
581            self.ty(ty);
582        }
583    }
584
585    fn encode_futures(&mut self, futures: &[Future]) {
586        for future in futures {
587            let Future {
588                id: _,
589                interface,
590                name,
591                ty,
592                new_elem_index,
593                read_elem_index,
594                write_elem_index,
595                cancel_read_elem_index,
596                cancel_write_elem_index,
597                drop_readable_elem_index,
598                drop_writable_elem_index,
599                lift_elem_index,
600                lower_elem_index,
601                abi_payload_size,
602                abi_payload_align,
603            } = future;
604            self.opt_string_ptr(interface.as_deref());
605            self.opt_string_ptr(name.as_deref());
606            self.opt_ty(ty.as_ref());
607            self.elem_index(*new_elem_index);
608            self.elem_index(*read_elem_index);
609            self.elem_index(*write_elem_index);
610            self.elem_index(*cancel_read_elem_index);
611            self.elem_index(*cancel_write_elem_index);
612            self.elem_index(*drop_readable_elem_index);
613            self.elem_index(*drop_writable_elem_index);
614            self.opt_elem_index(*lift_elem_index);
615            self.opt_elem_index(*lower_elem_index);
616            self.put_usize(*abi_payload_size);
617            self.put_usize(*abi_payload_align);
618        }
619    }
620
621    fn encode_streams(&mut self, streams: &[Stream]) {
622        for stream in streams {
623            let Stream {
624                id: _,
625                interface,
626                name,
627                ty,
628                new_elem_index,
629                read_elem_index,
630                write_elem_index,
631                cancel_read_elem_index,
632                cancel_write_elem_index,
633                drop_readable_elem_index,
634                drop_writable_elem_index,
635                lift_elem_index,
636                lower_elem_index,
637                abi_payload_size,
638                abi_payload_align,
639            } = stream;
640            self.opt_string_ptr(interface.as_deref());
641            self.opt_string_ptr(name.as_deref());
642            self.opt_ty(ty.as_ref());
643            self.elem_index(*new_elem_index);
644            self.elem_index(*read_elem_index);
645            self.elem_index(*write_elem_index);
646            self.elem_index(*cancel_read_elem_index);
647            self.elem_index(*cancel_write_elem_index);
648            self.elem_index(*drop_readable_elem_index);
649            self.elem_index(*drop_writable_elem_index);
650            self.opt_elem_index(*lift_elem_index);
651            self.opt_elem_index(*lower_elem_index);
652            self.put_usize(*abi_payload_size);
653            self.put_usize(*abi_payload_align);
654        }
655    }
656
657    fn encode_aliases(&mut self, aliases: &[Alias]) {
658        for alias in aliases {
659            let Alias {
660                id: _,
661                interface,
662                name,
663                ty,
664            } = alias;
665            self.opt_string_ptr(interface.as_deref());
666            self.string_ptr(name);
667            self.ty(ty);
668        }
669    }
670
671    fn encode_strings(&mut self) {
672        for (string, sym) in mem::take(&mut self.strings) {
673            self.bind(sym);
674            self.data.extend_from_slice(string.as_bytes());
675            self.data.push(0);
676        }
677    }
678
679    /// Creates a new, as yet unresolved, symbol.
680    ///
681    /// Suitable to pass to `memory_ptr` but must be `bind`-ed at some point
682    /// too.
683    fn symbol(&mut self) -> SymbolId {
684        let ret = SymbolId(self.symbol_offsets.len());
685        self.symbol_offsets.push(usize::MAX);
686        ret
687    }
688
689    /// Indicate that `sym` belongs at the current encoding offset.
690    ///
691    /// Cannot bind a symbol twice.
692    fn bind(&mut self, sym: SymbolId) {
693        assert_eq!(self.symbol_offsets[sym.0], usize::MAX);
694        self.symbol_offsets[sym.0] = self.data.len();
695    }
696
697    fn put_u32(&mut self, value: u32) {
698        self.data.extend_from_slice(&value.to_le_bytes());
699    }
700
701    fn put_usize(&mut self, value: usize) {
702        self.put_u32(value.try_into().unwrap());
703    }
704
705    /// Encodes a `list` at this location as a size/ptr combo.
706    ///
707    /// If the `list` is non-empty then the actual contents are pushed to
708    /// `deferred` with a symbol that should be bound to where the list starts.
709    fn list<'a, T>(&mut self, list: &'a [T], deferred: &mut Vec<(SymbolId, &'a [T])>) {
710        self.put_usize(list.len());
711        if list.is_empty() {
712            self.put_usize(0);
713        } else {
714            let sym = self.symbol();
715            deferred.push((sym, list));
716            self.memory_ptr(sym);
717        }
718    }
719
720    /// Encodes a pointer to `sym` at the current location.
721    fn memory_ptr(&mut self, sym: SymbolId) {
722        self.add_reloc(sym, 0, RelocKind::Data);
723        self.put_u32(0);
724    }
725
726    fn opt_elem_index(&mut self, value: Option<u32>) {
727        match value {
728            Some(name) => self.elem_index(name),
729            None => self.put_u32(0),
730        }
731    }
732
733    fn elem_index(&mut self, value: u32) {
734        self.add_reloc(SymbolId::TABLE, value.try_into().unwrap(), RelocKind::Table);
735        self.put_u32(0);
736    }
737
738    /// Encodes an optional string pointer at the current location.
739    fn opt_string_ptr(&mut self, value: Option<&str>) {
740        match value {
741            Some(name) => self.string_ptr(name),
742            None => self.put_u32(0),
743        }
744    }
745
746    /// Encodes a string pointer at the current location.
747    fn string_ptr(&mut self, value: &str) {
748        let string_sym = if self.strings.contains_key(value) {
749            self.strings[value]
750        } else {
751            let sym = self.symbol();
752            self.strings.insert(value.to_string(), sym);
753            sym
754        };
755        self.memory_ptr(string_sym);
756    }
757
758    fn ty(&mut self, ty: &Type) {
759        let index = |discr: u32, index: &usize| {
760            let index = u32::try_from(*index).unwrap();
761            assert_eq!(index << 8 >> 8, index);
762            (index << 8) | discr
763        };
764        let val = match ty {
765            Type::U8 => 0,
766            Type::U16 => 1,
767            Type::U32 => 2,
768            Type::U64 => 3,
769            Type::S8 => 4,
770            Type::S16 => 5,
771            Type::S32 => 6,
772            Type::S64 => 7,
773            Type::Bool => 8,
774            Type::Char => 9,
775            Type::F32 => 10,
776            Type::F64 => 11,
777            Type::String => 12,
778            Type::ErrorContext => 13,
779            Type::Record(i) => index(14, i),
780            Type::Own(i) => index(15, i),
781            Type::Borrow(i) => index(16, i),
782            Type::Flags(i) => index(17, i),
783            Type::Tuple(i) => index(18, i),
784            Type::Variant(i) => index(19, i),
785            Type::Enum(i) => index(20, i),
786            Type::Option(i) => index(21, i),
787            Type::Result(i) => index(22, i),
788            Type::List(i) => index(23, i),
789            Type::Map(i) => index(24, i),
790            Type::FixedLengthList(i) => index(25, i),
791            Type::Future(i) => index(26, i),
792            Type::Stream(i) => index(27, i),
793            Type::Alias(i) => index(28, i),
794        };
795        self.put_u32(val);
796    }
797
798    fn opt_ty(&mut self, ty: Option<&Type>) {
799        match ty {
800            Some(ty) => self.ty(ty),
801            None => self.put_u32(u32::MAX),
802        }
803    }
804
805    fn add_reloc(&mut self, sym: SymbolId, addend: usize, kind: RelocKind) {
806        self.relocs.push(Reloc {
807            sym,
808            offset: self.data.len(),
809            addend,
810            kind,
811        });
812    }
813
814    fn generate_apply_relocs(&mut self) -> Option<Function> {
815        if self.relocs.is_empty() {
816            return None;
817        }
818        let mut func = Function::new([]);
819        let mut ins = func.instructions();
820        for reloc in self.relocs.iter() {
821            let addend_i32 = u32::try_from(reloc.addend).unwrap() as i32;
822
823            ins.global_get(self.memory_base);
824            match reloc.kind {
825                RelocKind::Data => {
826                    ins.global_get(self.memory_base);
827                    let offset = self.symbol_offsets[reloc.sym.0];
828                    assert!(
829                        offset != usize::MAX,
830                        "failed to bind symbol {}",
831                        reloc.sym.0,
832                    );
833
834                    let sym_i32 = u32::try_from(offset).unwrap() as i32;
835                    ins.i32_const(sym_i32);
836                    ins.i32_add();
837                }
838                RelocKind::Table => {
839                    ins.global_get(self.table_base);
840                    assert_eq!(reloc.sym, SymbolId::TABLE);
841                }
842            }
843            if addend_i32 != 0 {
844                ins.i32_const(addend_i32);
845                ins.i32_add();
846            }
847            ins.i32_store(MemArg {
848                align: 2,
849                memory_index: 0,
850                offset: u64::try_from(reloc.offset).unwrap(),
851            });
852        }
853        ins.end();
854        Some(func)
855    }
856
857    fn finish(self) -> Vec<u8> {
858        self.data
859    }
860}