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
67pub(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 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 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 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 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 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 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 let wasm_signature = indirect_signature(isa, ty);
629
630 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 context.func = ir::Function::with_name_signature(UserFuncName::default(), host_signature);
645
646 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 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 {
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 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 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 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 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 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 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 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 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 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 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 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
926fn 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 cur_offset + cur_len == offset && loc == cur_loc {
944 cur_len += len;
945 continue;
946 }
947
948 ret.push(InstructionAddressMap {
950 srcloc: cvt(cur_loc),
951 code_offset: cur_offset,
952 });
953 if cur_offset + cur_len != offset {
956 ret.push(InstructionAddressMap {
957 srcloc: FilePos::default(),
958 code_offset: cur_offset + cur_len,
959 });
960 }
961 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 ir::TrapCode::User(_) => unreachable!(),
1035 },
1036 }
1037}
1038
1039fn mach_stack_maps_to_stack_maps(mach_stack_maps: &[MachStackMap]) -> Vec<StackMapInformation> {
1040 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}