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}