Skip to main content

wirm/ir/
types.rs

1//! Intermediate representation of sections in a wasm module.
2
3use log::error;
4use std::borrow::Cow;
5use std::cmp::PartialEq;
6use std::collections::HashMap;
7use std::fmt::Formatter;
8use std::fmt::{self};
9use std::mem::discriminant;
10use std::slice::Iter;
11use wasm_encoder::reencode::Reencode;
12use wasm_encoder::{AbstractHeapType, Encode, Ieee32, Ieee64};
13
14use wasmparser::types::TypeIdentifier;
15use wasmparser::{ConstExpr, HeapType, Operator, RefType, UnpackedIndex, ValType};
16
17use crate::error::Error;
18use crate::error::Error::{InstrumentationError, UnknownId};
19use crate::ir::id::{CustomSectionID, FunctionID, GlobalID, ModuleID, TypeID};
20use crate::ir::module::add_injection;
21use crate::ir::module::reindex::fix_op_id_mapping;
22use crate::ir::module::side_effects::{InjectType, Injection};
23use crate::ir::types;
24
25pub type Result<T> = std::result::Result<T, Error>;
26
27/// An optional tag that flags items that have been added to the module.
28/// It can also carry some bytes of information the explain why it was added.
29/// For injected items it will be Some(_), for items already in the module, it will be None.
30pub type InjectTag = Option<Tag>;
31
32#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
33pub struct Tag {
34    data: Vec<u8>,
35}
36impl Tag {
37    pub fn new(data: Vec<u8>) -> Self {
38        Self { data }
39    }
40    pub fn data_mut(&mut self) -> &mut Vec<u8> {
41        &mut self.data
42    }
43    pub fn data(&self) -> &Vec<u8> {
44        &self.data
45    }
46    pub fn is_empty(&self) -> bool {
47        self.data.is_empty()
48    }
49}
50pub(crate) trait TagUtils {
51    fn get_or_create_tag(&mut self) -> &mut Tag;
52    fn get_tag(&self) -> &Option<Tag>;
53}
54// Override the default private_bounds warning since I don't want the TagUtils trait to be public
55#[allow(private_bounds)]
56pub trait HasInjectTag: TagUtils {
57    fn append_to_tag(&mut self, mut data: Vec<u8>) {
58        self.get_or_create_tag().data.append(&mut data);
59    }
60}
61
62/// Wirm's Datatype. Combination of multiple [`wasmparser`] datatypes.
63///
64/// [ValType]: https://docs.rs/wasmparser/latest/wasmparser/enum.ValType.html
65#[derive(Debug, Clone, Eq, Hash, PartialEq, Copy)]
66pub enum DataType {
67    I8,
68    I16,
69    I32,
70    I64,
71    F32,
72    F64,
73    V128,
74    FuncRef,
75    FuncRefNull,
76    ExternRef,
77    ExternRefNull,
78    Any,
79    AnyNull,
80    None,
81    NoneNull,
82    NoExtern,
83    NoExternNull,
84    NoFunc,
85    NoFuncNull,
86    Eq,
87    EqNull,
88    Struct,
89    StructNull,
90    Array,
91    ArrayNull,
92    I31,
93    I31Null,
94    Exn,
95    ExnNull,
96    NoExn,
97    NoExnNull,
98    Module { ty_id: u32, nullable: bool },
99    RecGroup(u32),
100    CoreTypeId(u32), // TODO: Look at this
101    Cont,
102    ContNull,
103    NoCont,
104    NoContNull,
105}
106
107impl fmt::Display for DataType {
108    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
109        match *self {
110            DataType::I8 => write!(f, "DataType: I8"),
111            DataType::I16 => write!(f, "DataType: I16"),
112            DataType::I32 => write!(f, "DataType: I32"),
113            DataType::I64 => write!(f, "DataType: I64"),
114            DataType::F32 => write!(f, "DataType: F32"),
115            DataType::F64 => write!(f, "DataType: F64"),
116            DataType::V128 => write!(f, "DataType: V128"),
117            DataType::FuncRef => write!(f, "DataType: FuncRef"),
118            DataType::ExternRef => write!(f, "DataType: ExternRef"),
119            DataType::Any => write!(f, "DataType: Any"),
120            DataType::None => write!(f, "DataType: None"),
121            DataType::NoExtern => write!(f, "DataType: NoExtern"),
122            DataType::NoFunc => write!(f, "DataType: NoFunc"),
123            DataType::Eq => write!(f, "DataType: Eq"),
124            DataType::Struct => write!(f, "DataType: Struct"),
125            DataType::Array => write!(f, "DataType: Array"),
126            DataType::I31 => write!(f, "DataType: I31"),
127            DataType::Exn => write!(f, "DataType: Exn"),
128            DataType::ExnNull => write!(f, "exn: null"),
129            DataType::NoExn => write!(f, "DataType: NoExn"),
130            DataType::NoExnNull => write!(f, "noexn: null"),
131            DataType::Module { ty_id, nullable } => {
132                write!(f, "module: {ty_id}, nullable: {nullable}",)
133            }
134            DataType::RecGroup(idx) => write!(f, "recgroup: {idx}"),
135            DataType::CoreTypeId(idx) => write!(f, "coretypeid: {idx}"),
136            DataType::Cont => write!(f, "cont"),
137            DataType::ContNull => write!(f, "cont: null"),
138            DataType::NoCont => write!(f, "nocont"),
139            DataType::NoContNull => write!(f, "nocont: null"),
140            DataType::FuncRefNull => write!(f, "funcref: null"),
141            DataType::ExternRefNull => write!(f, "externref: null"),
142            DataType::AnyNull => write!(f, "any: null"),
143            DataType::NoneNull => write!(f, "none: null"),
144            DataType::NoFuncNull => write!(f, "nofunc: null"),
145            DataType::NoExternNull => write!(f, "noextern: null"),
146            DataType::EqNull => write!(f, "eq: null"),
147            DataType::StructNull => write!(f, "struct: null"),
148            DataType::ArrayNull => write!(f, "array: null"),
149            DataType::I31Null => write!(f, "i31: null"),
150        }
151    }
152}
153
154impl From<wasmparser::StorageType> for DataType {
155    fn from(value: wasmparser::StorageType) -> Self {
156        match value {
157            wasmparser::StorageType::I8 => DataType::I8,
158            wasmparser::StorageType::I16 => DataType::I16,
159            wasmparser::StorageType::Val(val) => DataType::from(val),
160        }
161    }
162}
163
164impl From<DataType> for wasm_encoder::StorageType {
165    fn from(value: DataType) -> Self {
166        match value {
167            DataType::I8 => wasm_encoder::StorageType::I8,
168            DataType::I16 => wasm_encoder::StorageType::I16,
169            _ => wasm_encoder::StorageType::Val(wasm_encoder::ValType::from(&value)),
170        }
171    }
172}
173
174impl From<ValType> for DataType {
175    fn from(value: ValType) -> Self {
176        match value {
177            ValType::I32 => DataType::I32,
178            ValType::I64 => DataType::I64,
179            ValType::F32 => DataType::F32,
180            ValType::F64 => DataType::F64,
181            ValType::V128 => DataType::V128,
182            ValType::Ref(ref_type) => match ref_type.heap_type() {
183                HeapType::Abstract { shared: _, ty } => match ty {
184                    wasmparser::AbstractHeapType::Func => {
185                        if ref_type.is_nullable() {
186                            DataType::FuncRefNull
187                        } else {
188                            DataType::FuncRef
189                        }
190                    }
191                    wasmparser::AbstractHeapType::Extern => {
192                        if ref_type.is_nullable() {
193                            DataType::ExternRefNull
194                        } else {
195                            DataType::ExternRef
196                        }
197                    }
198                    wasmparser::AbstractHeapType::Any => {
199                        if ref_type.is_nullable() {
200                            DataType::AnyNull
201                        } else {
202                            DataType::Any
203                        }
204                    }
205                    wasmparser::AbstractHeapType::None => {
206                        if ref_type.is_nullable() {
207                            DataType::NoneNull
208                        } else {
209                            DataType::None
210                        }
211                    }
212                    wasmparser::AbstractHeapType::NoExtern => {
213                        if ref_type.is_nullable() {
214                            DataType::NoExternNull
215                        } else {
216                            DataType::NoExtern
217                        }
218                    }
219                    wasmparser::AbstractHeapType::NoFunc => {
220                        if ref_type.is_nullable() {
221                            DataType::NoFuncNull
222                        } else {
223                            DataType::NoFunc
224                        }
225                    }
226                    wasmparser::AbstractHeapType::Eq => {
227                        if ref_type.is_nullable() {
228                            DataType::EqNull
229                        } else {
230                            DataType::Eq
231                        }
232                    }
233                    wasmparser::AbstractHeapType::Struct => {
234                        if ref_type.is_nullable() {
235                            DataType::StructNull
236                        } else {
237                            DataType::Struct
238                        }
239                    }
240                    wasmparser::AbstractHeapType::Array => {
241                        if ref_type.is_nullable() {
242                            DataType::ArrayNull
243                        } else {
244                            DataType::Array
245                        }
246                    }
247                    wasmparser::AbstractHeapType::I31 => {
248                        if ref_type.is_nullable() {
249                            DataType::I31Null
250                        } else {
251                            DataType::I31
252                        }
253                    }
254                    wasmparser::AbstractHeapType::Exn => {
255                        if ref_type.is_nullable() {
256                            DataType::ExnNull
257                        } else {
258                            DataType::Exn
259                        }
260                    }
261                    wasmparser::AbstractHeapType::NoExn => {
262                        if ref_type.is_nullable() {
263                            DataType::NoExnNull
264                        } else {
265                            DataType::NoExn
266                        }
267                    }
268                    wasmparser::AbstractHeapType::Cont => {
269                        if ref_type.is_nullable() {
270                            DataType::ContNull
271                        } else {
272                            DataType::Cont
273                        }
274                    }
275                    wasmparser::AbstractHeapType::NoCont => {
276                        if ref_type.is_nullable() {
277                            DataType::NoContNull
278                        } else {
279                            DataType::NoCont
280                        }
281                    }
282                },
283                HeapType::Concrete(u) | HeapType::Exact(u) => match u {
284                    UnpackedIndex::Module(idx) => DataType::Module {
285                        ty_id: *ModuleID(idx),
286                        nullable: ref_type.is_nullable(),
287                    },
288                    UnpackedIndex::RecGroup(idx) => DataType::RecGroup(idx),
289                    UnpackedIndex::Id(_id) => unimplemented!("Not supported yet!"),
290                },
291            },
292        }
293    }
294}
295
296/// Converts from Wirm's DataType to [`wasm_encoder::ValType`].
297///
298/// [`wasm_encoder::ValType`]: https://docs.rs/wasm-encoder/0.214.0/wasm_encoder/enum.ValType.html
299impl From<&DataType> for wasm_encoder::ValType {
300    fn from(ty: &DataType) -> Self {
301        match ty {
302            DataType::I8 | DataType::I16 => panic!("Not valtype equivalent!"),
303            DataType::I32 => wasm_encoder::ValType::I32,
304            DataType::I64 => wasm_encoder::ValType::I64,
305            DataType::F32 => wasm_encoder::ValType::F32,
306            DataType::F64 => wasm_encoder::ValType::F64,
307            DataType::V128 => wasm_encoder::ValType::V128,
308            DataType::FuncRef => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
309                nullable: false,
310                heap_type: wasm_encoder::HeapType::Abstract {
311                    shared: false,
312                    ty: AbstractHeapType::Func,
313                },
314            }),
315            DataType::ExternRef => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
316                nullable: false,
317                heap_type: wasm_encoder::HeapType::Abstract {
318                    shared: false,
319                    ty: AbstractHeapType::Extern,
320                },
321            }),
322            DataType::Any => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
323                nullable: false,
324                heap_type: wasm_encoder::HeapType::Abstract {
325                    shared: false,
326                    ty: AbstractHeapType::Any,
327                },
328            }),
329            DataType::NoneNull => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
330                nullable: true,
331                heap_type: wasm_encoder::HeapType::Abstract {
332                    shared: false,
333                    ty: AbstractHeapType::None,
334                },
335            }),
336            DataType::None => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
337                nullable: false,
338                heap_type: wasm_encoder::HeapType::Abstract {
339                    shared: false,
340                    ty: AbstractHeapType::None,
341                },
342            }),
343            DataType::NoExtern => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
344                nullable: false,
345                heap_type: wasm_encoder::HeapType::Abstract {
346                    shared: false,
347                    ty: AbstractHeapType::NoExtern,
348                },
349            }),
350            DataType::NoExternNull => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
351                nullable: true,
352                heap_type: wasm_encoder::HeapType::Abstract {
353                    shared: false,
354                    ty: AbstractHeapType::NoExtern,
355                },
356            }),
357            DataType::NoFunc => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
358                nullable: false,
359                heap_type: wasm_encoder::HeapType::Abstract {
360                    shared: false,
361                    ty: AbstractHeapType::NoFunc,
362                },
363            }),
364            DataType::NoFuncNull => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
365                nullable: true,
366                heap_type: wasm_encoder::HeapType::Abstract {
367                    shared: false,
368                    ty: AbstractHeapType::NoFunc,
369                },
370            }),
371            DataType::Eq => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
372                nullable: false,
373                heap_type: wasm_encoder::HeapType::Abstract {
374                    shared: false,
375                    ty: AbstractHeapType::Eq,
376                },
377            }),
378            DataType::Struct => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
379                nullable: false,
380                heap_type: wasm_encoder::HeapType::Abstract {
381                    shared: false,
382                    ty: AbstractHeapType::Struct,
383                },
384            }),
385            DataType::Array => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
386                nullable: false,
387                heap_type: wasm_encoder::HeapType::Abstract {
388                    shared: false,
389                    ty: AbstractHeapType::Array,
390                },
391            }),
392            DataType::I31 => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
393                nullable: false,
394                heap_type: wasm_encoder::HeapType::Abstract {
395                    shared: false,
396                    ty: AbstractHeapType::I31,
397                },
398            }),
399            DataType::Exn => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
400                nullable: false,
401                heap_type: wasm_encoder::HeapType::Abstract {
402                    shared: false,
403                    ty: AbstractHeapType::Exn,
404                },
405            }),
406            DataType::ExnNull => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
407                nullable: true,
408                heap_type: wasm_encoder::HeapType::Abstract {
409                    shared: false,
410                    ty: AbstractHeapType::Exn,
411                },
412            }),
413            DataType::NoExn => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
414                nullable: false,
415                heap_type: wasm_encoder::HeapType::Abstract {
416                    shared: false,
417                    ty: AbstractHeapType::NoExn,
418                },
419            }),
420            DataType::NoExnNull => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
421                nullable: true,
422                heap_type: wasm_encoder::HeapType::Abstract {
423                    shared: false,
424                    ty: AbstractHeapType::NoExn,
425                },
426            }),
427            DataType::Module { ty_id, nullable } => {
428                wasm_encoder::ValType::Ref(wasm_encoder::RefType {
429                    nullable: *nullable,
430                    heap_type: wasm_encoder::HeapType::Concrete(*ty_id),
431                })
432            }
433            DataType::RecGroup(idx) => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
434                nullable: false,
435                heap_type: wasm_encoder::HeapType::Concrete(*idx),
436            }),
437            DataType::CoreTypeId(idx) => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
438                nullable: false,
439                heap_type: wasm_encoder::HeapType::Concrete(*idx),
440            }),
441            DataType::Cont => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
442                nullable: false,
443                heap_type: wasm_encoder::HeapType::Abstract {
444                    shared: false,
445                    ty: AbstractHeapType::Cont,
446                },
447            }),
448            DataType::ContNull => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
449                nullable: true,
450                heap_type: wasm_encoder::HeapType::Abstract {
451                    shared: false,
452                    ty: AbstractHeapType::Cont,
453                },
454            }),
455            DataType::NoCont => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
456                nullable: false,
457                heap_type: wasm_encoder::HeapType::Abstract {
458                    shared: false,
459                    ty: AbstractHeapType::NoCont,
460                },
461            }),
462            DataType::NoContNull => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
463                nullable: true,
464                heap_type: wasm_encoder::HeapType::Abstract {
465                    shared: false,
466                    ty: AbstractHeapType::NoCont,
467                },
468            }),
469            DataType::FuncRefNull => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
470                nullable: true,
471                heap_type: wasm_encoder::HeapType::Abstract {
472                    shared: false,
473                    ty: AbstractHeapType::Func,
474                },
475            }),
476            DataType::ExternRefNull => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
477                nullable: true,
478                heap_type: wasm_encoder::HeapType::Abstract {
479                    shared: false,
480                    ty: AbstractHeapType::Extern,
481                },
482            }),
483            DataType::AnyNull => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
484                nullable: true,
485                heap_type: wasm_encoder::HeapType::Abstract {
486                    shared: false,
487                    ty: AbstractHeapType::Any,
488                },
489            }),
490            DataType::EqNull => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
491                nullable: true,
492                heap_type: wasm_encoder::HeapType::Abstract {
493                    shared: false,
494                    ty: AbstractHeapType::Eq,
495                },
496            }),
497            DataType::StructNull => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
498                nullable: true,
499                heap_type: wasm_encoder::HeapType::Abstract {
500                    shared: false,
501                    ty: AbstractHeapType::Struct,
502                },
503            }),
504            DataType::ArrayNull => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
505                nullable: true,
506                heap_type: wasm_encoder::HeapType::Abstract {
507                    shared: false,
508                    ty: AbstractHeapType::Array,
509                },
510            }),
511            DataType::I31Null => wasm_encoder::ValType::Ref(wasm_encoder::RefType {
512                nullable: true,
513                heap_type: wasm_encoder::HeapType::Abstract {
514                    shared: false,
515                    ty: AbstractHeapType::I31,
516                },
517            }),
518        }
519    }
520}
521
522impl From<&DataType> for ValType {
523    fn from(ty: &DataType) -> Self {
524        match ty {
525            DataType::I8 | DataType::I16 => panic!("No valtype equivalent!"),
526            DataType::I32 => ValType::I32,
527            DataType::I64 => ValType::I64,
528            DataType::F32 => ValType::F32,
529            DataType::F64 => ValType::F64,
530            DataType::V128 => ValType::V128,
531            DataType::FuncRef => ValType::FUNCREF,
532            DataType::ExternRef => ValType::EXTERNREF,
533            DataType::Any => ValType::Ref(
534                RefType::new(
535                    false,
536                    HeapType::Abstract {
537                        shared: false,
538                        ty: wasmparser::AbstractHeapType::Any,
539                    },
540                )
541                .unwrap(),
542            ),
543            DataType::None => ValType::Ref(
544                RefType::new(
545                    false,
546                    HeapType::Abstract {
547                        shared: false,
548                        ty: wasmparser::AbstractHeapType::None,
549                    },
550                )
551                .unwrap(),
552            ),
553            DataType::NoneNull => ValType::Ref(
554                RefType::new(
555                    true,
556                    HeapType::Abstract {
557                        shared: false,
558                        ty: wasmparser::AbstractHeapType::None,
559                    },
560                )
561                .unwrap(),
562            ),
563            DataType::NoExtern => ValType::Ref(
564                RefType::new(
565                    false,
566                    HeapType::Abstract {
567                        shared: false,
568                        ty: wasmparser::AbstractHeapType::NoExtern,
569                    },
570                )
571                .unwrap(),
572            ),
573            DataType::NoExternNull => ValType::Ref(
574                RefType::new(
575                    true,
576                    HeapType::Abstract {
577                        shared: false,
578                        ty: wasmparser::AbstractHeapType::NoExtern,
579                    },
580                )
581                .unwrap(),
582            ),
583            DataType::NoFunc => ValType::Ref(
584                RefType::new(
585                    false,
586                    HeapType::Abstract {
587                        shared: false,
588                        ty: wasmparser::AbstractHeapType::NoFunc,
589                    },
590                )
591                .unwrap(),
592            ),
593            DataType::NoFuncNull => ValType::Ref(
594                RefType::new(
595                    true,
596                    HeapType::Abstract {
597                        shared: false,
598                        ty: wasmparser::AbstractHeapType::NoFunc,
599                    },
600                )
601                .unwrap(),
602            ),
603            DataType::Eq => ValType::Ref(
604                RefType::new(
605                    false,
606                    HeapType::Abstract {
607                        shared: false,
608                        ty: wasmparser::AbstractHeapType::Eq,
609                    },
610                )
611                .unwrap(),
612            ),
613            DataType::Struct => ValType::Ref(
614                RefType::new(
615                    false,
616                    HeapType::Abstract {
617                        shared: false,
618                        ty: wasmparser::AbstractHeapType::Struct,
619                    },
620                )
621                .unwrap(),
622            ),
623            DataType::Array => ValType::Ref(
624                RefType::new(
625                    false,
626                    HeapType::Abstract {
627                        shared: false,
628                        ty: wasmparser::AbstractHeapType::Array,
629                    },
630                )
631                .unwrap(),
632            ),
633            DataType::I31 => ValType::Ref(
634                RefType::new(
635                    false,
636                    HeapType::Abstract {
637                        shared: false,
638                        ty: wasmparser::AbstractHeapType::I31,
639                    },
640                )
641                .unwrap(),
642            ),
643            DataType::Exn => ValType::Ref(
644                RefType::new(
645                    false,
646                    HeapType::Abstract {
647                        shared: false,
648                        ty: wasmparser::AbstractHeapType::Exn,
649                    },
650                )
651                .unwrap(),
652            ),
653            DataType::ExnNull => ValType::Ref(
654                RefType::new(
655                    true,
656                    HeapType::Abstract {
657                        shared: false,
658                        ty: wasmparser::AbstractHeapType::Exn,
659                    },
660                )
661                .unwrap(),
662            ),
663            DataType::NoExn => ValType::Ref(
664                RefType::new(
665                    false,
666                    HeapType::Abstract {
667                        shared: false,
668                        ty: wasmparser::AbstractHeapType::NoExn,
669                    },
670                )
671                .unwrap(),
672            ),
673            DataType::NoExnNull => ValType::Ref(
674                RefType::new(
675                    true,
676                    HeapType::Abstract {
677                        shared: false,
678                        ty: wasmparser::AbstractHeapType::NoExn,
679                    },
680                )
681                .unwrap(),
682            ),
683            DataType::Module { ty_id, nullable } => ValType::Ref(
684                RefType::new(
685                    *nullable,
686                    HeapType::Concrete(wasmparser::UnpackedIndex::Module(*ty_id)),
687                )
688                .unwrap(),
689            ),
690            DataType::RecGroup(idx) => ValType::Ref(
691                RefType::new(
692                    false,
693                    HeapType::Concrete(wasmparser::UnpackedIndex::RecGroup(*idx)),
694                )
695                .unwrap(),
696            ),
697            DataType::CoreTypeId(_idx) => unimplemented!("Not Supported Yet!"),
698            DataType::Cont => ValType::Ref(
699                RefType::new(
700                    false,
701                    HeapType::Abstract {
702                        shared: false,
703                        ty: wasmparser::AbstractHeapType::Cont,
704                    },
705                )
706                .unwrap(),
707            ),
708            DataType::ContNull => ValType::Ref(
709                RefType::new(
710                    true,
711                    HeapType::Abstract {
712                        shared: false,
713                        ty: wasmparser::AbstractHeapType::Cont,
714                    },
715                )
716                .unwrap(),
717            ),
718            DataType::NoCont => ValType::Ref(
719                RefType::new(
720                    false,
721                    HeapType::Abstract {
722                        shared: false,
723                        ty: wasmparser::AbstractHeapType::NoCont,
724                    },
725                )
726                .unwrap(),
727            ),
728            DataType::NoContNull => ValType::Ref(
729                RefType::new(
730                    true,
731                    HeapType::Abstract {
732                        shared: false,
733                        ty: wasmparser::AbstractHeapType::NoCont,
734                    },
735                )
736                .unwrap(),
737            ),
738            DataType::FuncRefNull => ValType::Ref(
739                RefType::new(
740                    true,
741                    HeapType::Abstract {
742                        shared: false,
743                        ty: wasmparser::AbstractHeapType::Func,
744                    },
745                )
746                .unwrap(),
747            ),
748            DataType::ExternRefNull => ValType::Ref(
749                RefType::new(
750                    true,
751                    HeapType::Abstract {
752                        shared: false,
753                        ty: wasmparser::AbstractHeapType::Extern,
754                    },
755                )
756                .unwrap(),
757            ),
758            DataType::AnyNull => ValType::Ref(
759                RefType::new(
760                    true,
761                    HeapType::Abstract {
762                        shared: false,
763                        ty: wasmparser::AbstractHeapType::Any,
764                    },
765                )
766                .unwrap(),
767            ),
768            DataType::EqNull => ValType::Ref(
769                RefType::new(
770                    true,
771                    HeapType::Abstract {
772                        shared: false,
773                        ty: wasmparser::AbstractHeapType::Eq,
774                    },
775                )
776                .unwrap(),
777            ),
778            DataType::StructNull => ValType::Ref(
779                RefType::new(
780                    true,
781                    HeapType::Abstract {
782                        shared: false,
783                        ty: wasmparser::AbstractHeapType::Struct,
784                    },
785                )
786                .unwrap(),
787            ),
788            DataType::ArrayNull => ValType::Ref(
789                RefType::new(
790                    true,
791                    HeapType::Abstract {
792                        shared: false,
793                        ty: wasmparser::AbstractHeapType::Array,
794                    },
795                )
796                .unwrap(),
797            ),
798            DataType::I31Null => ValType::Ref(
799                RefType::new(
800                    true,
801                    HeapType::Abstract {
802                        shared: false,
803                        ty: wasmparser::AbstractHeapType::I31,
804                    },
805                )
806                .unwrap(),
807            ),
808        }
809    }
810}
811
812/// Converts [`ValType`] to [`wasm_encoder::ValType`].
813///
814/// [`wasm_encoder::ValType`]: https://docs.rs/wasm-encoder/0.214.0/wasm_encoder/enum.ValType.html
815/// [`ValType`]: https://docs.rs/wasmparser/latest/wasmparser/enum.ValType.html
816pub fn valtype_to_wasmencoder_type(val_type: &ValType) -> wasm_encoder::ValType {
817    let mut reencoder = wasm_encoder::reencode::RoundtripReencoder;
818    reencoder.val_type(*val_type).unwrap()
819}
820
821#[derive(Debug, Clone)]
822/// Data Segment in a wasm module.
823pub struct DataSegment {
824    /// The kind of data segment.
825    pub kind: DataSegmentKind,
826    /// The data of the data segment.
827    pub data: Vec<u8>,
828    pub tag: InjectTag,
829}
830
831impl DataSegment {
832    pub fn from_wasmparser(data: wasmparser::Data) -> Result<DataSegment> {
833        Ok(DataSegment {
834            kind: DataSegmentKind::from_wasmparser(data.kind)?,
835            data: data.data.to_vec(),
836            tag: None,
837        })
838    }
839}
840impl TagUtils for DataSegment {
841    fn get_or_create_tag(&mut self) -> &mut Tag {
842        self.tag.get_or_insert_default()
843    }
844
845    fn get_tag(&self) -> &Option<Tag> {
846        &self.tag
847    }
848}
849
850/// The kind of data segment.
851#[derive(Debug, Clone)]
852pub enum DataSegmentKind {
853    /// The data segment is passive.
854    Passive,
855    /// The data segment is active.
856    Active {
857        /// The memory index for the data segment.
858        memory_index: u32,
859        /// The memory offset where this active data segment will be automatically
860        /// initialized.
861        offset_expr: InitExpr,
862    },
863}
864
865impl DataSegmentKind {
866    pub(crate) fn from_wasmparser(kind: wasmparser::DataKind) -> Result<DataSegmentKind> {
867        Ok(match kind {
868            wasmparser::DataKind::Passive => DataSegmentKind::Passive,
869            wasmparser::DataKind::Active {
870                memory_index,
871                offset_expr,
872            } => DataSegmentKind::Active {
873                memory_index,
874                offset_expr: InitExpr::eval(&offset_expr)?,
875            },
876        })
877    }
878}
879
880#[derive(Debug, Clone)]
881/// Kind of Element
882pub enum ElementKind {
883    Passive,
884    Active {
885        table_index: Option<u32>,
886        offset_expr: InitExpr,
887    },
888    Declared,
889}
890
891impl ElementKind {
892    pub(crate) fn from_wasmparser(kind: wasmparser::ElementKind) -> Result<ElementKind> {
893        match kind {
894            wasmparser::ElementKind::Passive => Ok(ElementKind::Passive),
895            wasmparser::ElementKind::Declared => Ok(ElementKind::Declared),
896            wasmparser::ElementKind::Active {
897                table_index,
898                offset_expr,
899            } => Ok(ElementKind::Active {
900                table_index,
901                offset_expr: InitExpr::eval(&offset_expr)?,
902            }),
903        }
904    }
905}
906
907#[derive(Debug, Clone)]
908/// Type of element
909pub enum ElementItems {
910    Functions(Vec<FunctionID>),
911    ConstExprs { ty: RefType, exprs: Vec<InitExpr> },
912}
913
914impl ElementItems {
915    pub(crate) fn from_wasmparser(items: wasmparser::ElementItems) -> Result<ElementItems> {
916        match items {
917            wasmparser::ElementItems::Functions(reader) => {
918                let functions = reader
919                    .into_iter()
920                    .collect::<std::result::Result<Vec<_>, _>>()?;
921                // unsure how to avoid a second iteration (cast while iterating above)
922                let fids = functions.iter().map(|id| FunctionID(*id)).collect();
923                Ok(ElementItems::Functions(fids))
924            }
925            wasmparser::ElementItems::Expressions(ref_type, reader) => {
926                let exprs = reader
927                    .into_iter()
928                    .collect::<std::result::Result<Vec<_>, _>>()?;
929                Ok(ElementItems::ConstExprs {
930                    ty: ref_type,
931                    exprs: exprs
932                        .iter()
933                        .map(InitExpr::eval)
934                        .collect::<Result<Vec<_>>>()?,
935                })
936            }
937        }
938    }
939}
940
941#[derive(Debug, Clone)]
942/// Mode of Function in case the function is mark as instrumented
943pub enum FuncInstrMode {
944    Entry,
945    Exit,
946}
947
948#[derive(Default, Debug, Clone)]
949/// Instrumentation Data that is stored with every function
950pub struct FuncInstrFlag<'a> {
951    /// boolean flag to say whether there are special instrumentation
952    /// modes to resolve for this function (see InstrumentationMode variants)
953    pub has_special_instr: bool,
954    pub current_mode: Option<FuncInstrMode>,
955    pub entry: InjectedInstrs<'a>,
956    pub exit: InjectedInstrs<'a>,
957}
958
959impl TagUtils for FuncInstrFlag<'_> {
960    fn get_or_create_tag(&mut self) -> &mut Tag {
961        match self.current_mode {
962            None => {
963                panic!("Internal error: Current mode is not set...cannot append to the tag!")
964            }
965            Some(FuncInstrMode::Entry) => self.entry.get_or_create_tag(),
966            Some(FuncInstrMode::Exit) => self.exit.get_or_create_tag(),
967        }
968    }
969
970    fn get_tag(&self) -> &Option<Tag> {
971        match self.current_mode {
972            None => {
973                panic!("Internal error: Current mode is not set...cannot append to the tag!")
974            }
975            Some(FuncInstrMode::Entry) => self.entry.get_tag(),
976            Some(FuncInstrMode::Exit) => self.exit.get_tag(),
977        }
978    }
979}
980impl HasInjectTag for FuncInstrFlag<'_> {}
981impl fmt::Display for FuncInstrFlag<'_> {
982    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
983        let FuncInstrFlag {
984            has_special_instr,
985            entry,
986            exit,
987            current_mode: _,
988        } = self;
989        if !self.has_instr() {
990            write!(f, "Not Instrumented")?;
991        }
992        write!(
993            f,
994            "Has special instrumentation: {}\n \
995             Func Entry: {:?} instructions\n \
996             Func Exit: {:?} instructions",
997            has_special_instr,
998            entry.instrs.len(),
999            exit.instrs.len()
1000        )
1001    }
1002}
1003
1004impl PartialEq for FuncInstrFlag<'_> {
1005    fn eq(&self, other: &Self) -> bool {
1006        // Using pattern match to help identify when this function needs to be extended in the future
1007        let Self {
1008            has_special_instr,
1009            entry,
1010            exit,
1011            current_mode,
1012        } = self;
1013        let mut result = *has_special_instr == other.has_special_instr;
1014        result &= entry.eq(&other.entry);
1015        result &= exit.eq(&other.exit);
1016        result &= discriminant(current_mode) == discriminant(&other.current_mode);
1017
1018        result
1019    }
1020}
1021
1022impl Eq for FuncInstrFlag<'_> {}
1023
1024impl<'a> FuncInstrFlag<'a> {
1025    pub fn has_instr(&self) -> bool {
1026        // Using pattern match to help identify when this function needs to be extended in the future
1027        let Self {
1028            entry,
1029            exit,
1030            has_special_instr: _,
1031            current_mode: _,
1032        } = self;
1033        !entry.instrs.is_empty() || !exit.instrs.is_empty()
1034    }
1035
1036    pub fn has_special_instr(&self) -> bool {
1037        self.has_special_instr
1038    }
1039
1040    /// Add an instruction to the current FuncInstrMode's list
1041    pub fn add_instr(&mut self, val: Operator<'a>) {
1042        self.has_special_instr = true;
1043        match self.current_mode {
1044            None => {
1045                panic!("Internal error: Current mode is not set...cannot inject instructions!")
1046            }
1047            Some(FuncInstrMode::Entry) => self.entry.instrs.push(val),
1048            Some(FuncInstrMode::Exit) => self.exit.instrs.push(val),
1049        }
1050    }
1051
1052    /// Get an instruction to the current FuncInstrMode's list
1053    pub fn get_instr(&self, idx: usize) -> &Operator<'_> {
1054        match self.current_mode {
1055            None => {
1056                panic!("Internal error: Current mode is not set...cannot grab instruction without context!")
1057            }
1058            Some(FuncInstrMode::Entry) => &self.entry.instrs[idx],
1059            Some(FuncInstrMode::Exit) => &self.exit.instrs[idx],
1060        }
1061    }
1062
1063    pub fn instr_len(&self) -> usize {
1064        match self.current_mode {
1065            None => {
1066                panic!("Internal error: Current mode is not set...cannot grab instruction without context!")
1067            }
1068            Some(FuncInstrMode::Entry) => self.entry.instrs.len(),
1069            Some(FuncInstrMode::Exit) => self.exit.instrs.len(),
1070        }
1071    }
1072
1073    pub fn add_injections(
1074        &mut self,
1075        fid: u32,
1076        func_mapping: &HashMap<u32, u32>,
1077        global_mapping: &HashMap<u32, u32>,
1078        memory_mapping: &HashMap<u32, u32>,
1079        side_effects: &mut HashMap<InjectType, Vec<Injection<'a>>>,
1080    ) -> types::Result<()> {
1081        let Self { entry, exit, .. } = self;
1082        let mut add_inj =
1083            |mode: FuncInstrMode, instrs: &mut InjectedInstrs<'a>| -> types::Result<()> {
1084                // Fix the ID mapping in each of the injected opcodes.
1085                for op in instrs.instrs.iter_mut() {
1086                    fix_op_id_mapping(op, func_mapping, global_mapping, memory_mapping)?;
1087                }
1088
1089                if instrs.instrs.is_empty() {
1090                    return Ok(());
1091                }
1092
1093                add_injection(
1094                    side_effects,
1095                    InjectType::Probe,
1096                    Injection::FuncProbe {
1097                        target_fid: fid,
1098                        mode,
1099                        body: instrs.instrs.clone(),
1100                        tag: instrs.tag.clone().unwrap_or_default(),
1101                    },
1102                );
1103                Ok(())
1104            };
1105
1106        add_inj(FuncInstrMode::Entry, entry)?;
1107        add_inj(FuncInstrMode::Exit, exit)?;
1108        Ok(())
1109    }
1110
1111    /// Can be called after finishing some instrumentation to reset the mode.
1112    pub fn finish_instr(&mut self) {
1113        self.current_mode = None
1114    }
1115}
1116
1117#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1118/// Mode of Instruction in case the instruction is marked as Instrumented
1119pub enum InstrumentationMode {
1120    Before,
1121    After,
1122    Alternate,
1123
1124    // special modes
1125    SemanticAfter,
1126    BlockEntry,
1127    BlockExit,
1128    BlockAlt,
1129}
1130
1131#[derive(Default, Debug, Clone)]
1132/// Instrumentation Data that is stored with every instruction
1133pub struct InstrumentationFlag<'a> {
1134    pub current_mode: Option<InstrumentationMode>,
1135    pub before: InjectedInstrs<'a>,
1136    pub after: InjectedInstrs<'a>,
1137    /// None means to replace with no instructions (effectively removing the original)
1138    /// Some(vec) means to replace with the vec of instructions
1139    /// Some(empty vec) means there is no alt instrumentation
1140    pub alternate: Option<InjectedInstrs<'a>>,
1141
1142    // special modes
1143    pub semantic_after: InjectedInstrs<'a>,
1144    pub block_entry: InjectedInstrs<'a>,
1145    pub block_exit: InjectedInstrs<'a>,
1146    /// None means to replace with no instructions (effectively removing the original)
1147    /// Some(vec) means to replace with the vec of instructions
1148    /// Some(empty vec) means there is no alt instrumentation
1149    pub block_alt: Option<InjectedInstrs<'a>>,
1150}
1151impl TagUtils for InstrumentationFlag<'_> {
1152    fn get_or_create_tag(&mut self) -> &mut Tag {
1153        match self.current_mode {
1154            None => {
1155                panic!("Internal error: Current mode is not set...cannot get the tag!")
1156            }
1157            Some(InstrumentationMode::Before) => self.before.get_or_create_tag(),
1158            Some(InstrumentationMode::After) => self.after.get_or_create_tag(),
1159            Some(InstrumentationMode::Alternate) => {
1160                self.alternate.get_or_insert_default().get_or_create_tag()
1161            }
1162            Some(InstrumentationMode::SemanticAfter) => self.semantic_after.get_or_create_tag(),
1163            Some(InstrumentationMode::BlockEntry) => self.block_entry.get_or_create_tag(),
1164            Some(InstrumentationMode::BlockExit) => self.block_exit.get_or_create_tag(),
1165            Some(InstrumentationMode::BlockAlt) => {
1166                self.block_alt.get_or_insert_default().get_or_create_tag()
1167            }
1168        }
1169    }
1170
1171    fn get_tag(&self) -> &Option<Tag> {
1172        match self.current_mode {
1173            None => {
1174                panic!("Internal error: Current mode is not set...cannot get the tag!")
1175            }
1176            Some(InstrumentationMode::Before) => self.before.get_tag(),
1177            Some(InstrumentationMode::After) => self.after.get_tag(),
1178            Some(InstrumentationMode::Alternate) => {
1179                if let Some(alt) = &self.alternate {
1180                    alt.get_tag()
1181                } else {
1182                    &None
1183                }
1184            }
1185            Some(InstrumentationMode::SemanticAfter) => self.semantic_after.get_tag(),
1186            Some(InstrumentationMode::BlockEntry) => self.block_entry.get_tag(),
1187            Some(InstrumentationMode::BlockExit) => self.block_exit.get_tag(),
1188            Some(InstrumentationMode::BlockAlt) => {
1189                if let Some(alt) = &self.block_alt {
1190                    alt.get_tag()
1191                } else {
1192                    &None
1193                }
1194            }
1195        }
1196    }
1197}
1198impl HasInjectTag for InstrumentationFlag<'_> {}
1199
1200impl fmt::Display for InstrumentationFlag<'_> {
1201    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1202        let InstrumentationFlag {
1203            before,
1204            after,
1205            alternate,
1206            semantic_after,
1207            block_entry,
1208            block_exit,
1209            block_alt,
1210            current_mode: _,
1211        } = self;
1212        if !self.has_instr() {
1213            write!(f, "Not Instrumented")?;
1214        }
1215        write!(
1216            f,
1217            "Before: {:?} instructions\n \
1218                   After: {:?} instructions\n \
1219                   Alternate: {:?} instructions\n \
1220                   Semantic After: {:?} instructions\n \
1221                   Block Entry: {:?} instructions\n \
1222                   Block Exit: {:?} instructions\n \
1223                   Block Alt: {:?} instructions",
1224            before.instrs.len(),
1225            after.instrs.len(),
1226            alternate.as_ref().unwrap().instrs.len(),
1227            semantic_after.instrs.len(),
1228            block_entry.instrs.len(),
1229            block_exit.instrs.len(),
1230            block_alt.as_ref().unwrap().instrs.len()
1231        )
1232    }
1233}
1234
1235impl PartialEq for InstrumentationFlag<'_> {
1236    fn eq(&self, other: &Self) -> bool {
1237        // Using pattern match to help identify when this function needs to be extended in the future
1238        let Self {
1239            before,
1240            after,
1241            alternate,
1242            semantic_after,
1243            block_entry,
1244            block_exit,
1245            block_alt,
1246            current_mode,
1247        } = self;
1248        let mut result = before.eq(&other.before);
1249        result &= after.eq(&other.after);
1250        result &= *alternate == other.alternate;
1251        result &= semantic_after.eq(&other.semantic_after);
1252        result &= block_entry.eq(&other.block_entry);
1253        result &= block_exit.eq(&other.block_exit);
1254        result &= block_alt.eq(&other.block_alt);
1255        result &= *current_mode == other.current_mode;
1256
1257        result
1258    }
1259}
1260
1261impl Eq for InstrumentationFlag<'_> {}
1262
1263impl<'a> InstrumentationFlag<'a> {
1264    pub fn has_instr(&self) -> bool {
1265        // Using pattern match to help identify when this function needs to be extended in the future
1266        let Self {
1267            before,
1268            after,
1269            alternate,
1270            semantic_after,
1271            block_entry,
1272            block_exit,
1273            block_alt,
1274            current_mode: _,
1275        } = self;
1276        !before.instrs.is_empty()
1277            || !after.instrs.is_empty()
1278            || !alternate.is_none() // Some(vec![]) means instruction removal!
1279            || !semantic_after.instrs.is_empty()
1280            || !block_entry.instrs.is_empty()
1281            || !block_exit.instrs.is_empty()
1282            || !block_alt.is_none() // Some(vec![]) means block removal!
1283    }
1284
1285    pub(crate) fn check_special_is_resolved(&self) {
1286        let Self {
1287            semantic_after,
1288            block_entry,
1289            block_exit,
1290            block_alt,
1291            ..
1292        } = self;
1293
1294        // Check if special instrumentation modes have been resolved!
1295        if !semantic_after.instrs.is_empty() {
1296            error!(
1297                "BUG: Semantic after instrumentation should be resolved already, please report."
1298            );
1299        }
1300        if !block_entry.instrs.is_empty() {
1301            error!("BUG: Block entry instrumentation should be resolved already, please report.");
1302        }
1303        if !block_exit.instrs.is_empty() {
1304            error!("BUG: Block exit instrumentation should be resolved already, please report.");
1305        }
1306        if !block_alt.is_none() {
1307            error!("BUG: Block alt instrumentation should be resolved already, please report.");
1308        }
1309    }
1310
1311    pub(crate) fn add_injections(
1312        &self,
1313        fid: u32,
1314        idx: u32,
1315        side_effects: &mut HashMap<InjectType, Vec<Injection<'a>>>,
1316    ) {
1317        let Self {
1318            before,
1319            after,
1320            alternate,
1321            ..
1322        } = self;
1323
1324        let mut add_inj = |mode: InstrumentationMode, instrs: &InjectedInstrs<'a>| {
1325            if instrs.instrs.is_empty() {
1326                return;
1327            }
1328            add_injection(
1329                side_effects,
1330                InjectType::Probe,
1331                Injection::FuncLocProbe {
1332                    target_fid: fid,
1333                    target_opcode_idx: idx,
1334                    mode,
1335                    body: instrs.instrs.clone(),
1336                    tag: instrs.tag.clone().unwrap_or_default(),
1337                },
1338            );
1339        };
1340
1341        add_inj(InstrumentationMode::Before, before);
1342        add_inj(InstrumentationMode::After, after);
1343        if let Some(alt) = alternate {
1344            add_inj(InstrumentationMode::Alternate, alt);
1345        }
1346    }
1347
1348    /// Add an instruction to the current InstrumentationMode's list
1349    /// Returns whether the instrumentation was a 'special' mode
1350    pub fn add_instr(&mut self, op: &Operator, val: Operator<'a>) -> bool {
1351        match self.current_mode {
1352            None => {
1353                panic!("Internal error: Current mode is not set...cannot inject instructions!")
1354            }
1355            Some(InstrumentationMode::Before) => {
1356                self.before.instrs.push(val);
1357                false
1358            }
1359            Some(InstrumentationMode::After) => {
1360                self.after.instrs.push(val);
1361                false
1362            }
1363            Some(InstrumentationMode::Alternate) => {
1364                match &mut self.alternate {
1365                    None => {
1366                        self.alternate = Some(InjectedInstrs {
1367                            instrs: vec![val],
1368                            tag: None,
1369                        })
1370                    }
1371                    Some(alternate) => alternate.instrs.push(val),
1372                }
1373                false
1374            }
1375            Some(InstrumentationMode::SemanticAfter) => {
1376                if Self::is_block_style_op(op) || Self::is_branching_op(op) {
1377                    self.semantic_after.instrs.push(val);
1378                    true
1379                } else {
1380                    // instrumentation type not applicable!
1381                    panic!(
1382                        "Cannot apply semantic after instrumentation mode to op type: {:?}",
1383                        op
1384                    );
1385                }
1386            }
1387            Some(InstrumentationMode::BlockEntry) => {
1388                if Self::is_block_style_op(op) {
1389                    self.block_entry.instrs.push(val);
1390                    true
1391                } else {
1392                    // instrumentation type not applicable!
1393                    panic!(
1394                        "Cannot apply block entry instrumentation mode to op type: {:?}",
1395                        op
1396                    );
1397                }
1398            }
1399            Some(InstrumentationMode::BlockExit) => {
1400                if Self::is_block_style_op(op) {
1401                    self.block_exit.instrs.push(val);
1402                    true
1403                } else {
1404                    // instrumentation type not applicable!
1405                    panic!(
1406                        "Cannot apply block exit instrumentation mode to op type: {:?}",
1407                        op
1408                    );
1409                }
1410            }
1411            Some(InstrumentationMode::BlockAlt) => {
1412                if Self::is_block_style_op(op) {
1413                    match &mut self.block_alt {
1414                        None => {
1415                            self.block_alt = Some(InjectedInstrs {
1416                                instrs: vec![val],
1417                                tag: None,
1418                            })
1419                        }
1420                        Some(block_alt) => block_alt.instrs.push(val),
1421                    }
1422                    true
1423                } else {
1424                    // instrumentation type not applicable!
1425                    panic!(
1426                        "Cannot apply block alternate instrumentation mode to op type: {:?}",
1427                        op
1428                    );
1429                }
1430            }
1431        }
1432    }
1433
1434    pub fn instr_len(&self) -> usize {
1435        match self.current_mode {
1436            None => {
1437                panic!("Current mode is not set...cannot inject instructions!")
1438            }
1439            Some(InstrumentationMode::Before) => self.before.instrs.len(),
1440            Some(InstrumentationMode::After) => self.after.instrs.len(),
1441            Some(InstrumentationMode::Alternate) => match &self.alternate {
1442                None => 0,
1443                Some(alternate) => alternate.instrs.len(),
1444            },
1445            Some(InstrumentationMode::SemanticAfter) => self.semantic_after.instrs.len(),
1446            Some(InstrumentationMode::BlockEntry) => self.block_entry.instrs.len(),
1447            Some(InstrumentationMode::BlockExit) => self.block_exit.instrs.len(),
1448            Some(InstrumentationMode::BlockAlt) => match &self.block_alt {
1449                None => 0,
1450                Some(block_alt) => block_alt.instrs.len(),
1451            },
1452        }
1453    }
1454
1455    pub fn clear_instr(&mut self, mode: InstrumentationMode) {
1456        match mode {
1457            InstrumentationMode::Before => {
1458                self.before.instrs.clear();
1459            }
1460            InstrumentationMode::After => self.after.instrs.clear(),
1461            InstrumentationMode::Alternate => {
1462                self.alternate = None;
1463            }
1464            InstrumentationMode::SemanticAfter => self.semantic_after.instrs.clear(),
1465            InstrumentationMode::BlockEntry => self.block_entry.instrs.clear(),
1466            InstrumentationMode::BlockExit => self.block_exit.instrs.clear(),
1467            InstrumentationMode::BlockAlt => {
1468                self.block_alt = None;
1469            }
1470        }
1471    }
1472
1473    fn is_block_style_op(op: &Operator) -> bool {
1474        matches!(
1475            op,
1476            Operator::Block { .. }
1477                | Operator::Loop { .. }
1478                | Operator::If { .. }
1479                | Operator::Else { .. }
1480        )
1481    }
1482
1483    fn is_branching_op(op: &Operator) -> bool {
1484        matches!(
1485            op,
1486            Operator::Br { .. }
1487                | Operator::BrIf { .. }
1488                | Operator::BrTable { .. }
1489                | Operator::BrOnCast { .. }
1490                | Operator::BrOnCastFail { .. }
1491                | Operator::BrOnNull { .. }
1492                | Operator::BrOnNonNull { .. }
1493        )
1494    }
1495
1496    /// Get an instruction to the current InstrumentationMode's list
1497    pub fn get_instr(&self, idx: usize) -> Result<&Operator<'_>> {
1498        match self.current_mode {
1499            None => Err(InstrumentationError(
1500                "Current mode is not set...cannot grab instruction without context!".to_string(),
1501            )),
1502            Some(InstrumentationMode::Before) => Ok(&self.before.instrs[idx]),
1503            Some(InstrumentationMode::After) => Ok(&self.after.instrs[idx]),
1504            Some(InstrumentationMode::Alternate) => match &self.alternate {
1505                None => Err(InstrumentationError(format!(
1506                    "No alternate instructions to pull idx '{}' from",
1507                    idx
1508                ))),
1509                Some(alternate) => Ok(&alternate.instrs[idx]),
1510            },
1511            Some(InstrumentationMode::SemanticAfter) => Ok(&self.semantic_after.instrs[idx]),
1512            Some(InstrumentationMode::BlockEntry) => Ok(&self.block_entry.instrs[idx]),
1513            Some(InstrumentationMode::BlockExit) => Ok(&self.block_exit.instrs[idx]),
1514            Some(InstrumentationMode::BlockAlt) => match &self.block_alt {
1515                None => Err(InstrumentationError(format!(
1516                    "No block alt instructions to pull idx '{}' from",
1517                    idx
1518                ))),
1519                Some(block_alt) => Ok(&block_alt.instrs[idx]),
1520            },
1521        }
1522    }
1523
1524    /// Can be called after finishing some instrumentation to reset the mode.
1525    pub fn finish_instr(&mut self) {
1526        self.current_mode = None
1527    }
1528}
1529
1530#[derive(Clone, Debug, Default, Eq, PartialEq)]
1531pub struct InjectedInstrs<'a> {
1532    pub(crate) instrs: Vec<Operator<'a>>,
1533    pub(crate) tag: InjectTag,
1534}
1535impl TagUtils for InjectedInstrs<'_> {
1536    fn get_or_create_tag(&mut self) -> &mut Tag {
1537        self.tag.get_or_insert_default()
1538    }
1539
1540    fn get_tag(&self) -> &Option<Tag> {
1541        &self.tag
1542    }
1543}
1544impl HasInjectTag for InjectedInstrs<'_> {}
1545
1546/// Used to represent a unique location in a wasm component or module.
1547#[derive(Debug, Clone, Copy)]
1548pub enum Location {
1549    Component {
1550        mod_idx: ModuleID,
1551        func_idx: FunctionID,
1552        instr_idx: usize,
1553    },
1554    Module {
1555        func_idx: FunctionID,
1556        instr_idx: usize,
1557    },
1558}
1559
1560/// A sequence of Wasm instructions which may be instrumented.
1561#[derive(Debug, Default, Clone)]
1562pub struct Instructions<'a> {
1563    instructions: Vec<Operator<'a>>,
1564    offsets: Option<Vec<usize>>,
1565    flags: Option<Vec<InstrumentationFlag<'a>>>,
1566}
1567
1568impl<'a> Instructions<'a> {
1569    fn force_flags(&mut self) {
1570        if self.flags.is_none() {
1571            self.flags = Some(vec![
1572                InstrumentationFlag::default();
1573                self.instructions.len()
1574            ]);
1575        }
1576    }
1577
1578    pub fn new(
1579        instructions: Vec<(Operator<'a>, usize)>,
1580        locals_start: usize,
1581        save_offsets: bool,
1582    ) -> Self {
1583        let mut instrs = vec![];
1584        let mut pcs = vec![];
1585        instructions.iter().for_each(|(operator, offset)| {
1586            instrs.push(operator.clone());
1587            // we want to store the offset inside a function body (including locals bytes)! not the overall module.
1588            pcs.push(*offset - locals_start);
1589        });
1590        Self {
1591            instructions: instrs,
1592            offsets: if save_offsets { Some(pcs) } else { None },
1593            flags: None,
1594        }
1595    }
1596
1597    /// Get array of operators (instructions).
1598    pub fn get_ops(&self) -> &[Operator<'a>] {
1599        &self.instructions
1600    }
1601
1602    /// Get array of instrumentation flags.
1603    pub fn get_flags(&self) -> Option<&[InstrumentationFlag<'a>]> {
1604        self.flags.as_ref().map(|v| &v[..])
1605    }
1606
1607    /// Only to be used internally for encoding.
1608    pub(crate) fn get_ops_flags_mut(
1609        &mut self,
1610    ) -> (&mut [Operator<'a>], Option<&mut [InstrumentationFlag<'a>]>) {
1611        match &mut self.flags {
1612            Some(flags) => (&mut self.instructions, Some(flags)),
1613            None => (&mut self.instructions, None),
1614        }
1615    }
1616
1617    /// Directly mutating the instructions will likely invalidate the
1618    /// instruction flags, so this will Error if the instructions have been
1619    /// instrumented.
1620    pub fn get_ops_mut(&mut self) -> Result<&mut Vec<Operator<'a>>> {
1621        if self.flags.is_some() {
1622            return Err(InstrumentationError(
1623                "Cannot get mutable instructions if flags are set. \
1624            Mutating instructions will invalidate instrumentation flags."
1625                    .to_string(),
1626            ));
1627        }
1628        Ok(&mut self.instructions)
1629    }
1630
1631    pub fn get_instr_flag(&self, idx: usize) -> Option<&InstrumentationFlag<'a>> {
1632        self.flags.as_ref().and_then(|f| f.get(idx))
1633    }
1634
1635    pub fn push(&mut self, op: Operator<'a>) {
1636        self.instructions.push(op);
1637        if let Some(flags) = &mut self.flags {
1638            flags.push(InstrumentationFlag::default());
1639        }
1640    }
1641
1642    pub fn len(&self) -> usize {
1643        self.instructions.len()
1644    }
1645
1646    pub fn is_empty(&self) -> bool {
1647        self.instructions.is_empty()
1648    }
1649
1650    pub fn add_instr(&mut self, index: usize, op: Operator<'a>) -> bool {
1651        self.force_flags();
1652        self.flags.as_mut().unwrap()[index].add_instr(&self.instructions[index], op)
1653    }
1654
1655    pub fn current_mode(&self, index: usize) -> Option<InstrumentationMode> {
1656        self.flags.as_ref().and_then(|f| f[index].current_mode)
1657    }
1658
1659    pub fn set_current_mode(&mut self, index: usize, mode: InstrumentationMode) {
1660        self.force_flags();
1661        self.flags.as_mut().unwrap()[index].current_mode = Some(mode);
1662    }
1663
1664    pub fn finish_instr(&mut self, index: usize) {
1665        self.force_flags();
1666        self.flags.as_mut().unwrap()[index].finish_instr();
1667    }
1668
1669    pub fn instr_len(&self, index: usize) -> usize {
1670        self.flags
1671            .as_ref()
1672            .map(|f| f[index].instr_len())
1673            .unwrap_or(0)
1674    }
1675
1676    pub fn set_alternate(&mut self, index: usize, alternate: InjectedInstrs<'a>) {
1677        self.force_flags();
1678        self.flags.as_mut().unwrap()[index].alternate = Some(alternate);
1679    }
1680
1681    pub fn set_block_alt(&mut self, index: usize, block_alt: InjectedInstrs<'a>) {
1682        self.force_flags();
1683        self.flags.as_mut().unwrap()[index].block_alt = Some(block_alt);
1684    }
1685
1686    pub fn append_to_tag(&mut self, index: usize, data: Vec<u8>) {
1687        self.force_flags();
1688        self.flags.as_mut().unwrap()[index].append_to_tag(data);
1689    }
1690
1691    pub fn clear_instr(&mut self, idx: usize, mode: InstrumentationMode) {
1692        if let Some(flags) = &mut self.flags {
1693            flags[idx].clear_instr(mode);
1694        }
1695    }
1696
1697    pub fn lookup_pc_offset_for(&self, instr_idx: usize) -> Option<usize> {
1698        if let Some(offsets) = self.offsets.as_ref() {
1699            offsets.get(instr_idx).copied()
1700        } else {
1701            None
1702        }
1703    }
1704}
1705
1706#[derive(Debug, Default, Clone)]
1707/// Body of a function in a wasm module
1708pub struct Body<'a> {
1709    /// Local variables of the function, given as tuples of (# of locals, type).
1710    /// Note that these do not include the function parameters which are given
1711    /// indices before the locals. So if a function has 2 parameters and a local
1712    /// defined here then local indices 0 and 1 will refer to the parameters and
1713    /// index 2 will refer to the local here.
1714    pub locals: Vec<(u32, DataType)>,
1715    pub num_locals: u32,
1716    pub instructions: Instructions<'a>,
1717    pub num_instructions: usize,
1718    pub name: Option<String>,
1719}
1720
1721// 'b should outlive 'a
1722impl<'a, 'b> Body<'a>
1723where
1724    'b: 'a,
1725{
1726    /// Push a new operator (instruction) to the end of the body
1727    pub fn push_op(&mut self, op: Operator<'b>) {
1728        self.instructions.push(op);
1729        self.num_instructions += 1;
1730    }
1731
1732    pub fn locals_as_vec(&self) -> Vec<DataType> {
1733        let mut locals = vec![];
1734        for (count, ty) in self.locals.iter() {
1735            for _ in 0..*count {
1736                locals.push(*ty);
1737            }
1738        }
1739        locals
1740    }
1741}
1742
1743/// A constant expression which is produced in WebAssembly, typically used in global
1744/// initializers or element/data offsets.
1745#[derive(Debug, Clone)]
1746pub struct InitExpr {
1747    pub exprs: Vec<InitInstr>,
1748}
1749
1750/// Set of instructions that can be used in Initialization Expressions
1751#[derive(Debug, Copy, Clone)]
1752pub enum InitInstr {
1753    /// An immediate constant value
1754    Value(Value),
1755    /// A constant value referenced by the global specified
1756    Global(GlobalID),
1757    /// A null reference
1758    RefNull(RefType),
1759    /// A function initializer
1760    RefFunc(FunctionID),
1761    /// Struct Initializer
1762    StructNew(TypeID),
1763    /// Struct Default
1764    StructNewDefault(TypeID),
1765    /// Array Initializer
1766    ArrayNew(TypeID),
1767    /// Default Initialisation
1768    ArrayNewDefault(TypeID),
1769    /// Fixed Array
1770    RefArrayFixed {
1771        array_type_index: u32,
1772        array_size: u32,
1773    },
1774    /// Array from Data
1775    RefArrayData {
1776        array_type_index: u32,
1777        array_data_index: u32,
1778    },
1779    /// Array from Elem
1780    RefArrayElem {
1781        array_type_index: u32,
1782        array_elem_index: u32,
1783    },
1784    RefI31,
1785}
1786impl InitInstr {
1787    pub fn fix_id_mapping(
1788        &mut self,
1789        func_mapping: &HashMap<u32, u32>,
1790        global_mapping: &HashMap<u32, u32>,
1791    ) -> types::Result<()> {
1792        match self {
1793            InitInstr::Global(id) => match global_mapping.get(&(*id)) {
1794                Some(new_index) => {
1795                    **id = *new_index;
1796                }
1797                None => return Err(InstrumentationError("Deleted global!".to_string())),
1798            },
1799            InitInstr::RefFunc(id) => match func_mapping.get(&(*id)) {
1800                Some(new_index) => {
1801                    **id = *new_index;
1802                }
1803                None => return Err(InstrumentationError("Deleted function!".to_string())),
1804            },
1805            _ => {}
1806        }
1807        Ok(())
1808    }
1809}
1810
1811impl InitExpr {
1812    /// Create a new initialisation expression given a vector of Instructions
1813    pub fn new(instructions: Vec<InitInstr>) -> Self {
1814        InitExpr {
1815            exprs: instructions,
1816        }
1817    }
1818
1819    pub fn instructions(&self) -> &[InitInstr] {
1820        self.exprs.as_slice()
1821    }
1822
1823    pub(crate) fn eval(init: &ConstExpr) -> Result<InitExpr> {
1824        use wasmparser::Operator::*;
1825        let mut reader = init.get_operators_reader();
1826        let mut instrs = vec![];
1827        loop {
1828            let op = reader.read()?;
1829            let val = match op {
1830                I32Const { value } => InitInstr::Value(Value::I32(value)),
1831                I64Const { value } => InitInstr::Value(Value::I64(value)),
1832                F32Const { value } => InitInstr::Value(Value::F32(f32::from_bits(value.bits()))),
1833                F64Const { value } => InitInstr::Value(Value::F64(f64::from_bits(value.bits()))),
1834                V128Const { value } => InitInstr::Value(Value::V128(v128_to_u128(&value))),
1835                GlobalGet { global_index } => InitInstr::Global(GlobalID(global_index)),
1836                // Marking nullable as true as it's a null reference
1837                RefNull { hty } => InitInstr::RefNull(RefType::new(true, hty).ok_or_else(|| {
1838                    Error::ConversionError(format!(
1839                        "ref.null in constant expression references an unrepresentable heap type: {hty:?}"
1840                    ))
1841                })?),
1842                RefFunc { function_index } => InitInstr::RefFunc(FunctionID(function_index)),
1843                StructNew { struct_type_index } => InitInstr::StructNew(TypeID(struct_type_index)),
1844                StructNewDefault { struct_type_index } => {
1845                    InitInstr::StructNewDefault(TypeID(struct_type_index))
1846                }
1847                ArrayNew { array_type_index } => InitInstr::ArrayNew(TypeID(array_type_index)),
1848                ArrayNewDefault { array_type_index } => {
1849                    InitInstr::ArrayNewDefault(TypeID(array_type_index))
1850                }
1851                ArrayNewFixed {
1852                    array_type_index,
1853                    array_size,
1854                } => InitInstr::RefArrayFixed {
1855                    array_type_index,
1856                    array_size,
1857                },
1858                ArrayNewData {
1859                    array_type_index,
1860                    array_data_index,
1861                } => InitInstr::RefArrayData {
1862                    array_data_index,
1863                    array_type_index,
1864                },
1865                ArrayNewElem {
1866                    array_type_index,
1867                    array_elem_index,
1868                } => InitInstr::RefArrayElem {
1869                    array_type_index,
1870                    array_elem_index,
1871                },
1872                RefI31 => InitInstr::RefI31,
1873                End => break,
1874                other => {
1875                    return Err(Error::ConversionError(format!(
1876                        "unsupported operator in constant expression: {other:?}"
1877                    )));
1878                }
1879            };
1880            instrs.push(val);
1881        }
1882        if !reader.eof() {
1883            return Err(Error::ConversionError(
1884                "trailing bytes after `end` in constant expression".to_string(),
1885            ));
1886        }
1887        Ok(InitExpr { exprs: instrs })
1888    }
1889
1890    pub(crate) fn to_wasmencoder_type(&self) -> wasm_encoder::ConstExpr {
1891        let mut bytes = vec![];
1892        for instr in self.exprs.iter() {
1893            match instr {
1894                InitInstr::Value(v) => match v {
1895                    Value::I32(v) => wasm_encoder::Instruction::I32Const(*v).encode(&mut bytes),
1896                    Value::I64(v) => wasm_encoder::Instruction::I64Const(*v).encode(&mut bytes),
1897                    Value::F32(v) => {
1898                        wasm_encoder::Instruction::F32Const(Ieee32::from(*v)).encode(&mut bytes)
1899                    }
1900                    Value::F64(v) => {
1901                        wasm_encoder::Instruction::F64Const(Ieee64::from(*v)).encode(&mut bytes)
1902                    }
1903                    Value::V128(v) => {
1904                        wasm_encoder::Instruction::V128Const(*v as i128).encode(&mut bytes)
1905                    }
1906                },
1907                InitInstr::Global(g) => {
1908                    wasm_encoder::Instruction::GlobalGet(**g).encode(&mut bytes)
1909                }
1910                InitInstr::RefNull(ty) => {
1911                    wasm_encoder::Instruction::RefNull(match ty.heap_type() {
1912                        HeapType::Abstract { shared, ty } => match ty {
1913                            wasmparser::AbstractHeapType::Func => {
1914                                wasm_encoder::HeapType::Abstract {
1915                                    ty: AbstractHeapType::Func,
1916                                    shared,
1917                                }
1918                            }
1919                            wasmparser::AbstractHeapType::Extern => {
1920                                wasm_encoder::HeapType::Abstract {
1921                                    ty: AbstractHeapType::Extern,
1922                                    shared,
1923                                }
1924                            }
1925                            wasmparser::AbstractHeapType::Any => wasm_encoder::HeapType::Abstract {
1926                                ty: AbstractHeapType::Any,
1927                                shared,
1928                            },
1929                            wasmparser::AbstractHeapType::None => {
1930                                wasm_encoder::HeapType::Abstract {
1931                                    ty: AbstractHeapType::None,
1932                                    shared,
1933                                }
1934                            }
1935                            wasmparser::AbstractHeapType::NoExtern => {
1936                                wasm_encoder::HeapType::Abstract {
1937                                    ty: AbstractHeapType::NoExtern,
1938                                    shared,
1939                                }
1940                            }
1941                            wasmparser::AbstractHeapType::NoFunc => {
1942                                wasm_encoder::HeapType::Abstract {
1943                                    ty: AbstractHeapType::NoFunc,
1944                                    shared,
1945                                }
1946                            }
1947                            wasmparser::AbstractHeapType::Eq => wasm_encoder::HeapType::Abstract {
1948                                ty: AbstractHeapType::Eq,
1949                                shared,
1950                            },
1951                            wasmparser::AbstractHeapType::Struct => {
1952                                wasm_encoder::HeapType::Abstract {
1953                                    ty: AbstractHeapType::Struct,
1954                                    shared,
1955                                }
1956                            }
1957                            wasmparser::AbstractHeapType::Array => {
1958                                wasm_encoder::HeapType::Abstract {
1959                                    ty: AbstractHeapType::Array,
1960                                    shared,
1961                                }
1962                            }
1963                            wasmparser::AbstractHeapType::I31 => wasm_encoder::HeapType::Abstract {
1964                                ty: AbstractHeapType::I31,
1965                                shared,
1966                            },
1967                            wasmparser::AbstractHeapType::Exn => wasm_encoder::HeapType::Abstract {
1968                                ty: AbstractHeapType::Exn,
1969                                shared,
1970                            },
1971                            wasmparser::AbstractHeapType::NoExn => {
1972                                wasm_encoder::HeapType::Abstract {
1973                                    ty: AbstractHeapType::NoExn,
1974                                    shared,
1975                                }
1976                            }
1977                            wasmparser::AbstractHeapType::Cont => {
1978                                wasm_encoder::HeapType::Abstract {
1979                                    ty: AbstractHeapType::Cont,
1980                                    shared,
1981                                }
1982                            }
1983                            wasmparser::AbstractHeapType::NoCont => {
1984                                wasm_encoder::HeapType::Abstract {
1985                                    ty: AbstractHeapType::NoCont,
1986                                    shared,
1987                                }
1988                            }
1989                        },
1990                        HeapType::Concrete(id) => {
1991                            if let Some(mod_id) = id.as_module_index() {
1992                                wasm_encoder::HeapType::Concrete(mod_id)
1993                            } else if let Some(rg_id) = id.as_rec_group_index() {
1994                                wasm_encoder::HeapType::Concrete(rg_id)
1995                            } else if let Some(core) = id.as_core_type_id() {
1996                                wasm_encoder::HeapType::Concrete(core.index() as u32)
1997                            } else {
1998                                unimplemented!("Did not unpack concrete type!")
1999                            }
2000                        }
2001                        HeapType::Exact(id) => {
2002                            if let Some(mod_id) = id.as_module_index() {
2003                                wasm_encoder::HeapType::Exact(mod_id)
2004                            } else if let Some(rg_id) = id.as_rec_group_index() {
2005                                wasm_encoder::HeapType::Exact(rg_id)
2006                            } else if let Some(core) = id.as_core_type_id() {
2007                                wasm_encoder::HeapType::Exact(core.index() as u32)
2008                            } else {
2009                                unimplemented!("Did not unpack exact type!")
2010                            }
2011                        }
2012                    })
2013                    .encode(&mut bytes)
2014                }
2015                InitInstr::RefFunc(f) => wasm_encoder::Instruction::RefFunc(**f).encode(&mut bytes),
2016                InitInstr::StructNew(id) => {
2017                    wasm_encoder::Instruction::StructNew(**id).encode(&mut bytes);
2018                }
2019                InitInstr::ArrayNew(id) => {
2020                    wasm_encoder::Instruction::ArrayNew(**id).encode(&mut bytes);
2021                }
2022
2023                InitInstr::StructNewDefault(id) => {
2024                    wasm_encoder::Instruction::StructNewDefault(**id).encode(&mut bytes);
2025                }
2026                InitInstr::ArrayNewDefault(id) => {
2027                    wasm_encoder::Instruction::ArrayNewDefault(**id).encode(&mut bytes);
2028                }
2029                InitInstr::RefArrayFixed {
2030                    array_type_index,
2031                    array_size,
2032                } => {
2033                    wasm_encoder::Instruction::ArrayNewFixed {
2034                        array_size: *array_size,
2035                        array_type_index: *array_type_index,
2036                    }
2037                    .encode(&mut bytes);
2038                }
2039                InitInstr::RefArrayData {
2040                    array_type_index,
2041                    array_data_index,
2042                } => {
2043                    wasm_encoder::Instruction::ArrayNewData {
2044                        array_data_index: *array_data_index,
2045                        array_type_index: *array_type_index,
2046                    }
2047                    .encode(&mut bytes);
2048                }
2049                InitInstr::RefArrayElem {
2050                    array_type_index,
2051                    array_elem_index,
2052                } => {
2053                    wasm_encoder::Instruction::ArrayNewElem {
2054                        array_elem_index: *array_elem_index,
2055                        array_type_index: *array_type_index,
2056                    }
2057                    .encode(&mut bytes);
2058                }
2059                InitInstr::RefI31 => wasm_encoder::Instruction::RefI31.encode(&mut bytes),
2060            }
2061        }
2062        wasm_encoder::ConstExpr::raw(bytes)
2063    }
2064}
2065
2066/// Constant values that can show up in WebAssembly
2067#[derive(Debug, Clone, Copy)]
2068pub enum Value {
2069    /// A constant 32-bit integer
2070    I32(i32),
2071    /// A constant 64-bit integer
2072    I64(i64),
2073    /// A constant 32-bit float
2074    F32(f32),
2075    /// A constant 64-bit float
2076    F64(f64),
2077    /// A constant 128-bit vector register
2078    V128(u128),
2079}
2080
2081impl fmt::Display for Value {
2082    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
2083        match self {
2084            Value::I32(i) => i.fmt(f),
2085            Value::I64(i) => i.fmt(f),
2086            Value::F32(i) => i.fmt(f),
2087            Value::F64(i) => i.fmt(f),
2088            Value::V128(i) => i.fmt(f),
2089        }
2090    }
2091}
2092
2093#[derive(Debug, Copy, Clone, PartialEq, Eq)]
2094pub enum BlockType {
2095    /// The block produces consumes nor produces any values.
2096    Empty,
2097    /// The block produces a singular value of the given type ([] -> \[t]).
2098    Type(DataType),
2099    /// The block is described by a function type.
2100    ///
2101    /// The index is to a function type in the types section.
2102    FuncType(TypeID),
2103}
2104
2105impl From<wasmparser::BlockType> for BlockType {
2106    fn from(value: wasmparser::BlockType) -> Self {
2107        match value {
2108            wasmparser::BlockType::Empty => BlockType::Empty,
2109            wasmparser::BlockType::FuncType(u) => BlockType::FuncType(TypeID(u)),
2110            wasmparser::BlockType::Type(val) => BlockType::Type(DataType::from(val)),
2111        }
2112    }
2113}
2114
2115impl From<BlockType> for wasmparser::BlockType {
2116    fn from(ty: BlockType) -> Self {
2117        match ty {
2118            BlockType::Empty => wasmparser::BlockType::Empty,
2119            BlockType::FuncType(u) => wasmparser::BlockType::FuncType(*u),
2120            BlockType::Type(data) => wasmparser::BlockType::Type(ValType::from(&data)),
2121        }
2122    }
2123}
2124
2125/// Intermediate Representation of Custom Sections
2126#[derive(Clone, Debug, Default)]
2127pub struct CustomSections<'a> {
2128    // Custom sections are special, they don't have to be append only!
2129    pub(crate) custom_sections: Vec<CustomSection<'a>>,
2130}
2131
2132impl<'a> CustomSections<'a> {
2133    pub fn new(custom_sections: Vec<(&'a str, &'a [u8])>) -> Self {
2134        CustomSections {
2135            custom_sections: custom_sections
2136                .iter()
2137                .map(|cs| CustomSection::new_borrowed(cs.0, cs.1))
2138                .collect(),
2139        }
2140    }
2141
2142    /// Get a custom section ID by name
2143    pub fn get_id(&self, name: String) -> Option<CustomSectionID> {
2144        for (index, section) in self.custom_sections.iter().enumerate() {
2145            if section.name == name {
2146                return Some(CustomSectionID(index as u32));
2147            }
2148        }
2149        None
2150    }
2151
2152    /// Get a custom section by its ID
2153    pub fn get_by_id(&self, custom_section_id: CustomSectionID) -> Result<&CustomSection<'_>> {
2154        if *custom_section_id >= self.custom_sections.len() as u32 {
2155            Err(UnknownId("Invalid custom section ID!".into()))
2156        } else {
2157            Ok(&self.custom_sections[*custom_section_id as usize])
2158        }
2159    }
2160
2161    /// Number of custom sections
2162    pub fn len(&self) -> usize {
2163        self.custom_sections.len()
2164    }
2165
2166    /// Check if there are any custom sections
2167    pub fn is_empty(&self) -> bool {
2168        self.custom_sections.is_empty()
2169    }
2170
2171    /// Creates an iterable over the custom sections
2172    pub fn iter(&self) -> Iter<'_, CustomSection<'a>> {
2173        self.custom_sections.iter()
2174    }
2175
2176    /// Get mutable reference to section data
2177    pub fn get_section_data_mut(&mut self, section_id: CustomSectionID) -> Option<&mut Vec<u8>> {
2178        if *section_id < self.custom_sections.len() as u32 {
2179            Some(self.custom_sections[*section_id as usize].data.to_mut())
2180        } else {
2181            None
2182        }
2183    }
2184
2185    /// Add a new custom section and return its ID
2186    pub(crate) fn add(&mut self, section: CustomSection<'a>) -> CustomSectionID {
2187        let id = CustomSectionID(self.custom_sections.len() as u32);
2188        self.custom_sections.push(section);
2189        id
2190    }
2191}
2192
2193/// Intermediate Representation of a single Custom Section
2194#[derive(Clone, Debug)]
2195pub struct CustomSection<'a> {
2196    pub name: &'a str,
2197    pub data: Cow<'a, [u8]>,
2198    pub deleted: bool,
2199}
2200
2201impl<'a> CustomSection<'a> {
2202    /// Create a new custom section
2203    pub fn new(name: &'a str, data: Vec<u8>) -> Self {
2204        CustomSection {
2205            name,
2206            data: Cow::Owned(data),
2207            deleted: false,
2208        }
2209    }
2210
2211    /// Create a new custom section with borrowed data (private)
2212    fn new_borrowed(name: &'a str, data: &'a [u8]) -> Self {
2213        CustomSection {
2214            name,
2215            data: Cow::Borrowed(data),
2216            deleted: false,
2217        }
2218    }
2219}
2220
2221#[allow(clippy::identity_op)]
2222pub(crate) fn v128_to_u128(value: &wasmparser::V128) -> u128 {
2223    let n = value.bytes();
2224    ((n[0] as u128) << 0)
2225        | ((n[1] as u128) << 8)
2226        | ((n[2] as u128) << 16)
2227        | ((n[3] as u128) << 24)
2228        | ((n[4] as u128) << 32)
2229        | ((n[5] as u128) << 40)
2230        | ((n[6] as u128) << 48)
2231        | ((n[7] as u128) << 56)
2232        | ((n[8] as u128) << 64)
2233        | ((n[9] as u128) << 72)
2234        | ((n[10] as u128) << 80)
2235        | ((n[11] as u128) << 88)
2236        | ((n[12] as u128) << 96)
2237        | ((n[13] as u128) << 104)
2238        | ((n[14] as u128) << 112)
2239        | ((n[15] as u128) << 120)
2240}