1use std::fmt;
2use std::vec::Vec;
3use std::borrow::ToOwned;
4
5use parity_wasm::elements::{
6 self, Section, DataSection, Instruction, DataSegment, InitExpr, Internal, External,
7 ImportCountType,
8};
9use parity_wasm::builder;
10use super::TargetRuntime;
11use super::gas::update_call_index;
12
13#[derive(Debug)]
18pub enum Error {
19 MalformedModule,
20 NoTypeSection,
21 NoExportSection,
22 NoCodeSection,
23 InvalidCreateSignature(&'static str),
24 NoCreateSymbol(&'static str),
25 InvalidCreateMember(&'static str),
26 NoImportSection,
27}
28
29impl fmt::Display for Error {
30 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
31 match *self {
32 Error::MalformedModule => write!(f, "Module internal references are inconsistent"),
33 Error::NoTypeSection => write!(f, "No type section in the module"),
34 Error::NoExportSection => write!(f, "No export section in the module"),
35 Error::NoCodeSection => write!(f, "No code section inthe module"),
36 Error::InvalidCreateSignature(sym) => write!(f, "Exported symbol `{}` has invalid signature, should be () -> ()", sym),
37 Error::InvalidCreateMember(sym) => write!(f, "Exported symbol `{}` should be a function", sym),
38 Error::NoCreateSymbol(sym) => write!(f, "No exported `{}` symbol", sym),
39 Error::NoImportSection => write!(f, "No import section in the module"),
40 }
41 }
42}
43
44pub fn pack_instance(raw_module: Vec<u8>, mut ctor_module: elements::Module, target: &TargetRuntime) -> Result<elements::Module, Error> {
48
49 let ctor_import_functions = ctor_module.import_section().map(|x| x.functions()).unwrap_or(0);
51
52 let mut create_func_id = {
55 let found_entry = ctor_module.export_section().ok_or(Error::NoExportSection)?.entries().iter()
56 .find(|entry| target.create_symbol == entry.field()).ok_or_else(|| Error::NoCreateSymbol(target.create_symbol))?;
57
58 let function_index: usize = match found_entry.internal() {
59 &Internal::Function(index) => index as usize,
60 _ => { return Err(Error::InvalidCreateMember(target.create_symbol)) },
61 };
62
63 let function_internal_index = function_index - ctor_import_functions;
65
66 let type_id = ctor_module.function_section().ok_or(Error::NoCodeSection)?
68 .entries().get(function_index - ctor_import_functions).ok_or(Error::MalformedModule)?
69 .type_ref();
70
71 let &elements::Type::Function(ref func) = ctor_module.type_section().ok_or(Error::NoTypeSection)?
72 .types().get(type_id as usize).ok_or(Error::MalformedModule)?;
73
74 if !func.params().is_empty() {
76 return Err(Error::InvalidCreateSignature(target.create_symbol));
77 }
78 if func.return_type().is_some() {
79 return Err(Error::InvalidCreateSignature(target.create_symbol));
80 }
81
82 function_internal_index
83 };
84
85 let ret_function_id = {
86 let mut id = 0;
87 let mut found = false;
88 for entry in ctor_module.import_section().ok_or(Error::NoImportSection)?.entries().iter() {
89 if let External::Function(_) = *entry.external() {
90 if entry.field() == target.return_symbol { found = true; break; }
91 else { id += 1; }
92 }
93 }
94 if !found {
95 let mut mbuilder = builder::from_module(ctor_module);
96 let import_sig = mbuilder.push_signature(
97 builder::signature()
98 .param().i32().param().i32()
99 .build_sig()
100 );
101
102 mbuilder.push_import(
103 builder::import()
104 .module("env")
105 .field(&target.return_symbol)
106 .external().func(import_sig)
107 .build()
108 );
109
110 ctor_module = mbuilder.build();
111
112 let ret_func = ctor_module.import_count(ImportCountType::Function) as u32 - 1;
113
114 for section in ctor_module.sections_mut() {
115 match *section {
116 elements::Section::Code(ref mut code_section) => {
117 for ref mut func_body in code_section.bodies_mut() {
118 update_call_index(func_body.code_mut(), ret_func);
119 }
120 },
121 elements::Section::Export(ref mut export_section) => {
122 for ref mut export in export_section.entries_mut() {
123 if let &mut elements::Internal::Function(ref mut func_index) = export.internal_mut() {
124 if *func_index >= ret_func { *func_index += 1}
125 }
126 }
127 },
128 elements::Section::Element(ref mut elements_section) => {
129 for ref mut segment in elements_section.entries_mut() {
130 for func_index in segment.members_mut() {
132 if *func_index >= ret_func { *func_index += 1}
133 }
134 }
135 },
136 _ => { }
137 }
138 }
139
140 create_func_id += 1;
141 ret_func
142 }
143 else { id }
144 };
145
146 let last_function_index = ctor_module.functions_space();
148
149 if ctor_module
151 .sections()
152 .iter()
153 .find(|section| match **section { Section::Data(ref _d) => true, _ => false })
154 .is_none() {
155 ctor_module.sections_mut().push(Section::Data(DataSection::with_entries(vec![])));
157 }
158
159 let mut code_data_address = 0i32;
161
162 for section in ctor_module.sections_mut() {
163 if let &mut Section::Data(ref mut data_section) = section {
164 let (index, offset) = if let Some(ref entry) = data_section.entries().iter().last() {
165 if let Instruction::I32Const(offst) = entry.offset().code()[0] {
166 let len = entry.value().len() as i32;
167 let offst = offst as i32;
168 (entry.index(), offst + (len + 4) - len % 4)
169 } else {
170 (0, 0)
171 }
172 } else {
173 (0, 0)
174 };
175 let code_data = DataSegment::new(
176 index,
177 InitExpr::new(vec![Instruction::I32Const(offset), Instruction::End]),
178 raw_module.clone()
179 );
180 data_section.entries_mut().push(code_data);
181 code_data_address = offset;
182 }
183 }
184
185 let mut new_module = builder::from_module(ctor_module)
186 .function()
187 .signature().build()
188 .body().with_instructions(elements::Instructions::new(
189 vec![
190 Instruction::Call((create_func_id + ctor_import_functions) as u32),
191 Instruction::I32Const(code_data_address),
192 Instruction::I32Const(raw_module.len() as i32),
193 Instruction::Call(ret_function_id as u32),
194 Instruction::End,
195 ])).build()
196 .build()
197 .build();
198
199 for section in new_module.sections_mut() {
200 if let &mut Section::Export(ref mut export_section) = section {
201 for entry in export_section.entries_mut().iter_mut() {
202 if target.create_symbol == entry.field() {
203 *entry.field_mut() = target.call_symbol.to_owned();
205 *entry.internal_mut() = elements::Internal::Function(last_function_index as u32);
206 }
207 }
208 }
209 };
210
211 Ok(new_module)
212}
213
214#[cfg(test)]
215mod test {
216 extern crate parity_wasm;
217
218 use parity_wasm::builder;
219 use super::*;
220 use super::super::optimize;
221
222 fn test_packer(mut module: elements::Module, target_runtime: &TargetRuntime) {
223 let mut ctor_module = module.clone();
224 optimize(&mut module, vec![target_runtime.call_symbol]).expect("Optimizer to finish without errors");
225 optimize(&mut ctor_module, vec![target_runtime.create_symbol]).expect("Optimizer to finish without errors");
226
227 let raw_module = parity_wasm::serialize(module).unwrap();
228 let ctor_module = pack_instance(raw_module.clone(), ctor_module, target_runtime).expect("Packing failed");
229
230 let data_section = ctor_module.data_section().expect("Packed module has to have a data section");
231 let data_segment = data_section.entries().iter().last().expect("Packed module has to have a data section with at least one entry");
232 assert!(data_segment.value() == AsRef::<[u8]>::as_ref(&raw_module), "Last data segment should be equal to the raw module");
233 }
234
235 #[test]
236 fn no_data_section() {
237 let target_runtime = TargetRuntime::owasm();
238
239 test_packer(builder::module()
240 .import()
241 .module("env")
242 .field("memory")
243 .external().memory(1 as u32, Some(1 as u32))
244 .build()
245 .function()
246 .signature()
247 .params().i32().i32().build()
248 .build()
249 .body().build()
250 .build()
251 .function()
252 .signature().build()
253 .body()
254 .with_instructions(elements::Instructions::new(
255 vec![
256 elements::Instruction::End
257 ]
258 ))
259 .build()
260 .build()
261 .function()
262 .signature().build()
263 .body()
264 .with_instructions(elements::Instructions::new(
265 vec![
266 elements::Instruction::End
267 ]
268 ))
269 .build()
270 .build()
271 .export()
272 .field(target_runtime.call_symbol)
273 .internal().func(1)
274 .build()
275 .export()
276 .field(target_runtime.create_symbol)
277 .internal().func(2)
278 .build()
279 .build(),
280 &target_runtime,
281 );
282 }
283
284 #[test]
285 fn with_data_section() {
286 let target_runtime = TargetRuntime::owasm();
287
288 test_packer(builder::module()
289 .import()
290 .module("env")
291 .field("memory")
292 .external().memory(1 as u32, Some(1 as u32))
293 .build()
294 .data()
295 .offset(elements::Instruction::I32Const(16)).value(vec![0u8])
296 .build()
297 .function()
298 .signature()
299 .params().i32().i32().build()
300 .build()
301 .body().build()
302 .build()
303 .function()
304 .signature().build()
305 .body()
306 .with_instructions(elements::Instructions::new(
307 vec![
308 elements::Instruction::End
309 ]
310 ))
311 .build()
312 .build()
313 .function()
314 .signature().build()
315 .body()
316 .with_instructions(elements::Instructions::new(
317 vec![
318 elements::Instruction::End
319 ]
320 ))
321 .build()
322 .build()
323 .export()
324 .field(target_runtime.call_symbol)
325 .internal().func(1)
326 .build()
327 .export()
328 .field(target_runtime.create_symbol)
329 .internal().func(2)
330 .build()
331 .build(),
332 &target_runtime,
333 );
334 }
335}