wasmer_compiler_cranelift/translator/
func_environ.rs

1// This file contains code from external sources.
2// Attributions: https://github.com/wasmerio/wasmer/blob/main/docs/ATTRIBUTIONS.md
3
4//! All the runtime support necessary for the wasm to cranelift translation is formalized by the
5//! traits `FunctionEnvMutironment`.
6
7use super::func_state::FuncTranslationState;
8use super::translation_utils::reference_type;
9use crate::heap::{Heap, HeapData};
10use crate::translator::func_state::LandingPad;
11use core::convert::From;
12use cranelift_codegen::cursor::FuncCursor;
13use cranelift_codegen::ir::immediates::Offset32;
14use cranelift_codegen::ir::{self, InstBuilder};
15use cranelift_codegen::isa::TargetFrontendConfig;
16use cranelift_frontend::FunctionBuilder;
17use smallvec::SmallVec;
18use wasmer_compiler::wasmparser::{HeapType, Operator};
19use wasmer_types::entity::PrimaryMap;
20use wasmer_types::{
21    FunctionIndex, FunctionType, GlobalIndex, LocalFunctionIndex, MemoryIndex, SignatureIndex,
22    TableIndex, TagIndex, Type as WasmerType, WasmResult,
23};
24
25/// The value of a WebAssembly global variable.
26#[derive(Clone, Copy)]
27pub enum GlobalVariable {
28    #[allow(dead_code)]
29    /// This is a constant global with a value known at compile time.
30    Const(ir::Value),
31
32    /// This is a variable in memory that should be referenced through a `GlobalValue`.
33    Memory {
34        /// The address of the global variable storage.
35        gv: ir::GlobalValue,
36        /// An offset to add to the address.
37        offset: Offset32,
38        /// The global variable's type.
39        ty: ir::Type,
40    },
41
42    #[allow(dead_code)]
43    /// This is a global variable that needs to be handled by the environment.
44    Custom,
45}
46
47#[allow(dead_code)]
48/// How to return from functions.
49#[derive(Copy, Clone, PartialEq, Eq, Debug)]
50pub enum ReturnMode {
51    /// Use normal return instructions as needed.
52    NormalReturns,
53}
54
55/// Environment affecting the translation of a WebAssembly.
56pub trait TargetEnvironment {
57    /// Get the information needed to produce Cranelift IR for the given target.
58    fn target_config(&self) -> TargetFrontendConfig;
59
60    /// Get the Cranelift integer type to use for native pointers.
61    ///
62    /// This returns `I64` for 64-bit architectures and `I32` for 32-bit architectures.
63    fn pointer_type(&self) -> ir::Type {
64        ir::Type::int(u16::from(self.target_config().pointer_bits())).unwrap()
65    }
66
67    /// Get the size of a native pointer, in bytes.
68    #[allow(dead_code)]
69    fn pointer_bytes(&self) -> u8 {
70        self.target_config().pointer_bytes()
71    }
72
73    /// Get the Cranelift reference type to use for native references.
74    ///
75    /// This returns the target pointer type for both `funcref` and `externref`.
76    fn reference_type(&self) -> ir::Type {
77        reference_type(self.target_config()).expect("expected reference type")
78    }
79}
80
81/// Environment affecting the translation of a single WebAssembly function.
82///
83/// A `FuncEnvironment` trait object is required to translate a WebAssembly function to Cranelift
84/// IR. The function environment provides information about the WebAssembly module as well as the
85/// runtime environment.
86pub trait FuncEnvironment: TargetEnvironment {
87    /// Whether to enable Spectre mitigations for heap accesses.
88    fn heap_access_spectre_mitigation(&self) -> bool;
89
90    /// Whether to add proof-carrying-code facts to verify memory accesses.
91    fn proof_carrying_code(&self) -> bool;
92
93    /// Is the given parameter of the given function a wasm-level parameter, as opposed to a hidden
94    /// parameter added for use by the implementation?
95    fn is_wasm_parameter(&self, signature: &ir::Signature, index: usize) -> bool {
96        signature.params[index].purpose == ir::ArgumentPurpose::Normal
97    }
98
99    /// Is the given return of the given function a wasm-level parameter, as
100    /// opposed to a hidden parameter added for use by the implementation?
101    fn is_wasm_return(&self, signature: &ir::Signature, index: usize) -> bool {
102        signature.returns[index].purpose == ir::ArgumentPurpose::Normal
103    }
104
105    /// Should the code be structured to use a single `fallthrough_return` instruction at the end
106    /// of the function body, rather than `return` instructions as needed? This is used by VMs
107    /// to append custom epilogues.
108    fn return_mode(&self) -> ReturnMode {
109        ReturnMode::NormalReturns
110    }
111
112    /// Set up the necessary preamble definitions in `func` to access the global variable
113    /// identified by `index`.
114    ///
115    /// The index space covers both imported globals and globals defined by the module.
116    ///
117    /// Return the global variable reference that should be used to access the global and the
118    /// WebAssembly type of the global.
119    fn make_global(
120        &mut self,
121        func: &mut ir::Function,
122        index: GlobalIndex,
123    ) -> WasmResult<GlobalVariable>;
124
125    /// Inserts code before updating a global.
126    fn update_global(
127        &mut self,
128        _builder: &mut FunctionBuilder,
129        _global_index: u32,
130        _value: ir::Value,
131    ) {
132    }
133
134    /// Get the heaps for this function environment.
135    ///
136    /// The returned map should provide heap format details (encoded in
137    /// `HeapData`) for each `Heap` that was previously returned by
138    /// `make_heap()`. The translator will first call make_heap for each Wasm
139    /// memory, and then later when translating code, will invoke `heaps()` to
140    /// learn how to access the environment's implementation of each memory.
141    fn heaps(&self) -> &PrimaryMap<Heap, HeapData>;
142
143    /// Set up the necessary preamble definitions in `func` to access the linear memory identified
144    /// by `index`.
145    ///
146    /// The index space covers both imported and locally declared memories.
147    fn make_heap(&mut self, func: &mut ir::Function, index: MemoryIndex) -> WasmResult<Heap>;
148
149    /// Set up a signature definition in the preamble of `func` that can be used for an indirect
150    /// call with signature `index`.
151    ///
152    /// The signature may contain additional arguments needed for an indirect call, but the
153    /// arguments marked as `ArgumentPurpose::Normal` must correspond to the WebAssembly signature
154    /// arguments.
155    ///
156    /// The signature will only be used for indirect calls, even if the module has direct function
157    /// calls with the same WebAssembly type.
158    fn make_indirect_sig(
159        &mut self,
160        func: &mut ir::Function,
161        index: SignatureIndex,
162    ) -> WasmResult<ir::SigRef>;
163
164    /// Set up an external function definition in the preamble of `func` that can be used to
165    /// directly call the function `index`.
166    ///
167    /// The index space covers both imported functions and functions defined in the current module.
168    ///
169    /// The function's signature may contain additional arguments needed for a direct call, but the
170    /// arguments marked as `ArgumentPurpose::Normal` must correspond to the WebAssembly signature
171    /// arguments.
172    ///
173    /// The function's signature will only be used for direct calls, even if the module has
174    /// indirect calls with the same WebAssembly type.
175    fn make_direct_func(
176        &mut self,
177        func: &mut ir::Function,
178        index: FunctionIndex,
179    ) -> WasmResult<ir::FuncRef>;
180
181    /// Translate a `call` WebAssembly instruction at `pos`.
182    ///
183    /// Insert instructions at `pos` for a direct call to the function `callee_index`.
184    ///
185    /// The function reference `callee` was previously created by `make_direct_func()`.
186    ///
187    /// Return the call instruction whose results are the WebAssembly return values.
188    fn translate_call(
189        &mut self,
190        builder: &mut FunctionBuilder,
191        _callee_index: FunctionIndex,
192        callee: ir::FuncRef,
193        call_args: &[ir::Value],
194        landing_pad: Option<LandingPad>,
195    ) -> WasmResult<SmallVec<[ir::Value; 4]>>;
196
197    /// Translate a `call_indirect` WebAssembly instruction at `pos`.
198    ///
199    /// Insert instructions at `pos` for an indirect call to the function `callee` in the table
200    /// `table_index` with WebAssembly signature `sig_index`. The `callee` value will have type
201    /// `i32`.
202    ///
203    /// The signature `sig_ref` was previously created by `make_indirect_sig()`.
204    ///
205    /// Return the call instruction whose results are the WebAssembly return values.
206    /// Returns `None` if this statically traps instead of creating a call
207    /// instruction.
208    #[allow(clippy::too_many_arguments)]
209    fn translate_call_indirect(
210        &mut self,
211        builder: &mut FunctionBuilder,
212        table_index: TableIndex,
213        sig_index: SignatureIndex,
214        sig_ref: ir::SigRef,
215        callee: ir::Value,
216        call_args: &[ir::Value],
217        landing_pad: Option<LandingPad>,
218    ) -> WasmResult<SmallVec<[ir::Value; 4]>>;
219
220    /// Return the number of WebAssembly values contained in the payload for the given exception tag.
221    fn tag_param_arity(&self, tag_index: TagIndex) -> usize;
222
223    /// Get the exception reference from the raw exception pointer (used by libunwind).
224    fn translate_exn_pointer_to_ref(
225        &mut self,
226        builder: &mut FunctionBuilder,
227        exn_ptr: ir::Value,
228    ) -> ir::Value;
229
230    /// Extract the payload values from an exception reference produced by the given tag.
231    fn translate_exn_unbox(
232        &mut self,
233        builder: &mut FunctionBuilder,
234        tag_index: TagIndex,
235        exnref: ir::Value,
236    ) -> WasmResult<SmallVec<[ir::Value; 4]>>;
237
238    /// Emit IR to allocate and throw a new exception with the specified tag.
239    fn translate_exn_throw(
240        &mut self,
241        builder: &mut FunctionBuilder,
242        tag_index: TagIndex,
243        args: &[ir::Value],
244        landing_pad: Option<LandingPad>,
245    ) -> WasmResult<()>;
246
247    /// Emit IR to rethrow an existing exception reference.
248    fn translate_exn_throw_ref(
249        &mut self,
250        builder: &mut FunctionBuilder,
251        exnref: ir::Value,
252        landing_pad: Option<LandingPad>,
253    ) -> WasmResult<()>;
254
255    /// Invoke the runtime personality helper to choose the matching catch tag for an exception.
256    fn translate_exn_personality_selector(
257        &mut self,
258        builder: &mut FunctionBuilder,
259        exn_ptr: ir::Value,
260    ) -> WasmResult<ir::Value>;
261
262    /// Reraise an exception when no catch clause within the current handler matches.
263    fn translate_exn_reraise_unmatched(
264        &mut self,
265        builder: &mut FunctionBuilder,
266        exnref: ir::Value,
267    ) -> WasmResult<()>;
268
269    /// Translate a `memory.grow` WebAssembly instruction.
270    ///
271    /// The `index` provided identifies the linear memory to grow, and `heap` is the heap reference
272    /// returned by `make_heap` for the same index.
273    ///
274    /// The `val` value is the requested memory size in pages.
275    ///
276    /// Returns the old size (in pages) of the memory.
277    fn translate_memory_grow(
278        &mut self,
279        pos: FuncCursor,
280        index: MemoryIndex,
281        heap: Heap,
282        val: ir::Value,
283    ) -> WasmResult<ir::Value>;
284
285    /// Translates a `memory.size` WebAssembly instruction.
286    ///
287    /// The `index` provided identifies the linear memory to query, and `heap` is the heap reference
288    /// returned by `make_heap` for the same index.
289    ///
290    /// Returns the size in pages of the memory.
291    fn translate_memory_size(
292        &mut self,
293        pos: FuncCursor,
294        index: MemoryIndex,
295        heap: Heap,
296    ) -> WasmResult<ir::Value>;
297
298    /// Translate a `memory.copy` WebAssembly instruction.
299    ///
300    /// The `index` provided identifies the linear memory to query, and `heap` is the heap reference
301    /// returned by `make_heap` for the same index.
302    #[allow(clippy::too_many_arguments)]
303    fn translate_memory_copy(
304        &mut self,
305        pos: FuncCursor,
306        src_index: MemoryIndex,
307        src_heap: Heap,
308        dst_index: MemoryIndex,
309        dst_heap: Heap,
310        dst: ir::Value,
311        src: ir::Value,
312        len: ir::Value,
313    ) -> WasmResult<()>;
314
315    /// Translate a `memory.fill` WebAssembly instruction.
316    ///
317    /// The `index` provided identifies the linear memory to query, and `heap` is the heap reference
318    /// returned by `make_heap` for the same index.
319    fn translate_memory_fill(
320        &mut self,
321        pos: FuncCursor,
322        index: MemoryIndex,
323        heap: Heap,
324        dst: ir::Value,
325        val: ir::Value,
326        len: ir::Value,
327    ) -> WasmResult<()>;
328
329    /// Translate a `memory.init` WebAssembly instruction.
330    ///
331    /// The `index` provided identifies the linear memory to query, and `heap` is the heap reference
332    /// returned by `make_heap` for the same index. `seg_index` is the index of the segment to copy
333    /// from.
334    #[allow(clippy::too_many_arguments)]
335    fn translate_memory_init(
336        &mut self,
337        pos: FuncCursor,
338        index: MemoryIndex,
339        heap: Heap,
340        seg_index: u32,
341        dst: ir::Value,
342        src: ir::Value,
343        len: ir::Value,
344    ) -> WasmResult<()>;
345
346    /// Translate a `data.drop` WebAssembly instruction.
347    fn translate_data_drop(&mut self, pos: FuncCursor, seg_index: u32) -> WasmResult<()>;
348
349    /// Translate a `table.size` WebAssembly instruction.
350    fn translate_table_size(&mut self, pos: FuncCursor, index: TableIndex)
351    -> WasmResult<ir::Value>;
352
353    /// Translate a `table.grow` WebAssembly instruction.
354    fn translate_table_grow(
355        &mut self,
356        pos: FuncCursor,
357        table_index: TableIndex,
358        delta: ir::Value,
359        init_value: ir::Value,
360    ) -> WasmResult<ir::Value>;
361
362    /// Translate a `table.get` WebAssembly instruction.
363    fn translate_table_get(
364        &mut self,
365        builder: &mut FunctionBuilder,
366        table_index: TableIndex,
367        index: ir::Value,
368    ) -> WasmResult<ir::Value>;
369
370    /// Translate a `table.set` WebAssembly instruction.
371    fn translate_table_set(
372        &mut self,
373        builder: &mut FunctionBuilder,
374        table_index: TableIndex,
375        value: ir::Value,
376        index: ir::Value,
377    ) -> WasmResult<()>;
378
379    /// Translate a `table.copy` WebAssembly instruction.
380    #[allow(clippy::too_many_arguments)]
381    fn translate_table_copy(
382        &mut self,
383        pos: FuncCursor,
384        dst_table_index: TableIndex,
385        src_table_index: TableIndex,
386        dst: ir::Value,
387        src: ir::Value,
388        len: ir::Value,
389    ) -> WasmResult<()>;
390
391    /// Translate a `table.fill` WebAssembly instruction.
392    fn translate_table_fill(
393        &mut self,
394        pos: FuncCursor,
395        table_index: TableIndex,
396        dst: ir::Value,
397        val: ir::Value,
398        len: ir::Value,
399    ) -> WasmResult<()>;
400
401    /// Translate a `table.init` WebAssembly instruction.
402    #[allow(clippy::too_many_arguments)]
403    fn translate_table_init(
404        &mut self,
405        pos: FuncCursor,
406        seg_index: u32,
407        table_index: TableIndex,
408        dst: ir::Value,
409        src: ir::Value,
410        len: ir::Value,
411    ) -> WasmResult<()>;
412
413    /// Translate a `elem.drop` WebAssembly instruction.
414    fn translate_elem_drop(&mut self, pos: FuncCursor, seg_index: u32) -> WasmResult<()>;
415
416    /// Translate a `ref.null T` WebAssembly instruction.
417    ///
418    /// By default, translates into a null reference type.
419    ///
420    /// Override this if you don't use Cranelift reference types for all Wasm
421    /// reference types (e.g. you use a raw pointer for `funcref`s) or if the
422    /// null sentinel is not a null reference type pointer for your type. If you
423    /// override this method, then you should also override
424    /// `translate_ref_is_null` as well.
425    fn translate_ref_null(&mut self, mut pos: FuncCursor, ty: HeapType) -> WasmResult<ir::Value> {
426        let _ = ty;
427        Ok(pos.ins().iconst(self.reference_type(), 0))
428    }
429
430    /// Translate a `ref.is_null` WebAssembly instruction.
431    ///
432    /// By default, assumes that `value` is a Cranelift reference type, and that
433    /// a null Cranelift reference type is the null value for all Wasm reference
434    /// types.
435    ///
436    /// If you override this method, you probably also want to override
437    /// `translate_ref_null` as well.
438    fn translate_ref_is_null(
439        &mut self,
440        mut pos: FuncCursor,
441        value: ir::Value,
442    ) -> WasmResult<ir::Value> {
443        let is_null = pos
444            .ins()
445            .icmp_imm(cranelift_codegen::ir::condcodes::IntCC::Equal, value, 0);
446        Ok(pos.ins().uextend(ir::types::I32, is_null))
447    }
448
449    /// Translate a `ref.func` WebAssembly instruction.
450    fn translate_ref_func(
451        &mut self,
452        pos: FuncCursor,
453        func_index: FunctionIndex,
454    ) -> WasmResult<ir::Value>;
455
456    /// Translate a `global.get` WebAssembly instruction at `pos` for a global
457    /// that is custom.
458    fn translate_custom_global_get(
459        &mut self,
460        pos: FuncCursor,
461        global_index: GlobalIndex,
462    ) -> WasmResult<ir::Value>;
463
464    /// Translate a `global.set` WebAssembly instruction at `pos` for a global
465    /// that is custom.
466    fn translate_custom_global_set(
467        &mut self,
468        pos: FuncCursor,
469        global_index: GlobalIndex,
470        val: ir::Value,
471    ) -> WasmResult<()>;
472
473    /// Translate an `i32.atomic.wait` or `i64.atomic.wait` WebAssembly instruction.
474    /// The `index` provided identifies the linear memory containing the value
475    /// to wait on, and `heap` is the heap reference returned by `make_heap`
476    /// for the same index.  Whether the waited-on value is 32- or 64-bit can be
477    /// determined by examining the type of `expected`, which must be only I32 or I64.
478    ///
479    /// Returns an i32, which is negative if the helper call failed.
480    fn translate_atomic_wait(
481        &mut self,
482        pos: FuncCursor,
483        index: MemoryIndex,
484        heap: Heap,
485        addr: ir::Value,
486        expected: ir::Value,
487        timeout: ir::Value,
488    ) -> WasmResult<ir::Value>;
489
490    /// Translate an `atomic.notify` WebAssembly instruction.
491    /// The `index` provided identifies the linear memory containing the value
492    /// to wait on, and `heap` is the heap reference returned by `make_heap`
493    /// for the same index.
494    ///
495    /// Returns an i64, which is negative if the helper call failed.
496    fn translate_atomic_notify(
497        &mut self,
498        pos: FuncCursor,
499        index: MemoryIndex,
500        heap: Heap,
501        addr: ir::Value,
502        count: ir::Value,
503    ) -> WasmResult<ir::Value>;
504
505    /// Emit code at the beginning of every wasm loop.
506    ///
507    /// This can be used to insert explicit interrupt or safepoint checking at
508    /// the beginnings of loops.
509    fn translate_loop_header(&mut self, _pos: FuncCursor) -> WasmResult<()> {
510        // By default, don't emit anything.
511        Ok(())
512    }
513
514    /// Optional callback for the `FunctionEnvMutironment` performing this translation to maintain
515    /// internal state or prepare custom state for the operator to translate
516    fn before_translate_operator(
517        &mut self,
518        _op: &Operator,
519        _builder: &mut FunctionBuilder,
520        _state: &FuncTranslationState,
521    ) -> WasmResult<()> {
522        Ok(())
523    }
524
525    /// Optional callback for the `FunctionEnvMutironment` performing this translation to maintain
526    /// internal state or finalize custom state for the operator that was translated
527    fn after_translate_operator(
528        &mut self,
529        _op: &Operator,
530        _builder: &mut FunctionBuilder,
531        _state: &FuncTranslationState,
532    ) -> WasmResult<()> {
533        Ok(())
534    }
535
536    /// Optional callback for the `FuncEnvironment` performing this translation
537    /// to maintain, prepare, or finalize custom, internal state when we
538    /// statically determine that a Wasm memory access will unconditionally
539    /// trap, rendering the rest of the block unreachable. Called just before
540    /// the unconditional trap is emitted.
541    fn before_unconditionally_trapping_memory_access(
542        &mut self,
543        _builder: &mut FunctionBuilder,
544    ) -> WasmResult<()> {
545        Ok(())
546    }
547
548    /// Get the type of the global at the given index.
549    #[allow(dead_code)]
550    fn get_global_type(&self, global_index: GlobalIndex) -> Option<WasmerType>;
551
552    /// Push a local declaration on to the stack to track the type of locals.
553    fn push_local_decl_on_stack(&mut self, ty: WasmerType);
554
555    /// Push locals for a the params of a function on to the stack.
556    fn push_params_on_stack(&mut self, function_index: LocalFunctionIndex);
557
558    /// Get the type of the local at the given index.
559    #[allow(dead_code)]
560    fn get_local_type(&self, local_index: u32) -> Option<WasmerType>;
561
562    /// Get the types of all the current locals.
563    #[allow(dead_code)]
564    fn get_local_types(&self) -> &[WasmerType];
565
566    /// Get the type of the local at the given index.
567    #[allow(dead_code)]
568    fn get_function_type(&self, function_index: FunctionIndex) -> Option<&FunctionType>;
569
570    /// Get the type of a function with the given signature index.
571    #[allow(dead_code)]
572    fn get_function_sig(&self, sig_index: SignatureIndex) -> Option<&FunctionType>;
573
574    /// Inserts code before a function return.
575    fn handle_before_return(&mut self, _retvals: &[ir::Value], _builder: &mut FunctionBuilder) {}
576
577    /// Inserts code before a load.
578    fn before_load(
579        &mut self,
580        _builder: &mut FunctionBuilder,
581        _val_size: u8,
582        _addr: ir::Value,
583        _offset: u64,
584    ) {
585    }
586
587    /// Inserts code before a store.
588    fn before_store(
589        &mut self,
590        _builder: &mut FunctionBuilder,
591        _val_size: u8,
592        _addr: ir::Value,
593        _offset: u64,
594    ) {
595    }
596}