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