1#![warn(missing_docs)]
4
5use xwasm::elements;
6use super::ref_list::{RefList, EntryRef};
7use 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 xwasm::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 xwasm::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 idx = 0;
242 let mut res = Module::default();
243
244 let mut imported_functions = 0;
245
246 for section in module.sections() {
247 match section {
248 elements::Section::Type(type_section) => {
249 res.types = RefList::from_slice(type_section.types());
250 },
251 elements::Section::Import(import_section) => {
252 for entry in import_section.entries() {
253 match *entry.external() {
254 elements::External::Function(f) => {
255 res.funcs.push(Func {
256 type_ref: res.types.get(f as usize).ok_or(Error::InconsistentSource)?.clone(),
257 origin: entry.into(),
258 });
259 imported_functions += 1;
260 },
261 elements::External::Memory(m) => {
262 res.memory.push(Memory {
263 limits: m.limits().clone(),
264 origin: entry.into(),
265 });
266 },
267 elements::External::Global(g) => {
268 res.globals.push(Global {
269 content: g.content_type(),
270 is_mut: g.is_mutable(),
271 origin: entry.into(),
272 });
273 },
274 elements::External::Table(t) => {
275 res.tables.push(Table {
276 limits: t.limits().clone(),
277 origin: entry.into(),
278 });
279 },
280 };
281 }
282 },
283 elements::Section::Function(function_section) => {
284 for f in function_section.entries() {
285 res.funcs.push(Func {
286 type_ref: res.types.get(f.type_ref() as usize)
287 .ok_or(Error::InconsistentSource)?.clone(),
288 origin: ImportedOrDeclared::Declared(FuncBody {
289 locals: Vec::new(),
290 code: Vec::new(),
292 }),
293 });
294 };
295 },
296 elements::Section::Table(table_section) => {
297 for t in table_section.entries() {
298 res.tables.push(Table {
299 limits: t.limits().clone(),
300 origin: ImportedOrDeclared::Declared(()),
301 });
302 }
303 },
304 elements::Section::Memory(table_section) => {
305 for t in table_section.entries() {
306 res.memory.push(Memory {
307 limits: t.limits().clone(),
308 origin: ImportedOrDeclared::Declared(()),
309 });
310 }
311 },
312 elements::Section::Global(global_section) => {
313 for g in global_section.entries() {
314 let init_code = res.map_instructions(g.init_expr().code());
315 res.globals.push(Global {
316 content: g.global_type().content_type(),
317 is_mut: g.global_type().is_mutable(),
318 origin: ImportedOrDeclared::Declared(init_code),
319 });
320 }
321 },
322 elements::Section::Export(export_section) => {
323 for e in export_section.entries() {
324 let local = match e.internal() {
325 &elements::Internal::Function(func_idx) => {
326 ExportLocal::Func(res.funcs.clone_ref(func_idx as usize))
327 },
328 &elements::Internal::Global(global_idx) => {
329 ExportLocal::Global(res.globals.clone_ref(global_idx as usize))
330 },
331 &elements::Internal::Memory(mem_idx) => {
332 ExportLocal::Memory(res.memory.clone_ref(mem_idx as usize))
333 },
334 &elements::Internal::Table(table_idx) => {
335 ExportLocal::Table(res.tables.clone_ref(table_idx as usize))
336 },
337 };
338
339 res.exports.push(Export { local: local, name: e.field().to_owned() })
340 }
341 },
342 elements::Section::Start(start_func) => {
343 res.start = Some(res.funcs.clone_ref(*start_func as usize));
344 },
345 elements::Section::Element(element_section) => {
346 for element_segment in element_section.entries() {
347
348 let location = SegmentLocation::Default(
358 res.map_instructions(element_segment.offset().code())
359 );
360
361 let funcs_map = element_segment
362 .members().iter()
363 .map(|idx| res.funcs.clone_ref(*idx as usize))
364 .collect::<Vec<EntryRef<Func>>>();
365
366 res.elements.push(ElementSegment {
367 value: funcs_map,
368 location: location,
369 });
370 }
371 },
372 elements::Section::Code(code_section) => {
373 let mut idx = 0;
374 for func_body in code_section.bodies() {
375 let code = res.map_instructions(func_body.code().elements());
376
377 let mut func = res.funcs.get_ref(imported_functions + idx).write();
378 match func.origin {
379 ImportedOrDeclared::Declared(ref mut body) => {
380 body.code = code;
381 body.locals = func_body.locals().iter().cloned().collect();
382 },
383 _ => { return Err(Error::InconsistentSource); }
384 }
385
386 idx += 1;
387 }
388 },
389 elements::Section::Data(data_section) => {
390 for data_segment in data_section.entries() {
391 let location = SegmentLocation::Default(
394 res.map_instructions(data_segment.offset().code())
395 );
396
397 res.data.push(DataSegment {
398 value: data_segment.value().to_vec(),
399 location: location,
400 });
401 }
402 },
403 _ => {
404 res.other.insert(idx, section.clone());
405 }
406 }
407 idx += 1;
408 }
409
410 Ok(res)
411 }
412
413 pub fn generate(&self) -> Result<elements::Module, Error> {
415 use self::ImportedOrDeclared::*;
416
417 let mut idx = 0;
418 let mut sections = Vec::new();
419
420 custom_round(&self.other, &mut idx, &mut sections);
421
422 if self.types.len() > 0 {
423 let mut type_section = elements::TypeSection::default();
425 {
426 let types = type_section.types_mut();
427
428 for type_entry in self.types.iter() {
429 types.push(type_entry.read().clone())
430 }
431 }
432 sections.push(elements::Section::Type(type_section));
433 idx += 1;
434
435 custom_round(&self.other, &mut idx, &mut sections);
436 }
437
438 let mut import_section = elements::ImportSection::default();
440
441 let add = {
442 let imports = import_section.entries_mut();
443 for func in self.funcs.iter() {
444 match func.read().origin {
445 Imported(ref module, ref field) => {
446 imports.push(
447 elements::ImportEntry::new(
448 module.to_owned(),
449 field.to_owned(),
450 elements::External::Function(
451 func.read().type_ref.order().ok_or(Error::DetachedEntry)? as u32
452 ),
453 )
454 )
455 },
456 _ => continue,
457 }
458 }
459
460 for global in self.globals.iter() {
461 match global.read().origin {
462 Imported(ref module, ref field) => {
463 imports.push(
464 elements::ImportEntry::new(
465 module.to_owned(),
466 field.to_owned(),
467 elements::External::Global(
468 elements::GlobalType::new(
469 global.read().content,
470 global.read().is_mut,
471 )
472 ),
473 )
474 )
475 },
476 _ => continue,
477 }
478 }
479
480 for memory in self.memory.iter() {
481 match memory.read().origin {
482 Imported(ref module, ref field) => {
483 imports.push(
484 elements::ImportEntry::new(
485 module.to_owned(),
486 field.to_owned(),
487 elements::External::Memory(
488 elements::MemoryType::new(
489 memory.read().limits.initial(),
490 memory.read().limits.maximum(),
491 )
492 ),
493 )
494 )
495 },
496 _ => continue,
497 }
498 }
499
500 for table in self.tables.iter() {
501 match table.read().origin {
502 Imported(ref module, ref field) => {
503 imports.push(
504 elements::ImportEntry::new(
505 module.to_owned(),
506 field.to_owned(),
507 elements::External::Table(
508 elements::TableType::new(
509 table.read().limits.initial(),
510 table.read().limits.maximum(),
511 )
512 ),
513 )
514 )
515 },
516 _ => continue,
517 }
518 }
519 imports.len() > 0
520 };
521
522 if add {
523 sections.push(elements::Section::Import(import_section));
524 idx += 1;
525 custom_round(&self.other, &mut idx, &mut sections);
526 }
527
528 if self.funcs.len() > 0 {
529 let mut func_section = elements::FunctionSection::default();
531 {
532 let funcs = func_section.entries_mut();
533
534 for func in self.funcs.iter() {
535 match func.read().origin {
536 Declared(_) => {
537 funcs.push(elements::Func::new(
538 func.read().type_ref.order().ok_or(Error::DetachedEntry)? as u32
539 ));
540 },
541 _ => continue,
542 }
543 }
544 }
545 sections.push(elements::Section::Function(func_section));
546 idx += 1;
547
548 custom_round(&self.other, &mut idx, &mut sections);
549 }
550
551 if self.tables.len() > 0 {
552 let mut table_section = elements::TableSection::default();
554 {
555 let tables = table_section.entries_mut();
556
557 for table in self.tables.iter() {
558 match table.read().origin {
559 Declared(_) => {
560 tables.push(elements::TableType::new(
561 table.read().limits.initial(),
562 table.read().limits.maximum(),
563 ));
564 },
565 _ => continue,
566 }
567 }
568 }
569 sections.push(elements::Section::Table(table_section));
570 idx += 1;
571
572 custom_round(&self.other, &mut idx, &mut sections);
573 }
574
575 if self.memory.len() > 0 {
576 let mut memory_section = elements::MemorySection::default();
578 {
579 let memories = memory_section.entries_mut();
580
581 for memory in self.memory.iter() {
582 match memory.read().origin {
583 Declared(_) => {
584 memories.push(elements::MemoryType::new(
585 memory.read().limits.initial(),
586 memory.read().limits.maximum(),
587 ));
588 },
589 _ => continue,
590 }
591 }
592 }
593 sections.push(elements::Section::Memory(memory_section));
594 idx += 1;
595
596 custom_round(&self.other, &mut idx, &mut sections);
597 }
598
599 if self.globals.len() > 0 {
600 let mut global_section = elements::GlobalSection::default();
602 {
603 let globals = global_section.entries_mut();
604
605 for global in self.globals.iter() {
606 match global.read().origin {
607 Declared(ref init_code) => {
608 globals.push(elements::GlobalEntry::new(
609 elements::GlobalType::new(global.read().content, global.read().is_mut),
610 elements::InitExpr::new(self.generate_instructions(&init_code[..])),
611 ));
612 },
613 _ => continue,
614 }
615 }
616 }
617 sections.push(elements::Section::Global(global_section));
618 idx += 1;
619
620 custom_round(&self.other, &mut idx, &mut sections);
621 }
622
623 if self.exports.len() > 0 {
624 let mut export_section = elements::ExportSection::default();
626 {
627 let exports = export_section.entries_mut();
628
629 for export in self.exports.iter() {
630 let internal = match export.local {
631 ExportLocal::Func(ref func_ref) => {
632 elements::Internal::Function(func_ref.order().ok_or(Error::DetachedEntry)? as u32)
633 },
634 ExportLocal::Global(ref global_ref) => {
635 elements::Internal::Global(global_ref.order().ok_or(Error::DetachedEntry)? as u32)
636 },
637 ExportLocal::Table(ref table_ref) => {
638 elements::Internal::Table(table_ref.order().ok_or(Error::DetachedEntry)? as u32)
639 },
640 ExportLocal::Memory(ref memory_ref) => {
641 elements::Internal::Memory(memory_ref.order().ok_or(Error::DetachedEntry)? as u32)
642 },
643 };
644
645 exports.push(elements::ExportEntry::new(export.name.to_owned(), internal));
646 }
647 }
648 sections.push(elements::Section::Export(export_section));
649 idx += 1;
650
651 custom_round(&self.other, &mut idx, &mut sections);
652 }
653
654 if let Some(ref func_ref) = self.start {
655 sections.push(elements::Section::Start(
657 func_ref.order().ok_or(Error::DetachedEntry)? as u32
658 ));
659 }
660
661 if self.elements.len() > 0 {
662 let mut element_section = elements::ElementSection::default();
664 {
665 let element_segments = element_section.entries_mut();
666
667 for element in self.elements.iter() {
668 match element.location {
669 SegmentLocation::Default(ref offset_expr) => {
670 let mut elements_map = Vec::new();
671 for f in element.value.iter() {
672 elements_map.push(f.order().ok_or(Error::DetachedEntry)? as u32);
673 }
674
675 element_segments.push(
676 elements::ElementSegment::new(
677 0,
678 elements::InitExpr::new(self.generate_instructions(&offset_expr[..])),
679 elements_map,
680 )
681 );
682 },
683 _ => unreachable!("Other segment location types are never added"),
684 }
685 }
686 }
687
688 sections.push(elements::Section::Element(element_section));
689 idx += 1;
690
691 custom_round(&self.other, &mut idx, &mut sections);
692 }
693
694 if self.funcs.len() > 0 {
695 let mut code_section = elements::CodeSection::default();
697 {
698 let funcs = code_section.bodies_mut();
699
700 for func in self.funcs.iter() {
701 match func.read().origin {
702 Declared(ref body) => {
703 funcs.push(elements::FuncBody::new(
704 body.locals.clone(),
705 elements::Instructions::new(self.generate_instructions(&body.code[..])),
706 ));
707 },
708 _ => continue,
709 }
710 }
711 }
712 sections.push(elements::Section::Code(code_section));
713 idx += 1;
714
715 custom_round(&self.other, &mut idx, &mut sections);
716 }
717
718
719 if self.data.len() > 0 {
720 let mut data_section = elements::DataSection::default();
722 {
723 let data_segments = data_section.entries_mut();
724
725 for data_entry in self.data.iter() {
726 match data_entry.location {
727 SegmentLocation::Default(ref offset_expr) => {
728 data_segments.push(
729 elements::DataSegment::new(
730 0,
731 elements::InitExpr::new(self.generate_instructions(&offset_expr[..])),
732 data_entry.value.clone(),
733 )
734 );
735 },
736 _ => unreachable!("Other segment location types are never added"),
737 }
738 }
739 }
740
741 sections.push(elements::Section::Data(data_section));
742 idx += 1;
743
744 custom_round(&self.other, &mut idx, &mut sections);
745 }
746
747 Ok(elements::Module::new(sections))
748 }
749}
750
751fn custom_round(
752 map: &BTreeMap<usize, elements::Section>,
753 idx: &mut usize,
754 sections: &mut Vec<elements::Section>,
755) {
756 while let Some(other_section) = map.get(&idx) {
757 sections.push(other_section.clone());
758 *idx += 1;
759 }
760}
761
762pub fn parse(xwasm: &[u8]) -> Result<Module, Error> {
764 Module::from_elements(&::xwasm::deserialize_buffer(xwasm).map_err(Error::Format)?)
765}
766
767pub fn generate(f: &Module) -> Result<Vec<u8>, Error> {
769 let pm = f.generate()?;
770 ::xwasm::serialize(pm).map_err(Error::Format)
771}
772
773#[cfg(test)]
774mod tests {
775
776 extern crate wabt;
777
778 use xwasm::elements;
779
780 fn load_sample(wat: &'static str) -> super::Module {
781 super::parse(&wabt::wat2xwasm(wat).expect("faled to parse wat!")[..])
782 .expect("error making representation")
783 }
784
785 fn validate_sample(module: &super::Module) {
786 let binary = super::generate(module).expect("Failed to generate binary");
787 wabt::Module::read_binary(&binary, &Default::default())
788 .expect("Wabt failed to read final binary")
789 .validate()
790 .expect("Invalid module");
791 }
792
793 #[test]
794 fn smoky() {
795 let sample = load_sample(indoc!(r#"
796 (module
797 (type (func))
798 (func (type 0))
799 (memory 0 1)
800 (export "simple" (func 0)))"#
801 ));
802
803 assert_eq!(sample.types.len(), 1);
804 assert_eq!(sample.funcs.len(), 1);
805 assert_eq!(sample.tables.len(), 0);
806 assert_eq!(sample.memory.len(), 1);
807 assert_eq!(sample.exports.len(), 1);
808
809 assert_eq!(sample.types.get_ref(0).link_count(), 1);
810 assert_eq!(sample.funcs.get_ref(0).link_count(), 1);
811 }
812
813 #[test]
814 fn table() {
815 let mut sample = load_sample(indoc!(r#"
816 (module
817 (import "env" "foo" (func $foo))
818 (func (param i32)
819 get_local 0
820 i32.const 0
821 call $i32.add
822 drop
823 )
824 (func $i32.add (export "i32.add") (param i32 i32) (result i32)
825 get_local 0
826 get_local 1
827 i32.add
828 )
829 (table 10 anyfunc)
830
831 ;; Refer all types of functions: imported, defined not exported and defined exported.
832 (elem (i32.const 0) 0 1 2)
833 )"#
834 ));
835
836 {
837 let element_func = &sample.elements[0].value[1];
838 let rfunc = element_func.read();
839 let rtype = &**rfunc.type_ref.read();
840 let elements::Type::Function(ref ftype) = rtype;
841
842 assert_eq!(rfunc.order(), Some(1));
844 assert_eq!(ftype.params().len(), 1);
846 }
847
848 sample.funcs.begin_delete().push(0).done();
849
850 {
851 let element_func = &sample.elements[0].value[1];
852 let rfunc = element_func.read();
853 let rtype = &**rfunc.type_ref.read();
854 let elements::Type::Function(ref ftype) = rtype;
855
856 assert_eq!(rfunc.order(), Some(0));
858 assert_eq!(ftype.params().len(), 1);
860 }
861 }
862
863 #[test]
864 fn new_import() {
865 let mut sample = load_sample(indoc!(r#"
866 (module
867 (type (;0;) (func))
868 (type (;1;) (func (param i32 i32) (result i32)))
869 (import "env" "foo" (func (type 1)))
870 (func (param i32)
871 get_local 0
872 i32.const 0
873 call 0
874 drop
875 )
876 (func (type 0)
877 i32.const 0
878 call 1
879 )
880 )"#
881 ));
882
883 {
884 let type_ref_0 = sample.types.clone_ref(0);
885 let declared_func_2 = sample.funcs.clone_ref(2);
886
887 let mut tx = sample.funcs.begin_insert_not_until(
888 |f| match f.origin {
889 super::ImportedOrDeclared::Imported(_, _) => true,
890 _ => false,
891 }
892 );
893
894 let new_import_func = tx.push(super::Func {
895 type_ref: type_ref_0,
896 origin: super::ImportedOrDeclared::Imported("env".to_owned(), "bar".to_owned()),
897 });
898
899 tx.done();
900
901 assert_eq!(new_import_func.order(), Some(1));
902 assert_eq!(declared_func_2.order(), Some(3));
903 assert_eq!(
904 match &declared_func_2.read().origin {
905 super::ImportedOrDeclared::Declared(ref body) => {
906 match body.code[1] {
907 super::Instruction::Call(ref called_func) => called_func.order(),
908 _ => panic!("instruction #2 should be a call!"),
909 }
910 },
911 _ => panic!("func #3 should be declared!"),
912 },
913 Some(2),
914 "Call should be recalculated to 2"
915 );
916 }
917
918 validate_sample(&sample);
919 }
920
921 #[test]
922 fn simple_opt() {
923 let mut sample = load_sample(indoc!(r#"
924 (module
925 (type (;0;) (func))
926 (type (;1;) (func (param i32 i32) (result i32)))
927 (type (;2;) (func (param i32 i32) (result i32)))
928 (type (;3;) (func (param i32 i32) (result i32)))
929 (import "env" "foo" (func (type 1)))
930 (import "env" "foo2" (func (type 2)))
931 (import "env" "foo3" (func (type 3)))
932 (func (type 0)
933 i32.const 1
934 i32.const 1
935 call 0
936 drop
937 )
938 (func (type 0)
939 i32.const 2
940 i32.const 2
941 call 1
942 drop
943 )
944 (func (type 0)
945 i32.const 3
946 i32.const 3
947 call 2
948 drop
949 )
950 (func (type 0)
951 call 3
952 )
953 )"#
954 ));
955
956 validate_sample(&sample);
957
958 sample.funcs.begin_delete().push(4).push(5).done();
961 validate_sample(&sample);
962
963 sample.funcs.begin_delete().push(1).push(2).done();
966 validate_sample(&sample);
967
968 let declared_func_2 = sample.funcs.clone_ref(2);
970 assert_eq!(
971 match &declared_func_2.read().origin {
972 super::ImportedOrDeclared::Declared(ref body) => {
973 match body.code[0] {
974 super::Instruction::Call(ref called_func) => called_func.order(),
975 ref wrong_instruction => panic!("instruction #2 should be a call but got {:?}!", wrong_instruction),
976 }
977 },
978 _ => panic!("func #0 should be declared!"),
979 },
980 Some(1),
981 "Call should be recalculated to 1"
982 );
983 }
984}