owasm_utils/
build.rs

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