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