wasmtime_cranelift/
compiler.rs

1use crate::debug::{DwarfSectionRelocTarget, ModuleMemoryOffset};
2use crate::func_environ::FuncEnvironment;
3use crate::{
4    blank_sig, builder::LinkOptions, func_signature, indirect_signature, value_type,
5    wasmtime_call_conv, CompiledFunction, FunctionAddressMap,
6};
7use anyhow::{Context as _, Result};
8use cranelift_codegen::ir::{
9    self, ExternalName, Function, InstBuilder, MemFlags, UserExternalName, UserFuncName, Value,
10};
11use cranelift_codegen::isa::{OwnedTargetIsa, TargetIsa};
12use cranelift_codegen::print_errors::pretty_error;
13use cranelift_codegen::Context;
14use cranelift_codegen::{CompiledCode, MachSrcLoc, MachStackMap};
15use cranelift_codegen::{MachReloc, MachTrap};
16use cranelift_entity::{EntityRef, PrimaryMap};
17use cranelift_frontend::FunctionBuilder;
18use cranelift_wasm::{
19    DefinedFuncIndex, FuncIndex, FuncTranslator, MemoryIndex, OwnedMemoryIndex, WasmFuncType,
20};
21use object::write::{Object, StandardSegment, SymbolId};
22use object::{RelocationEncoding, RelocationKind, SectionKind};
23use std::any::Any;
24use std::cmp;
25use std::collections::BTreeMap;
26use std::collections::HashMap;
27use std::convert::TryFrom;
28use std::mem;
29use std::sync::{Arc, Mutex};
30use wasmparser::{FuncValidatorAllocations, FunctionBody};
31use wasmtime_cranelift_shared::obj::ModuleTextBuilder;
32use wasmtime_cranelift_shared::{Relocation, RelocationTarget};
33use wasmtime_environ::{
34    AddressMapSection, CacheStore, CompileError, FilePos, FlagValue, FunctionBodyData, FunctionLoc,
35    InstructionAddressMap, ModuleTranslation, ModuleTypes, PtrSize, StackMapInformation, Trap,
36    TrapEncodingBuilder, TrapInformation, Tunables, VMOffsets, WasmFunctionInfo,
37};
38
39#[cfg(feature = "component-model")]
40mod component;
41
42struct IncrementalCacheContext {
43    #[cfg(feature = "incremental-cache")]
44    cache_store: Arc<dyn CacheStore>,
45    num_hits: usize,
46    num_cached: usize,
47}
48
49struct CompilerContext {
50    func_translator: FuncTranslator,
51    codegen_context: Context,
52    incremental_cache_ctx: Option<IncrementalCacheContext>,
53    validator_allocations: FuncValidatorAllocations,
54}
55
56impl Default for CompilerContext {
57    fn default() -> Self {
58        Self {
59            func_translator: FuncTranslator::new(),
60            codegen_context: Context::new(),
61            incremental_cache_ctx: None,
62            validator_allocations: Default::default(),
63        }
64    }
65}
66
67/// A compiler that compiles a WebAssembly module with Compiler, translating
68/// the Wasm to Compiler IR, optimizing it and then translating to assembly.
69pub(crate) struct Compiler {
70    contexts: Mutex<Vec<CompilerContext>>,
71    isa: OwnedTargetIsa,
72    linkopts: LinkOptions,
73    cache_store: Option<Arc<dyn CacheStore>>,
74}
75
76impl Drop for Compiler {
77    fn drop(&mut self) {
78        if self.cache_store.is_none() {
79            return;
80        }
81
82        let mut num_hits = 0;
83        let mut num_cached = 0;
84        for ctx in self.contexts.lock().unwrap().iter() {
85            if let Some(ref cache_ctx) = ctx.incremental_cache_ctx {
86                num_hits += cache_ctx.num_hits;
87                num_cached += cache_ctx.num_cached;
88            }
89        }
90
91        let total = num_hits + num_cached;
92        if num_hits + num_cached > 0 {
93            log::trace!(
94                "Incremental compilation cache stats: {}/{} = {}% (hits/lookup)\ncached: {}",
95                num_hits,
96                total,
97                (num_hits as f32) / (total as f32) * 100.0,
98                num_cached
99            );
100        }
101    }
102}
103
104impl Compiler {
105    pub(crate) fn new(
106        isa: OwnedTargetIsa,
107        cache_store: Option<Arc<dyn CacheStore>>,
108        linkopts: LinkOptions,
109    ) -> Compiler {
110        Compiler {
111            contexts: Default::default(),
112            isa,
113            linkopts,
114            cache_store,
115        }
116    }
117
118    fn take_context(&self) -> CompilerContext {
119        let candidate = self.contexts.lock().unwrap().pop();
120        candidate
121            .map(|mut ctx| {
122                ctx.codegen_context.clear();
123                ctx
124            })
125            .unwrap_or_else(|| CompilerContext {
126                #[cfg(feature = "incremental-cache")]
127                incremental_cache_ctx: self.cache_store.as_ref().map(|cache_store| {
128                    IncrementalCacheContext {
129                        cache_store: cache_store.clone(),
130                        num_hits: 0,
131                        num_cached: 0,
132                    }
133                }),
134                ..Default::default()
135            })
136    }
137
138    fn save_context(&self, ctx: CompilerContext) {
139        self.contexts.lock().unwrap().push(ctx);
140    }
141
142    fn get_function_address_map(
143        compiled_code: &CompiledCode,
144        body: &FunctionBody<'_>,
145        body_len: u32,
146        tunables: &Tunables,
147    ) -> FunctionAddressMap {
148        // Generate artificial srcloc for function start/end to identify boundary
149        // within module.
150        let data = body.get_binary_reader();
151        let offset = data.original_position();
152        let len = data.bytes_remaining();
153        assert!((offset + len) <= u32::max_value() as usize);
154        let start_srcloc = FilePos::new(offset as u32);
155        let end_srcloc = FilePos::new((offset + len) as u32);
156
157        // New-style backend: we have a `CompiledCode` that will give us `MachSrcLoc` mapping
158        // tuples.
159        let instructions = if tunables.generate_address_map {
160            collect_address_maps(
161                body_len,
162                compiled_code
163                    .buffer
164                    .get_srclocs_sorted()
165                    .into_iter()
166                    .map(|&MachSrcLoc { start, end, loc }| (loc, start, (end - start))),
167            )
168        } else {
169            Vec::new()
170        };
171
172        FunctionAddressMap {
173            instructions: instructions.into(),
174            start_srcloc,
175            end_srcloc,
176            body_offset: 0,
177            body_len,
178        }
179    }
180}
181
182impl wasmtime_environ::Compiler for Compiler {
183    fn compile_function(
184        &self,
185        translation: &ModuleTranslation<'_>,
186        func_index: DefinedFuncIndex,
187        input: FunctionBodyData<'_>,
188        tunables: &Tunables,
189        types: &ModuleTypes,
190    ) -> Result<(WasmFunctionInfo, Box<dyn Any + Send>), CompileError> {
191        let isa = &*self.isa;
192        let module = &translation.module;
193        let func_index = module.func_index(func_index);
194
195        let CompilerContext {
196            mut func_translator,
197            codegen_context: mut context,
198            incremental_cache_ctx: mut cache_ctx,
199            validator_allocations,
200        } = self.take_context();
201
202        context.func.signature = func_signature(isa, translation, types, func_index);
203        context.func.name = UserFuncName::User(UserExternalName {
204            namespace: 0,
205            index: func_index.as_u32(),
206        });
207
208        if tunables.generate_native_debuginfo {
209            context.func.collect_debug_info();
210        }
211
212        let mut func_env = FuncEnvironment::new(isa, translation, types, tunables);
213
214        // The `stack_limit` global value below is the implementation of stack
215        // overflow checks in Wasmtime.
216        //
217        // The Wasm spec defines that stack overflows will raise a trap, and
218        // there's also an added constraint where as an embedder you frequently
219        // are running host-provided code called from wasm. WebAssembly and
220        // native code currently share the same call stack, so Wasmtime needs to
221        // make sure that host-provided code will have enough call-stack
222        // available to it.
223        //
224        // The way that stack overflow is handled here is by adding a prologue
225        // check to all functions for how much native stack is remaining. The
226        // `VMContext` pointer is the first argument to all functions, and the
227        // first field of this structure is `*const VMRuntimeLimits` and the
228        // first field of that is the stack limit. Note that the stack limit in
229        // this case means "if the stack pointer goes below this, trap". Each
230        // function which consumes stack space or isn't a leaf function starts
231        // off by loading the stack limit, checking it against the stack
232        // pointer, and optionally traps.
233        //
234        // This manual check allows the embedder to give wasm a relatively
235        // precise amount of stack allocation. Using this scheme we reserve a
236        // chunk of stack for wasm code relative from where wasm code was
237        // called. This ensures that native code called by wasm should have
238        // native stack space to run, and the numbers of stack spaces here
239        // should all be configurable for various embeddings.
240        //
241        // Note that this check is independent of each thread's stack guard page
242        // here. If the stack guard page is reached that's still considered an
243        // abort for the whole program since the runtime limits configured by
244        // the embedder should cause wasm to trap before it reaches that
245        // (ensuring the host has enough space as well for its functionality).
246        let vmctx = context
247            .func
248            .create_global_value(ir::GlobalValueData::VMContext);
249        let interrupts_ptr = context.func.create_global_value(ir::GlobalValueData::Load {
250            base: vmctx,
251            offset: i32::try_from(func_env.offsets.vmctx_runtime_limits())
252                .unwrap()
253                .into(),
254            global_type: isa.pointer_type(),
255            readonly: true,
256        });
257        let stack_limit = context.func.create_global_value(ir::GlobalValueData::Load {
258            base: interrupts_ptr,
259            offset: i32::try_from(func_env.offsets.ptr.vmruntime_limits_stack_limit())
260                .unwrap()
261                .into(),
262            global_type: isa.pointer_type(),
263            readonly: false,
264        });
265        context.func.stack_limit = Some(stack_limit);
266        let FunctionBodyData { validator, body } = input;
267        let mut validator = validator.into_validator(validator_allocations);
268        func_translator.translate_body(
269            &mut validator,
270            body.clone(),
271            &mut context.func,
272            &mut func_env,
273        )?;
274
275        let (_, code_buf) = compile_maybe_cached(&mut context, isa, cache_ctx.as_mut())?;
276        // compile_maybe_cached returns the compiled_code but that borrow has the same lifetime as
277        // the mutable borrow of `context`, so the borrow checker prohibits other borrows from
278        // `context` while it's alive. Borrow it again to make the borrow checker happy.
279        let compiled_code = context.compiled_code().unwrap();
280        let alignment = compiled_code.alignment;
281
282        let func_relocs = compiled_code
283            .buffer
284            .relocs()
285            .into_iter()
286            .map(|item| mach_reloc_to_reloc(&context.func, item))
287            .collect();
288
289        let traps = compiled_code
290            .buffer
291            .traps()
292            .into_iter()
293            .map(mach_trap_to_trap)
294            .collect();
295
296        let stack_maps = mach_stack_maps_to_stack_maps(compiled_code.buffer.stack_maps());
297
298        let unwind_info = if isa.flags().unwind_info() {
299            compiled_code
300                .create_unwind_info(isa)
301                .map_err(|error| CompileError::Codegen(pretty_error(&context.func, error)))?
302        } else {
303            None
304        };
305
306        let length = u32::try_from(code_buf.len()).unwrap();
307
308        let address_transform =
309            Self::get_function_address_map(compiled_code, &body, length, tunables);
310
311        let ranges = if tunables.generate_native_debuginfo {
312            Some(compiled_code.value_labels_ranges.clone())
313        } else {
314            None
315        };
316
317        let timing = cranelift_codegen::timing::take_current();
318        log::debug!("{:?} translated in {:?}", func_index, timing.total());
319        log::trace!("{:?} timing info\n{}", func_index, timing);
320
321        let sized_stack_slots = std::mem::take(&mut context.func.sized_stack_slots);
322
323        self.save_context(CompilerContext {
324            func_translator,
325            codegen_context: context,
326            incremental_cache_ctx: cache_ctx,
327            validator_allocations: validator.into_allocations(),
328        });
329
330        Ok((
331            WasmFunctionInfo {
332                start_srcloc: address_transform.start_srcloc,
333                stack_maps: stack_maps.into(),
334            },
335            Box::new(CompiledFunction {
336                body: code_buf,
337                relocations: func_relocs,
338                value_labels_ranges: ranges.unwrap_or(Default::default()),
339                sized_stack_slots,
340                unwind_info,
341                traps,
342                alignment,
343                address_map: address_transform,
344            }),
345        ))
346    }
347
348    fn compile_host_to_wasm_trampoline(
349        &self,
350        ty: &WasmFuncType,
351    ) -> Result<Box<dyn Any + Send>, CompileError> {
352        self.host_to_wasm_trampoline(ty)
353            .map(|x| Box::new(x) as Box<_>)
354    }
355
356    fn append_code(
357        &self,
358        obj: &mut Object<'static>,
359        funcs: &[(String, Box<dyn Any + Send>)],
360        tunables: &Tunables,
361        resolve_reloc: &dyn Fn(usize, FuncIndex) -> usize,
362    ) -> Result<Vec<(SymbolId, FunctionLoc)>> {
363        let mut builder =
364            ModuleTextBuilder::new(obj, self, self.isa.text_section_builder(funcs.len()));
365        if self.linkopts.force_jump_veneers {
366            builder.force_veneers();
367        }
368        let mut addrs = AddressMapSection::default();
369        let mut traps = TrapEncodingBuilder::default();
370
371        let mut ret = Vec::with_capacity(funcs.len());
372        for (i, (sym, func)) in funcs.iter().enumerate() {
373            let func = func.downcast_ref::<CompiledFunction>().unwrap();
374            let (sym, range) = builder.append_func(
375                &sym,
376                &func.body,
377                func.alignment,
378                func.unwind_info.as_ref(),
379                &func.relocations,
380                |idx| resolve_reloc(i, idx),
381            );
382            if tunables.generate_address_map {
383                addrs.push(range.clone(), &func.address_map.instructions);
384            }
385            traps.push(range.clone(), &func.traps);
386            builder.append_padding(self.linkopts.padding_between_functions);
387            let info = FunctionLoc {
388                start: u32::try_from(range.start).unwrap(),
389                length: u32::try_from(range.end - range.start).unwrap(),
390            };
391            ret.push((sym, info));
392        }
393
394        builder.finish();
395
396        if tunables.generate_address_map {
397            addrs.append_to(obj);
398        }
399        traps.append_to(obj);
400
401        Ok(ret)
402    }
403
404    fn emit_trampoline_obj(
405        &self,
406        ty: &WasmFuncType,
407        host_fn: usize,
408        obj: &mut Object<'static>,
409    ) -> Result<(FunctionLoc, FunctionLoc)> {
410        let host_to_wasm = self.host_to_wasm_trampoline(ty)?;
411        let wasm_to_host = self.wasm_to_host_trampoline(ty, host_fn)?;
412        let mut builder = ModuleTextBuilder::new(obj, self, self.isa.text_section_builder(2));
413        let (_, a) = builder.append_func(
414            "host_to_wasm",
415            &host_to_wasm.body,
416            host_to_wasm.alignment,
417            host_to_wasm.unwind_info.as_ref(),
418            &host_to_wasm.relocations,
419            |_| unreachable!(),
420        );
421        let (_, b) = builder.append_func(
422            "wasm_to_host",
423            &wasm_to_host.body,
424            wasm_to_host.alignment,
425            wasm_to_host.unwind_info.as_ref(),
426            &wasm_to_host.relocations,
427            |_| unreachable!(),
428        );
429        let a = FunctionLoc {
430            start: u32::try_from(a.start).unwrap(),
431            length: u32::try_from(a.end - a.start).unwrap(),
432        };
433        let b = FunctionLoc {
434            start: u32::try_from(b.start).unwrap(),
435            length: u32::try_from(b.end - b.start).unwrap(),
436        };
437        builder.finish();
438        Ok((a, b))
439    }
440
441    fn triple(&self) -> &target_lexicon::Triple {
442        self.isa.triple()
443    }
444
445    fn flags(&self) -> BTreeMap<String, FlagValue> {
446        wasmtime_cranelift_shared::clif_flags_to_wasmtime(self.isa.flags().iter())
447    }
448
449    fn isa_flags(&self) -> BTreeMap<String, FlagValue> {
450        wasmtime_cranelift_shared::clif_flags_to_wasmtime(self.isa.isa_flags())
451    }
452
453    fn is_branch_protection_enabled(&self) -> bool {
454        self.isa.is_branch_protection_enabled()
455    }
456
457    #[cfg(feature = "component-model")]
458    fn component_compiler(&self) -> &dyn wasmtime_environ::component::ComponentCompiler {
459        self
460    }
461
462    fn append_dwarf(
463        &self,
464        obj: &mut Object<'_>,
465        translation: &ModuleTranslation<'_>,
466        funcs: &PrimaryMap<DefinedFuncIndex, (SymbolId, &(dyn Any + Send))>,
467    ) -> Result<()> {
468        let ofs = VMOffsets::new(
469            self.isa
470                .triple()
471                .architecture
472                .pointer_width()
473                .unwrap()
474                .bytes(),
475            &translation.module,
476        );
477
478        let memory_offset = if ofs.num_imported_memories > 0 {
479            ModuleMemoryOffset::Imported(ofs.vmctx_vmmemory_import(MemoryIndex::new(0)))
480        } else if ofs.num_defined_memories > 0 {
481            // The addition of shared memory makes the following assumption,
482            // "owned memory index = 0", possibly false. If the first memory
483            // is a shared memory, the base pointer will not be stored in
484            // the `owned_memories` array. The following code should
485            // eventually be fixed to not only handle shared memories but
486            // also multiple memories.
487            assert_eq!(
488                ofs.num_defined_memories, ofs.num_owned_memories,
489                "the memory base pointer may be incorrect due to sharing memory"
490            );
491            ModuleMemoryOffset::Defined(
492                ofs.vmctx_vmmemory_definition_base(OwnedMemoryIndex::new(0)),
493            )
494        } else {
495            ModuleMemoryOffset::None
496        };
497        let compiled_funcs = funcs
498            .iter()
499            .map(|(_, (_, func))| func.downcast_ref().unwrap())
500            .collect();
501        let dwarf_sections = crate::debug::emit_dwarf(
502            &*self.isa,
503            &translation.debuginfo,
504            &compiled_funcs,
505            &memory_offset,
506        )
507        .with_context(|| "failed to emit DWARF debug information")?;
508
509        let (debug_bodies, debug_relocs): (Vec<_>, Vec<_>) = dwarf_sections
510            .iter()
511            .map(|s| ((s.name, &s.body), (s.name, &s.relocs)))
512            .unzip();
513        let mut dwarf_sections_ids = HashMap::new();
514        for (name, body) in debug_bodies {
515            let segment = obj.segment_name(StandardSegment::Debug).to_vec();
516            let section_id = obj.add_section(segment, name.as_bytes().to_vec(), SectionKind::Debug);
517            dwarf_sections_ids.insert(name, section_id);
518            obj.append_section_data(section_id, &body, 1);
519        }
520
521        // Write all debug data relocations.
522        for (name, relocs) in debug_relocs {
523            let section_id = *dwarf_sections_ids.get(name).unwrap();
524            for reloc in relocs {
525                let target_symbol = match reloc.target {
526                    DwarfSectionRelocTarget::Func(index) => funcs[DefinedFuncIndex::new(index)].0,
527                    DwarfSectionRelocTarget::Section(name) => {
528                        obj.section_symbol(dwarf_sections_ids[name])
529                    }
530                };
531                obj.add_relocation(
532                    section_id,
533                    object::write::Relocation {
534                        offset: u64::from(reloc.offset),
535                        size: reloc.size << 3,
536                        kind: RelocationKind::Absolute,
537                        encoding: RelocationEncoding::Generic,
538                        symbol: target_symbol,
539                        addend: i64::from(reloc.addend),
540                    },
541                )?;
542            }
543        }
544
545        Ok(())
546    }
547
548    fn function_alignment(&self) -> u32 {
549        self.isa.function_alignment()
550    }
551
552    fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
553        self.isa.create_systemv_cie()
554    }
555}
556
557#[cfg(feature = "incremental-cache")]
558mod incremental_cache {
559    use super::*;
560
561    struct CraneliftCacheStore(Arc<dyn CacheStore>);
562
563    impl cranelift_codegen::incremental_cache::CacheKvStore for CraneliftCacheStore {
564        fn get(&self, key: &[u8]) -> Option<std::borrow::Cow<[u8]>> {
565            self.0.get(key)
566        }
567        fn insert(&mut self, key: &[u8], val: Vec<u8>) {
568            self.0.insert(key, val);
569        }
570    }
571
572    pub(super) fn compile_maybe_cached<'a>(
573        context: &'a mut Context,
574        isa: &dyn TargetIsa,
575        cache_ctx: Option<&mut IncrementalCacheContext>,
576    ) -> Result<(&'a CompiledCode, Vec<u8>), CompileError> {
577        let cache_ctx = match cache_ctx {
578            Some(ctx) => ctx,
579            None => return compile_uncached(context, isa),
580        };
581
582        let mut cache_store = CraneliftCacheStore(cache_ctx.cache_store.clone());
583        let (compiled_code, from_cache) = context
584            .compile_with_cache(isa, &mut cache_store)
585            .map_err(|error| CompileError::Codegen(pretty_error(&error.func, error.inner)))?;
586
587        if from_cache {
588            cache_ctx.num_hits += 1;
589        } else {
590            cache_ctx.num_cached += 1;
591        }
592
593        Ok((compiled_code, compiled_code.code_buffer().to_vec()))
594    }
595}
596
597#[cfg(feature = "incremental-cache")]
598use incremental_cache::*;
599
600#[cfg(not(feature = "incremental-cache"))]
601fn compile_maybe_cached<'a>(
602    context: &'a mut Context,
603    isa: &dyn TargetIsa,
604    _cache_ctx: Option<&mut IncrementalCacheContext>,
605) -> Result<(&'a CompiledCode, Vec<u8>), CompileError> {
606    compile_uncached(context, isa)
607}
608
609fn compile_uncached<'a>(
610    context: &'a mut Context,
611    isa: &dyn TargetIsa,
612) -> Result<(&'a CompiledCode, Vec<u8>), CompileError> {
613    let mut code_buf = Vec::new();
614    let compiled_code = context
615        .compile_and_emit(isa, &mut code_buf)
616        .map_err(|error| CompileError::Codegen(pretty_error(&error.func, error.inner)))?;
617    Ok((compiled_code, code_buf))
618}
619
620impl Compiler {
621    fn host_to_wasm_trampoline(&self, ty: &WasmFuncType) -> Result<CompiledFunction, CompileError> {
622        let isa = &*self.isa;
623        let value_size = mem::size_of::<u128>();
624        let pointer_type = isa.pointer_type();
625
626        // The wasm signature we're calling in this trampoline has the actual
627        // ABI of the function signature described by `ty`
628        let wasm_signature = indirect_signature(isa, ty);
629
630        // The host signature has the `VMTrampoline` signature where the ABI is
631        // fixed.
632        let mut host_signature = blank_sig(isa, wasmtime_call_conv(isa));
633        host_signature.params.push(ir::AbiParam::new(pointer_type));
634        host_signature.params.push(ir::AbiParam::new(pointer_type));
635
636        let CompilerContext {
637            mut func_translator,
638            codegen_context: mut context,
639            incremental_cache_ctx: mut cache_ctx,
640            validator_allocations,
641        } = self.take_context();
642
643        // The name doesn't matter here.
644        context.func = ir::Function::with_name_signature(UserFuncName::default(), host_signature);
645
646        // This trampoline will load all the parameters from the `values_vec`
647        // that is passed in and then call the real function (also passed
648        // indirectly) with the specified ABI.
649        //
650        // All the results are then stored into the same `values_vec`.
651        let mut builder = FunctionBuilder::new(&mut context.func, func_translator.context());
652        let block0 = builder.create_block();
653
654        builder.append_block_params_for_function_params(block0);
655        builder.switch_to_block(block0);
656        builder.seal_block(block0);
657
658        let (vmctx_ptr_val, caller_vmctx_ptr_val, callee_value, values_vec_ptr_val) = {
659            let params = builder.func.dfg.block_params(block0);
660            (params[0], params[1], params[2], params[3])
661        };
662
663        // Load the argument values out of `values_vec`.
664        let mut mflags = ir::MemFlags::trusted();
665        mflags.set_endianness(ir::Endianness::Little);
666        let callee_args = wasm_signature
667            .params
668            .iter()
669            .enumerate()
670            .map(|(i, r)| {
671                match i {
672                    0 => vmctx_ptr_val,
673                    1 => caller_vmctx_ptr_val,
674                    _ =>
675                    // i - 2 because vmctx and caller vmctx aren't passed through `values_vec`.
676                    {
677                        builder.ins().load(
678                            r.value_type,
679                            mflags,
680                            values_vec_ptr_val,
681                            ((i - 2) * value_size) as i32,
682                        )
683                    }
684                }
685            })
686            .collect::<Vec<_>>();
687
688        // Call the indirect function pointer we were given
689        let new_sig = builder.import_signature(wasm_signature);
690        let call = builder
691            .ins()
692            .call_indirect(new_sig, callee_value, &callee_args);
693        let results = builder.func.dfg.inst_results(call).to_vec();
694
695        // Store the return values into `values_vec`.
696        for (i, r) in results.iter().enumerate() {
697            builder
698                .ins()
699                .store(mflags, *r, values_vec_ptr_val, (i * value_size) as i32);
700        }
701        builder.ins().return_(&[]);
702        builder.finalize();
703
704        let func = self.finish_trampoline(&mut context, cache_ctx.as_mut(), isa)?;
705        self.save_context(CompilerContext {
706            func_translator,
707            codegen_context: context,
708            incremental_cache_ctx: cache_ctx,
709            validator_allocations,
710        });
711        Ok(func)
712    }
713
714    /// Creates a trampoline for WebAssembly calling into the host where all the
715    /// arguments are spilled to the stack and results are loaded from the
716    /// stack.
717    ///
718    /// This style of trampoline is currently only used with the
719    /// `Func::new`-style created functions in the Wasmtime embedding API. The
720    /// generated trampoline has a function signature appropriate to the `ty`
721    /// specified (e.g. a System-V ABI) and will call a `host_fn` that has a
722    /// type signature of:
723    ///
724    /// ```ignore
725    /// extern "C" fn(*mut VMContext, *mut VMContext, *mut ValRaw, usize)
726    /// ```
727    ///
728    /// where the first two arguments are forwarded from the trampoline
729    /// generated here itself, and the second two arguments are a pointer/length
730    /// into stack-space of this trampoline with storage for both the arguments
731    /// to the function and the results.
732    ///
733    /// Note that `host_fn` is an immediate which is an actual function pointer
734    /// in this process. As such this compiled trampoline is not suitable for
735    /// serialization.
736    fn wasm_to_host_trampoline(
737        &self,
738        ty: &WasmFuncType,
739        host_fn: usize,
740    ) -> Result<CompiledFunction, CompileError> {
741        let isa = &*self.isa;
742        let pointer_type = isa.pointer_type();
743        let wasm_signature = indirect_signature(isa, ty);
744        let mut host_signature = blank_sig(isa, wasmtime_call_conv(isa));
745        // The host signature has an added parameter for the `values_vec`
746        // input/output buffer in addition to the size of the buffer, in units
747        // of `ValRaw`.
748        host_signature.params.push(ir::AbiParam::new(pointer_type));
749        host_signature.params.push(ir::AbiParam::new(pointer_type));
750
751        let CompilerContext {
752            mut func_translator,
753            codegen_context: mut context,
754            incremental_cache_ctx: mut cache_ctx,
755            validator_allocations,
756        } = self.take_context();
757
758        // The name doesn't matter here.
759        context.func = ir::Function::with_name_signature(Default::default(), wasm_signature);
760
761        let mut builder = FunctionBuilder::new(&mut context.func, func_translator.context());
762        let block0 = builder.create_block();
763
764        let (values_vec_ptr_val, values_vec_len) =
765            self.wasm_to_host_spill_args(ty, &mut builder, block0);
766
767        let block_params = builder.func.dfg.block_params(block0);
768        let callee_args = [
769            block_params[0],
770            block_params[1],
771            values_vec_ptr_val,
772            builder
773                .ins()
774                .iconst(pointer_type, i64::from(values_vec_len)),
775        ];
776
777        let new_sig = builder.import_signature(host_signature);
778        let callee_value = builder.ins().iconst(pointer_type, host_fn as i64);
779        builder
780            .ins()
781            .call_indirect(new_sig, callee_value, &callee_args);
782
783        self.wasm_to_host_load_results(ty, builder, values_vec_ptr_val);
784
785        let func = self.finish_trampoline(&mut context, cache_ctx.as_mut(), isa)?;
786        self.save_context(CompilerContext {
787            func_translator,
788            codegen_context: context,
789            incremental_cache_ctx: cache_ctx,
790            validator_allocations,
791        });
792        Ok(func)
793    }
794
795    /// Used for spilling arguments in wasm-to-host trampolines into the stack
796    /// of the function of `builder` specified.
797    ///
798    /// The `block0` is the entry block of the function and `ty` is the wasm
799    /// signature of the trampoline generated. This function will allocate a
800    /// stack slot suitable for storing both the arguments and return values of
801    /// the function, and then the arguments will all be stored in this block.
802    ///
803    /// The stack slot pointer is returned in addition to the size, in units of
804    /// `ValRaw`, of the stack slot.
805    fn wasm_to_host_spill_args(
806        &self,
807        ty: &WasmFuncType,
808        builder: &mut FunctionBuilder,
809        block0: ir::Block,
810    ) -> (Value, u32) {
811        let isa = &*self.isa;
812        let pointer_type = isa.pointer_type();
813
814        // Compute the size of the values vector.
815        let value_size = mem::size_of::<u128>();
816        let values_vec_len = cmp::max(ty.params().len(), ty.returns().len());
817        let values_vec_byte_size = u32::try_from(value_size * values_vec_len).unwrap();
818        let values_vec_len = u32::try_from(values_vec_len).unwrap();
819
820        let ss = builder.func.create_sized_stack_slot(ir::StackSlotData::new(
821            ir::StackSlotKind::ExplicitSlot,
822            values_vec_byte_size,
823        ));
824
825        builder.append_block_params_for_function_params(block0);
826        builder.switch_to_block(block0);
827        builder.seal_block(block0);
828
829        // Note that loads and stores are unconditionally done in the
830        // little-endian format rather than the host's native-endianness,
831        // despite this load/store being unrelated to execution in wasm itself.
832        // For more details on this see the `ValRaw` type in the
833        // `wasmtime-runtime` crate.
834        let mut mflags = MemFlags::trusted();
835        mflags.set_endianness(ir::Endianness::Little);
836
837        let values_vec_ptr_val = builder.ins().stack_addr(pointer_type, ss, 0);
838        for i in 0..ty.params().len() {
839            let val = builder.func.dfg.block_params(block0)[i + 2];
840            builder
841                .ins()
842                .store(mflags, val, values_vec_ptr_val, (i * value_size) as i32);
843        }
844        (values_vec_ptr_val, values_vec_len)
845    }
846
847    /// Use for loading the results of a host call from a trampoline's stack
848    /// space.
849    ///
850    /// This is intended to be used with the stack space allocated by
851    /// `wasm_to_host_spill_args` above. This is called after the function call
852    /// is made which will load results from the stack space and then return
853    /// them with the appropriate ABI (e.g. System-V).
854    fn wasm_to_host_load_results(
855        &self,
856        ty: &WasmFuncType,
857        mut builder: FunctionBuilder,
858        values_vec_ptr_val: Value,
859    ) {
860        let isa = &*self.isa;
861        let value_size = mem::size_of::<u128>();
862
863        // Note that this is little-endian like `wasm_to_host_spill_args` above,
864        // see notes there for more information.
865        let mut mflags = MemFlags::trusted();
866        mflags.set_endianness(ir::Endianness::Little);
867
868        let mut results = Vec::new();
869        for (i, r) in ty.returns().iter().enumerate() {
870            let load = builder.ins().load(
871                value_type(isa, *r),
872                mflags,
873                values_vec_ptr_val,
874                (i * value_size) as i32,
875            );
876            results.push(load);
877        }
878        builder.ins().return_(&results);
879        builder.finalize();
880    }
881
882    fn finish_trampoline(
883        &self,
884        context: &mut Context,
885        cache_ctx: Option<&mut IncrementalCacheContext>,
886        isa: &dyn TargetIsa,
887    ) -> Result<CompiledFunction, CompileError> {
888        let (compiled_code, code_buf) = compile_maybe_cached(context, isa, cache_ctx)?;
889
890        // Processing relocations isn't the hardest thing in the world here but
891        // no trampoline should currently generate a relocation, so assert that
892        // they're all empty and if this ever trips in the future then handling
893        // will need to be added here to ensure they make their way into the
894        // `CompiledFunction` below.
895        assert!(compiled_code.buffer.relocs().is_empty());
896
897        let traps = compiled_code
898            .buffer
899            .traps()
900            .into_iter()
901            .map(mach_trap_to_trap)
902            .collect();
903        let alignment = compiled_code.alignment;
904
905        let unwind_info = if isa.flags().unwind_info() {
906            compiled_code
907                .create_unwind_info(isa)
908                .map_err(|error| CompileError::Codegen(pretty_error(&context.func, error)))?
909        } else {
910            None
911        };
912
913        Ok(CompiledFunction {
914            body: code_buf,
915            unwind_info,
916            relocations: Default::default(),
917            sized_stack_slots: Default::default(),
918            value_labels_ranges: Default::default(),
919            address_map: Default::default(),
920            traps,
921            alignment,
922        })
923    }
924}
925
926// Collects an iterator of `InstructionAddressMap` into a `Vec` for insertion
927// into a `FunctionAddressMap`. This will automatically coalesce adjacent
928// instructions which map to the same original source position.
929fn collect_address_maps(
930    code_size: u32,
931    iter: impl IntoIterator<Item = (ir::SourceLoc, u32, u32)>,
932) -> Vec<InstructionAddressMap> {
933    let mut iter = iter.into_iter();
934    let (mut cur_loc, mut cur_offset, mut cur_len) = match iter.next() {
935        Some(i) => i,
936        None => return Vec::new(),
937    };
938    let mut ret = Vec::new();
939    for (loc, offset, len) in iter {
940        // If this instruction is adjacent to the previous and has the same
941        // source location then we can "coalesce" it with the current
942        // instruction.
943        if cur_offset + cur_len == offset && loc == cur_loc {
944            cur_len += len;
945            continue;
946        }
947
948        // Push an entry for the previous source item.
949        ret.push(InstructionAddressMap {
950            srcloc: cvt(cur_loc),
951            code_offset: cur_offset,
952        });
953        // And push a "dummy" entry if necessary to cover the span of ranges,
954        // if any, between the previous source offset and this one.
955        if cur_offset + cur_len != offset {
956            ret.push(InstructionAddressMap {
957                srcloc: FilePos::default(),
958                code_offset: cur_offset + cur_len,
959            });
960        }
961        // Update our current location to get extended later or pushed on at
962        // the end.
963        cur_loc = loc;
964        cur_offset = offset;
965        cur_len = len;
966    }
967    ret.push(InstructionAddressMap {
968        srcloc: cvt(cur_loc),
969        code_offset: cur_offset,
970    });
971    if cur_offset + cur_len != code_size {
972        ret.push(InstructionAddressMap {
973            srcloc: FilePos::default(),
974            code_offset: cur_offset + cur_len,
975        });
976    }
977
978    return ret;
979
980    fn cvt(loc: ir::SourceLoc) -> FilePos {
981        if loc.is_default() {
982            FilePos::default()
983        } else {
984            FilePos::new(loc.bits())
985        }
986    }
987}
988
989fn mach_reloc_to_reloc(func: &Function, reloc: &MachReloc) -> Relocation {
990    let &MachReloc {
991        offset,
992        kind,
993        ref name,
994        addend,
995    } = reloc;
996    let reloc_target = if let ExternalName::User(user_func_ref) = *name {
997        let UserExternalName { namespace, index } = func.params.user_named_funcs()[user_func_ref];
998        debug_assert_eq!(namespace, 0);
999        RelocationTarget::UserFunc(FuncIndex::from_u32(index))
1000    } else if let ExternalName::LibCall(libcall) = *name {
1001        RelocationTarget::LibCall(libcall)
1002    } else {
1003        panic!("unrecognized external name")
1004    };
1005    Relocation {
1006        reloc: kind,
1007        reloc_target,
1008        offset,
1009        addend,
1010    }
1011}
1012
1013const ALWAYS_TRAP_CODE: u16 = 100;
1014
1015fn mach_trap_to_trap(trap: &MachTrap) -> TrapInformation {
1016    let &MachTrap { offset, code } = trap;
1017    TrapInformation {
1018        code_offset: offset,
1019        trap_code: match code {
1020            ir::TrapCode::StackOverflow => Trap::StackOverflow,
1021            ir::TrapCode::HeapOutOfBounds => Trap::MemoryOutOfBounds,
1022            ir::TrapCode::HeapMisaligned => Trap::HeapMisaligned,
1023            ir::TrapCode::TableOutOfBounds => Trap::TableOutOfBounds,
1024            ir::TrapCode::IndirectCallToNull => Trap::IndirectCallToNull,
1025            ir::TrapCode::BadSignature => Trap::BadSignature,
1026            ir::TrapCode::IntegerOverflow => Trap::IntegerOverflow,
1027            ir::TrapCode::IntegerDivisionByZero => Trap::IntegerDivisionByZero,
1028            ir::TrapCode::BadConversionToInteger => Trap::BadConversionToInteger,
1029            ir::TrapCode::UnreachableCodeReached => Trap::UnreachableCodeReached,
1030            ir::TrapCode::Interrupt => Trap::Interrupt,
1031            ir::TrapCode::User(ALWAYS_TRAP_CODE) => Trap::AlwaysTrapAdapter,
1032
1033            // these should never be emitted by wasmtime-cranelift
1034            ir::TrapCode::User(_) => unreachable!(),
1035        },
1036    }
1037}
1038
1039fn mach_stack_maps_to_stack_maps(mach_stack_maps: &[MachStackMap]) -> Vec<StackMapInformation> {
1040    // This is converting from Cranelift's representation of a stack map to
1041    // Wasmtime's representation. They happen to align today but that may
1042    // not always be true in the future.
1043    let mut stack_maps = Vec::new();
1044    for &MachStackMap {
1045        offset_end,
1046        ref stack_map,
1047        ..
1048    } in mach_stack_maps
1049    {
1050        let stack_map = wasmtime_environ::StackMap::new(
1051            stack_map.mapped_words(),
1052            stack_map.as_slice().iter().map(|a| a.0),
1053        );
1054        stack_maps.push(StackMapInformation {
1055            code_offset: offset_end,
1056            stack_map,
1057        });
1058    }
1059    stack_maps.sort_unstable_by_key(|info| info.code_offset);
1060    stack_maps
1061}