1#![warn(missing_docs)]
4
5use parity_wasm::elements;
6use crate::ref_list::{RefList, EntryRef};
7use std::collections::BTreeMap;
8
9#[derive(Debug)]
14pub enum ImportedOrDeclared<T=()> {
15 Imported(String, String),
17 Declared(T),
19}
20
21impl<T> From<&elements::ImportEntry> for ImportedOrDeclared<T> {
22 fn from(v: &elements::ImportEntry) -> Self {
23 ImportedOrDeclared::Imported(v.module().to_owned(), v.field().to_owned())
24 }
25}
26
27#[derive(Debug)]
29pub enum Error {
30 InconsistentSource,
32 Format(elements::Error),
34 DetachedEntry,
36}
37
38impl From<elements::Error> for Error {
39 fn from(v: elements::Error) -> Self {
40 Self::Format(v)
41 }
42}
43
44
45impl ::std::fmt::Display for Error {
46 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
47 match *self {
48 Error::InconsistentSource => write!(f, "Inconsistent source"),
49 Error::Format(ref e) => write!(f, "Format error: {e}"),
50 Error::DetachedEntry => write!(f, "Detached entry in the current module state"),
51 }
52 }
53}
54
55
56impl ::std::error::Error for Error {
57 fn description(&self) -> &str {
58 match *self {
59 Error::InconsistentSource => "Inconsistent source",
60 Error::Format(_) => "Format error of the source bytes",
61 Error::DetachedEntry => "Detached entry in the current module state",
62 }
63 }
64}
65
66
67pub type FuncOrigin = ImportedOrDeclared<FuncBody>;
69pub type GlobalOrigin = ImportedOrDeclared<Vec<Instruction>>;
71pub type MemoryOrigin = ImportedOrDeclared;
73pub type TableOrigin = ImportedOrDeclared;
75
76#[derive(Debug)]
81pub struct FuncBody {
82 pub locals: Vec<elements::Local>,
84 pub code: Vec<Instruction>,
86}
87
88#[derive(Debug)]
93pub struct Func {
94 pub type_ref: EntryRef<elements::Type>,
96 pub origin: FuncOrigin,
98}
99
100#[derive(Debug)]
105pub struct Global {
106 pub content: elements::ValueType,
108 pub is_mut: bool,
110 pub origin: GlobalOrigin,
112}
113
114#[derive(Debug)]
119pub enum Instruction {
120 Plain(elements::Instruction),
122 Call(EntryRef<Func>),
124 CallIndirect(EntryRef<elements::Type>, u8),
126 GetGlobal(EntryRef<Global>),
128 SetGlobal(EntryRef<Global>),
130}
131
132#[derive(Debug)]
137pub struct Memory {
138 pub limits: elements::ResizableLimits,
140 pub origin: MemoryOrigin,
142}
143
144#[derive(Debug)]
149pub struct Table {
150 pub limits: elements::ResizableLimits,
152 pub origin: TableOrigin,
154}
155
156#[derive(Debug)]
160pub enum SegmentLocation {
161 Passive,
163 Default(Vec<Instruction>),
165 WithIndex(u32, Vec<Instruction>),
167}
168
169#[derive(Debug)]
171pub struct DataSegment {
172 pub location: SegmentLocation,
174 pub value: Vec<u8>,
176}
177
178#[derive(Debug)]
180pub struct ElementSegment {
181 pub location: SegmentLocation,
183 pub value: Vec<EntryRef<Func>>,
185}
186
187#[derive(Debug)]
192pub enum ExportLocal {
193 Func(EntryRef<Func>),
195 Global(EntryRef<Global>),
197 Table(EntryRef<Table>),
199 Memory(EntryRef<Memory>),
201}
202
203#[derive(Debug)]
205pub struct Export {
206 pub name: String,
208 pub local: ExportLocal,
210}
211
212#[derive(Debug, Default)]
214pub struct Module {
215 pub types: RefList<elements::Type>,
217 pub funcs: RefList<Func>,
219 pub memory: RefList<Memory>,
221 pub tables: RefList<Table>,
223 pub globals: RefList<Global>,
225 pub start: Option<EntryRef<Func>>,
227 pub exports: Vec<Export>,
229 pub elements: Vec<ElementSegment>,
231 pub data: Vec<DataSegment>,
233 pub other: BTreeMap<usize, elements::Section>,
235}
236
237impl Module {
238
239 fn map_instructions(&self, instructions: &[elements::Instruction]) -> Vec<Instruction> {
240 use parity_wasm::elements::Instruction::*;
241 instructions.iter().map(|instruction| match instruction {
242 Call(func_idx) => Instruction::Call(self.funcs.clone_ref(*func_idx as usize)),
243 CallIndirect(type_idx, arg2) =>
244 Instruction::CallIndirect(
245 self.types.clone_ref(*type_idx as usize),
246 *arg2,
247 ),
248 SetGlobal(global_idx) =>
249 Instruction::SetGlobal(self.globals.clone_ref(*global_idx as usize)),
250 GetGlobal(global_idx) =>
251 Instruction::GetGlobal(self.globals.clone_ref(*global_idx as usize)),
252 other_instruction => Instruction::Plain(other_instruction.clone()),
253 }).collect()
254 }
255
256 fn generate_instructions(&self, instructions: &[Instruction]) -> Vec<elements::Instruction> {
257 use parity_wasm::elements::Instruction::*;
258 instructions.iter().map(|instruction| match instruction {
259 Instruction::Call(func_ref) => Call(func_ref.order().expect("detached instruction!") as u32),
260 Instruction::CallIndirect(type_ref, arg2) => CallIndirect(type_ref.order().expect("detached instruction!") as u32, *arg2),
261 Instruction::SetGlobal(global_ref) => SetGlobal(global_ref.order().expect("detached instruction!") as u32),
262 Instruction::GetGlobal(global_ref) => GetGlobal(global_ref.order().expect("detached instruction!") as u32),
263 Instruction::Plain(plain) => plain.clone(),
264 }).collect()
265 }
266
267 pub fn from_elements(module: &elements::Module) -> Result<Self, Error> {
269
270 let mut idx = 0;
271 let mut res = Module::default();
272
273 let mut imported_functions = 0;
274
275 for section in module.sections() {
276 match section {
277 elements::Section::Type(type_section) => {
278 res.types = RefList::from_slice(type_section.types());
279 },
280 elements::Section::Import(import_section) => {
281 for entry in import_section.entries() {
282 match *entry.external() {
283 elements::External::Function(f) => {
284 res.funcs.push(Func {
285 type_ref: res.types.get(f as usize).ok_or(Error::InconsistentSource)?.clone(),
286 origin: entry.into(),
287 });
288 imported_functions += 1;
289 },
290 elements::External::Memory(m) => {
291 res.memory.push(Memory {
292 limits: m.limits().clone(),
293 origin: entry.into(),
294 });
295 },
296 elements::External::Global(g) => {
297 res.globals.push(Global {
298 content: g.content_type(),
299 is_mut: g.is_mutable(),
300 origin: entry.into(),
301 });
302 },
303 elements::External::Table(t) => {
304 res.tables.push(Table {
305 limits: t.limits().clone(),
306 origin: entry.into(),
307 });
308 },
309 };
310 }
311 },
312 elements::Section::Function(function_section) => {
313 for f in function_section.entries() {
314 res.funcs.push(Func {
315 type_ref: res.types.get(f.type_ref() as usize)
316 .ok_or(Error::InconsistentSource)?.clone(),
317 origin: ImportedOrDeclared::Declared(FuncBody {
318 locals: Vec::new(),
319 code: Vec::new(),
321 }),
322 });
323 };
324 },
325 elements::Section::Table(table_section) => {
326 for t in table_section.entries() {
327 res.tables.push(Table {
328 limits: t.limits().clone(),
329 origin: ImportedOrDeclared::Declared(()),
330 });
331 }
332 },
333 elements::Section::Memory(table_section) => {
334 for t in table_section.entries() {
335 res.memory.push(Memory {
336 limits: t.limits().clone(),
337 origin: ImportedOrDeclared::Declared(()),
338 });
339 }
340 },
341 elements::Section::Global(global_section) => {
342 for g in global_section.entries() {
343 let init_code = res.map_instructions(g.init_expr().code());
344 res.globals.push(Global {
345 content: g.global_type().content_type(),
346 is_mut: g.global_type().is_mutable(),
347 origin: ImportedOrDeclared::Declared(init_code),
348 });
349 }
350 },
351 elements::Section::Export(export_section) => {
352 for e in export_section.entries() {
353 let local = match e.internal() {
354 &elements::Internal::Function(func_idx) => {
355 ExportLocal::Func(res.funcs.clone_ref(func_idx as usize))
356 },
357 &elements::Internal::Global(global_idx) => {
358 ExportLocal::Global(res.globals.clone_ref(global_idx as usize))
359 },
360 &elements::Internal::Memory(mem_idx) => {
361 ExportLocal::Memory(res.memory.clone_ref(mem_idx as usize))
362 },
363 &elements::Internal::Table(table_idx) => {
364 ExportLocal::Table(res.tables.clone_ref(table_idx as usize))
365 },
366 };
367
368 res.exports.push(Export { local: local, name: e.field().to_owned() })
369 }
370 },
371 elements::Section::Start(start_func) => {
372 res.start = Some(res.funcs.clone_ref(*start_func as usize));
373 },
374 elements::Section::Element(element_section) => {
375 for element_segment in element_section.entries() {
376
377 let init_expr = element_segment
387 .offset()
388 .as_ref()
389 .expect("parity-wasm is compiled without bulk-memory operations")
390 .code();
391 let location = SegmentLocation::Default(res.map_instructions(init_expr));
392
393 let funcs_map = element_segment
394 .members().iter()
395 .map(|idx| res.funcs.clone_ref(*idx as usize))
396 .collect::<Vec<EntryRef<Func>>>();
397
398 res.elements.push(ElementSegment {
399 value: funcs_map,
400 location: location,
401 });
402 }
403 },
404 elements::Section::Code(code_section) => {
405 let mut idx = 0;
406 for func_body in code_section.bodies() {
407 let code = res.map_instructions(func_body.code().elements());
408
409 let mut func = res.funcs.get_ref(imported_functions + idx).write();
410 match func.origin {
411 ImportedOrDeclared::Declared(ref mut body) => {
412 body.code = code;
413 body.locals = func_body.locals().iter().cloned().collect();
414 },
415 _ => { return Err(Error::InconsistentSource); }
416 }
417
418 idx += 1;
419 }
420 },
421 elements::Section::Data(data_section) => {
422 for data_segment in data_section.entries() {
423 let init_expr = data_segment
426 .offset()
427 .as_ref()
428 .expect("parity-wasm is compiled without bulk-memory operations")
429 .code();
430 let location = SegmentLocation::Default(res.map_instructions(init_expr));
431
432 res.data.push(DataSegment {
433 value: data_segment.value().to_vec(),
434 location: location,
435 });
436 }
437 },
438 _ => {
439 res.other.insert(idx, section.clone());
440 }
441 }
442 idx += 1;
443 }
444
445 Ok(res)
446 }
447
448 pub fn generate(&self) -> Result<elements::Module, Error> {
450 use self::ImportedOrDeclared::*;
451
452 let mut idx = 0;
453 let mut sections = Vec::new();
454
455 custom_round(&self.other, &mut idx, &mut sections);
456
457 if self.types.len() > 0 {
458 let mut type_section = elements::TypeSection::default();
460 {
461 let types = type_section.types_mut();
462
463 for type_entry in self.types.iter() {
464 types.push(type_entry.read().clone())
465 }
466 }
467 sections.push(elements::Section::Type(type_section));
468 idx += 1;
469
470 custom_round(&self.other, &mut idx, &mut sections);
471 }
472
473 let mut import_section = elements::ImportSection::default();
475
476 let add = {
477 let imports = import_section.entries_mut();
478 for func in self.funcs.iter() {
479 match func.read().origin {
480 Imported(ref module, ref field) => {
481 imports.push(
482 elements::ImportEntry::new(
483 module.to_owned(),
484 field.to_owned(),
485 elements::External::Function(
486 func.read().type_ref.order().ok_or(Error::DetachedEntry)? as u32
487 ),
488 )
489 )
490 },
491 _ => continue,
492 }
493 }
494
495 for global in self.globals.iter() {
496 match global.read().origin {
497 Imported(ref module, ref field) => {
498 imports.push(
499 elements::ImportEntry::new(
500 module.to_owned(),
501 field.to_owned(),
502 elements::External::Global(
503 elements::GlobalType::new(
504 global.read().content,
505 global.read().is_mut,
506 )
507 ),
508 )
509 )
510 },
511 _ => continue,
512 }
513 }
514
515 for memory in self.memory.iter() {
516 match memory.read().origin {
517 Imported(ref module, ref field) => {
518 imports.push(
519 elements::ImportEntry::new(
520 module.to_owned(),
521 field.to_owned(),
522 elements::External::Memory(
523 elements::MemoryType::new(
524 memory.read().limits.initial(),
525 memory.read().limits.maximum(),
526 )
527 ),
528 )
529 )
530 },
531 _ => continue,
532 }
533 }
534
535 for table in self.tables.iter() {
536 match table.read().origin {
537 Imported(ref module, ref field) => {
538 imports.push(
539 elements::ImportEntry::new(
540 module.to_owned(),
541 field.to_owned(),
542 elements::External::Table(
543 elements::TableType::new(
544 table.read().limits.initial(),
545 table.read().limits.maximum(),
546 )
547 ),
548 )
549 )
550 },
551 _ => continue,
552 }
553 }
554 imports.len() > 0
555 };
556
557 if add {
558 sections.push(elements::Section::Import(import_section));
559 idx += 1;
560 custom_round(&self.other, &mut idx, &mut sections);
561 }
562
563 if self.funcs.len() > 0 {
564 let mut func_section = elements::FunctionSection::default();
566 {
567 let funcs = func_section.entries_mut();
568
569 for func in self.funcs.iter() {
570 match func.read().origin {
571 Declared(_) => {
572 funcs.push(elements::Func::new(
573 func.read().type_ref.order().ok_or(Error::DetachedEntry)? as u32
574 ));
575 },
576 _ => continue,
577 }
578 }
579 }
580 sections.push(elements::Section::Function(func_section));
581 idx += 1;
582
583 custom_round(&self.other, &mut idx, &mut sections);
584 }
585
586 if self.tables.len() > 0 {
587 let mut table_section = elements::TableSection::default();
589 {
590 let tables = table_section.entries_mut();
591
592 for table in self.tables.iter() {
593 match table.read().origin {
594 Declared(_) => {
595 tables.push(elements::TableType::new(
596 table.read().limits.initial(),
597 table.read().limits.maximum(),
598 ));
599 },
600 _ => continue,
601 }
602 }
603 }
604 sections.push(elements::Section::Table(table_section));
605 idx += 1;
606
607 custom_round(&self.other, &mut idx, &mut sections);
608 }
609
610 if self.memory.len() > 0 {
611 let mut memory_section = elements::MemorySection::default();
613 {
614 let memories = memory_section.entries_mut();
615
616 for memory in self.memory.iter() {
617 match memory.read().origin {
618 Declared(_) => {
619 memories.push(elements::MemoryType::new(
620 memory.read().limits.initial(),
621 memory.read().limits.maximum(),
622 ));
623 },
624 _ => continue,
625 }
626 }
627 }
628 sections.push(elements::Section::Memory(memory_section));
629 idx += 1;
630
631 custom_round(&self.other, &mut idx, &mut sections);
632 }
633
634 if self.globals.len() > 0 {
635 let mut global_section = elements::GlobalSection::default();
637 {
638 let globals = global_section.entries_mut();
639
640 for global in self.globals.iter() {
641 match global.read().origin {
642 Declared(ref init_code) => {
643 globals.push(elements::GlobalEntry::new(
644 elements::GlobalType::new(global.read().content, global.read().is_mut),
645 elements::InitExpr::new(self.generate_instructions(&init_code[..])),
646 ));
647 },
648 _ => continue,
649 }
650 }
651 }
652 sections.push(elements::Section::Global(global_section));
653 idx += 1;
654
655 custom_round(&self.other, &mut idx, &mut sections);
656 }
657
658 if self.exports.len() > 0 {
659 let mut export_section = elements::ExportSection::default();
661 {
662 let exports = export_section.entries_mut();
663
664 for export in self.exports.iter() {
665 let internal = match export.local {
666 ExportLocal::Func(ref func_ref) => {
667 elements::Internal::Function(func_ref.order().ok_or(Error::DetachedEntry)? as u32)
668 },
669 ExportLocal::Global(ref global_ref) => {
670 elements::Internal::Global(global_ref.order().ok_or(Error::DetachedEntry)? as u32)
671 },
672 ExportLocal::Table(ref table_ref) => {
673 elements::Internal::Table(table_ref.order().ok_or(Error::DetachedEntry)? as u32)
674 },
675 ExportLocal::Memory(ref memory_ref) => {
676 elements::Internal::Memory(memory_ref.order().ok_or(Error::DetachedEntry)? as u32)
677 },
678 };
679
680 exports.push(elements::ExportEntry::new(export.name.to_owned(), internal));
681 }
682 }
683 sections.push(elements::Section::Export(export_section));
684 idx += 1;
685
686 custom_round(&self.other, &mut idx, &mut sections);
687 }
688
689 if let Some(ref func_ref) = self.start {
690 sections.push(elements::Section::Start(
692 func_ref.order().ok_or(Error::DetachedEntry)? as u32
693 ));
694 }
695
696 if self.elements.len() > 0 {
697 let mut element_section = elements::ElementSection::default();
699 {
700 let element_segments = element_section.entries_mut();
701
702 for element in self.elements.iter() {
703 match element.location {
704 SegmentLocation::Default(ref offset_expr) => {
705 let mut elements_map = Vec::new();
706 for f in element.value.iter() {
707 elements_map.push(f.order().ok_or(Error::DetachedEntry)? as u32);
708 }
709
710 element_segments.push(
711 elements::ElementSegment::new(
712 0,
713 Some(elements::InitExpr::new(self.generate_instructions(&offset_expr[..]))),
714 elements_map,
715 )
716 );
717 },
718 _ => unreachable!("Other segment location types are never added"),
719 }
720 }
721 }
722
723 sections.push(elements::Section::Element(element_section));
724 idx += 1;
725
726 custom_round(&self.other, &mut idx, &mut sections);
727 }
728
729 if self.funcs.len() > 0 {
730 let mut code_section = elements::CodeSection::default();
732 {
733 let funcs = code_section.bodies_mut();
734
735 for func in self.funcs.iter() {
736 match func.read().origin {
737 Declared(ref body) => {
738 funcs.push(elements::FuncBody::new(
739 body.locals.clone(),
740 elements::Instructions::new(self.generate_instructions(&body.code[..])),
741 ));
742 },
743 _ => continue,
744 }
745 }
746 }
747 sections.push(elements::Section::Code(code_section));
748 idx += 1;
749
750 custom_round(&self.other, &mut idx, &mut sections);
751 }
752
753
754 if self.data.len() > 0 {
755 let mut data_section = elements::DataSection::default();
757 {
758 let data_segments = data_section.entries_mut();
759
760 for data_entry in self.data.iter() {
761 match data_entry.location {
762 SegmentLocation::Default(ref offset_expr) => {
763 data_segments.push(
764 elements::DataSegment::new(
765 0,
766 Some(elements::InitExpr::new(self.generate_instructions(&offset_expr[..]))),
767 data_entry.value.clone(),
768 )
769 );
770 },
771 _ => unreachable!("Other segment location types are never added"),
772 }
773 }
774 }
775
776 sections.push(elements::Section::Data(data_section));
777 idx += 1;
778
779 custom_round(&self.other, &mut idx, &mut sections);
780 }
781
782 Ok(elements::Module::new(sections))
783 }
784}
785
786fn custom_round(
787 map: &BTreeMap<usize, elements::Section>,
788 idx: &mut usize,
789 sections: &mut Vec<elements::Section>,
790) {
791 while let Some(other_section) = map.get(&idx) {
792 sections.push(other_section.clone());
793 *idx += 1;
794 }
795}
796
797pub fn parse(wasm: &[u8]) -> Result<Module, Error> {
799 Module::from_elements(&::parity_wasm::deserialize_buffer(wasm).map_err(Error::Format)?)
800}
801
802pub fn generate(f: &Module) -> Result<Vec<u8>, Error> {
804 let pm = f.generate()?;
805 ::parity_wasm::serialize(pm).map_err(Error::Format)
806}
807
808#[cfg(test)]
809mod tests {
810
811 use indoc::indoc;
812
813 use parity_wasm::elements;
814
815 fn load_sample(wat: &'static str) -> super::Module {
816 super::parse(&wabt::wat2wasm(wat).expect("faled to parse wat!")[..])
817 .expect("error making representation")
818 }
819
820 fn validate_sample(module: &super::Module) {
821 let binary = super::generate(module).expect("Failed to generate binary");
822 wabt::Module::read_binary(&binary, &Default::default())
823 .expect("Wabt failed to read final binary")
824 .validate()
825 .expect("Invalid module");
826 }
827
828 #[test]
829 fn smoky() {
830 let sample = load_sample(indoc!(r#"
831 (module
832 (type (func))
833 (func (type 0))
834 (memory 0 1)
835 (export "simple" (func 0)))"#
836 ));
837
838 assert_eq!(sample.types.len(), 1);
839 assert_eq!(sample.funcs.len(), 1);
840 assert_eq!(sample.tables.len(), 0);
841 assert_eq!(sample.memory.len(), 1);
842 assert_eq!(sample.exports.len(), 1);
843
844 assert_eq!(sample.types.get_ref(0).link_count(), 1);
845 assert_eq!(sample.funcs.get_ref(0).link_count(), 1);
846 }
847
848 #[test]
849 fn table() {
850 let mut sample = load_sample(indoc!(r#"
851 (module
852 (import "env" "foo" (func $foo))
853 (func (param i32)
854 get_local 0
855 i32.const 0
856 call $i32.add
857 drop
858 )
859 (func $i32.add (export "i32.add") (param i32 i32) (result i32)
860 get_local 0
861 get_local 1
862 i32.add
863 )
864 (table 10 anyfunc)
865
866 ;; Refer all types of functions: imported, defined not exported and defined exported.
867 (elem (i32.const 0) 0 1 2)
868 )"#
869 ));
870
871 {
872 let element_func = &sample.elements[0].value[1];
873 let rfunc = element_func.read();
874 let rtype = &**rfunc.type_ref.read();
875 let elements::Type::Function(ref ftype) = rtype;
876
877 assert_eq!(rfunc.order(), Some(1));
879 assert_eq!(ftype.params().len(), 1);
881 }
882
883 sample.funcs.begin_delete().push(0).done();
884
885 {
886 let element_func = &sample.elements[0].value[1];
887 let rfunc = element_func.read();
888 let rtype = &**rfunc.type_ref.read();
889 let elements::Type::Function(ref ftype) = rtype;
890
891 assert_eq!(rfunc.order(), Some(0));
893 assert_eq!(ftype.params().len(), 1);
895 }
896 }
897
898 #[test]
899 fn new_import() {
900 let mut sample = load_sample(indoc!(r#"
901 (module
902 (type (;0;) (func))
903 (type (;1;) (func (param i32 i32) (result i32)))
904 (import "env" "foo" (func (type 1)))
905 (func (param i32)
906 get_local 0
907 i32.const 0
908 call 0
909 drop
910 )
911 (func (type 0)
912 i32.const 0
913 call 1
914 )
915 )"#
916 ));
917
918 {
919 let type_ref_0 = sample.types.clone_ref(0);
920 let declared_func_2 = sample.funcs.clone_ref(2);
921
922 let mut tx = sample.funcs.begin_insert_not_until(
923 |f| match f.origin {
924 super::ImportedOrDeclared::Imported(_, _) => true,
925 _ => false,
926 }
927 );
928
929 let new_import_func = tx.push(super::Func {
930 type_ref: type_ref_0,
931 origin: super::ImportedOrDeclared::Imported("env".to_owned(), "bar".to_owned()),
932 });
933
934 tx.done();
935
936 assert_eq!(new_import_func.order(), Some(1));
937 assert_eq!(declared_func_2.order(), Some(3));
938 assert_eq!(
939 match &declared_func_2.read().origin {
940 super::ImportedOrDeclared::Declared(ref body) => {
941 match body.code[1] {
942 super::Instruction::Call(ref called_func) => called_func.order(),
943 _ => panic!("instruction #2 should be a call!"),
944 }
945 },
946 _ => panic!("func #3 should be declared!"),
947 },
948 Some(2),
949 "Call should be recalculated to 2"
950 );
951 }
952
953 validate_sample(&sample);
954 }
955
956 #[test]
957 fn simple_opt() {
958 let mut sample = load_sample(indoc!(r#"
959 (module
960 (type (;0;) (func))
961 (type (;1;) (func (param i32 i32) (result i32)))
962 (type (;2;) (func (param i32 i32) (result i32)))
963 (type (;3;) (func (param i32 i32) (result i32)))
964 (import "env" "foo" (func (type 1)))
965 (import "env" "foo2" (func (type 2)))
966 (import "env" "foo3" (func (type 3)))
967 (func (type 0)
968 i32.const 1
969 i32.const 1
970 call 0
971 drop
972 )
973 (func (type 0)
974 i32.const 2
975 i32.const 2
976 call 1
977 drop
978 )
979 (func (type 0)
980 i32.const 3
981 i32.const 3
982 call 2
983 drop
984 )
985 (func (type 0)
986 call 3
987 )
988 )"#
989 ));
990
991 validate_sample(&sample);
992
993 sample.funcs.begin_delete().push(4).push(5).done();
996 validate_sample(&sample);
997
998 sample.funcs.begin_delete().push(1).push(2).done();
1001 validate_sample(&sample);
1002
1003 let declared_func_2 = sample.funcs.clone_ref(2);
1005 assert_eq!(
1006 match &declared_func_2.read().origin {
1007 super::ImportedOrDeclared::Declared(ref body) => {
1008 match body.code[0] {
1009 super::Instruction::Call(ref called_func) => called_func.order(),
1010 ref wrong_instruction => panic!("instruction #2 should be a call but got {:?}!", wrong_instruction),
1011 }
1012 },
1013 _ => panic!("func #0 should be declared!"),
1014 },
1015 Some(1),
1016 "Call should be recalculated to 1"
1017 );
1018 }
1019}