Next Generation WASM Microkernel Operating System
1use alloc::borrow::Cow;
2#[cfg(feature = "component-model")]
3use crate::component::Component;
4use crate::core::*;
5use crate::encode::Encode;
6use crate::token::*;
7use crate::Wat;
8use alloc::vec;
9use alloc::vec::Vec;
10use core::marker;
11
12/// Options that can be specified when encoding a component or a module to
13/// customize what the final binary looks like.
14///
15/// Methods such as [`Module::encode`], [`Wat::encode`], and
16/// [`Component::encode`] will use the default options.
17#[derive(Default)]
18pub struct EncodeOptions<'a> {
19 #[cfg(feature = "dwarf")]
20 dwarf_info: Option<(&'a str, &'a str, GenerateDwarf)>,
21
22 _marker: marker::PhantomData<&'a str>,
23}
24
25#[cfg(feature = "dwarf")]
26mod dwarf;
27
28#[cfg(not(feature = "dwarf"))]
29mod dwarf_disabled;
30#[cfg(not(feature = "dwarf"))]
31use self::dwarf_disabled as dwarf;
32
33/// Configuration of how DWARF debugging information may be generated.
34#[derive(Copy, Clone, Debug)]
35#[non_exhaustive]
36pub enum GenerateDwarf {
37 /// Only generate line tables to map binary offsets back to source
38 /// locations.
39 Lines,
40
41 /// Generate full debugging information for both line numbers and
42 /// variables/locals/operands.
43 Full,
44}
45
46impl<'a> EncodeOptions<'a> {
47 /// Creates a new set of default encoding options.
48 pub fn new() -> EncodeOptions<'a> {
49 EncodeOptions::default()
50 }
51
52 /// Enables emission of DWARF debugging information in the final binary.
53 ///
54 /// This method will use the `file` specified as the source file for the
55 /// `*.wat` file whose `contents` must also be supplied here. These are
56 /// used to calculate filenames/line numbers and are referenced from the
57 /// generated DWARF.
58 #[cfg(feature = "dwarf")]
59 pub fn dwarf(&mut self, file: &'a str, contents: &'a str, style: GenerateDwarf) -> &mut Self {
60 self.dwarf_info = Some((file, contents, style));
61 self
62 }
63
64 /// Encodes the given [`Module`] with these options.
65 ///
66 /// For more information see [`Module::encode`].
67 pub fn encode_module(
68 &self,
69 module: &mut Module<'_>,
70 ) -> core::result::Result<Vec<u8>, crate::Error> {
71 module.resolve()?;
72 Ok(match &module.kind {
73 ModuleKind::Text(fields) => encode(&module.id, &module.name, fields, self),
74 ModuleKind::Binary(blobs) => blobs.iter().flat_map(|b| b.iter().cloned()).collect(),
75 })
76 }
77
78 /// Encodes the given [`Component`] with these options.
79 ///
80 /// For more information see [`Component::encode`].
81 #[cfg(feature = "component-model")]
82 pub fn encode_component(
83 &self,
84 component: &mut Component<'_>,
85 ) -> core::result::Result<Vec<u8>, crate::Error> {
86 component.resolve()?;
87 Ok(crate::component::binary::encode(component, self))
88 }
89
90 /// Encodes the given [`Wat`] with these options.
91 ///
92 /// For more information see [`Wat::encode`].
93 pub fn encode_wat(&self, wat: &mut Wat<'_>) -> core::result::Result<Vec<u8>, crate::Error> {
94 match wat {
95 Wat::Module(m) => self.encode_module(m),
96 #[cfg(feature = "component-model")]
97 Wat::Component(c) => self.encode_component(c),
98 #[cfg(not(feature = "component-model"))]
99 Wat::Component(_) => unreachable!(),
100 }
101 }
102}
103
104pub(crate) fn encode(
105 module_id: &Option<Id<'_>>,
106 module_name: &Option<NameAnnotation<'_>>,
107 fields: &[ModuleField<'_>],
108 opts: &EncodeOptions,
109) -> Vec<u8> {
110 use CustomPlace::*;
111 use CustomPlaceAnchor::*;
112
113 let mut types = Vec::new();
114 let mut imports = Vec::new();
115 let mut funcs = Vec::new();
116 let mut tables = Vec::new();
117 let mut memories = Vec::new();
118 let mut globals = Vec::new();
119 let mut exports = Vec::new();
120 let mut start = Vec::new();
121 let mut elem = Vec::new();
122 let mut data = Vec::new();
123 let mut tags = Vec::new();
124 let mut customs = Vec::new();
125 for field in fields {
126 match field {
127 ModuleField::Type(i) => types.push(RecOrType::Type(i)),
128 ModuleField::Rec(i) => types.push(RecOrType::Rec(i)),
129 ModuleField::Import(i) => imports.push(i),
130 ModuleField::Func(i) => funcs.push(i),
131 ModuleField::Table(i) => tables.push(i),
132 ModuleField::Memory(i) => memories.push(i),
133 ModuleField::Global(i) => globals.push(i),
134 ModuleField::Export(i) => exports.push(i),
135 ModuleField::Start(i) => start.push(i),
136 ModuleField::Elem(i) => elem.push(i),
137 ModuleField::Data(i) => data.push(i),
138 ModuleField::Tag(i) => tags.push(i),
139 ModuleField::Custom(i) => customs.push(i),
140 }
141 }
142
143 let mut e = Encoder {
144 wasm: wasm_encoder::Module::new(),
145 customs: &customs,
146 };
147
148 e.custom_sections(BeforeFirst);
149
150 e.typed_section(&types);
151 e.typed_section(&imports);
152
153 let functys = funcs
154 .iter()
155 .map(|f| FuncSectionTy(&f.ty))
156 .collect::<Vec<_>>();
157 e.typed_section(&functys);
158 e.typed_section(&tables);
159 e.typed_section(&memories);
160 e.typed_section(&tags);
161 e.typed_section(&globals);
162 e.typed_section(&exports);
163 e.custom_sections(Before(Start));
164 if let Some(start) = start.first() {
165 e.wasm.section(&wasm_encoder::StartSection {
166 function_index: start.unwrap_u32(),
167 });
168 }
169 e.custom_sections(After(Start));
170 e.typed_section(&elem);
171 if needs_data_count(&funcs) {
172 e.wasm.section(&wasm_encoder::DataCountSection {
173 count: data.len().try_into().unwrap(),
174 });
175 }
176
177 // Prepare to and emit the code section. This is where DWARF may optionally
178 // be emitted depending on configuration settings. Note that `code_section`
179 // will internally emit the branch hints section if necessary.
180 let names = find_names(module_id, module_name, fields);
181 let num_import_funcs = imports
182 .iter()
183 .filter(|i| matches!(i.item.kind, ItemKind::Func(..)))
184 .count() as u32;
185 let mut dwarf = dwarf::Dwarf::new(num_import_funcs, opts, &names, &types);
186 e.code_section(&funcs, num_import_funcs, dwarf.as_mut());
187
188 e.typed_section(&data);
189
190 if !names.is_empty() {
191 e.wasm.section(&names.to_name_section());
192 }
193 e.custom_sections(AfterLast);
194 if let Some(dwarf) = &mut dwarf {
195 dwarf.emit(&mut e);
196 }
197
198 return e.wasm.finish();
199
200 fn needs_data_count(funcs: &[&crate::core::Func<'_>]) -> bool {
201 funcs
202 .iter()
203 .filter_map(|f| match &f.kind {
204 FuncKind::Inline { expression, .. } => Some(expression),
205 _ => None,
206 })
207 .flat_map(|e| e.instrs.iter())
208 .any(|i| i.needs_data_count())
209 }
210}
211
212struct Encoder<'a> {
213 wasm: wasm_encoder::Module,
214 customs: &'a [&'a Custom<'a>],
215}
216
217impl Encoder<'_> {
218 fn custom_sections(&mut self, place: CustomPlace) {
219 for entry in self.customs.iter() {
220 if entry.place() == place {
221 entry.encode(&mut self.wasm);
222 }
223 }
224 }
225
226 fn typed_section<T>(&mut self, list: &[T])
227 where
228 T: SectionItem,
229 {
230 self.custom_sections(CustomPlace::Before(T::ANCHOR));
231 if !list.is_empty() {
232 let mut section = T::Section::default();
233 for item in list {
234 item.encode(&mut section);
235 }
236 self.wasm.section(§ion);
237 }
238 self.custom_sections(CustomPlace::After(T::ANCHOR));
239 }
240
241 /// Encodes the code section of a wasm module module while additionally
242 /// handling the branch hinting proposal.
243 ///
244 /// The branch hinting proposal requires to encode the offsets of the
245 /// instructions relative from the beginning of the function. Here we encode
246 /// each instruction and we save its offset. If needed, we use this
247 /// information to build the branch hint section and insert it before the
248 /// code section.
249 ///
250 /// The `list` provided is the list of functions that are emitted into the
251 /// code section. The `func_index` provided is the initial index of defined
252 /// functions, so it's the count of imported functions. The `dwarf` field is
253 /// optionally used to track debugging information.
254 fn code_section<'a>(
255 &'a mut self,
256 list: &[&'a Func<'_>],
257 mut func_index: u32,
258 mut dwarf: Option<&mut dwarf::Dwarf>,
259 ) {
260 self.custom_sections(CustomPlace::Before(CustomPlaceAnchor::Code));
261
262 if !list.is_empty() {
263 let mut branch_hints = wasm_encoder::BranchHints::new();
264 let mut code_section = wasm_encoder::CodeSection::new();
265
266 for func in list.iter() {
267 let hints = func.encode(&mut code_section, dwarf.as_deref_mut());
268 if !hints.is_empty() {
269 branch_hints.function_hints(func_index, hints.into_iter());
270 }
271 func_index += 1;
272 }
273
274 // Branch hints section has to be inserted before the Code section
275 // Insert the section only if we have some hints
276 if !branch_hints.is_empty() {
277 self.wasm.section(&branch_hints);
278 }
279
280 // Finally, insert the Code section from the tmp buffer
281 self.wasm.section(&code_section);
282
283 if let Some(dwarf) = &mut dwarf {
284 dwarf.set_code_section_size(code_section.byte_len());
285 }
286 }
287 self.custom_sections(CustomPlace::After(CustomPlaceAnchor::Code));
288 }
289}
290
291trait SectionItem {
292 type Section: wasm_encoder::Section + Default;
293 const ANCHOR: CustomPlaceAnchor;
294
295 fn encode(&self, section: &mut Self::Section);
296}
297
298impl<T> SectionItem for &T
299where
300 T: SectionItem,
301{
302 type Section = T::Section;
303 const ANCHOR: CustomPlaceAnchor = T::ANCHOR;
304
305 fn encode(&self, section: &mut Self::Section) {
306 T::encode(self, section)
307 }
308}
309
310impl From<&FunctionType<'_>> for wasm_encoder::FuncType {
311 fn from(ft: &FunctionType) -> Self {
312 wasm_encoder::FuncType::new(
313 ft.params.iter().map(|(_, _, ty)| (*ty).into()),
314 ft.results.iter().map(|ty| (*ty).into()),
315 )
316 }
317}
318
319impl From<&StructType<'_>> for wasm_encoder::StructType {
320 fn from(st: &StructType) -> wasm_encoder::StructType {
321 wasm_encoder::StructType {
322 fields: st.fields.iter().map(|f| f.into()).collect(),
323 }
324 }
325}
326
327impl From<&StructField<'_>> for wasm_encoder::FieldType {
328 fn from(f: &StructField) -> wasm_encoder::FieldType {
329 wasm_encoder::FieldType {
330 element_type: f.ty.into(),
331 mutable: f.mutable,
332 }
333 }
334}
335
336impl From<&ArrayType<'_>> for wasm_encoder::ArrayType {
337 fn from(at: &ArrayType) -> Self {
338 let field = wasm_encoder::FieldType {
339 element_type: at.ty.into(),
340 mutable: at.mutable,
341 };
342 wasm_encoder::ArrayType(field)
343 }
344}
345
346impl From<&ContType<'_>> for wasm_encoder::ContType {
347 fn from(at: &ContType) -> Self {
348 wasm_encoder::ContType(at.0.into())
349 }
350}
351
352enum RecOrType<'a> {
353 Type(&'a Type<'a>),
354 Rec(&'a Rec<'a>),
355}
356
357impl SectionItem for RecOrType<'_> {
358 type Section = wasm_encoder::TypeSection;
359 const ANCHOR: CustomPlaceAnchor = CustomPlaceAnchor::Type;
360
361 fn encode(&self, types: &mut wasm_encoder::TypeSection) {
362 match self {
363 RecOrType::Type(ty) => types.ty().subtype(&ty.to_subtype()),
364 RecOrType::Rec(rec) => types.ty().rec(rec.types.iter().map(|t| t.to_subtype())),
365 }
366 }
367}
368
369impl Type<'_> {
370 pub(crate) fn to_subtype(&self) -> wasm_encoder::SubType {
371 self.def.to_subtype()
372 }
373}
374
375impl TypeDef<'_> {
376 pub(crate) fn to_subtype(&self) -> wasm_encoder::SubType {
377 use wasm_encoder::CompositeInnerType::*;
378 let composite_type = wasm_encoder::CompositeType {
379 inner: match &self.kind {
380 InnerTypeKind::Func(ft) => Func(ft.into()),
381 InnerTypeKind::Struct(st) => Struct(st.into()),
382 InnerTypeKind::Array(at) => Array(at.into()),
383 InnerTypeKind::Cont(ct) => Cont(ct.into()),
384 },
385 shared: self.shared,
386 };
387 wasm_encoder::SubType {
388 composite_type,
389 is_final: self.final_type.unwrap_or(true),
390 supertype_idx: self.parent.map(|i| i.unwrap_u32()),
391 }
392 }
393}
394
395impl From<ValType<'_>> for wasm_encoder::ValType {
396 fn from(ty: ValType) -> Self {
397 match ty {
398 ValType::I32 => Self::I32,
399 ValType::I64 => Self::I64,
400 ValType::F32 => Self::F32,
401 ValType::F64 => Self::F64,
402 ValType::V128 => Self::V128,
403 ValType::Ref(r) => Self::Ref(r.into()),
404 }
405 }
406}
407
408impl From<RefType<'_>> for wasm_encoder::RefType {
409 fn from(r: RefType<'_>) -> Self {
410 wasm_encoder::RefType {
411 nullable: r.nullable,
412 heap_type: r.heap.into(),
413 }
414 }
415}
416
417impl From<HeapType<'_>> for wasm_encoder::HeapType {
418 fn from(r: HeapType<'_>) -> Self {
419 use wasm_encoder::AbstractHeapType::*;
420 match r {
421 HeapType::Abstract { shared, ty } => {
422 let ty = match ty {
423 AbstractHeapType::Func => Func,
424 AbstractHeapType::Extern => Extern,
425 AbstractHeapType::Exn => Exn,
426 AbstractHeapType::NoExn => NoExn,
427 AbstractHeapType::Any => Any,
428 AbstractHeapType::Eq => Eq,
429 AbstractHeapType::Struct => Struct,
430 AbstractHeapType::Array => Array,
431 AbstractHeapType::NoFunc => NoFunc,
432 AbstractHeapType::NoExtern => NoExtern,
433 AbstractHeapType::None => None,
434 AbstractHeapType::I31 => I31,
435 AbstractHeapType::Cont => Cont,
436 AbstractHeapType::NoCont => NoCont,
437 };
438 Self::Abstract { shared, ty }
439 }
440 HeapType::Concrete(i) => Self::Concrete(i.unwrap_u32()),
441 }
442 }
443}
444
445impl Encode for Option<Id<'_>> {
446 fn encode(&self, _e: &mut Vec<u8>) {
447 // used for parameters in the tuple impl as well as instruction labels
448 }
449}
450
451impl<'a> Encode for ValType<'a> {
452 fn encode(&self, e: &mut Vec<u8>) {
453 wasm_encoder::Encode::encode(&wasm_encoder::ValType::from(*self), e)
454 }
455}
456
457impl<'a> Encode for HeapType<'a> {
458 fn encode(&self, e: &mut Vec<u8>) {
459 wasm_encoder::Encode::encode(&wasm_encoder::HeapType::from(*self), e)
460 }
461}
462
463impl From<StorageType<'_>> for wasm_encoder::StorageType {
464 fn from(st: StorageType) -> Self {
465 use wasm_encoder::StorageType::*;
466 match st {
467 StorageType::I8 => I8,
468 StorageType::I16 => I16,
469 StorageType::Val(vt) => Val(vt.into()),
470 }
471 }
472}
473
474impl SectionItem for Import<'_> {
475 type Section = wasm_encoder::ImportSection;
476 const ANCHOR: CustomPlaceAnchor = CustomPlaceAnchor::Import;
477
478 fn encode(&self, section: &mut wasm_encoder::ImportSection) {
479 section.import(self.module, self.field, self.item.to_entity_type());
480 }
481}
482
483impl ItemSig<'_> {
484 pub(crate) fn to_entity_type(&self) -> wasm_encoder::EntityType {
485 self.kind.to_entity_type()
486 }
487}
488
489impl ItemKind<'_> {
490 fn to_entity_type(&self) -> wasm_encoder::EntityType {
491 use wasm_encoder::EntityType as ET;
492 match self {
493 ItemKind::Func(t) => ET::Function(t.unwrap_u32()),
494 ItemKind::Table(t) => ET::Table(t.to_table_type()),
495 ItemKind::Memory(t) => ET::Memory(t.to_memory_type()),
496 ItemKind::Global(t) => ET::Global(t.to_global_type()),
497 ItemKind::Tag(t) => ET::Tag(t.to_tag_type()),
498 }
499 }
500}
501
502impl TableType<'_> {
503 fn to_table_type(self) -> wasm_encoder::TableType {
504 wasm_encoder::TableType {
505 element_type: self.elem.into(),
506 minimum: self.limits.min,
507 maximum: self.limits.max,
508 table64: self.limits.is64,
509 shared: self.shared,
510 }
511 }
512}
513
514impl MemoryType {
515 fn to_memory_type(self) -> wasm_encoder::MemoryType {
516 wasm_encoder::MemoryType {
517 minimum: self.limits.min,
518 maximum: self.limits.max,
519 memory64: self.limits.is64,
520 shared: self.shared,
521 page_size_log2: self.page_size_log2,
522 }
523 }
524}
525
526impl GlobalType<'_> {
527 fn to_global_type(self) -> wasm_encoder::GlobalType {
528 wasm_encoder::GlobalType {
529 val_type: self.ty.into(),
530 mutable: self.mutable,
531 shared: self.shared,
532 }
533 }
534}
535
536impl TagType<'_> {
537 fn to_tag_type(&self) -> wasm_encoder::TagType {
538 match self {
539 TagType::Exception(r) => wasm_encoder::TagType {
540 kind: wasm_encoder::TagKind::Exception,
541 func_type_idx: r.unwrap_u32(),
542 },
543 }
544 }
545}
546
547impl<T> TypeUse<'_, T> {
548 fn unwrap_u32(&self) -> u32 {
549 self.index
550 .as_ref()
551 .expect("TypeUse should be filled in by this point")
552 .unwrap_u32()
553 }
554}
555
556struct FuncSectionTy<'a>(&'a TypeUse<'a, FunctionType<'a>>);
557
558impl SectionItem for FuncSectionTy<'_> {
559 type Section = wasm_encoder::FunctionSection;
560 const ANCHOR: CustomPlaceAnchor = CustomPlaceAnchor::Func;
561
562 fn encode(&self, section: &mut wasm_encoder::FunctionSection) {
563 section.function(self.0.unwrap_u32());
564 }
565}
566
567impl Encode for Index<'_> {
568 fn encode(&self, e: &mut Vec<u8>) {
569 self.unwrap_u32().encode(e)
570 }
571}
572
573impl Index<'_> {
574 fn unwrap_u32(&self) -> u32 {
575 match self {
576 Index::Num(n, _) => *n,
577 Index::Id(n) => panic!("unresolved index in emission: {:?}", n),
578 }
579 }
580}
581
582impl From<Index<'_>> for u32 {
583 fn from(i: Index<'_>) -> Self {
584 match i {
585 Index::Num(i, _) => i,
586 Index::Id(_) => unreachable!("unresolved index in encoding: {:?}", i),
587 }
588 }
589}
590
591impl SectionItem for Table<'_> {
592 type Section = wasm_encoder::TableSection;
593 const ANCHOR: CustomPlaceAnchor = CustomPlaceAnchor::Table;
594
595 fn encode(&self, section: &mut wasm_encoder::TableSection) {
596 assert!(self.exports.names.is_empty());
597 match &self.kind {
598 TableKind::Normal {
599 ty,
600 init_expr: None,
601 } => {
602 section.table(ty.to_table_type());
603 }
604 TableKind::Normal {
605 ty,
606 init_expr: Some(init_expr),
607 } => {
608 section.table_with_init(ty.to_table_type(), &init_expr.to_const_expr());
609 }
610 _ => panic!("TableKind should be normal during encoding"),
611 }
612 }
613}
614
615impl SectionItem for Memory<'_> {
616 type Section = wasm_encoder::MemorySection;
617 const ANCHOR: CustomPlaceAnchor = CustomPlaceAnchor::Memory;
618
619 fn encode(&self, section: &mut wasm_encoder::MemorySection) {
620 assert!(self.exports.names.is_empty());
621 match &self.kind {
622 MemoryKind::Normal(t) => {
623 section.memory(t.to_memory_type());
624 }
625 _ => panic!("MemoryKind should be normal during encoding"),
626 }
627 }
628}
629
630impl SectionItem for Global<'_> {
631 type Section = wasm_encoder::GlobalSection;
632 const ANCHOR: CustomPlaceAnchor = CustomPlaceAnchor::Global;
633
634 fn encode(&self, section: &mut wasm_encoder::GlobalSection) {
635 assert!(self.exports.names.is_empty());
636 let init = match &self.kind {
637 GlobalKind::Inline(expr) => expr.to_const_expr(),
638 _ => panic!("GlobalKind should be inline during encoding"),
639 };
640 section.global(self.ty.to_global_type(), &init);
641 }
642}
643
644impl SectionItem for Export<'_> {
645 type Section = wasm_encoder::ExportSection;
646 const ANCHOR: CustomPlaceAnchor = CustomPlaceAnchor::Export;
647
648 fn encode(&self, section: &mut wasm_encoder::ExportSection) {
649 section.export(self.name, self.kind.into(), self.item.unwrap_u32());
650 }
651}
652
653impl From<ExportKind> for wasm_encoder::ExportKind {
654 fn from(kind: ExportKind) -> Self {
655 match kind {
656 ExportKind::Func => Self::Func,
657 ExportKind::Table => Self::Table,
658 ExportKind::Memory => Self::Memory,
659 ExportKind::Global => Self::Global,
660 ExportKind::Tag => Self::Tag,
661 }
662 }
663}
664
665impl SectionItem for Elem<'_> {
666 type Section = wasm_encoder::ElementSection;
667 const ANCHOR: CustomPlaceAnchor = CustomPlaceAnchor::Elem;
668
669 fn encode(&self, section: &mut wasm_encoder::ElementSection) {
670 use wasm_encoder::Elements;
671
672 let elements = match &self.payload {
673 ElemPayload::Indices(v) => {
674 Elements::Functions(Cow::Owned(v.iter().map(|i| i.unwrap_u32()).collect()))
675 }
676 ElemPayload::Exprs { exprs, ty } => Elements::Expressions(
677 (*ty).into(),
678 Cow::Owned(exprs.iter().map(|e| e.to_const_expr()).collect()),
679 ),
680 };
681 match &self.kind {
682 ElemKind::Active { table, offset } => {
683 section.active(
684 table.map(|t| t.unwrap_u32()),
685 &offset.to_const_expr(),
686 elements,
687 );
688 }
689 ElemKind::Passive => {
690 section.passive(elements);
691 }
692 ElemKind::Declared => {
693 section.declared(elements);
694 }
695 }
696 }
697}
698
699impl SectionItem for Data<'_> {
700 type Section = wasm_encoder::DataSection;
701 const ANCHOR: CustomPlaceAnchor = CustomPlaceAnchor::Data;
702
703 fn encode(&self, section: &mut wasm_encoder::DataSection) {
704 let mut data = Vec::new();
705 for val in self.data.iter() {
706 val.push_onto(&mut data);
707 }
708 match &self.kind {
709 DataKind::Passive => {
710 section.passive(data);
711 }
712 DataKind::Active { memory, offset } => {
713 section.active(memory.unwrap_u32(), &offset.to_const_expr(), data);
714 }
715 }
716 }
717}
718
719impl Func<'_> {
720 /// Encodes the function into `e` while returning all branch hints with
721 /// known relative offsets after encoding.
722 ///
723 /// The `dwarf` field is optional and used to track debugging information
724 /// for each instruction.
725 fn encode(
726 &self,
727 section: &mut wasm_encoder::CodeSection,
728 mut dwarf: Option<&mut dwarf::Dwarf>,
729 ) -> Vec<wasm_encoder::BranchHint> {
730 assert!(self.exports.names.is_empty());
731 let (expr, locals) = match &self.kind {
732 FuncKind::Inline { expression, locals } => (expression, locals),
733 _ => panic!("should only have inline functions in emission"),
734 };
735
736 if let Some(dwarf) = &mut dwarf {
737 let index = match self.ty.index.as_ref().unwrap() {
738 Index::Num(n, _) => *n,
739 _ => unreachable!(),
740 };
741 dwarf.start_func(self.span, index, locals);
742 }
743
744 // Encode the function into a temporary vector because functions are
745 // prefixed with their length. The temporary vector, when encoded,
746 // encodes its length first then the body.
747 let mut func =
748 wasm_encoder::Function::new_with_locals_types(locals.iter().map(|t| t.ty.into()));
749 let branch_hints = expr.encode(&mut func, dwarf.as_deref_mut());
750 let func_size = func.byte_len();
751 section.function(&func);
752
753 if let Some(dwarf) = &mut dwarf {
754 dwarf.end_func(func_size, section.byte_len());
755 }
756
757 branch_hints
758 }
759}
760
761impl Expression<'_> {
762 /// Encodes this expression into `e` and optionally tracks debugging
763 /// information for each instruction in `dwarf`.
764 ///
765 /// Returns all branch hints, if any, found while parsing this function.
766 fn encode(
767 &self,
768 func: &mut wasm_encoder::Function,
769 mut dwarf: Option<&mut dwarf::Dwarf>,
770 ) -> Vec<wasm_encoder::BranchHint> {
771 let mut hints = Vec::with_capacity(self.branch_hints.len());
772 let mut next_hint = self.branch_hints.iter().peekable();
773 let mut tmp = Vec::new();
774
775 for (i, instr) in self.instrs.iter().enumerate() {
776 // Branch hints are stored in order of increasing `instr_index` so
777 // check to see if the next branch hint matches this instruction's
778 // index.
779 if let Some(hint) = next_hint.next_if(|h| h.instr_index == i) {
780 hints.push(wasm_encoder::BranchHint {
781 branch_func_offset: u32::try_from(func.byte_len() + tmp.len()).unwrap(),
782 branch_hint_value: hint.value,
783 });
784 }
785
786 // If DWARF is enabled then track this instruction's binary offset
787 // and source location.
788 if let Some(dwarf) = &mut dwarf {
789 if let Some(span) = self.instr_spans.as_ref().map(|s| s[i]) {
790 dwarf.instr(func.byte_len() + tmp.len(), span);
791 }
792 }
793
794 // Finally emit the instruction and move to the next.
795 instr.encode(&mut tmp);
796 }
797 func.raw(tmp.iter().copied());
798 func.instructions().end();
799
800 hints
801 }
802
803 fn to_const_expr(&self) -> wasm_encoder::ConstExpr {
804 let mut tmp = Vec::new();
805 for instr in self.instrs.iter() {
806 instr.encode(&mut tmp);
807 }
808 wasm_encoder::ConstExpr::raw(tmp)
809 }
810}
811
812impl Encode for BlockType<'_> {
813 fn encode(&self, e: &mut Vec<u8>) {
814 // block types using an index are encoded as an sleb, not a uleb
815 if let Some(Index::Num(n, _)) = &self.ty.index {
816 return i64::from(*n).encode(e);
817 }
818 let ty = self
819 .ty
820 .inline
821 .as_ref()
822 .expect("function type not filled in");
823 if ty.params.is_empty() && ty.results.is_empty() {
824 return e.push(0x40);
825 }
826 if ty.params.is_empty() && ty.results.len() == 1 {
827 return ty.results[0].encode(e);
828 }
829 panic!("multi-value block types should have an index");
830 }
831}
832
833impl Encode for LaneArg {
834 fn encode(&self, e: &mut Vec<u8>) {
835 self.lane.encode(e);
836 }
837}
838
839impl Encode for MemArg<'_> {
840 fn encode(&self, e: &mut Vec<u8>) {
841 match &self.memory {
842 Index::Num(0, _) => {
843 self.align.trailing_zeros().encode(e);
844 self.offset.encode(e);
845 }
846 _ => {
847 (self.align.trailing_zeros() | (1 << 6)).encode(e);
848 self.memory.encode(e);
849 self.offset.encode(e);
850 }
851 }
852 }
853}
854
855impl Encode for Ordering {
856 fn encode(&self, buf: &mut Vec<u8>) {
857 let flag: u8 = match self {
858 Ordering::SeqCst => 0,
859 Ordering::AcqRel => 1,
860 };
861 flag.encode(buf);
862 }
863}
864
865impl<T> Encode for Ordered<T>
866where
867 T: Encode,
868{
869 fn encode(&self, buf: &mut Vec<u8>) {
870 self.ordering.encode(buf);
871 self.inner.encode(buf);
872 }
873}
874
875impl Encode for LoadOrStoreLane<'_> {
876 fn encode(&self, e: &mut Vec<u8>) {
877 self.memarg.encode(e);
878 self.lane.encode(e);
879 }
880}
881
882impl Encode for CallIndirect<'_> {
883 fn encode(&self, e: &mut Vec<u8>) {
884 self.ty.unwrap_u32().encode(e);
885 self.table.encode(e);
886 }
887}
888
889impl Encode for TableInit<'_> {
890 fn encode(&self, e: &mut Vec<u8>) {
891 self.elem.encode(e);
892 self.table.encode(e);
893 }
894}
895
896impl Encode for TableCopy<'_> {
897 fn encode(&self, e: &mut Vec<u8>) {
898 self.dst.encode(e);
899 self.src.encode(e);
900 }
901}
902
903impl Encode for TableArg<'_> {
904 fn encode(&self, e: &mut Vec<u8>) {
905 self.dst.encode(e);
906 }
907}
908
909impl Encode for MemoryArg<'_> {
910 fn encode(&self, e: &mut Vec<u8>) {
911 self.mem.encode(e);
912 }
913}
914
915impl Encode for MemoryInit<'_> {
916 fn encode(&self, e: &mut Vec<u8>) {
917 self.data.encode(e);
918 self.mem.encode(e);
919 }
920}
921
922impl Encode for MemoryCopy<'_> {
923 fn encode(&self, e: &mut Vec<u8>) {
924 self.dst.encode(e);
925 self.src.encode(e);
926 }
927}
928
929impl Encode for BrTableIndices<'_> {
930 fn encode(&self, e: &mut Vec<u8>) {
931 self.labels.encode(e);
932 self.default.encode(e);
933 }
934}
935
936impl Encode for F32 {
937 fn encode(&self, e: &mut Vec<u8>) {
938 e.extend_from_slice(&self.bits.to_le_bytes());
939 }
940}
941
942impl Encode for F64 {
943 fn encode(&self, e: &mut Vec<u8>) {
944 e.extend_from_slice(&self.bits.to_le_bytes());
945 }
946}
947
948#[derive(Default)]
949struct Names<'a> {
950 module: Option<&'a str>,
951 funcs: Vec<(u32, &'a str)>,
952 func_idx: u32,
953 locals: Vec<(u32, Vec<(u32, &'a str)>)>,
954 labels: Vec<(u32, Vec<(u32, &'a str)>)>,
955 globals: Vec<(u32, &'a str)>,
956 global_idx: u32,
957 memories: Vec<(u32, &'a str)>,
958 memory_idx: u32,
959 tables: Vec<(u32, &'a str)>,
960 table_idx: u32,
961 tags: Vec<(u32, &'a str)>,
962 tag_idx: u32,
963 types: Vec<(u32, &'a str)>,
964 type_idx: u32,
965 data: Vec<(u32, &'a str)>,
966 data_idx: u32,
967 elems: Vec<(u32, &'a str)>,
968 elem_idx: u32,
969 fields: Vec<(u32, Vec<(u32, &'a str)>)>,
970}
971
972fn find_names<'a>(
973 module_id: &Option<Id<'a>>,
974 module_name: &Option<NameAnnotation<'a>>,
975 fields: &[ModuleField<'a>],
976) -> Names<'a> {
977 fn get_name<'a>(id: &Option<Id<'a>>, name: &Option<NameAnnotation<'a>>) -> Option<&'a str> {
978 name.as_ref().map(|n| n.name).or(id.and_then(|id| {
979 if id.is_gensym() {
980 None
981 } else {
982 Some(id.name())
983 }
984 }))
985 }
986
987 enum Name {
988 Type,
989 Global,
990 Func,
991 Memory,
992 Table,
993 Tag,
994 Elem,
995 Data,
996 }
997
998 let mut ret = Names { module: get_name(module_id, module_name), ..Default::default() };
999 let mut names = Vec::new();
1000 for field in fields {
1001 // Extract the kind/id/name from whatever kind of field this is...
1002 let (kind, id, name) = match field {
1003 ModuleField::Import(i) => (
1004 match i.item.kind {
1005 ItemKind::Func(_) => Name::Func,
1006 ItemKind::Table(_) => Name::Table,
1007 ItemKind::Memory(_) => Name::Memory,
1008 ItemKind::Global(_) => Name::Global,
1009 ItemKind::Tag(_) => Name::Tag,
1010 },
1011 &i.item.id,
1012 &i.item.name,
1013 ),
1014 ModuleField::Global(g) => (Name::Global, &g.id, &g.name),
1015 ModuleField::Table(t) => (Name::Table, &t.id, &t.name),
1016 ModuleField::Memory(m) => (Name::Memory, &m.id, &m.name),
1017 ModuleField::Tag(t) => (Name::Tag, &t.id, &t.name),
1018 ModuleField::Type(t) => (Name::Type, &t.id, &t.name),
1019 ModuleField::Rec(r) => {
1020 for ty in &r.types {
1021 names.push((Name::Type, &ty.id, &ty.name, field));
1022 }
1023 continue;
1024 }
1025 ModuleField::Elem(e) => (Name::Elem, &e.id, &e.name),
1026 ModuleField::Data(d) => (Name::Data, &d.id, &d.name),
1027 ModuleField::Func(f) => (Name::Func, &f.id, &f.name),
1028 ModuleField::Export(_) | ModuleField::Start(_) | ModuleField::Custom(_) => continue,
1029 };
1030 names.push((kind, id, name, field));
1031 }
1032
1033 for (kind, id, name, field) in names {
1034 // .. and using the kind we can figure out where to place this name
1035 let (list, idx) = match kind {
1036 Name::Func => (&mut ret.funcs, &mut ret.func_idx),
1037 Name::Table => (&mut ret.tables, &mut ret.table_idx),
1038 Name::Memory => (&mut ret.memories, &mut ret.memory_idx),
1039 Name::Global => (&mut ret.globals, &mut ret.global_idx),
1040 Name::Tag => (&mut ret.tags, &mut ret.tag_idx),
1041 Name::Type => (&mut ret.types, &mut ret.type_idx),
1042 Name::Elem => (&mut ret.elems, &mut ret.elem_idx),
1043 Name::Data => (&mut ret.data, &mut ret.data_idx),
1044 };
1045 if let Some(name) = get_name(id, name) {
1046 list.push((*idx, name));
1047 }
1048
1049 // Handle module locals separately from above
1050 if let ModuleField::Func(f) = field {
1051 let mut local_names = Vec::new();
1052 let mut label_names = Vec::new();
1053 let mut local_idx = 0;
1054 let mut label_idx = 0;
1055
1056 // Consult the inline type listed for local names of parameters.
1057 // This is specifically preserved during the name resolution
1058 // pass, but only for functions, so here we can look at the
1059 // original source's names.
1060 if let Some(ty) = &f.ty.inline {
1061 for (id, name, _) in ty.params.iter() {
1062 if let Some(name) = get_name(id, name) {
1063 local_names.push((local_idx, name));
1064 }
1065 local_idx += 1;
1066 }
1067 }
1068 if let FuncKind::Inline {
1069 locals, expression, ..
1070 } = &f.kind
1071 {
1072 for local in locals.iter() {
1073 if let Some(name) = get_name(&local.id, &local.name) {
1074 local_names.push((local_idx, name));
1075 }
1076 local_idx += 1;
1077 }
1078
1079 for i in expression.instrs.iter() {
1080 match i {
1081 Instruction::If(block)
1082 | Instruction::Block(block)
1083 | Instruction::Loop(block)
1084 | Instruction::Try(block)
1085 | Instruction::TryTable(TryTable { block, .. }) => {
1086 if let Some(name) = get_name(&block.label, &block.label_name) {
1087 label_names.push((label_idx, name));
1088 }
1089 label_idx += 1;
1090 }
1091 _ => {}
1092 }
1093 }
1094 }
1095 if !local_names.is_empty() {
1096 ret.locals.push((*idx, local_names));
1097 }
1098 if !label_names.is_empty() {
1099 ret.labels.push((*idx, label_names));
1100 }
1101 }
1102
1103 // Handle struct fields separately from above
1104 if let ModuleField::Type(ty) = field {
1105 let mut field_names = vec![];
1106 match &ty.def.kind {
1107 InnerTypeKind::Func(_) | InnerTypeKind::Array(_) | InnerTypeKind::Cont(_) => {}
1108 InnerTypeKind::Struct(ty_struct) => {
1109 for (idx, field) in ty_struct.fields.iter().enumerate() {
1110 if let Some(name) = get_name(&field.id, &None) {
1111 field_names.push((idx as u32, name))
1112 }
1113 }
1114 }
1115 }
1116 if !field_names.is_empty() {
1117 ret.fields.push((*idx, field_names))
1118 }
1119 }
1120
1121 *idx += 1;
1122 }
1123
1124 ret
1125}
1126
1127impl Names<'_> {
1128 fn is_empty(&self) -> bool {
1129 self.module.is_none()
1130 && self.funcs.is_empty()
1131 && self.locals.is_empty()
1132 && self.labels.is_empty()
1133 && self.globals.is_empty()
1134 && self.memories.is_empty()
1135 && self.tables.is_empty()
1136 && self.types.is_empty()
1137 && self.elems.is_empty()
1138 && self.data.is_empty()
1139 && self.fields.is_empty()
1140 && self.tags.is_empty()
1141 }
1142}
1143
1144impl Names<'_> {
1145 fn to_name_section(&self) -> wasm_encoder::NameSection {
1146 let mut names = wasm_encoder::NameSection::default();
1147
1148 if let Some(id) = self.module {
1149 names.module(id);
1150 }
1151 let name_map = |indices: &[(u32, &str)]| {
1152 if indices.is_empty() {
1153 return None;
1154 }
1155 let mut map = wasm_encoder::NameMap::default();
1156 for (idx, name) in indices {
1157 map.append(*idx, name);
1158 }
1159 Some(map)
1160 };
1161 let indirect_name_map = |indices: &[(u32, Vec<(u32, &str)>)]| {
1162 if indices.is_empty() {
1163 return None;
1164 }
1165 let mut map = wasm_encoder::IndirectNameMap::default();
1166 for (idx, names) in indices {
1167 if let Some(names) = name_map(names) {
1168 map.append(*idx, &names);
1169 }
1170 }
1171 Some(map)
1172 };
1173 if let Some(map) = name_map(&self.funcs) {
1174 names.functions(&map);
1175 }
1176 if let Some(map) = indirect_name_map(&self.locals) {
1177 names.locals(&map);
1178 }
1179 if let Some(map) = indirect_name_map(&self.labels) {
1180 names.labels(&map);
1181 }
1182 if let Some(map) = name_map(&self.types) {
1183 names.types(&map);
1184 }
1185 if let Some(map) = name_map(&self.tables) {
1186 names.tables(&map);
1187 }
1188 if let Some(map) = name_map(&self.memories) {
1189 names.memories(&map);
1190 }
1191 if let Some(map) = name_map(&self.globals) {
1192 names.globals(&map);
1193 }
1194 if let Some(map) = name_map(&self.elems) {
1195 names.elements(&map);
1196 }
1197 if let Some(map) = name_map(&self.data) {
1198 names.data(&map);
1199 }
1200 if let Some(map) = indirect_name_map(&self.fields) {
1201 names.fields(&map);
1202 }
1203 if let Some(map) = name_map(&self.tags) {
1204 names.tags(&map);
1205 }
1206 names
1207 }
1208}
1209
1210impl Encode for Id<'_> {
1211 fn encode(&self, dst: &mut Vec<u8>) {
1212 assert!(!self.is_gensym());
1213 self.name().encode(dst);
1214 }
1215}
1216
1217impl<'a> Encode for TryTable<'a> {
1218 fn encode(&self, dst: &mut Vec<u8>) {
1219 self.block.encode(dst);
1220 self.catches.encode(dst);
1221 }
1222}
1223
1224impl<'a> Encode for TryTableCatch<'a> {
1225 fn encode(&self, dst: &mut Vec<u8>) {
1226 let flag_byte: u8 = match self.kind {
1227 TryTableCatchKind::Catch(..) => 0,
1228 TryTableCatchKind::CatchRef(..) => 1,
1229 TryTableCatchKind::CatchAll => 2,
1230 TryTableCatchKind::CatchAllRef => 3,
1231 };
1232 flag_byte.encode(dst);
1233 match self.kind {
1234 TryTableCatchKind::Catch(tag) | TryTableCatchKind::CatchRef(tag) => {
1235 tag.encode(dst);
1236 }
1237 TryTableCatchKind::CatchAll | TryTableCatchKind::CatchAllRef => {}
1238 }
1239 self.label.encode(dst);
1240 }
1241}
1242
1243impl<'a> Encode for ContBind<'a> {
1244 fn encode(&self, dst: &mut Vec<u8>) {
1245 self.argument_index.encode(dst);
1246 self.result_index.encode(dst);
1247 }
1248}
1249
1250impl<'a> Encode for Resume<'a> {
1251 fn encode(&self, dst: &mut Vec<u8>) {
1252 self.type_index.encode(dst);
1253 self.table.encode(dst);
1254 }
1255}
1256
1257impl<'a> Encode for ResumeThrow<'a> {
1258 fn encode(&self, dst: &mut Vec<u8>) {
1259 self.type_index.encode(dst);
1260 self.tag_index.encode(dst);
1261 self.table.encode(dst);
1262 }
1263}
1264
1265impl<'a> Encode for ResumeTable<'a> {
1266 fn encode(&self, dst: &mut Vec<u8>) {
1267 self.handlers.encode(dst);
1268 }
1269}
1270
1271impl<'a> Encode for Handle<'a> {
1272 fn encode(&self, dst: &mut Vec<u8>) {
1273 match self {
1274 Handle::OnLabel { tag, label } => {
1275 dst.push(0x00);
1276 tag.encode(dst);
1277 label.encode(dst);
1278 }
1279 Handle::OnSwitch { tag } => {
1280 dst.push(0x01);
1281 tag.encode(dst);
1282 }
1283 }
1284 }
1285}
1286
1287impl<'a> Encode for Switch<'a> {
1288 fn encode(&self, dst: &mut Vec<u8>) {
1289 self.type_index.encode(dst);
1290 self.tag_index.encode(dst);
1291 }
1292}
1293
1294impl Encode for V128Const {
1295 fn encode(&self, dst: &mut Vec<u8>) {
1296 dst.extend_from_slice(&self.to_le_bytes());
1297 }
1298}
1299
1300impl Encode for I8x16Shuffle {
1301 fn encode(&self, dst: &mut Vec<u8>) {
1302 dst.extend_from_slice(&self.lanes);
1303 }
1304}
1305
1306impl<'a> Encode for SelectTypes<'a> {
1307 fn encode(&self, dst: &mut Vec<u8>) {
1308 match &self.tys {
1309 Some(list) => {
1310 dst.push(0x1c);
1311 list.encode(dst);
1312 }
1313 None => dst.push(0x1b),
1314 }
1315 }
1316}
1317
1318impl Custom<'_> {
1319 fn encode(&self, module: &mut wasm_encoder::Module) {
1320 match self {
1321 Custom::Raw(r) => {
1322 module.section(&r.to_section());
1323 }
1324 Custom::Producers(p) => {
1325 module.section(&p.to_section());
1326 }
1327 Custom::Dylink0(p) => {
1328 module.section(&p.to_section());
1329 }
1330 }
1331 }
1332}
1333
1334impl RawCustomSection<'_> {
1335 fn to_section(&self) -> wasm_encoder::CustomSection<'_> {
1336 let mut ret = Vec::new();
1337 for list in self.data.iter() {
1338 ret.extend_from_slice(list);
1339 }
1340 wasm_encoder::CustomSection {
1341 name: self.name.into(),
1342 data: ret.into(),
1343 }
1344 }
1345}
1346
1347impl Producers<'_> {
1348 pub(crate) fn to_section(&self) -> wasm_encoder::ProducersSection {
1349 let mut ret = wasm_encoder::ProducersSection::default();
1350 for (name, fields) in self.fields.iter() {
1351 let mut field = wasm_encoder::ProducersField::new();
1352 for (key, value) in fields {
1353 field.value(key, value);
1354 }
1355 ret.field(name, &field);
1356 }
1357 ret
1358 }
1359}
1360
1361impl Dylink0<'_> {
1362 fn to_section(&self) -> wasm_encoder::CustomSection<'_> {
1363 let mut e = Vec::new();
1364 for section in self.subsections.iter() {
1365 e.push(section.id());
1366 let mut tmp = Vec::new();
1367 section.encode(&mut tmp);
1368 tmp.encode(&mut e);
1369 }
1370 wasm_encoder::CustomSection {
1371 name: "dylink.0".into(),
1372 data: e.into(),
1373 }
1374 }
1375}
1376
1377impl Encode for Dylink0Subsection<'_> {
1378 fn encode(&self, e: &mut Vec<u8>) {
1379 match self {
1380 Dylink0Subsection::MemInfo {
1381 memory_size,
1382 memory_align,
1383 table_size,
1384 table_align,
1385 } => {
1386 memory_size.encode(e);
1387 memory_align.encode(e);
1388 table_size.encode(e);
1389 table_align.encode(e);
1390 }
1391 Dylink0Subsection::Needed(libs) => libs.encode(e),
1392 Dylink0Subsection::ExportInfo(list) => list.encode(e),
1393 Dylink0Subsection::ImportInfo(list) => list.encode(e),
1394 }
1395 }
1396}
1397
1398impl SectionItem for Tag<'_> {
1399 type Section = wasm_encoder::TagSection;
1400 const ANCHOR: CustomPlaceAnchor = CustomPlaceAnchor::Tag;
1401
1402 fn encode(&self, section: &mut wasm_encoder::TagSection) {
1403 section.tag(self.ty.to_tag_type());
1404 match &self.kind {
1405 TagKind::Inline() => {}
1406 _ => panic!("TagKind should be inline during encoding"),
1407 }
1408 }
1409}
1410
1411impl Encode for StructAccess<'_> {
1412 fn encode(&self, e: &mut Vec<u8>) {
1413 self.r#struct.encode(e);
1414 self.field.encode(e);
1415 }
1416}
1417
1418impl Encode for ArrayFill<'_> {
1419 fn encode(&self, e: &mut Vec<u8>) {
1420 self.array.encode(e);
1421 }
1422}
1423
1424impl Encode for ArrayCopy<'_> {
1425 fn encode(&self, e: &mut Vec<u8>) {
1426 self.dest_array.encode(e);
1427 self.src_array.encode(e);
1428 }
1429}
1430
1431impl Encode for ArrayInit<'_> {
1432 fn encode(&self, e: &mut Vec<u8>) {
1433 self.array.encode(e);
1434 self.segment.encode(e);
1435 }
1436}
1437
1438impl Encode for ArrayNewFixed<'_> {
1439 fn encode(&self, e: &mut Vec<u8>) {
1440 self.array.encode(e);
1441 self.length.encode(e);
1442 }
1443}
1444
1445impl Encode for ArrayNewData<'_> {
1446 fn encode(&self, e: &mut Vec<u8>) {
1447 self.array.encode(e);
1448 self.data_idx.encode(e);
1449 }
1450}
1451
1452impl Encode for ArrayNewElem<'_> {
1453 fn encode(&self, e: &mut Vec<u8>) {
1454 self.array.encode(e);
1455 self.elem_idx.encode(e);
1456 }
1457}
1458
1459impl Encode for RefTest<'_> {
1460 fn encode(&self, e: &mut Vec<u8>) {
1461 e.push(0xfb);
1462 if self.r#type.nullable {
1463 e.push(0x15);
1464 } else {
1465 e.push(0x14);
1466 }
1467 self.r#type.heap.encode(e);
1468 }
1469}
1470
1471impl Encode for RefCast<'_> {
1472 fn encode(&self, e: &mut Vec<u8>) {
1473 e.push(0xfb);
1474 if self.r#type.nullable {
1475 e.push(0x17);
1476 } else {
1477 e.push(0x16);
1478 }
1479 self.r#type.heap.encode(e);
1480 }
1481}
1482
1483fn br_on_cast_flags(from_nullable: bool, to_nullable: bool) -> u8 {
1484 let mut flag = 0;
1485 if from_nullable {
1486 flag |= 1 << 0;
1487 }
1488 if to_nullable {
1489 flag |= 1 << 1;
1490 }
1491 flag
1492}
1493
1494impl Encode for BrOnCast<'_> {
1495 fn encode(&self, e: &mut Vec<u8>) {
1496 e.push(0xfb);
1497 e.push(0x18);
1498 e.push(br_on_cast_flags(
1499 self.from_type.nullable,
1500 self.to_type.nullable,
1501 ));
1502 self.label.encode(e);
1503 self.from_type.heap.encode(e);
1504 self.to_type.heap.encode(e);
1505 }
1506}
1507
1508impl Encode for BrOnCastFail<'_> {
1509 fn encode(&self, e: &mut Vec<u8>) {
1510 e.push(0xfb);
1511 e.push(0x19);
1512 e.push(br_on_cast_flags(
1513 self.from_type.nullable,
1514 self.to_type.nullable,
1515 ));
1516 self.label.encode(e);
1517 self.from_type.heap.encode(e);
1518 self.to_type.heap.encode(e);
1519 }
1520}