near_vm_compiler/translator/
environ.rs

1// This file contains code from external sources.
2// Attributions: https://github.com/wasmerio/wasmer/blob/2.3.0/ATTRIBUTIONS.md
3use super::state::ModuleTranslationState;
4use crate::lib::std::borrow::ToOwned;
5use crate::lib::std::string::ToString;
6use crate::lib::std::{boxed::Box, string::String, vec::Vec};
7use crate::translate_module;
8use crate::{WasmError, WasmResult};
9use near_vm_types::FunctionType;
10use near_vm_types::entity::PrimaryMap;
11use near_vm_types::{
12    CustomSectionIndex, DataIndex, DataInitializer, DataInitializerLocation, ElemIndex,
13    ExportIndex, FunctionIndex, GlobalIndex, GlobalInit, GlobalType, ImportIndex,
14    LocalFunctionIndex, MemoryIndex, MemoryType, ModuleInfo, OwnedTableInitializer, SignatureIndex,
15    TableIndex, TableType,
16};
17use std::convert::{TryFrom, TryInto};
18use std::sync::Arc;
19pub use wasmparser::FunctionBody as FunctionReader;
20
21/// Contains function data: bytecode and its offset in the module.
22#[derive(Hash)]
23pub struct FunctionBodyData<'a> {
24    /// Function body bytecode.
25    pub data: &'a [u8],
26
27    /// Body offset relative to the module file.
28    pub module_offset: usize,
29}
30
31/// The result of translating via `ModuleEnvironment`. Function bodies are not
32/// yet translated, and data initializers have not yet been copied out of the
33/// original buffer.
34/// The function bodies will be translated by a specific compiler backend.
35pub struct ModuleEnvironment<'data> {
36    /// ModuleInfo information.
37    pub module: ModuleInfo,
38
39    /// References to the function bodies.
40    pub function_body_inputs: PrimaryMap<LocalFunctionIndex, FunctionBodyData<'data>>,
41
42    /// References to the data initializers.
43    pub data_initializers: Vec<DataInitializer<'data>>,
44
45    /// The decoded Wasm types for the module.
46    pub module_translation_state: Option<ModuleTranslationState>,
47}
48
49impl<'data> ModuleEnvironment<'data> {
50    /// Allocates the environment data structures.
51    pub fn new() -> Self {
52        Self {
53            module: ModuleInfo::new(),
54            function_body_inputs: PrimaryMap::new(),
55            data_initializers: Vec::new(),
56            module_translation_state: None,
57        }
58    }
59
60    /// Translate a wasm module using this environment. This consumes the
61    /// `ModuleEnvironment` and produces a `ModuleInfoTranslation`.
62    #[tracing::instrument(target = "near_vm", level = "trace", skip_all)]
63    pub fn translate(mut self, data: &'data [u8]) -> WasmResult<Self> {
64        assert!(self.module_translation_state.is_none());
65        let module_translation_state = translate_module(data, &mut self)?;
66        self.module_translation_state = Some(module_translation_state);
67        Ok(self)
68    }
69
70    pub(crate) fn declare_export(&mut self, export: ExportIndex, name: &str) -> WasmResult<()> {
71        self.module.exports.insert(String::from(name), export);
72        Ok(())
73    }
74
75    pub(crate) fn declare_import(
76        &mut self,
77        import: ImportIndex,
78        module: &str,
79        field: &str,
80    ) -> WasmResult<()> {
81        self.module.imports.insert(
82            (
83                String::from(module),
84                String::from(field),
85                self.module.imports.len().try_into().unwrap(),
86            ),
87            import,
88        );
89        Ok(())
90    }
91
92    pub(crate) fn reserve_signatures(&mut self, num: u32) -> WasmResult<()> {
93        self.module.signatures.reserve_exact(usize::try_from(num).unwrap());
94        Ok(())
95    }
96
97    pub(crate) fn declare_signature(&mut self, sig: FunctionType) -> WasmResult<()> {
98        // TODO: Deduplicate signatures.
99        self.module.signatures.push(sig);
100        Ok(())
101    }
102
103    pub(crate) fn declare_func_import(
104        &mut self,
105        sig_index: SignatureIndex,
106        module: &str,
107        field: &str,
108    ) -> WasmResult<()> {
109        debug_assert_eq!(
110            self.module.functions.len(),
111            self.module.import_counts.functions as usize,
112            "Imported functions must be declared first"
113        );
114        self.declare_import(
115            ImportIndex::Function(FunctionIndex::from_u32(self.module.import_counts.functions)),
116            module,
117            field,
118        )?;
119        self.module.functions.push(sig_index);
120        self.module.import_counts.functions += 1;
121        Ok(())
122    }
123
124    pub(crate) fn declare_table_import(
125        &mut self,
126        table: TableType,
127        module: &str,
128        field: &str,
129    ) -> WasmResult<()> {
130        debug_assert_eq!(
131            self.module.tables.len(),
132            self.module.import_counts.tables as usize,
133            "Imported tables must be declared first"
134        );
135        self.declare_import(
136            ImportIndex::Table(TableIndex::from_u32(self.module.import_counts.tables)),
137            module,
138            field,
139        )?;
140        self.module.tables.push(table);
141        self.module.import_counts.tables += 1;
142        Ok(())
143    }
144
145    pub(crate) fn declare_memory_import(
146        &mut self,
147        memory: MemoryType,
148        module: &str,
149        field: &str,
150    ) -> WasmResult<()> {
151        debug_assert_eq!(
152            self.module.memories.len(),
153            self.module.import_counts.memories as usize,
154            "Imported memories must be declared first"
155        );
156        self.declare_import(
157            ImportIndex::Memory(MemoryIndex::from_u32(self.module.import_counts.memories)),
158            module,
159            field,
160        )?;
161        self.module.memories.push(memory);
162        self.module.import_counts.memories += 1;
163        Ok(())
164    }
165
166    pub(crate) fn declare_global_import(
167        &mut self,
168        global: GlobalType,
169        module: &str,
170        field: &str,
171    ) -> WasmResult<()> {
172        debug_assert_eq!(
173            self.module.globals.len(),
174            self.module.import_counts.globals as usize,
175            "Imported globals must be declared first"
176        );
177        self.declare_import(
178            ImportIndex::Global(GlobalIndex::from_u32(self.module.import_counts.globals)),
179            module,
180            field,
181        )?;
182        self.module.globals.push(global);
183        self.module.import_counts.globals += 1;
184        Ok(())
185    }
186
187    pub(crate) fn finish_imports(&self) -> WasmResult<()> {
188        Ok(())
189    }
190
191    pub(crate) fn reserve_func_types(&mut self, num: u32) -> WasmResult<()> {
192        self.module.functions.reserve_exact(usize::try_from(num).unwrap());
193        self.function_body_inputs.reserve_exact(usize::try_from(num).unwrap());
194        Ok(())
195    }
196
197    pub(crate) fn declare_func_type(&mut self, sig_index: SignatureIndex) -> WasmResult<()> {
198        self.module.functions.push(sig_index);
199        Ok(())
200    }
201
202    pub(crate) fn reserve_tables(&mut self, num: u32) -> WasmResult<()> {
203        self.module.tables.reserve_exact(usize::try_from(num).unwrap());
204        Ok(())
205    }
206
207    pub(crate) fn declare_table(&mut self, table: TableType) -> WasmResult<()> {
208        self.module.tables.push(table);
209        Ok(())
210    }
211
212    pub(crate) fn reserve_memories(&mut self, num: u32) -> WasmResult<()> {
213        self.module.memories.reserve_exact(usize::try_from(num).unwrap());
214        Ok(())
215    }
216
217    pub(crate) fn declare_memory(&mut self, memory: MemoryType) -> WasmResult<()> {
218        if memory.shared {
219            return Err(WasmError::Unsupported("shared memories are not supported yet".to_owned()));
220        }
221        self.module.memories.push(memory);
222        Ok(())
223    }
224
225    pub(crate) fn reserve_globals(&mut self, num: u32) -> WasmResult<()> {
226        self.module.globals.reserve_exact(usize::try_from(num).unwrap());
227        Ok(())
228    }
229
230    pub(crate) fn declare_global(
231        &mut self,
232        global: GlobalType,
233        initializer: GlobalInit,
234    ) -> WasmResult<()> {
235        self.module.globals.push(global);
236        self.module.global_initializers.push(initializer);
237        Ok(())
238    }
239
240    pub(crate) fn reserve_exports(&mut self, num: u32) -> WasmResult<()> {
241        self.module.exports.reserve(usize::try_from(num).unwrap());
242        Ok(())
243    }
244
245    pub(crate) fn declare_func_export(
246        &mut self,
247        func_index: FunctionIndex,
248        name: &str,
249    ) -> WasmResult<()> {
250        self.declare_export(ExportIndex::Function(func_index), name)
251    }
252
253    pub(crate) fn declare_table_export(
254        &mut self,
255        table_index: TableIndex,
256        name: &str,
257    ) -> WasmResult<()> {
258        self.declare_export(ExportIndex::Table(table_index), name)
259    }
260
261    pub(crate) fn declare_memory_export(
262        &mut self,
263        memory_index: MemoryIndex,
264        name: &str,
265    ) -> WasmResult<()> {
266        self.declare_export(ExportIndex::Memory(memory_index), name)
267    }
268
269    pub(crate) fn declare_global_export(
270        &mut self,
271        global_index: GlobalIndex,
272        name: &str,
273    ) -> WasmResult<()> {
274        self.declare_export(ExportIndex::Global(global_index), name)
275    }
276
277    pub(crate) fn declare_start_function(&mut self, func_index: FunctionIndex) -> WasmResult<()> {
278        debug_assert!(self.module.start_function.is_none());
279        self.module.start_function = Some(func_index);
280        Ok(())
281    }
282
283    pub(crate) fn reserve_table_initializers(&mut self, num: u32) -> WasmResult<()> {
284        self.module.table_initializers.reserve_exact(usize::try_from(num).unwrap());
285        Ok(())
286    }
287
288    pub(crate) fn declare_table_initializers(
289        &mut self,
290        table_index: TableIndex,
291        base: Option<GlobalIndex>,
292        offset: usize,
293        elements: Box<[FunctionIndex]>,
294    ) -> WasmResult<()> {
295        self.module.table_initializers.push(OwnedTableInitializer {
296            table_index,
297            base,
298            offset,
299            elements,
300        });
301        Ok(())
302    }
303
304    pub(crate) fn declare_passive_element(
305        &mut self,
306        elem_index: ElemIndex,
307        segments: Box<[FunctionIndex]>,
308    ) -> WasmResult<()> {
309        let old = self.module.passive_elements.insert(elem_index, segments);
310        debug_assert!(
311            old.is_none(),
312            "should never get duplicate element indices, that would be a bug in `near_vm_compiler`'s \
313             translation"
314        );
315        Ok(())
316    }
317
318    pub(crate) fn define_function_body(
319        &mut self,
320        _module_translation_state: &ModuleTranslationState,
321        body_bytes: &'data [u8],
322        body_offset: usize,
323    ) -> WasmResult<()> {
324        self.function_body_inputs
325            .push(FunctionBodyData { data: body_bytes, module_offset: body_offset });
326        Ok(())
327    }
328
329    pub(crate) fn reserve_data_initializers(&mut self, num: u32) -> WasmResult<()> {
330        self.data_initializers.reserve_exact(usize::try_from(num).unwrap());
331        Ok(())
332    }
333
334    pub(crate) fn declare_data_initialization(
335        &mut self,
336        memory_index: MemoryIndex,
337        base: Option<GlobalIndex>,
338        offset: usize,
339        data: &'data [u8],
340    ) -> WasmResult<()> {
341        self.data_initializers.push(DataInitializer {
342            location: DataInitializerLocation { memory_index, base, offset },
343            data,
344        });
345        Ok(())
346    }
347
348    pub(crate) fn reserve_passive_data(&self, _count: u32) -> WasmResult<()> {
349        // TODO(0-copy): consider finding a more appropriate data structure for this?
350        Ok(())
351    }
352
353    pub(crate) fn declare_passive_data(
354        &mut self,
355        data_index: DataIndex,
356        data: &'data [u8],
357    ) -> WasmResult<()> {
358        let old = self.module.passive_data.insert(data_index, Arc::from(data));
359        debug_assert!(
360            old.is_none(),
361            "a module can't have duplicate indices, this would be a near_vm-compiler bug"
362        );
363        Ok(())
364    }
365
366    pub(crate) fn declare_module_name(&mut self, name: &'data str) -> WasmResult<()> {
367        self.module.name = Some(name.to_string());
368        Ok(())
369    }
370
371    pub(crate) fn declare_function_name(
372        &mut self,
373        func_index: FunctionIndex,
374        name: &'data str,
375    ) -> WasmResult<()> {
376        self.module.function_names.insert(func_index, name.to_string());
377        Ok(())
378    }
379
380    /// Provides the number of imports up front. By default, this does nothing, but
381    /// implementations can use this to preallocate memory if desired.
382    pub(crate) fn reserve_imports(&self, _num: u32) -> WasmResult<()> {
383        Ok(())
384    }
385
386    /// Notifies the implementation that all exports have been declared.
387    pub(crate) fn finish_exports(&self) -> WasmResult<()> {
388        Ok(())
389    }
390
391    /// Indicates that a custom section has been found in the wasm file
392    pub(crate) fn custom_section(&mut self, name: &'data str, data: &'data [u8]) -> WasmResult<()> {
393        let custom_section = CustomSectionIndex::from_u32(
394            self.module.custom_sections_data.len().try_into().unwrap(),
395        );
396        self.module.custom_sections.insert(String::from(name), custom_section);
397        self.module.custom_sections_data.push(Arc::from(data));
398        Ok(())
399    }
400}