twasm_utils/
build.rs

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		// 49152 is 48kb!
77		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}