1use super::{
2 optimize,
3 pack_instance,
4 ununderscore_funcs,
5 externalize_mem,
6 shrink_unknown_stack,
7 inject_runtime_type,
8 PackingError,
9 OptimizerError,
10 TargetRuntime,
11 std::fmt,
12};
13use tetsy_wasm::elements;
14
15#[derive(Debug)]
16pub enum Error {
17 Encoding(elements::Error),
18 Packing(PackingError),
19 Optimizer,
20}
21
22impl From<OptimizerError> for Error {
23 fn from(_err: OptimizerError) -> Self {
24 Error::Optimizer
25 }
26}
27
28impl From<PackingError> for Error {
29 fn from(err: PackingError) -> Self {
30 Error::Packing(err)
31 }
32}
33
34#[derive(Debug, Clone, Copy)]
35pub enum SourceTarget {
36 Emscripten,
37 Unknown,
38}
39
40impl fmt::Display for Error {
41 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
42 use self::Error::*;
43 match self {
44 Encoding(err) => write!(f, "Encoding error ({})", err),
45 Optimizer => write!(f, "Optimization error due to missing export section. Pointed wrong file?"),
46 Packing(e) => write!(f, "Packing failed due to module structure error: {}. Sure used correct libraries for building contracts?", e),
47 }
48 }
49}
50
51fn has_ctor(module: &elements::Module, target_runtime: &TargetRuntime) -> bool {
52 if let Some(section) = module.export_section() {
53 section.entries().iter().any(|e| target_runtime.symbols().create == e.field())
54 } else {
55 false
56 }
57}
58
59#[allow(clippy::too_many_arguments)]
60pub fn build(
61 mut module: elements::Module,
62 source_target: SourceTarget,
63 runtime_type_version: Option<([u8; 4], u32)>,
64 public_api_entries: &[&str],
65 enforce_stack_adjustment: bool,
66 stack_size: u32,
67 skip_optimization: bool,
68 target_runtime: &TargetRuntime,
69) -> Result<(elements::Module, Option<elements::Module>), Error> {
70
71 if let SourceTarget::Emscripten = source_target {
72 module = ununderscore_funcs(module);
73 }
74
75 if let SourceTarget::Unknown = source_target {
76 if enforce_stack_adjustment {
78 assert!(stack_size <= 1024*1024);
79 let (new_module, new_stack_top) = shrink_unknown_stack(module, 1024 * 1024 - stack_size);
80 module = new_module;
81 let mut stack_top_page = new_stack_top / 65536;
82 if new_stack_top % 65536 > 0 { stack_top_page += 1 };
83 module = externalize_mem(module, Some(stack_top_page), 16);
84 } else {
85 module = externalize_mem(module, None, 16);
86 }
87 }
88
89 if let Some(runtime_type_version) = runtime_type_version {
90 let (runtime_type, runtime_version) = runtime_type_version;
91 module = inject_runtime_type(module, runtime_type, runtime_version);
92 }
93
94 let mut ctor_module = module.clone();
95
96 let mut public_api_entries = public_api_entries.to_vec();
97 public_api_entries.push(target_runtime.symbols().call);
98 if !skip_optimization {
99 optimize(&mut module, public_api_entries)?;
100 }
101
102 if !has_ctor(&ctor_module, target_runtime) {
103 return Ok((module, None))
104 }
105
106 if !skip_optimization {
107 let preserved_exports = match target_runtime {
108 TargetRuntime::TWasm(_) => vec![target_runtime.symbols().create],
109 TargetRuntime::Tetcore(_) => vec![target_runtime.symbols().call, target_runtime.symbols().create],
110 };
111 optimize(&mut ctor_module, preserved_exports)?;
112 }
113
114 if let TargetRuntime::TWasm(_) = target_runtime {
115 ctor_module = pack_instance(
116 tetsy_wasm::serialize(module.clone()).map_err(Error::Encoding)?,
117 ctor_module.clone(),
118 target_runtime,
119 )?;
120 }
121
122 Ok((module, Some(ctor_module)))
123}