diff --git a/crates/cranelift/src/compiler.rs b/crates/cranelift/src/compiler.rs index 6de5f2ada723..eb11451715c9 100644 --- a/crates/cranelift/src/compiler.rs +++ b/crates/cranelift/src/compiler.rs @@ -28,7 +28,7 @@ use std::sync::{Arc, Mutex}; use wasmparser::{FuncValidatorAllocations, FunctionBody}; use wasmtime_environ::{ AddressMapSection, BuiltinFunctionIndex, CacheStore, CompileError, DefinedFuncIndex, FlagValue, - FunctionBodyData, FunctionLoc, ModuleTranslation, ModuleTypesBuilder, PtrSize, + FunctionBodyData, FunctionLoc, HostCall, ModuleTranslation, ModuleTypesBuilder, PtrSize, RelocationTarget, StackMapInformation, StaticModuleIndex, TrapEncodingBuilder, TrapSentinel, Tunables, VMOffsets, WasmFuncType, WasmFunctionInfo, WasmValType, }; @@ -135,6 +135,7 @@ impl Compiler { fn call_indirect_host( &self, builder: &mut FunctionBuilder<'_>, + hostcall: impl Into, sig: ir::SigRef, addr: Value, args: &[Value], @@ -165,27 +166,7 @@ impl Compiler { let name = ir::ExternalName::User(builder.func.declare_imported_user_function( ir::UserExternalName { namespace: crate::NS_PULLEY_HOSTCALL, - // FIXME: this'll require some more refactoring to get this - // working entirely. The goal is to enumerate all possible - // reasons to call the host in some sort of enum, probably - // something like: - // - // enum wasmtime_environ::HostCall { - // ArrayCall, - // Builtin(BuiltinFunctionIndex), - // ComponentCall, - // ComponentBuiltin(ComponentBuiltinFunctionIndex), - // } - // - // that doesn't exist yet though but would be pretty - // reasonable to encode within a `u32` here. Doing that work - // is left as a future refactoring for Pulley. - index: { - let pulley_hostcall_index = || { - unimplemented!(); - }; - pulley_hostcall_index() - }, + index: hostcall.into().index(), }, )); let func = builder.func.import_function(ir::ExtFuncData { @@ -445,6 +426,7 @@ impl wasmtime_environ::Compiler for Compiler { let callee_signature = builder.func.import_signature(array_call_sig); let call = self.call_indirect_host( &mut builder, + HostCall::ArrayCall, callee_signature, callee, &[callee_vmctx, caller_vmctx, args_base, args_len], @@ -950,7 +932,7 @@ impl Compiler { .load(pointer_type, mem_flags, array_addr, body_offset); let sig = builder.func.import_signature(sig); - self.call_indirect_host(builder, sig, func_addr, args) + self.call_indirect_host(builder, builtin, sig, func_addr, args) } pub fn isa(&self) -> &dyn TargetIsa { diff --git a/crates/cranelift/src/compiler/component.rs b/crates/cranelift/src/compiler/component.rs index b437136fc2b5..c3c84ad6bfc8 100644 --- a/crates/cranelift/src/compiler/component.rs +++ b/crates/cranelift/src/compiler/component.rs @@ -8,7 +8,7 @@ use cranelift_codegen::isa::{CallConv, TargetIsa}; use cranelift_frontend::FunctionBuilder; use std::any::Any; use wasmtime_environ::component::*; -use wasmtime_environ::{ModuleInternedTypeIndex, PtrSize, Tunables, WasmValType}; +use wasmtime_environ::{HostCall, ModuleInternedTypeIndex, PtrSize, Tunables, WasmValType}; struct TrampolineCompiler<'a> { compiler: &'a Compiler, @@ -247,9 +247,13 @@ impl<'a> TrampolineCompiler<'a> { i32::try_from(self.offsets.lowering_callee(index)).unwrap(), ); let host_sig = self.builder.import_signature(host_sig); - let call = - self.compiler - .call_indirect_host(&mut self.builder, host_sig, host_fn, &callee_args); + let call = self.compiler.call_indirect_host( + &mut self.builder, + HostCall::ComponentLowerImport, + host_sig, + host_fn, + &callee_args, + ); let succeeded = self.builder.func.dfg.inst_results(call)[0]; match self.abi { @@ -280,15 +284,20 @@ impl<'a> TrampolineCompiler<'a> { let args = self.abi_load_params(); let vmctx = args[0]; - let (host_sig, offset) = host::trap(self.isa, &mut self.builder.func); - let host_fn = self.load_libcall(vmctx, offset); + let (host_sig, index) = host::trap(self.isa, &mut self.builder.func); + let host_fn = self.load_libcall(vmctx, index); let code = self.builder.ins().iconst( ir::types::I8, i64::from(wasmtime_environ::Trap::AlwaysTrapAdapter as u8), ); - self.compiler - .call_indirect_host(&mut self.builder, host_sig, host_fn, &[vmctx, code]); + self.compiler.call_indirect_host( + &mut self.builder, + index, + host_sig, + host_fn, + &[vmctx, code], + ); let succeeded = self.builder.ins().iconst(ir::types::I8, 0); self.raise_if_host_trapped(succeeded); // debug trap in case execution actually falls through, but this @@ -319,12 +328,7 @@ impl<'a> TrampolineCompiler<'a> { self.types[self.signature].unwrap_func().params()[0], WasmValType::I32 ); - let (host_sig, offset) = host::resource_new32(self.isa, &mut self.builder.func); - - let host_fn = self.load_libcall(vmctx, offset); - let call = - self.compiler - .call_indirect_host(&mut self.builder, host_sig, host_fn, &host_args); + let call = self.call_libcall(vmctx, host::resource_new32, &host_args); let result = self.builder.func.dfg.inst_results(call)[0]; let result = self.raise_if_resource_trapped(result); self.abi_store_results(&[result]); @@ -353,12 +357,7 @@ impl<'a> TrampolineCompiler<'a> { self.types[self.signature].unwrap_func().returns()[0], WasmValType::I32 ); - let (host_sig, offset) = host::resource_rep32(self.isa, &mut self.builder.func); - - let host_fn = self.load_libcall(vmctx, offset); - let call = - self.compiler - .call_indirect_host(&mut self.builder, host_sig, host_fn, &host_args); + let call = self.call_libcall(vmctx, host::resource_rep32, &host_args); let result = self.builder.func.dfg.inst_results(call)[0]; let result = self.raise_if_resource_trapped(result); self.abi_store_results(&[result]); @@ -384,11 +383,7 @@ impl<'a> TrampolineCompiler<'a> { ); host_args.push(args[2]); - let (host_sig, offset) = host::resource_drop(self.isa, &mut self.builder.func); - let host_fn = self.load_libcall(vmctx, offset); - let call = - self.compiler - .call_indirect_host(&mut self.builder, host_sig, host_fn, &host_args); + let call = self.call_libcall(vmctx, host::resource_drop, &host_args); let should_run_destructor = self.builder.func.dfg.inst_results(call)[0]; // Immediately raise a trap if requested by the host @@ -557,7 +552,10 @@ impl<'a> TrampolineCompiler<'a> { /// from the wasm abi to host. fn translate_resource_libcall( &mut self, - get_libcall: fn(&dyn TargetIsa, &mut ir::Function) -> (ir::SigRef, u32), + get_libcall: fn( + &dyn TargetIsa, + &mut ir::Function, + ) -> (ir::SigRef, ComponentBuiltinFunctionIndex), handle_results: fn(&mut Self, &mut Vec), ) { match self.abi { @@ -575,11 +573,8 @@ impl<'a> TrampolineCompiler<'a> { let vmctx = args[0]; let mut host_args = vec![vmctx]; host_args.extend(args[2..].iter().copied()); - let (host_sig, offset) = get_libcall(self.isa, &mut self.builder.func); - let host_fn = self.load_libcall(vmctx, offset); - let call = - self.compiler - .call_indirect_host(&mut self.builder, host_sig, host_fn, &host_args); + + let call = self.call_libcall(vmctx, get_libcall, &host_args); let mut results = self.builder.func.dfg.inst_results(call).to_vec(); handle_results(self, &mut results); self.builder.ins().return_(&results); @@ -589,22 +584,26 @@ impl<'a> TrampolineCompiler<'a> { /// provided in the libcalls array. /// /// The offset is calculated in the `host` module below. - fn load_libcall(&mut self, vmctx: ir::Value, offset: u32) -> ir::Value { + fn load_libcall( + &mut self, + vmctx: ir::Value, + index: ComponentBuiltinFunctionIndex, + ) -> ir::Value { let pointer_type = self.isa.pointer_type(); - // First load the pointer to the libcalls structure which is static + // First load the pointer to the builtins structure which is static // per-process. - let libcalls_array = self.builder.ins().load( + let builtins_array = self.builder.ins().load( pointer_type, MemFlags::trusted().with_readonly(), vmctx, - i32::try_from(self.offsets.libcalls()).unwrap(), + i32::try_from(self.offsets.builtins()).unwrap(), ); // Next load the function pointer at `offset` and return that. self.builder.ins().load( pointer_type, MemFlags::trusted().with_readonly(), - libcalls_array, - i32::try_from(offset * u32::from(self.offsets.ptr.size())).unwrap(), + builtins_array, + i32::try_from(index.index() * u32::from(self.offsets.ptr.size())).unwrap(), ) } @@ -679,6 +678,21 @@ impl<'a> TrampolineCompiler<'a> { self.raise_if_host_trapped(succeeded); self.builder.ins().ireduce(ir::types::I32, ret) } + + fn call_libcall( + &mut self, + vmctx: ir::Value, + get_libcall: fn( + &dyn TargetIsa, + &mut ir::Function, + ) -> (ir::SigRef, ComponentBuiltinFunctionIndex), + args: &[ir::Value], + ) -> ir::Inst { + let (host_sig, index) = get_libcall(self.isa, &mut self.builder.func); + let host_fn = self.load_libcall(vmctx, index); + self.compiler + .call_indirect_host(&mut self.builder, index, host_sig, host_fn, args) + } } impl ComponentCompiler for Compiler { @@ -756,26 +770,21 @@ impl TrampolineCompiler<'_> { // Determine the static signature of the host libcall for this transcode // operation and additionally calculate the static offset within the // transode libcalls array. - let func = &mut self.builder.func; - let (sig, offset) = match op { - Transcode::Copy(FixedEncoding::Utf8) => host::utf8_to_utf8(self.isa, func), - Transcode::Copy(FixedEncoding::Utf16) => host::utf16_to_utf16(self.isa, func), - Transcode::Copy(FixedEncoding::Latin1) => host::latin1_to_latin1(self.isa, func), - Transcode::Latin1ToUtf16 => host::latin1_to_utf16(self.isa, func), - Transcode::Latin1ToUtf8 => host::latin1_to_utf8(self.isa, func), - Transcode::Utf16ToCompactProbablyUtf16 => { - host::utf16_to_compact_probably_utf16(self.isa, func) - } - Transcode::Utf16ToCompactUtf16 => host::utf16_to_compact_utf16(self.isa, func), - Transcode::Utf16ToLatin1 => host::utf16_to_latin1(self.isa, func), - Transcode::Utf16ToUtf8 => host::utf16_to_utf8(self.isa, func), - Transcode::Utf8ToCompactUtf16 => host::utf8_to_compact_utf16(self.isa, func), - Transcode::Utf8ToLatin1 => host::utf8_to_latin1(self.isa, func), - Transcode::Utf8ToUtf16 => host::utf8_to_utf16(self.isa, func), + let get_libcall = match op { + Transcode::Copy(FixedEncoding::Utf8) => host::utf8_to_utf8, + Transcode::Copy(FixedEncoding::Utf16) => host::utf16_to_utf16, + Transcode::Copy(FixedEncoding::Latin1) => host::latin1_to_latin1, + Transcode::Latin1ToUtf16 => host::latin1_to_utf16, + Transcode::Latin1ToUtf8 => host::latin1_to_utf8, + Transcode::Utf16ToCompactProbablyUtf16 => host::utf16_to_compact_probably_utf16, + Transcode::Utf16ToCompactUtf16 => host::utf16_to_compact_utf16, + Transcode::Utf16ToLatin1 => host::utf16_to_latin1, + Transcode::Utf16ToUtf8 => host::utf16_to_utf8, + Transcode::Utf8ToCompactUtf16 => host::utf8_to_compact_utf16, + Transcode::Utf8ToLatin1 => host::utf8_to_latin1, + Transcode::Utf8ToUtf16 => host::utf8_to_utf16, }; - let libcall = self.load_libcall(vmctx, offset); - // Load the base pointers for the from/to linear memories. let from_base = self.load_runtime_memory_base(vmctx, from); let to_base = self.load_runtime_memory_base(vmctx, to); @@ -831,9 +840,7 @@ impl TrampolineCompiler<'_> { )); args.push(self.builder.ins().stack_addr(pointer_type, slot, 0)); } - let call = self - .compiler - .call_indirect_host(&mut self.builder, sig, libcall, &args); + let call = self.call_libcall(vmctx, get_libcall, &args); let mut results = self.builder.func.dfg.inst_results(call).to_vec(); if uses_retptr { results.push(self.builder.ins().load( @@ -945,6 +952,7 @@ impl TrampolineCompiler<'_> { mod host { use cranelift_codegen::ir::{self, AbiParam}; use cranelift_codegen::isa::{CallConv, TargetIsa}; + use wasmtime_environ::component::ComponentBuiltinFunctionIndex; macro_rules! define { ( @@ -954,7 +962,7 @@ mod host { )* ) => { $( - pub(super) fn $name(isa: &dyn TargetIsa, func: &mut ir::Function) -> (ir::SigRef, u32) { + pub(super) fn $name(isa: &dyn TargetIsa, func: &mut ir::Function) -> (ir::SigRef, ComponentBuiltinFunctionIndex) { let pointer_type = isa.pointer_type(); let params = vec![ $( AbiParam::new(define!(@ty pointer_type $param)) ),* @@ -968,7 +976,7 @@ mod host { call_conv: CallConv::triple_default(isa.triple()), }); - (sig, offsets::$name) + (sig, ComponentBuiltinFunctionIndex::$name()) } )* }; @@ -984,46 +992,5 @@ mod host { (@ty $ptr:ident vmctx) => ($ptr); } - wasmtime_environ::foreach_transcoder!(define); wasmtime_environ::foreach_builtin_component_function!(define); - - mod offsets { - macro_rules! offsets { - ( - $( - $( #[$attr:meta] )* - $name:ident($($t:tt)*) $( -> $result:ident )?; - )* - ) => { - offsets!(@declare (0) $($name)*); - }; - - (@declare ($n:expr)) => (const LAST_BUILTIN: u32 = $n;); - (@declare ($n:expr) $name:ident $($rest:tt)*) => ( - pub const $name: u32 = $n; - offsets!(@declare ($n + 1) $($rest)*); - ); - } - - wasmtime_environ::foreach_builtin_component_function!(offsets); - - macro_rules! transcode_offsets { - ( - $( - $( #[$attr:meta] )* - $name:ident($($t:tt)*) $( -> $result:ident )?; - )* - ) => { - transcode_offsets!(@declare (0) $($name)*); - }; - - (@declare ($n:expr)) => (); - (@declare ($n:expr) $name:ident $($rest:tt)*) => ( - pub const $name: u32 = LAST_BUILTIN + $n; - transcode_offsets!(@declare ($n + 1) $($rest)*); - ); - } - - wasmtime_environ::foreach_transcoder!(transcode_offsets); - } } diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs index b7de05219d40..53db72ca394c 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -33,15 +33,14 @@ use wasmtime_environ::{FUNCREF_INIT_BIT, FUNCREF_MASK}; pub(crate) struct BuiltinFunctions { types: BuiltinFunctionSignatures, - builtins: - [Option; BuiltinFunctionIndex::builtin_functions_total_number() as usize], + builtins: [Option; BuiltinFunctionIndex::len() as usize], } impl BuiltinFunctions { fn new(compiler: &Compiler) -> Self { Self { types: BuiltinFunctionSignatures::new(compiler), - builtins: [None; BuiltinFunctionIndex::builtin_functions_total_number() as usize], + builtins: [None; BuiltinFunctionIndex::len() as usize], } } diff --git a/crates/environ/src/builtin.rs b/crates/environ/src/builtin.rs index 39fbf8bb84f1..3bc11515f0c5 100644 --- a/crates/environ/src/builtin.rs +++ b/crates/environ/src/builtin.rs @@ -209,46 +209,55 @@ macro_rules! foreach_builtin_function { }; } -/// An index type for builtin functions. -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct BuiltinFunctionIndex(u32); +/// Helper macro to define a builtin type such as `BuiltinFunctionIndex` and +/// `ComponentBuiltinFunctionIndex` using the iterator macro, e.g. +/// `foreach_builtin_function`, as the way to generate accessor methods. +macro_rules! declare_builtin_index { + ($index_name:ident, $iter:ident) => { + /// An index type for builtin functions. + #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct $index_name(u32); + + impl $index_name { + /// Create a new builtin from its raw index + pub const fn from_u32(i: u32) -> Self { + assert!(i < Self::len()); + Self(i) + } -impl BuiltinFunctionIndex { - /// Create a new `BuiltinFunctionIndex` from its index - pub const fn from_u32(i: u32) -> Self { - Self(i) - } + /// Return the index as an u32 number. + pub const fn index(&self) -> u32 { + self.0 + } - /// Return the index as an u32 number. - pub const fn index(&self) -> u32 { - self.0 - } + $iter!(declare_builtin_index_constructors); + } + }; } -macro_rules! declare_indexes { +/// Helper macro used by the above macro. +macro_rules! declare_builtin_index_constructors { ( $( $( #[$attr:meta] )* $name:ident( $( $pname:ident: $param:ident ),* ) $( -> $result:ident )?; )* ) => { - impl BuiltinFunctionIndex { - declare_indexes!( - @indices; - 0; - $( $( #[$attr] )* $name; )* - ); - - /// Returns a symbol name for this builtin. - pub fn name(&self) -> &'static str { - $( - $( #[$attr] )* - if *self == BuiltinFunctionIndex::$name() { - return stringify!($name); - } - )* - unreachable!() - } + declare_builtin_index_constructors!( + @indices; + 0; + $( $( #[$attr] )* $name; )* + ); + + /// Returns a symbol name for this builtin. + pub fn name(&self) -> &'static str { + $( + $( #[$attr] )* + if *self == Self::$name() { + return stringify!($name); + } + )* + unreachable!() } }; @@ -259,7 +268,7 @@ macro_rules! declare_indexes { $len:expr; ) => { /// Returns the total number of builtin functions. - pub const fn builtin_functions_total_number() -> u32 { + pub const fn len() -> u32 { $len } }; @@ -282,7 +291,7 @@ macro_rules! declare_indexes { Self($index) } - declare_indexes!( + declare_builtin_index_constructors!( @indices; ($index + 1); $( $( #[$rest_attr] )* $rest_name; )* @@ -290,7 +299,8 @@ macro_rules! declare_indexes { } } -foreach_builtin_function!(declare_indexes); +// Define `struct BuiltinFunctionIndex` +declare_builtin_index!(BuiltinFunctionIndex, foreach_builtin_function); /// Return value of [`BuiltinFunctionIndex::trap_sentinel`]. pub enum TrapSentinel { diff --git a/crates/environ/src/component.rs b/crates/environ/src/component.rs index dd7ea8ef3a00..b3899b4caa03 100644 --- a/crates/environ/src/component.rs +++ b/crates/environ/src/component.rs @@ -63,28 +63,6 @@ pub use self::translate::*; #[cfg(feature = "compile")] pub use self::types_builder::*; -/// Helper macro to iterate over the transcoders that the host will provide -/// adapter modules through libcalls. -#[macro_export] -macro_rules! foreach_transcoder { - ($mac:ident) => { - $mac! { - utf8_to_utf8(src: ptr_u8, len: size, dst: ptr_u8) -> bool; - utf16_to_utf16(src: ptr_u16, len: size, dst: ptr_u16) -> bool; - latin1_to_latin1(src: ptr_u8, len: size, dst: ptr_u8) -> bool; - latin1_to_utf16(src: ptr_u8, len: size, dst: ptr_u16) -> bool; - utf8_to_utf16(src: ptr_u8, len: size, dst: ptr_u16) -> size; - utf16_to_utf8(src: ptr_u16, src_len: size, dst: ptr_u8, dst_len: size, ret2: ptr_size) -> size; - latin1_to_utf8(src: ptr_u8, src_len: size, dst: ptr_u8, dst_len: size, ret2: ptr_size) -> size; - utf16_to_compact_probably_utf16(src: ptr_u16, len: size, dst: ptr_u16) -> size; - utf8_to_latin1(src: ptr_u8, len: size, dst: ptr_u8, ret2: ptr_size) -> size; - utf16_to_latin1(src: ptr_u16, len: size, dst: ptr_u8, ret2: ptr_size) -> size; - utf8_to_compact_utf16(src: ptr_u8, src_len: size, dst: ptr_u16, dst_len: size, bytes_so_far: size) -> size; - utf16_to_compact_utf16(src: ptr_u16, src_len: size, dst: ptr_u16, dst_len: size, bytes_so_far: size) -> size; - } - }; -} - /// Helper macro, like `foreach_transcoder`, to iterate over builtins for /// components unrelated to transcoding. #[macro_export] @@ -106,6 +84,25 @@ macro_rules! foreach_builtin_component_function { resource_exit_call(vmctx: vmctx) -> bool; trap(vmctx: vmctx, code: u8); + + utf8_to_utf8(src: ptr_u8, len: size, dst: ptr_u8) -> bool; + utf16_to_utf16(src: ptr_u16, len: size, dst: ptr_u16) -> bool; + latin1_to_latin1(src: ptr_u8, len: size, dst: ptr_u8) -> bool; + latin1_to_utf16(src: ptr_u8, len: size, dst: ptr_u16) -> bool; + utf8_to_utf16(src: ptr_u8, len: size, dst: ptr_u16) -> size; + utf16_to_utf8(src: ptr_u16, src_len: size, dst: ptr_u8, dst_len: size, ret2: ptr_size) -> size; + latin1_to_utf8(src: ptr_u8, src_len: size, dst: ptr_u8, dst_len: size, ret2: ptr_size) -> size; + utf16_to_compact_probably_utf16(src: ptr_u16, len: size, dst: ptr_u16) -> size; + utf8_to_latin1(src: ptr_u8, len: size, dst: ptr_u8, ret2: ptr_size) -> size; + utf16_to_latin1(src: ptr_u16, len: size, dst: ptr_u8, ret2: ptr_size) -> size; + utf8_to_compact_utf16(src: ptr_u8, src_len: size, dst: ptr_u16, dst_len: size, bytes_so_far: size) -> size; + utf16_to_compact_utf16(src: ptr_u16, src_len: size, dst: ptr_u16, dst_len: size, bytes_so_far: size) -> size; } }; } + +// Define `struct ComponentBuiltinFunctionIndex` +declare_builtin_index!( + ComponentBuiltinFunctionIndex, + foreach_builtin_component_function +); diff --git a/crates/environ/src/component/vmcomponent_offsets.rs b/crates/environ/src/component/vmcomponent_offsets.rs index a770fb2eeecf..a46b855461da 100644 --- a/crates/environ/src/component/vmcomponent_offsets.rs +++ b/crates/environ/src/component/vmcomponent_offsets.rs @@ -2,7 +2,7 @@ // // struct VMComponentContext { // magic: u32, -// libcalls: &'static VMComponentLibcalls, +// builtins: &'static VMComponentBuiltins, // store: *mut dyn Store, // limits: *const VMRuntimeLimits, // flags: [VMGlobalDefinition; component.num_runtime_component_instances], @@ -59,7 +59,7 @@ pub struct VMComponentOffsets

{ // precalculated offsets of various member fields magic: u32, - libcalls: u32, + builtins: u32, store: u32, limits: u32, flags: u32, @@ -95,7 +95,7 @@ impl VMComponentOffsets

{ num_trampolines: component.trampolines.len().try_into().unwrap(), num_resources: component.num_resources, magic: 0, - libcalls: 0, + builtins: 0, store: 0, limits: 0, flags: 0, @@ -135,7 +135,7 @@ impl VMComponentOffsets

{ fields! { size(magic) = 4u32, align(u32::from(ret.ptr.size())), - size(libcalls) = ret.ptr.size(), + size(builtins) = ret.ptr.size(), size(store) = cmul(2, ret.ptr.size()), size(limits) = ret.ptr.size(), align(16), @@ -171,10 +171,10 @@ impl VMComponentOffsets

{ self.magic } - /// The offset of the `libcalls` field. + /// The offset of the `builtins` field. #[inline] - pub fn libcalls(&self) -> u32 { - self.libcalls + pub fn builtins(&self) -> u32 { + self.builtins } /// The offset of the `flags` field. diff --git a/crates/environ/src/hostcall.rs b/crates/environ/src/hostcall.rs new file mode 100644 index 000000000000..38e2edc992a1 --- /dev/null +++ b/crates/environ/src/hostcall.rs @@ -0,0 +1,59 @@ +#[cfg(feature = "component-model")] +use crate::component::ComponentBuiltinFunctionIndex; +use crate::BuiltinFunctionIndex; + +/// Enumeration of all possible ways that wasm may execute code in the +/// host. +/// +/// This type is intended to be serialized into a 32-bit index (or smaller) and +/// is used by Pulley for example to identify how transitions from the guest to +/// the host are performed. +pub enum HostCall { + /// An "array call" is being done which means that the wasm is calling the + /// host using the array calling convention (e.g. `VMArrayCallNative`). + ArrayCall, + + /// A builtin function, e.g. for `memory.grow`, is being called. Each + /// builtin has its own ABI. + Builtin(BuiltinFunctionIndex), + + /// A lowered component function is being called. This is done by a + /// trampoline generated by Cranelift and is distinct from the array calling + /// convention. + /// + /// This correspond to `VMLoweringCallee`. + #[cfg(feature = "component-model")] + ComponentLowerImport, + + /// A builtin function, but specifically for components. For example string + /// transcoders. + #[cfg(feature = "component-model")] + ComponentBuiltin(ComponentBuiltinFunctionIndex), +} + +impl HostCall { + /// Returns a 32-bit index for this hostcall. + pub const fn index(&self) -> u32 { + match self { + HostCall::ArrayCall => 0, + HostCall::Builtin(i) => 1 + i.index(), + #[cfg(feature = "component-model")] + HostCall::ComponentLowerImport => 1 + BuiltinFunctionIndex::len(), + #[cfg(feature = "component-model")] + HostCall::ComponentBuiltin(i) => 2 + BuiltinFunctionIndex::len() + i.index(), + } + } +} + +impl From for HostCall { + fn from(idx: BuiltinFunctionIndex) -> HostCall { + HostCall::Builtin(idx) + } +} + +#[cfg(feature = "component-model")] +impl From for HostCall { + fn from(idx: ComponentBuiltinFunctionIndex) -> HostCall { + HostCall::ComponentBuiltin(idx) + } +} diff --git a/crates/environ/src/lib.rs b/crates/environ/src/lib.rs index d77d60b1f99a..555e5586678a 100644 --- a/crates/environ/src/lib.rs +++ b/crates/environ/src/lib.rs @@ -15,10 +15,12 @@ extern crate alloc; pub mod prelude; mod address_map; +#[macro_use] mod builtin; mod demangling; mod error; mod gc; +mod hostcall; mod module; mod module_artifacts; mod module_types; @@ -36,6 +38,7 @@ pub use crate::builtin::*; pub use crate::demangling::*; pub use crate::error::*; pub use crate::gc::*; +pub use crate::hostcall::*; pub use crate::module::*; pub use crate::module_artifacts::*; pub use crate::module_types::*; diff --git a/crates/wasmtime/src/runtime/vm/component.rs b/crates/wasmtime/src/runtime/vm/component.rs index b06296f85802..263045b57091 100644 --- a/crates/wasmtime/src/runtime/vm/component.rs +++ b/crates/wasmtime/src/runtime/vm/component.rs @@ -441,7 +441,7 @@ impl ComponentInstance { unsafe fn initialize_vmctx(&mut self, store: *mut dyn VMStore) { *self.vmctx_plus_offset_mut(self.offsets.magic()) = VMCOMPONENT_MAGIC; - *self.vmctx_plus_offset_mut(self.offsets.libcalls()) = &libcalls::VMComponentLibcalls::INIT; + *self.vmctx_plus_offset_mut(self.offsets.builtins()) = &libcalls::VMComponentBuiltins::INIT; *self.vmctx_plus_offset_mut(self.offsets.store()) = store; *self.vmctx_plus_offset_mut(self.offsets.limits()) = (*store).vmruntime_limits(); diff --git a/crates/wasmtime/src/runtime/vm/component/libcalls.rs b/crates/wasmtime/src/runtime/vm/component/libcalls.rs index af6bee7ed0d3..94d83babe75f 100644 --- a/crates/wasmtime/src/runtime/vm/component/libcalls.rs +++ b/crates/wasmtime/src/runtime/vm/component/libcalls.rs @@ -10,19 +10,6 @@ use wasmtime_environ::component::TypeResourceTableIndex; const UTF16_TAG: usize = 1 << 31; -#[repr(C)] // this is read by Cranelift code so it's layout must be as-written -pub struct VMComponentLibcalls { - builtins: VMComponentBuiltins, - transcoders: VMBuiltinTranscodeArray, -} - -impl VMComponentLibcalls { - pub const INIT: VMComponentLibcalls = VMComponentLibcalls { - builtins: VMComponentBuiltins::INIT, - transcoders: VMBuiltinTranscodeArray::INIT, - }; -} - macro_rules! signature { (@ty size) => (usize); (@ty ptr_u8) => (*mut u8); @@ -47,7 +34,7 @@ macro_rules! define_builtins { /// An array that stores addresses of builtin functions. We translate code /// to use indirect calls. This way, we don't have to patch the code. #[repr(C)] - struct VMComponentBuiltins { + pub struct VMComponentBuiltins { $( $name: unsafe extern "C" fn( $(signature!(@ty $param),)* @@ -56,7 +43,7 @@ macro_rules! define_builtins { } impl VMComponentBuiltins { - const INIT: VMComponentBuiltins = VMComponentBuiltins { + pub const INIT: VMComponentBuiltins = VMComponentBuiltins { $($name: trampolines::$name,)* }; } @@ -65,43 +52,6 @@ macro_rules! define_builtins { wasmtime_environ::foreach_builtin_component_function!(define_builtins); -/// Macro to define the `VMBuiltinTranscodeArray` type which contains all of the -/// function pointers to the actual transcoder functions. This structure is read -/// by Cranelift-generated code, hence the `repr(C)`. -/// -/// Note that this references the `trampolines` module rather than the functions -/// below as the `trampolines` module has the raw ABI. -/// -/// This is modeled after the similar macros and usages in `libcalls.rs` and -/// `vmcontext.rs` -macro_rules! define_transcoders { - ( - $( - $( #[$attr:meta] )* - $name:ident( $( $pname:ident: $param:ident ),* ) $( -> $result:ident )?; - )* - ) => { - /// An array that stores addresses of builtin functions. We translate code - /// to use indirect calls. This way, we don't have to patch the code. - #[repr(C)] - struct VMBuiltinTranscodeArray { - $( - $name: unsafe extern "C" fn( - $(signature!(@ty $param),)* - ) $( -> signature!(@ty $result))?, - )* - } - - impl VMBuiltinTranscodeArray { - const INIT: VMBuiltinTranscodeArray = VMBuiltinTranscodeArray { - $($name: trampolines::$name,)* - }; - } - }; -} - -wasmtime_environ::foreach_transcoder!(define_transcoders); - /// Submodule with macro-generated constants which are the actual libcall /// transcoders that are invoked by Cranelift. These functions have a specific /// ABI defined by the macro itself and will defer to the actual bodies of each @@ -167,7 +117,6 @@ mod trampolines { } wasmtime_environ::foreach_builtin_component_function!(shims); - wasmtime_environ::foreach_transcoder!(shims); } /// This property should already be guaranteed by construction in the component diff --git a/crates/wasmtime/src/runtime/vm/vmcontext.rs b/crates/wasmtime/src/runtime/vm/vmcontext.rs index 18c7adae2347..8b14680e22c0 100644 --- a/crates/wasmtime/src/runtime/vm/vmcontext.rs +++ b/crates/wasmtime/src/runtime/vm/vmcontext.rs @@ -818,8 +818,7 @@ wasmtime_environ::foreach_builtin_function!(define_builtin_array); const _: () = { assert!( mem::size_of::() - == mem::size_of::() - * (BuiltinFunctionIndex::builtin_functions_total_number() as usize) + == mem::size_of::() * (BuiltinFunctionIndex::len() as usize) ) }; diff --git a/tests/disas/pulley/epoch-simple.wat b/tests/disas/pulley/epoch-simple.wat new file mode 100644 index 000000000000..6eace319937b --- /dev/null +++ b/tests/disas/pulley/epoch-simple.wat @@ -0,0 +1,19 @@ +;;! target = "pulley64" +;;! test = "compile" +;;! flags = '-Wepoch-interruption' + +(module + (func) +) +;; wasm[0]::function[0]: +;; push_frame +;; load64_offset8 x7, x0, 8 +;; load64_offset8 x8, x0, 32 +;; load64 x8, x8 +;; load64_offset8 x7, x7, 8 +;; xulteq64 x7, x7, x8 +;; br_if x7, 0x8 // target = 0x1b +;; 19: pop_frame +;; ret +;; 1b: call 0xa // target = 0x25 +;; 20: jump 0xfffffffffffffff9 // target = 0x19