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