From be58c61a2f661d76810c1c1f7e35dbcff3a0da99 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 12 Aug 2025 12:46:52 -0500 Subject: [PATCH 1/3] Enable clippy in CI for WASIp3 bits (#11420) Much of these are off-by-default at compile time currently so opt-in to auditing them. --- .github/workflows/main.yml | 2 +- crates/wasi/src/p3/filesystem/host.rs | 4 ++-- crates/wasi/src/p3/sockets/host/types/tcp.rs | 5 ++--- crates/wasi/src/sockets/udp.rs | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 105e313a6..f932534e7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -447,7 +447,7 @@ jobs: - uses: ./.github/actions/install-rust - run: rustup component add clippy - - run: cargo clippy --workspace --all-targets + - run: cargo clippy --workspace --all-targets --features p3,component-model-async # Similar to `micro_checks` but where we need to install some more state # (e.g. Android NDK) and we haven't factored support for those things out into diff --git a/crates/wasi/src/p3/filesystem/host.rs b/crates/wasi/src/p3/filesystem/host.rs index 9e9f44554..34e8304ec 100644 --- a/crates/wasi/src/p3/filesystem/host.rs +++ b/crates/wasi/src/p3/filesystem/host.rs @@ -573,8 +573,8 @@ impl types::HostDescriptorWithStore for WasiFilesystem { ) -> wasmtime::Result { let (fd, other) = store.with(|mut store| { let table = store.get().table; - let fd = get_descriptor(table, &fd).map(|fd| fd.clone())?; - let other = get_descriptor(table, &other).map(|other| other.clone())?; + let fd = get_descriptor(table, &fd)?.clone(); + let other = get_descriptor(table, &other)?.clone(); anyhow::Ok((fd, other)) })?; fd.is_same_object(&other).await diff --git a/crates/wasi/src/p3/sockets/host/types/tcp.rs b/crates/wasi/src/p3/sockets/host/types/tcp.rs index 66314d537..0195ed32d 100644 --- a/crates/wasi/src/p3/sockets/host/types/tcp.rs +++ b/crates/wasi/src/p3/sockets/host/types/tcp.rs @@ -169,15 +169,14 @@ impl HostTcpSocketWithStore for WasiSockets { if !is_addr_allowed(store, remote_address, SocketAddrUse::TcpConnect).await { return Err(ErrorCode::AccessDenied.into()); } - let addr = remote_address.into(); let sock = store.with(|mut view| -> SocketResult<_> { let socket = get_socket_mut(view.get().table, &socket)?; - Ok(socket.start_connect(&addr)?) + Ok(socket.start_connect(&remote_address)?) })?; // FIXME: handle possible cancellation of the outer `connect` // https://github.com/bytecodealliance/wasmtime/pull/11291#discussion_r2223917986 - let res = sock.connect(addr).await; + let res = sock.connect(remote_address).await; store.with(|mut view| -> SocketResult<_> { let socket = get_socket_mut(view.get().table, &socket)?; socket.finish_connect(res)?; diff --git a/crates/wasi/src/sockets/udp.rs b/crates/wasi/src/sockets/udp.rs index 82b6ea270..b7a044da3 100644 --- a/crates/wasi/src/sockets/udp.rs +++ b/crates/wasi/src/sockets/udp.rs @@ -213,7 +213,7 @@ impl UdpSocket { let socket = match self.udp_state { UdpState::Default | UdpState::BindStarted => Err(ErrorCode::InvalidState), UdpState::Bound => Ok(Mode::RecvFrom(Arc::clone(&self.socket))), - UdpState::Connected(addr) => Ok(Mode::Recv(Arc::clone(&self.socket), addr.into())), + UdpState::Connected(addr) => Ok(Mode::Recv(Arc::clone(&self.socket), addr)), }; async move { let socket = socket?; From 2ee62900591c557fc7f1bb0ade7b80ac108aca44 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 12 Aug 2025 12:59:11 -0500 Subject: [PATCH 2/3] Add a cwasm produced during testing to `.gitignore` (#11421) * Add a cwasm produced during testing to `.gitignore` Added in wasip3-prototyping but never made its way upstream here, so doing so now. * Ignore all cwasms in gitignore --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index d2f8f4b8b..28a72405b 100644 --- a/.gitignore +++ b/.gitignore @@ -26,8 +26,7 @@ examples/.cache *.smt2 cranelift/isle/veri/veri_engine/test_output crates/explorer/node_modules -tests/all/pulley_provenance_test.cwasm -tests/all/pulley_provenance_test_component.cwasm +*.cwasm /artifacts testcase*.wat testcase*.wasm From cfc056386f163be37ff150df257f49ad05900acb Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Tue, 12 Aug 2025 11:38:04 -0700 Subject: [PATCH 3/3] Make Wasmtime's `FuncKey` one-to-one with Cranelift's `ir::UserExternalName` (#11415) * Make Wasmtime's `FuncKey` one-to-one with Cranelift's `ir::UserExternalName` `FuncKey`, which used to be called `CompileKey`, is now one-to-one with `cranelift_codegen::ir::UserExternalName`, and is used for not just identifying compilation objects but also relocations and call-graph edges. This allows us to determine the `StaticModuleIndex` and `DefinedFuncIndex` pair for any `cranelift_codegen::ir::FuncRef`, regardless of inlining depth, which fixes some fuzz bugs on OSS-Fuzz. This continues pushing on the idea that Wasmtime's compilation orchestration and linking should be relatively agnostic to the kinds of things it is actually compiling and linking, allowing us to tweak, add, and remove new kinds of `FuncKey`s more easily. Adding a new `FuncKey` should not require modifying relocation resolution, for example, just a little bit of code to run the associated compilation and optionally some code to extract metadata into our final artifacts for querying at runtime. Everything in between should Just Continue Working. We still aren't all the way there yet, but this does bring us a little bit closer. Finally, in Cranelift's inlining pass, this adds a check that a block is inserted in the layout before attempting to remove it from the layout, which would otherwise cause panics. This was triggered by multi-level inlining and now-unreachable blocks in the inner callees. I'll note that this does update basically all of the disas tests, or at least nearly all of them that make function calls. This is because the namespace/index numbering pair changed slightly to align with `FuncKey`, but that should pretty much be the only changes. * remove debug info from panic message, it is only available in some `cfg`s * fill out module doc comment * Fix compilation without `component-model` feature * Fix some more cfg compilations * cargo fmt * fix a wrong `&dyn Any` auto coercion; add helpful debug logging and assertions for this kind of thing --- Cargo.lock | 1 + cranelift/codegen/src/inline.rs | 2 +- crates/cranelift/src/compiler.rs | 197 ++++-- crates/cranelift/src/compiler/component.rs | 10 +- .../src/debug/transform/address_transform.rs | 4 +- crates/cranelift/src/debug/transform/mod.rs | 24 +- crates/cranelift/src/func_environ.rs | 52 +- crates/cranelift/src/lib.rs | 31 +- crates/cranelift/src/obj.rs | 102 ++- crates/environ/src/compile/key.rs | 221 +++++++ crates/environ/src/compile/mod.rs | 34 +- crates/environ/src/compile/module_environ.rs | 35 +- crates/environ/src/component/compiler.rs | 6 +- crates/environ/src/component/translate.rs | 7 +- .../environ/src/component/translate/adapt.rs | 7 +- crates/environ/src/hostcall.rs | 23 + crates/environ/src/module_artifacts.rs | 2 +- crates/wasmtime/src/compile.rs | 609 ++++++------------ crates/wasmtime/src/engine/serialization.rs | 2 + crates/winch/Cargo.toml | 1 + crates/winch/src/compiler.rs | 77 ++- tests/disas/call-indirect.wat | 2 +- .../direct-adapter-calls-inlining.wat | 4 +- .../component-model/direct-adapter-calls.wat | 6 +- tests/disas/component-model/enum.wat | 2 +- ...xported-module-makes-adapters-indirect.wat | 2 +- tests/disas/component-model/inlining-bug.wat | 93 +++ .../component-model/inlining-fuzz-bug.wat | 4 +- ...instantiations-makes-adapters-indirect.wat | 2 +- tests/disas/duplicate-function-types.wat | 2 +- tests/disas/epoch-interruption.wat | 2 +- .../gc/drc/array-new-fixed-of-gc-refs.wat | 2 +- tests/disas/gc/drc/array-new-fixed.wat | 2 +- tests/disas/gc/drc/array-new.wat | 2 +- tests/disas/gc/drc/br-on-cast-fail.wat | 4 +- tests/disas/gc/drc/br-on-cast.wat | 4 +- .../gc/drc/call-indirect-and-subtyping.wat | 6 +- tests/disas/gc/drc/externref-globals.wat | 2 +- tests/disas/gc/drc/funcref-in-gc-heap-get.wat | 2 +- tests/disas/gc/drc/funcref-in-gc-heap-new.wat | 4 +- tests/disas/gc/drc/funcref-in-gc-heap-set.wat | 2 +- tests/disas/gc/drc/ref-cast.wat | 2 +- .../gc/drc/ref-test-concrete-func-type.wat | 2 +- tests/disas/gc/drc/ref-test-concrete-type.wat | 2 +- tests/disas/gc/drc/struct-new-default.wat | 2 +- tests/disas/gc/drc/struct-new.wat | 2 +- tests/disas/gc/drc/struct-set.wat | 2 +- .../gc/null/array-new-fixed-of-gc-refs.wat | 2 +- tests/disas/gc/null/array-new-fixed.wat | 2 +- tests/disas/gc/null/array-new.wat | 2 +- tests/disas/gc/null/br-on-cast-fail.wat | 4 +- tests/disas/gc/null/br-on-cast.wat | 4 +- .../gc/null/call-indirect-and-subtyping.wat | 6 +- .../disas/gc/null/funcref-in-gc-heap-get.wat | 2 +- .../disas/gc/null/funcref-in-gc-heap-new.wat | 4 +- .../disas/gc/null/funcref-in-gc-heap-set.wat | 2 +- tests/disas/gc/null/ref-cast.wat | 2 +- .../gc/null/ref-test-concrete-func-type.wat | 2 +- .../disas/gc/null/ref-test-concrete-type.wat | 2 +- tests/disas/gc/null/struct-new-default.wat | 2 +- tests/disas/gc/null/struct-new.wat | 2 +- tests/disas/gc/struct-new-default.wat | 2 +- tests/disas/gc/struct-new.wat | 2 +- tests/disas/icall-loop.wat | 4 +- tests/disas/icall-simd.wat | 2 +- tests/disas/icall.wat | 2 +- tests/disas/indirect-call-no-caching.wat | 2 +- tests/disas/memory-min-max-same.wat | 2 +- tests/disas/passive-data.wat | 4 +- tests/disas/readonly-funcrefs.wat | 2 +- tests/disas/ref-func-0.wat | 2 +- tests/disas/table-copy.wat | 4 +- tests/disas/table-set-fixed-size.wat | 4 +- tests/disas/table-set.wat | 4 +- tests/disas/typed-funcrefs.wat | 4 +- .../disas/winch/x64/table/init_copy_drop.wat | 18 +- tests/disas/x64-simd-round-without-sse41.wat | 16 +- winch/codegen/src/codegen/call.rs | 9 +- winch/codegen/src/codegen/env.rs | 22 +- 79 files changed, 996 insertions(+), 755 deletions(-) create mode 100644 crates/environ/src/compile/key.rs create mode 100644 tests/disas/component-model/inlining-bug.wat diff --git a/Cargo.lock b/Cargo.lock index 530cec5a0..8e9797bbb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4914,6 +4914,7 @@ dependencies = [ "anyhow", "cranelift-codegen", "gimli 0.32.0", + "log", "object 0.37.1", "target-lexicon", "wasmparser 0.236.0", diff --git a/cranelift/codegen/src/inline.rs b/cranelift/codegen/src/inline.rs index 1d3f21c9a..1f75378e1 100644 --- a/cranelift/codegen/src/inline.rs +++ b/cranelift/codegen/src/inline.rs @@ -445,7 +445,7 @@ fn inline_one( // terminator, so do a quick pass over the inlined blocks and remove any // empty blocks from the caller's layout. for block in entity_map.iter_inlined_blocks(func) { - if func.layout.first_inst(block).is_none() { + if func.layout.is_block_inserted(block) && func.layout.first_inst(block).is_none() { func.layout.remove_block(block); } } diff --git a/crates/cranelift/src/compiler.rs b/crates/cranelift/src/compiler.rs index c0434a271..afe17279b 100644 --- a/crates/cranelift/src/compiler.rs +++ b/crates/cranelift/src/compiler.rs @@ -30,10 +30,10 @@ use std::sync::{Arc, Mutex}; use wasmparser::{FuncValidatorAllocations, FunctionBody}; use wasmtime_environ::{ AddressMapSection, BuiltinFunctionIndex, CacheStore, CompileError, CompiledFunctionBody, - DefinedFuncIndex, FlagValue, FuncIndex, FunctionBodyData, FunctionLoc, HostCall, - InliningCompiler, ModuleTranslation, ModuleTypesBuilder, PtrSize, RelocationTarget, - StackMapSection, StaticModuleIndex, TrapEncodingBuilder, TrapSentinel, TripleExt, Tunables, - VMOffsets, WasmFuncType, WasmValType, + DefinedFuncIndex, FlagValue, FuncKey, FunctionBodyData, FunctionLoc, HostCall, + InliningCompiler, ModuleTranslation, ModuleTypesBuilder, PtrSize, StackMapSection, + StaticModuleIndex, TrapEncodingBuilder, TrapSentinel, TripleExt, Tunables, VMOffsets, + WasmFuncType, WasmValType, }; #[cfg(feature = "component-model")] @@ -176,12 +176,13 @@ impl Compiler { .params .insert(0, ir::AbiParam::new(self.isa.pointer_type())); let new_sig = builder.func.import_signature(new_signature); - let name = ir::ExternalName::User(builder.func.declare_imported_user_function( - ir::UserExternalName { - namespace: crate::NS_PULLEY_HOSTCALL, - index: hostcall.into().index(), - }, - )); + let key = FuncKey::PulleyHostCall(hostcall.into()); + let (namespace, index) = key.into_raw_parts(); + let name = ir::ExternalName::User( + builder + .func + .declare_imported_user_function(ir::UserExternalName { namespace, index }), + ); let func = builder.func.import_function(ir::ExtFuncData { name, signature: new_sig, @@ -198,6 +199,29 @@ impl Compiler { } } +fn box_dyn_any_compiled_function(f: CompiledFunction) -> Box { + let b = box_dyn_any(f); + debug_assert!(b.is::()); + b +} + +fn box_dyn_any_compiler_context(ctx: Option) -> Box { + let b = box_dyn_any(ctx); + debug_assert!(b.is::>()); + b +} + +fn box_dyn_any(x: impl Any + Send + Sync) -> Box { + log::trace!( + "making Box of {}", + std::any::type_name_of_val(&x) + ); + let b = Box::new(x); + let r: &(dyn Any + Sync + Send) = &*b; + log::trace!(" --> {r:#p}"); + b +} + impl wasmtime_environ::Compiler for Compiler { fn inlining_compiler(&self) -> Option<&dyn wasmtime_environ::InliningCompiler> { Some(self) @@ -206,14 +230,20 @@ impl wasmtime_environ::Compiler for Compiler { fn compile_function( &self, translation: &ModuleTranslation<'_>, - func_index: DefinedFuncIndex, + key: FuncKey, input: FunctionBodyData<'_>, types: &ModuleTypesBuilder, symbol: &str, ) -> Result { + log::trace!("compiling Wasm function: {key:?} = {symbol:?}"); + let isa = &*self.isa; let module = &translation.module; - let func_index = module.func_index(func_index); + + let (module_index, def_func_index) = key.unwrap_defined_wasm_function(); + debug_assert_eq!(translation.module_index, module_index); + + let func_index = module.func_index(def_func_index); let sig = translation.module.functions[func_index] .signature .unwrap_module_type_index(); @@ -223,10 +253,8 @@ impl wasmtime_environ::Compiler for Compiler { let context = &mut compiler.cx.codegen_context; context.func.signature = wasm_call_signature(isa, wasm_func_ty, &self.tunables); - context.func.name = UserFuncName::User(UserExternalName { - namespace: crate::NS_WASM_FUNC, - index: func_index.as_u32(), - }); + let (namespace, index) = key.into_raw_parts(); + context.func.name = UserFuncName::User(UserExternalName { namespace, index }); if self.tunables.generate_native_debuginfo { context.func.collect_debug_info(); @@ -311,7 +339,7 @@ impl wasmtime_environ::Compiler for Compiler { log::trace!("`{symbol}` timing info\n{timing}"); Ok(CompiledFunctionBody { - code: Box::new(Some(compiler.cx)), + code: box_dyn_any_compiler_context(Some(compiler.cx)), needs_gc_heap: func_env.needs_gc_heap(), }) } @@ -320,9 +348,14 @@ impl wasmtime_environ::Compiler for Compiler { &self, translation: &ModuleTranslation<'_>, types: &ModuleTypesBuilder, - def_func_index: DefinedFuncIndex, - _symbol: &str, + key: FuncKey, + symbol: &str, ) -> Result { + log::trace!("compiling array-to-wasm trampoline: {key:?} = {symbol:?}"); + + let (module_index, def_func_index) = key.unwrap_array_to_wasm_trampoline(); + debug_assert_eq!(translation.module_index, module_index); + let func_index = translation.module.func_index(def_func_index); let sig = translation.module.functions[func_index] .signature @@ -369,7 +402,8 @@ impl wasmtime_environ::Compiler for Compiler { ); // Then call the Wasm function with those arguments. - let call = declare_and_call(&mut builder, wasm_call_sig, func_index.as_u32(), &args); + let callee_key = FuncKey::DefinedWasmFunction(module_index, def_func_index); + let call = declare_and_call(&mut builder, wasm_call_sig, callee_key, &args); let results = builder.func.dfg.inst_results(call).to_vec(); // Then store the results back into the array. @@ -390,7 +424,7 @@ impl wasmtime_environ::Compiler for Compiler { builder.finalize(); Ok(CompiledFunctionBody { - code: Box::new(Some(compiler.cx)), + code: box_dyn_any_compiler_context(Some(compiler.cx)), needs_gc_heap: false, }) } @@ -398,8 +432,11 @@ impl wasmtime_environ::Compiler for Compiler { fn compile_wasm_to_array_trampoline( &self, wasm_func_ty: &WasmFuncType, - _symbol: &str, + key: FuncKey, + symbol: &str, ) -> Result { + log::trace!("compiling wasm-to-array trampoline: {key:?} = {symbol:?}"); + let isa = &*self.isa; let pointer_type = isa.pointer_type(); let wasm_call_sig = wasm_call_signature(isa, wasm_func_ty, &self.tunables); @@ -464,7 +501,7 @@ impl wasmtime_environ::Compiler for Compiler { builder.finalize(); Ok(CompiledFunctionBody { - code: Box::new(Some(compiler.cx)), + code: box_dyn_any_compiler_context(Some(compiler.cx)), needs_gc_heap: false, }) } @@ -473,8 +510,13 @@ impl wasmtime_environ::Compiler for Compiler { &self, obj: &mut Object<'static>, funcs: &[(String, Box)], - resolve_reloc: &dyn Fn(usize, RelocationTarget) -> usize, + resolve_reloc: &dyn Fn(usize, FuncKey) -> usize, ) -> Result> { + log::trace!( + "appending functions to object file: {:#?}", + funcs.iter().map(|(sym, _)| sym).collect::>() + ); + let mut builder = ModuleTextBuilder::new(obj, self, self.isa.text_section_builder(funcs.len())); if self.linkopts.force_jump_veneers { @@ -486,24 +528,32 @@ impl wasmtime_environ::Compiler for Compiler { let mut ret = Vec::with_capacity(funcs.len()); for (i, (sym, func)) in funcs.iter().enumerate() { + debug_assert!(!func.is::>()); + debug_assert!(func.is::()); let func = func.downcast_ref::().unwrap(); - let (sym, range) = builder.append_func(&sym, func, |idx| resolve_reloc(i, idx)); + + let (sym_id, range) = builder.append_func(&sym, func, |idx| resolve_reloc(i, idx)); + log::trace!("symbol id {sym_id:?} = {sym:?}"); + if self.tunables.generate_address_map { let addr = func.address_map(); addrs.push(range.clone(), &addr.instructions); } + clif_to_env_stack_maps( &mut stack_maps, range.clone(), func.buffer.user_stack_maps(), ); + traps.push(range.clone(), &func.traps().collect::>()); builder.append_padding(self.linkopts.padding_between_functions); + let info = FunctionLoc { start: u32::try_from(range.start).unwrap(), length: u32::try_from(range.end - range.start).unwrap(), }; - ret.push((sym, info)); + ret.push((sym_id, info)); } builder.finish(); @@ -549,13 +599,19 @@ impl wasmtime_environ::Compiler for Compiler { dwarf_package_bytes: Option<&'a [u8]>, tunables: &'a Tunables, ) -> Result<()> { + log::trace!("appending DWARF debug info"); + let get_func = move |m, f| { let (sym, any) = get_func(m, f); + log::trace!("get_func({m:?}, {f:?}) -> ({sym:?}, {any:#p})"); + debug_assert!(!any.is::>()); + debug_assert!(any.is::()); ( sym, any.downcast_ref::().unwrap().metadata(), ) }; + let mut compilation = crate::debug::Compilation::new( &*self.isa, translations, @@ -613,15 +669,18 @@ impl wasmtime_environ::Compiler for Compiler { fn compile_wasm_to_builtin( &self, - index: BuiltinFunctionIndex, - _symbol: &str, + key: FuncKey, + symbol: &str, ) -> Result { + log::trace!("compiling wasm-to-builtin trampoline: {key:?} = {symbol:?}"); + let isa = &*self.isa; let ptr_size = isa.pointer_bytes(); let pointer_type = isa.pointer_type(); let sigs = BuiltinFunctionSignatures::new(self); - let wasm_sig = sigs.wasm_signature(index); - let host_sig = sigs.host_signature(index); + let builtin_func_index = key.unwrap_wasm_to_builtin_trampoline(); + let wasm_sig = sigs.wasm_signature(builtin_func_index); + let host_sig = sigs.host_signature(builtin_func_index); let mut compiler = self.function_compiler(); let func = ir::Function::with_name_signature(Default::default(), wasm_sig.clone()); @@ -643,7 +702,7 @@ impl wasmtime_environ::Compiler for Compiler { // Now it's time to delegate to the actual builtin. Forward all our own // arguments to the libcall itself. let args = builder.block_params(block0).to_vec(); - let call = self.call_builtin(&mut builder, vmctx, &args, index, host_sig); + let call = self.call_builtin(&mut builder, vmctx, &args, builtin_func_index, host_sig); let results = builder.func.dfg.inst_results(call).to_vec(); // Libcalls do not explicitly `longjmp` for example but instead return a @@ -652,7 +711,7 @@ impl wasmtime_environ::Compiler for Compiler { // value and raise a trap as appropriate. With the `results` above check // what `index` is and for each libcall that has a trapping return value // process it here. - match index.trap_sentinel() { + match builtin_func_index.trap_sentinel() { Some(TrapSentinel::Falsy) => { self.raise_if_host_trapped(&mut builder, vmctx, results[0]); } @@ -685,7 +744,7 @@ impl wasmtime_environ::Compiler for Compiler { builder.finalize(); Ok(CompiledFunctionBody { - code: Box::new(Some(compiler.cx)), + code: box_dyn_any_compiler_context(Some(compiler.cx)), needs_gc_heap: false, }) } @@ -693,7 +752,9 @@ impl wasmtime_environ::Compiler for Compiler { fn compiled_function_relocation_targets<'a>( &'a self, func: &'a dyn Any, - ) -> Box + 'a> { + ) -> Box + 'a> { + debug_assert!(!func.is::>()); + debug_assert!(func.is::()); let func = func.downcast_ref::().unwrap(); Box::new(func.relocations().map(|r| r.reloc_target)) } @@ -703,8 +764,10 @@ impl InliningCompiler for Compiler { fn calls( &self, func_body: &CompiledFunctionBody, - calls: &mut wasmtime_environ::prelude::IndexSet, + calls: &mut wasmtime_environ::prelude::IndexSet, ) -> Result<()> { + debug_assert!(!func_body.code.is::()); + debug_assert!(func_body.code.is::>()); let cx = func_body .code .downcast_ref::>() @@ -716,13 +779,15 @@ impl InliningCompiler for Compiler { func.params .user_named_funcs() .values() - .filter(|name| name.namespace == crate::NS_WASM_FUNC) - .map(|name| FuncIndex::from_u32(name.index)), + .map(|name| FuncKey::from_raw_parts(name.namespace, name.index)) + .filter(|key| matches!(key, FuncKey::DefinedWasmFunction(_, _))), ); Ok(()) } fn size(&self, func_body: &CompiledFunctionBody) -> u32 { + debug_assert!(!func_body.code.is::()); + debug_assert!(func_body.code.is::>()); let cx = func_body .code .downcast_ref::>() @@ -737,8 +802,10 @@ impl InliningCompiler for Compiler { fn inline<'a>( &self, func_body: &mut CompiledFunctionBody, - get_callee: &'a mut dyn FnMut(FuncIndex) -> Option<&'a CompiledFunctionBody>, + get_callee: &'a mut dyn FnMut(FuncKey) -> Option<&'a CompiledFunctionBody>, ) -> Result<()> { + debug_assert!(!func_body.code.is::()); + debug_assert!(func_body.code.is::>()); let code = func_body .code .downcast_mut::>() @@ -748,7 +815,7 @@ impl InliningCompiler for Compiler { cx.codegen_context.inline(Inliner(get_callee))?; return Ok(()); - struct Inliner<'a>(&'a mut dyn FnMut(FuncIndex) -> Option<&'a CompiledFunctionBody>); + struct Inliner<'a>(&'a mut dyn FnMut(FuncKey) -> Option<&'a CompiledFunctionBody>); impl cranelift_codegen::inline::Inline for Inliner<'_> { fn inline( @@ -767,22 +834,23 @@ impl InliningCompiler for Compiler { | ir::ExternalName::KnownSymbol(_) => return InlineCommand::KeepCall, }; let callee = &caller.params.user_named_funcs()[callee]; - let callee = if callee.namespace == crate::NS_WASM_FUNC { - FuncIndex::from_u32(callee.index) - } else { - return InlineCommand::KeepCall; - }; - match (self.0)(callee) { - None => InlineCommand::KeepCall, - Some(func_body) => { - let cx = func_body - .code - .downcast_ref::>() - .unwrap(); - InlineCommand::Inline(Cow::Borrowed( - &cx.as_ref().unwrap().codegen_context.func, - )) - } + let callee = FuncKey::from_raw_parts(callee.namespace, callee.index); + match callee { + FuncKey::DefinedWasmFunction(_, _) => match (self.0)(callee) { + None => InlineCommand::KeepCall, + Some(func_body) => { + debug_assert!(!func_body.code.is::()); + debug_assert!(func_body.code.is::>()); + let cx = func_body + .code + .downcast_ref::>() + .unwrap(); + InlineCommand::Inline(Cow::Borrowed( + &cx.as_ref().unwrap().codegen_context.func, + )) + } + }, + _ => InlineCommand::KeepCall, } } } @@ -794,6 +862,9 @@ impl InliningCompiler for Compiler { input: Option>, symbol: &str, ) -> Result<()> { + log::trace!("finish compiling {symbol:?}"); + debug_assert!(!func_body.code.is::()); + debug_assert!(func_body.code.is::>()); let cx = func_body .code .downcast_mut::>() @@ -818,7 +889,7 @@ impl InliningCompiler for Compiler { log::debug!("`{symbol}` compiled in {:?}", timing.total()); log::trace!("`{symbol}` timing info\n{timing}"); - func_body.code = Box::new(compiled_func); + func_body.code = box_dyn_any_compiled_function(compiled_func); Ok(()) } } @@ -1256,15 +1327,15 @@ fn clif_to_env_stack_maps( fn declare_and_call( builder: &mut FunctionBuilder, signature: ir::Signature, - func_index: u32, + callee_key: FuncKey, args: &[ir::Value], ) -> ir::Inst { - let name = ir::ExternalName::User(builder.func.declare_imported_user_function( - ir::UserExternalName { - namespace: crate::NS_WASM_FUNC, - index: func_index, - }, - )); + let (namespace, index) = callee_key.into_raw_parts(); + let name = ir::ExternalName::User( + builder + .func + .declare_imported_user_function(ir::UserExternalName { namespace, index }), + ); let signature = builder.func.import_signature(signature); let callee = builder.func.dfg.ext_funcs.push(ir::ExtFuncData { name, diff --git a/crates/cranelift/src/compiler/component.rs b/crates/cranelift/src/compiler/component.rs index b60b5a2a9..1fee2475a 100644 --- a/crates/cranelift/src/compiler/component.rs +++ b/crates/cranelift/src/compiler/component.rs @@ -9,12 +9,12 @@ use cranelift_codegen::ir::condcodes::IntCC; use cranelift_codegen::ir::{self, InstBuilder, MemFlags, Value}; use cranelift_codegen::isa::{CallConv, TargetIsa}; use cranelift_frontend::FunctionBuilder; -use wasmtime_environ::fact::PREPARE_CALL_FIXED_PARAMS; use wasmtime_environ::{CompiledFunctionBody, component::*}; use wasmtime_environ::{ EntityRef, HostCall, ModuleInternedTypeIndex, PtrSize, TrapSentinel, Tunables, WasmFuncType, WasmValType, }; +use wasmtime_environ::{FuncKey, fact::PREPARE_CALL_FIXED_PARAMS}; struct TrampolineCompiler<'a> { compiler: &'a Compiler, @@ -1281,7 +1281,7 @@ impl ComponentCompiler for Compiler { &self, component: &ComponentTranslation, types: &ComponentTypesBuilder, - index: TrampolineIndex, + key: FuncKey, tunables: &Tunables, _symbol: &str, ) -> Result> { @@ -1292,7 +1292,7 @@ impl ComponentCompiler for Compiler { &mut compiler, &component.component, types, - index, + key.unwrap_component_trampoline(), abi, tunables, ); @@ -1325,12 +1325,12 @@ impl ComponentCompiler for Compiler { ); } - c.translate(&component.trampolines[index]); + c.translate(&component.trampolines[key.unwrap_component_trampoline()]); c.builder.finalize(); compiler.cx.abi = Some(abi); Ok(CompiledFunctionBody { - code: Box::new(Some(compiler.cx)), + code: super::box_dyn_any_compiler_context(Some(compiler.cx)), needs_gc_heap: false, }) }; diff --git a/crates/cranelift/src/debug/transform/address_transform.rs b/crates/cranelift/src/debug/transform/address_transform.rs index 9d84b4ce2..7de691c7f 100644 --- a/crates/cranelift/src/debug/transform/address_transform.rs +++ b/crates/cranelift/src/debug/transform/address_transform.rs @@ -498,8 +498,10 @@ impl AddressTransform { >, wasm_file: wasmtime_environ::WasmFileInfo, ) -> Self { + use cranelift_entity::EntityRef; + let mut translations = wasmtime_environ::PrimaryMap::new(); - let mut translation = wasmtime_environ::ModuleTranslation::default(); + let mut translation = wasmtime_environ::ModuleTranslation::new(StaticModuleIndex::new(0)); translation.debuginfo.wasm_file = wasm_file; translation .module diff --git a/crates/cranelift/src/debug/transform/mod.rs b/crates/cranelift/src/debug/transform/mod.rs index 4eb20832d..2cf171bb8 100644 --- a/crates/cranelift/src/debug/transform/mod.rs +++ b/crates/cranelift/src/debug/transform/mod.rs @@ -121,16 +121,20 @@ fn read_dwarf_package_from_bytes<'data>( let mut validator = wasmparser::Validator::new(); let parser = wasmparser::Parser::new(0); let mut types = wasmtime_environ::ModuleTypesBuilder::new(&validator); - let translation = - match wasmtime_environ::ModuleEnvironment::new(tunables, &mut validator, &mut types) - .translate(parser, dwp_bytes) - { - Ok(translation) => translation, - Err(e) => { - log::warn!("failed to parse wasm dwarf package: {e:?}"); - return None; - } - }; + let translation = match wasmtime_environ::ModuleEnvironment::new( + tunables, + &mut validator, + &mut types, + StaticModuleIndex::from_u32(0), + ) + .translate(parser, dwp_bytes) + { + Ok(translation) => translation, + Err(e) => { + log::warn!("failed to parse wasm dwarf package: {e:?}"); + return None; + } + }; match load_dwp(translation, buffer) { Ok(package) => Some(package), diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs index 5586da114..e0ed28ba1 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -23,10 +23,10 @@ use std::mem; use wasmparser::{Operator, WasmFeatures}; use wasmtime_environ::{ BuiltinFunctionIndex, DataIndex, DefinedFuncIndex, ElemIndex, EngineOrModuleTypeIndex, - FuncIndex, GlobalIndex, IndexType, Memory, MemoryIndex, Module, ModuleInternedTypeIndex, - ModuleTranslation, ModuleTypesBuilder, PtrSize, Table, TableIndex, TripleExt, Tunables, - TypeConvert, TypeIndex, VMOffsets, WasmCompositeInnerType, WasmFuncType, WasmHeapTopType, - WasmHeapType, WasmRefType, WasmResult, WasmValType, + FuncIndex, FuncKey, GlobalIndex, IndexType, Memory, MemoryIndex, Module, + ModuleInternedTypeIndex, ModuleTranslation, ModuleTypesBuilder, PtrSize, Table, TableIndex, + TripleExt, Tunables, TypeConvert, TypeIndex, VMOffsets, WasmCompositeInnerType, WasmFuncType, + WasmHeapTopType, WasmHeapType, WasmRefType, WasmResult, WasmValType, }; use wasmtime_environ::{FUNCREF_INIT_BIT, FUNCREF_MASK}; use wasmtime_math::f64_cvt_to_int_bounds; @@ -53,17 +53,17 @@ impl BuiltinFunctions { } } - fn load_builtin(&mut self, func: &mut Function, index: BuiltinFunctionIndex) -> ir::FuncRef { - let cache = &mut self.builtins[index.index() as usize]; + fn load_builtin(&mut self, func: &mut Function, builtin: BuiltinFunctionIndex) -> ir::FuncRef { + let cache = &mut self.builtins[builtin.index() as usize]; if let Some(f) = cache { return *f; } - let signature = func.import_signature(self.types.wasm_signature(index)); - let name = - ir::ExternalName::User(func.declare_imported_user_function(ir::UserExternalName { - namespace: crate::NS_WASMTIME_BUILTIN, - index: index.index(), - })); + let signature = func.import_signature(self.types.wasm_signature(builtin)); + let key = FuncKey::WasmToBuiltinTrampoline(builtin); + let (namespace, index) = key.into_raw_parts(); + let name = ir::ExternalName::User( + func.declare_imported_user_function(ir::UserExternalName { namespace, index }), + ); let f = func.import_function(ir::ExtFuncData { name, signature, @@ -1265,15 +1265,18 @@ impl FuncEnvironment<'_> { def_func_index: DefinedFuncIndex, ) -> ir::FuncRef { let func_index = self.module.func_index(def_func_index); + let ty = self.module.functions[func_index] .signature .unwrap_module_type_index(); let signature = self.get_or_create_interned_sig_ref(func, ty); - let name = - ir::ExternalName::User(func.declare_imported_user_function(ir::UserExternalName { - namespace: crate::NS_WASM_FUNC, - index: func_index.as_u32(), - })); + + let key = FuncKey::DefinedWasmFunction(self.translation.module_index, def_func_index); + let (namespace, index) = key.into_raw_parts(); + let name = ir::ExternalName::User( + func.declare_imported_user_function(ir::UserExternalName { namespace, index }), + ); + func.import_function(ir::ExtFuncData { name, signature, @@ -1288,15 +1291,20 @@ impl FuncEnvironment<'_> { ) -> ir::FuncRef { assert!(self.module.is_imported_function(func_index)); assert!(self.translation.known_imported_functions[func_index].is_some()); + let ty = self.module.functions[func_index] .signature .unwrap_module_type_index(); let signature = self.get_or_create_interned_sig_ref(func, ty); - let name = - ir::ExternalName::User(func.declare_imported_user_function(ir::UserExternalName { - namespace: crate::NS_WASM_FUNC, - index: func_index.as_u32(), - })); + + let (module, def_func_index) = + self.translation.known_imported_functions[func_index].unwrap(); + let key = FuncKey::DefinedWasmFunction(module, def_func_index); + let (namespace, index) = key.into_raw_parts(); + let name = ir::ExternalName::User( + func.declare_imported_user_function(ir::UserExternalName { namespace, index }), + ); + func.import_function(ir::ExtFuncData { name, signature, diff --git a/crates/cranelift/src/lib.rs b/crates/cranelift/src/lib.rs index 93748ad40..b25fc8921 100644 --- a/crates/cranelift/src/lib.rs +++ b/crates/cranelift/src/lib.rs @@ -25,8 +25,8 @@ use cranelift_entity::PrimaryMap; use target_lexicon::Architecture; use wasmtime_environ::{ - BuiltinFunctionIndex, FlagValue, FuncIndex, RelocationTarget, Trap, TrapInformation, Tunables, - WasmFuncType, WasmHeapTopType, WasmHeapType, WasmValType, + BuiltinFunctionIndex, FlagValue, FuncKey, Trap, TrapInformation, Tunables, WasmFuncType, + WasmHeapTopType, WasmHeapType, WasmValType, }; pub use builder::builder; @@ -223,29 +223,13 @@ fn reference_type(wasm_ht: WasmHeapType, pointer_type: ir::Type) -> ir::Type { // List of namespaces which are processed in `mach_reloc_to_reloc` below. -/// Namespace corresponding to wasm functions, the index is the index of the -/// defined function that's being referenced. -pub const NS_WASM_FUNC: u32 = 0; - -/// Namespace for builtin function trampolines. The index is the index of the -/// builtin that's being referenced. These trampolines invoke the real host -/// function through an indirect function call loaded by the `VMContext`. -pub const NS_WASMTIME_BUILTIN: u32 = 1; - -/// Namespace used to when a call from Pulley to the host is being made. This is -/// used with a `colocated: false` name to trigger codegen for a special opcode -/// for pulley-to-host communication. The index of the functions used in this -/// namespace correspond to the function signature of `for_each_host_signature!` -/// in the pulley_interpreter crate. -pub const NS_PULLEY_HOSTCALL: u32 = 2; - /// A record of a relocation to perform. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Relocation { /// The relocation code. pub reloc: binemit::Reloc, /// Relocation target. - pub reloc_target: RelocationTarget, + pub reloc_target: FuncKey, /// The offset where to apply the relocation. pub offset: binemit::CodeOffset, /// The addend to add to the relocation value. @@ -312,14 +296,7 @@ fn mach_reloc_to_reloc( let reloc_target = match *target { FinalizedRelocTarget::ExternalName(ExternalName::User(user_func_ref)) => { let name = &name_map[user_func_ref]; - match name.namespace { - NS_WASM_FUNC => RelocationTarget::Wasm(FuncIndex::from_u32(name.index)), - NS_WASMTIME_BUILTIN => { - RelocationTarget::Builtin(BuiltinFunctionIndex::from_u32(name.index)) - } - NS_PULLEY_HOSTCALL => RelocationTarget::PulleyHostcall(name.index), - _ => panic!("unknown namespace {}", name.namespace), - } + FuncKey::from_raw_parts(name.namespace, name.index) } FinalizedRelocTarget::ExternalName(ExternalName::LibCall(libcall)) => { // We should have avoided any code that needs this style of libcalls diff --git a/crates/cranelift/src/obj.rs b/crates/cranelift/src/obj.rs index db7667315..cd3142abe 100644 --- a/crates/cranelift/src/obj.rs +++ b/crates/cranelift/src/obj.rs @@ -13,7 +13,7 @@ //! function body, the imported wasm function do not. The trampolines symbol //! names have format "_trampoline_N", where N is `SignatureIndex`. -use crate::{CompiledFunction, RelocationTarget}; +use crate::CompiledFunction; use anyhow::Result; use cranelift_codegen::TextSectionBuilder; use cranelift_codegen::isa::unwind::{UnwindInfo, systemv}; @@ -23,8 +23,8 @@ use gimli::write::{Address, EhFrame, EndianVec, FrameTable, Writer}; use object::write::{Object, SectionId, StandardSegment, Symbol, SymbolId, SymbolSection}; use object::{Architecture, SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope}; use std::ops::Range; -use wasmtime_environ::obj; use wasmtime_environ::{Compiler, TripleExt}; +use wasmtime_environ::{FuncKey, obj}; const TEXT_SECTION_NAME: &[u8] = b".text"; @@ -120,7 +120,7 @@ impl<'a> ModuleTextBuilder<'a> { &mut self, name: &str, compiled_func: &'a CompiledFunction, - resolve_reloc_target: impl Fn(wasmtime_environ::RelocationTarget) -> usize, + resolve_reloc_target: impl Fn(wasmtime_environ::FuncKey) -> usize, ) -> (SymbolId, Range) { let body = compiled_func.buffer.data(); let alignment = compiled_func.alignment; @@ -146,65 +146,49 @@ impl<'a> ModuleTextBuilder<'a> { for r in compiled_func.relocations() { let reloc_offset = off + u64::from(r.offset); - match r.reloc_target { - // Relocations against user-defined functions means that this is - // a relocation against a module-local function, typically a - // call between functions. The `text` field is given priority to - // resolve this relocation before we actually emit an object - // file, but if it can't handle it then we pass through the - // relocation. - RelocationTarget::Wasm(_) | RelocationTarget::Builtin(_) => { - let target = resolve_reloc_target(r.reloc_target); - if self - .text - .resolve_reloc(reloc_offset, r.reloc, r.addend, target) - { - continue; - } - - // At this time it's expected that all relocations are - // handled by `text.resolve_reloc`, and anything that isn't - // handled is a bug in `text.resolve_reloc` or something - // transitively there. If truly necessary, though, then this - // loop could also be updated to forward the relocation to - // the final object file as well. - panic!( - "unresolved relocation could not be processed against \ - {:?}: {r:?}", - r.reloc_target, - ); - } - // This relocation is used to fill in which hostcall id is - // desired within the `call_indirect_host` opcode of Pulley - // itself. The relocation target is the start of the instruction - // and the goal is to insert the static signature number, `n`, - // into the instruction. - // - // At this time the instruction looks like: - // - // +------+------+------+------+ - // | OP | OP_EXTENDED | N | - // +------+------+------+------+ - // - // This 4-byte encoding has `OP` indicating this is an "extended - // opcode" where `OP_EXTENDED` is a 16-bit extended opcode. - // The `N` byte is the index of the signature being called and - // is what's b eing filled in. - // - // See the `test_call_indirect_host_width` in - // `pulley/tests/all.rs` for this guarantee as well. - RelocationTarget::PulleyHostcall(n) => { - #[cfg(feature = "pulley")] - { - use pulley_interpreter::encode::Encode; - assert_eq!(pulley_interpreter::CallIndirectHost::WIDTH, 4); - } - let byte = u8::try_from(n).unwrap(); - self.text.write(reloc_offset + 3, &[byte]); + // This relocation is used to fill in which hostcall id is + // desired within the `call_indirect_host` opcode of Pulley + // itself. The relocation target is the start of the instruction + // and the goal is to insert the static signature number, `n`, + // into the instruction. + // + // At this time the instruction looks like: + // + // +------+------+------+------+ + // | OP | OP_EXTENDED | N | + // +------+------+------+------+ + // + // This 4-byte encoding has `OP` indicating this is an "extended + // opcode" where `OP_EXTENDED` is a 16-bit extended opcode. + // The `N` byte is the index of the signature being called and + // is what's b eing filled in. + // + // See the `test_call_indirect_host_width` in + // `pulley/tests/all.rs` for this guarantee as well. + if let FuncKey::PulleyHostCall(host_call) = r.reloc_target { + #[cfg(feature = "pulley")] + { + use pulley_interpreter::encode::Encode; + assert_eq!(pulley_interpreter::CallIndirectHost::WIDTH, 4); } - }; + let n = host_call.index(); + let byte = u8::try_from(n).unwrap(); + self.text.write(reloc_offset + 3, &[byte]); + continue; + } + + let target = resolve_reloc_target(r.reloc_target); + if self + .text + .resolve_reloc(reloc_offset, r.reloc, r.addend, target) + { + continue; + } + + panic!("failed to resolve relocation: {r:?} -> {target}"); } + (symbol_id, off..off + body_len) } diff --git a/crates/environ/src/compile/key.rs b/crates/environ/src/compile/key.rs new file mode 100644 index 000000000..140bd08c7 --- /dev/null +++ b/crates/environ/src/compile/key.rs @@ -0,0 +1,221 @@ +//! Keys for identifying functions during compilation, in call graphs, and when +//! resolving relocations. + +#[cfg(feature = "component-model")] +use crate::component; +use crate::{ + BuiltinFunctionIndex, DefinedFuncIndex, HostCall, ModuleInternedTypeIndex, StaticModuleIndex, +}; + +/// A sortable, comparable function key for compilation output, call graph +/// edges, and relocations. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum FuncKey { + /// A Wasm-defined function. + DefinedWasmFunction(StaticModuleIndex, DefinedFuncIndex), + + /// A trampoline from an array-caller to the given Wasm-callee. + ArrayToWasmTrampoline(StaticModuleIndex, DefinedFuncIndex), + + /// A trampoline from a Wasm-caller to an array-callee of the given type. + WasmToArrayTrampoline(ModuleInternedTypeIndex), + + /// A trampoline from a Wasm-caller to the given builtin. + WasmToBuiltinTrampoline(BuiltinFunctionIndex), + + /// A Pulley-specific host call. + PulleyHostCall(HostCall), + + /// A Wasm-caller to component builtin trampoline. + #[cfg(feature = "component-model")] + ComponentTrampoline(component::TrampolineIndex), + + /// A Wasm-caller to array-callee `resource.drop` trampoline. + #[cfg(feature = "component-model")] + ResourceDropTrampoline, +} + +impl FuncKey { + const KIND_BITS: u32 = 3; + const KIND_OFFSET: u32 = 32 - Self::KIND_BITS; + const KIND_MASK: u32 = ((1 << Self::KIND_BITS) - 1) << Self::KIND_OFFSET; + const MODULE_MASK: u32 = !Self::KIND_MASK; + + const fn new_kind(kind: u32) -> u32 { + assert!(kind < (1 << Self::KIND_BITS)); + kind << Self::KIND_OFFSET + } + + const DEFINED_WASM_FUNCTION_KIND: u32 = Self::new_kind(0); + const ARRAY_TO_WASM_TRAMPOLINE_KIND: u32 = Self::new_kind(1); + const WASM_TO_ARRAY_TRAMPOLINE_KIND: u32 = Self::new_kind(2); + const WASM_TO_BUILTIN_TRAMPOLINE_KIND: u32 = Self::new_kind(3); + const PULLEY_HOST_CALL_KIND: u32 = Self::new_kind(4); + + #[cfg(feature = "component-model")] + const COMPONENT_TRAMPOLINE_KIND: u32 = Self::new_kind(5); + #[cfg(feature = "component-model")] + const RESOURCE_DROP_TRAMPOLINE_KIND: u32 = Self::new_kind(6); + + /// Get the raw, underlying representation of this compilation key. + /// + /// The resulting values should only be used for (eventually) calling + /// `CompileKey::from_raw_parts`. + // + // NB: We use two `u32`s to exactly match + // `cranelift_codegen::ir::UserExternalName` and ensure that we can map + // one-to-one between that and `FuncKey`. + pub fn into_raw_parts(self) -> (u32, u32) { + match self { + FuncKey::DefinedWasmFunction(module, def_func) => { + assert_eq!(module.as_u32() & Self::KIND_MASK, 0); + let namespace = Self::DEFINED_WASM_FUNCTION_KIND | module.as_u32(); + let index = def_func.as_u32(); + (namespace, index) + } + FuncKey::ArrayToWasmTrampoline(module, def_func) => { + assert_eq!(module.as_u32() & Self::KIND_MASK, 0); + let namespace = Self::ARRAY_TO_WASM_TRAMPOLINE_KIND | module.as_u32(); + let index = def_func.as_u32(); + (namespace, index) + } + FuncKey::WasmToArrayTrampoline(ty) => { + let namespace = Self::WASM_TO_ARRAY_TRAMPOLINE_KIND; + let index = ty.as_u32(); + (namespace, index) + } + FuncKey::WasmToBuiltinTrampoline(builtin) => { + let namespace = Self::WASM_TO_BUILTIN_TRAMPOLINE_KIND; + let index = builtin.index(); + (namespace, index) + } + FuncKey::PulleyHostCall(host_call) => { + let namespace = Self::PULLEY_HOST_CALL_KIND; + let index = host_call.index(); + (namespace, index) + } + + #[cfg(feature = "component-model")] + FuncKey::ComponentTrampoline(trampoline) => { + let namespace = Self::COMPONENT_TRAMPOLINE_KIND; + let index = trampoline.as_u32(); + (namespace, index) + } + #[cfg(feature = "component-model")] + FuncKey::ResourceDropTrampoline => { + let namespace = Self::RESOURCE_DROP_TRAMPOLINE_KIND; + let index = 0; + (namespace, index) + } + } + } + + /// Create a compilation key from its raw, underlying representation. + /// + /// Should only be given the results of a previous call to + /// `CompileKey::into_raw_parts`. + pub fn from_raw_parts(a: u32, b: u32) -> Self { + match a & Self::KIND_MASK { + Self::DEFINED_WASM_FUNCTION_KIND => { + let module = StaticModuleIndex::from_u32(a & Self::MODULE_MASK); + let def_func = DefinedFuncIndex::from_u32(b); + Self::DefinedWasmFunction(module, def_func) + } + Self::ARRAY_TO_WASM_TRAMPOLINE_KIND => { + let module = StaticModuleIndex::from_u32(a & Self::MODULE_MASK); + let def_func = DefinedFuncIndex::from_u32(b); + Self::ArrayToWasmTrampoline(module, def_func) + } + Self::WASM_TO_ARRAY_TRAMPOLINE_KIND => { + assert_eq!(a & Self::MODULE_MASK, 0); + let ty = ModuleInternedTypeIndex::from_u32(b); + Self::WasmToArrayTrampoline(ty) + } + Self::WASM_TO_BUILTIN_TRAMPOLINE_KIND => { + assert_eq!(a & Self::MODULE_MASK, 0); + let builtin = BuiltinFunctionIndex::from_u32(b); + Self::WasmToBuiltinTrampoline(builtin) + } + Self::PULLEY_HOST_CALL_KIND => { + assert_eq!(a & Self::MODULE_MASK, 0); + let host_call = HostCall::from_index(b); + Self::PulleyHostCall(host_call) + } + + #[cfg(feature = "component-model")] + Self::COMPONENT_TRAMPOLINE_KIND => { + assert_eq!(a & Self::MODULE_MASK, 0); + let trampoline = component::TrampolineIndex::from_u32(b); + Self::ComponentTrampoline(trampoline) + } + #[cfg(feature = "component-model")] + Self::RESOURCE_DROP_TRAMPOLINE_KIND => { + assert_eq!(a & Self::MODULE_MASK, 0); + assert_eq!(b, 0); + Self::ResourceDropTrampoline + } + + k => panic!( + "bad raw parts given to `FuncKey::from_raw_parts` call: ({a}, {b}), kind would be {k}" + ), + } + } + + /// Unwrap a `FuncKey::DefinedWasmFunction` or else panic. + pub fn unwrap_defined_wasm_function(self) -> (StaticModuleIndex, DefinedFuncIndex) { + match self { + Self::DefinedWasmFunction(module, def_func) => (module, def_func), + _ => panic!("`FuncKey::unwrap_defined_wasm_function` called on {self:?}"), + } + } + + /// Unwrap a `FuncKey::ArrayToWasmTrampoline` or else panic. + pub fn unwrap_array_to_wasm_trampoline(self) -> (StaticModuleIndex, DefinedFuncIndex) { + match self { + Self::ArrayToWasmTrampoline(module, def_func) => (module, def_func), + _ => panic!("`FuncKey::unwrap_array_to_wasm_trampoline` called on {self:?}"), + } + } + + /// Unwrap a `FuncKey::WasmToArrayTrampoline` or else panic. + pub fn unwrap_wasm_to_array_trampoline(self) -> ModuleInternedTypeIndex { + match self { + Self::WasmToArrayTrampoline(ty) => ty, + _ => panic!("`FuncKey::unwrap_wasm_to_array_trampoline` called on {self:?}"), + } + } + + /// Unwrap a `FuncKey::WasmToBuiltinTrampoline` or else panic. + pub fn unwrap_wasm_to_builtin_trampoline(self) -> BuiltinFunctionIndex { + match self { + Self::WasmToBuiltinTrampoline(builtin) => builtin, + _ => panic!("`FuncKey::unwrap_wasm_to_builtin_trampoline` called on {self:?}"), + } + } + + /// Unwrap a `FuncKey::PulleyHostCall` or else panic. + pub fn unwrap_pulley_host_call(self) -> HostCall { + match self { + Self::PulleyHostCall(host_call) => host_call, + _ => panic!("`FuncKey::unwrap_pulley_host_call` called on {self:?}"), + } + } + + /// Unwrap a `FuncKey::ComponentTrampoline` or else panic. + #[cfg(feature = "component-model")] + pub fn unwrap_component_trampoline(self) -> component::TrampolineIndex { + match self { + Self::ComponentTrampoline(trampoline) => trampoline, + _ => panic!("`FuncKey::unwrap_component_trampoline` called on {self:?}"), + } + } + + /// Unwrap a `FuncKey::ResourceDropTrampoline` or else panic. + #[cfg(feature = "component-model")] + pub fn unwrap_resource_drop_trampoline(self) { + match self { + Self::ResourceDropTrampoline => {} + _ => panic!("`FuncKey::unwrap_resource_drop_trampoline` called on {self:?}"), + } + } +} diff --git a/crates/environ/src/compile/mod.rs b/crates/environ/src/compile/mod.rs index c4059cd96..ad35b2a45 100644 --- a/crates/environ/src/compile/mod.rs +++ b/crates/environ/src/compile/mod.rs @@ -3,8 +3,8 @@ use crate::prelude::*; use crate::{ - BuiltinFunctionIndex, DefinedFuncIndex, FlagValue, FuncIndex, FunctionLoc, ObjectKind, - PrimaryMap, StaticModuleIndex, TripleExt, WasmError, WasmFuncType, + DefinedFuncIndex, FlagValue, FunctionLoc, ObjectKind, PrimaryMap, StaticModuleIndex, TripleExt, + WasmError, WasmFuncType, }; use crate::{Tunables, obj}; use anyhow::Result; @@ -17,6 +17,7 @@ use std::path; use std::sync::Arc; mod address_map; +mod key; mod module_artifacts; mod module_environ; mod module_types; @@ -24,6 +25,7 @@ mod stack_maps; mod trap_encoding; pub use self::address_map::*; +pub use self::key::*; pub use self::module_artifacts::*; pub use self::module_environ::*; pub use self::module_types::*; @@ -70,19 +72,6 @@ impl core::error::Error for CompileError { } } -/// What relocations can be applied against. -/// -/// Each wasm function may refer to various other `RelocationTarget` entries. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum RelocationTarget { - /// This is a reference to another defined wasm function in the same module. - Wasm(FuncIndex), - /// This is a reference to a trampoline for a builtin function. - Builtin(BuiltinFunctionIndex), - /// A pulley->host call from the interpreter. - PulleyHostcall(u32), -} - /// Implementation of an incremental compilation's key/value cache store. /// /// In theory, this could just be Cranelift's `CacheKvStore` trait, but it is not as we want to @@ -259,7 +248,7 @@ pub trait Compiler: Send + Sync { fn compile_function( &self, translation: &ModuleTranslation<'_>, - index: DefinedFuncIndex, + key: FuncKey, data: FunctionBodyData<'_>, types: &ModuleTypesBuilder, symbol: &str, @@ -274,7 +263,7 @@ pub trait Compiler: Send + Sync { &self, translation: &ModuleTranslation<'_>, types: &ModuleTypesBuilder, - index: DefinedFuncIndex, + key: FuncKey, symbol: &str, ) -> Result; @@ -286,6 +275,7 @@ pub trait Compiler: Send + Sync { fn compile_wasm_to_array_trampoline( &self, wasm_func_ty: &WasmFuncType, + key: FuncKey, symbol: &str, ) -> Result; @@ -300,7 +290,7 @@ pub trait Compiler: Send + Sync { /// call. fn compile_wasm_to_builtin( &self, - index: BuiltinFunctionIndex, + key: FuncKey, symbol: &str, ) -> Result; @@ -309,7 +299,7 @@ pub trait Compiler: Send + Sync { fn compiled_function_relocation_targets<'a>( &'a self, func: &'a dyn Any, - ) -> Box + 'a>; + ) -> Box + 'a>; /// Appends a list of compiled functions to an in-memory object. /// @@ -342,7 +332,7 @@ pub trait Compiler: Send + Sync { &self, obj: &mut Object<'static>, funcs: &[(String, Box)], - resolve_reloc: &dyn Fn(usize, RelocationTarget) -> usize, + resolve_reloc: &dyn Fn(usize, FuncKey) -> usize, ) -> Result>; /// Creates a new `Object` file which is used to build the results of a @@ -469,7 +459,7 @@ pub trait Compiler: Send + Sync { /// An inlining compiler. pub trait InliningCompiler: Sync + Send { /// Enumerate the function calls that the given `func` makes. - fn calls(&self, func: &CompiledFunctionBody, calls: &mut IndexSet) -> Result<()>; + fn calls(&self, func: &CompiledFunctionBody, calls: &mut IndexSet) -> Result<()>; /// Get the abstract size of the given function, for the purposes of /// inlining heuristics. @@ -483,7 +473,7 @@ pub trait InliningCompiler: Sync + Send { fn inline<'a>( &self, func: &mut CompiledFunctionBody, - get_callee: &'a mut dyn FnMut(FuncIndex) -> Option<&'a CompiledFunctionBody>, + get_callee: &'a mut dyn FnMut(FuncKey) -> Option<&'a CompiledFunctionBody>, ) -> Result<()>; /// Finish compiling the given function. diff --git a/crates/environ/src/compile/module_environ.rs b/crates/environ/src/compile/module_environ.rs index 9347cfca0..fb4b98d8c 100644 --- a/crates/environ/src/compile/module_environ.rs +++ b/crates/environ/src/compile/module_environ.rs @@ -37,14 +37,17 @@ pub struct ModuleEnvironment<'a, 'data> { tunables: &'a Tunables, } -/// The result of translating via `ModuleEnvironment`. Function bodies are not -/// yet translated, and data initializers have not yet been copied out of the -/// original buffer. -#[derive(Default)] +/// The result of translating via `ModuleEnvironment`. +/// +/// Function bodies are not yet translated, and data initializers have not yet +/// been copied out of the original buffer. pub struct ModuleTranslation<'data> { /// Module information. pub module: Module, + /// This module's index. + pub module_index: StaticModuleIndex, + /// The input wasm binary. /// /// This can be useful, for example, when modules are parsed from a @@ -109,6 +112,27 @@ pub struct ModuleTranslation<'data> { } impl<'data> ModuleTranslation<'data> { + /// Create a new translation for the module with the given index. + pub fn new(module_index: StaticModuleIndex) -> Self { + Self { + module_index, + module: Module::default(), + wasm: &[], + function_body_inputs: PrimaryMap::default(), + known_imported_functions: SecondaryMap::default(), + exported_signatures: Vec::default(), + debuginfo: DebugInfoData::default(), + has_unparsed_debuginfo: false, + data: Vec::default(), + data_align: None, + total_data: 0, + passive_data: Vec::default(), + total_passive_data: 0, + code_index: 0, + types: None, + } + } + /// Returns a reference to the type information of the current module. pub fn get_types(&self) -> &Types { self.types @@ -174,9 +198,10 @@ impl<'a, 'data> ModuleEnvironment<'a, 'data> { tunables: &'a Tunables, validator: &'a mut Validator, types: &'a mut ModuleTypesBuilder, + module_index: StaticModuleIndex, ) -> Self { Self { - result: ModuleTranslation::default(), + result: ModuleTranslation::new(module_index), types, tunables, validator, diff --git a/crates/environ/src/component/compiler.rs b/crates/environ/src/component/compiler.rs index b5278428b..1f0658bad 100644 --- a/crates/environ/src/component/compiler.rs +++ b/crates/environ/src/component/compiler.rs @@ -1,5 +1,5 @@ -use crate::component::{AllCallFunc, ComponentTranslation, ComponentTypesBuilder, TrampolineIndex}; -use crate::{CompiledFunctionBody, Tunables}; +use crate::component::{AllCallFunc, ComponentTranslation, ComponentTypesBuilder}; +use crate::{CompiledFunctionBody, FuncKey, Tunables}; use anyhow::Result; /// Compilation support necessary for components. @@ -14,7 +14,7 @@ pub trait ComponentCompiler: Send + Sync { &self, component: &ComponentTranslation, types: &ComponentTypesBuilder, - trampoline: TrampolineIndex, + key: FuncKey, tunables: &Tunables, symbol: &str, ) -> Result>; diff --git a/crates/environ/src/component/translate.rs b/crates/environ/src/component/translate.rs index ecdb0e421..3ff2bb4e7 100644 --- a/crates/environ/src/component/translate.rs +++ b/crates/environ/src/component/translate.rs @@ -1082,10 +1082,12 @@ impl<'a, 'data> Translator<'a, 'data> { } => { let index = self.validator.types(0).unwrap().module_count(); self.validator.module_section(&unchecked_range)?; + let static_module_index = self.static_modules.next_key(); let translation = ModuleEnvironment::new( self.tunables, self.validator, self.types.module_types_builder(), + static_module_index, ) .translate( parser, @@ -1101,12 +1103,13 @@ impl<'a, 'data> Translator<'a, 'data> { .context("wasm component contains an invalid module section") })?, )?; - let static_idx = self.static_modules.push(translation); + let static_module_index2 = self.static_modules.push(translation); + assert_eq!(static_module_index, static_module_index2); let types = self.validator.types(0).unwrap(); let ty = types.module_at(index); self.result .initializers - .push(LocalInitializer::ModuleStatic(static_idx, ty)); + .push(LocalInitializer::ModuleStatic(static_module_index, ty)); return Ok(Action::Skip(unchecked_range.end - unchecked_range.start)); } diff --git a/crates/environ/src/component/translate/adapt.rs b/crates/environ/src/component/translate/adapt.rs index 37f1a9284..c85163aaa 100644 --- a/crates/environ/src/component/translate/adapt.rs +++ b/crates/environ/src/component/translate/adapt.rs @@ -231,10 +231,12 @@ impl<'data> Translator<'_, 'data> { // likely to use that if anything is actually indirected through // memory. self.validator.reset(); + let static_module_index = self.static_modules.next_key(); let translation = ModuleEnvironment::new( self.tunables, &mut self.validator, self.types.module_types_builder(), + static_module_index, ) .translate(Parser::new(0), wasm) .expect("invalid adapter module generated"); @@ -260,8 +262,9 @@ impl<'data> Translator<'_, 'data> { .zip(translation.module.imports()) .map(|(arg, (_, _, ty))| fact_import_to_core_def(component, arg, ty)) .collect::>(); - let static_index = self.static_modules.push(translation); - let id = component.adapter_modules.push((static_index, args)); + let static_module_index2 = self.static_modules.push(translation); + assert_eq!(static_module_index, static_module_index2); + let id = component.adapter_modules.push((static_module_index, args)); assert_eq!(id, module_id); } } diff --git a/crates/environ/src/hostcall.rs b/crates/environ/src/hostcall.rs index b31331ada..0a57fb57e 100644 --- a/crates/environ/src/hostcall.rs +++ b/crates/environ/src/hostcall.rs @@ -8,6 +8,7 @@ use crate::component::ComponentBuiltinFunctionIndex; /// 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. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 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`). @@ -43,6 +44,28 @@ impl HostCall { HostCall::ComponentBuiltin(i) => 2 + BuiltinFunctionIndex::len() + i.index(), } } + + /// Create a `HostCall` from the result of an earlier call to + /// `HostCall::index`. + pub fn from_index(index: u32) -> Self { + let host_call = match index { + 0 => Self::ArrayCall, + _ if index < 1 + BuiltinFunctionIndex::len() => { + Self::Builtin(BuiltinFunctionIndex::from_u32(index - 1)) + } + #[cfg(feature = "component-model")] + _ if index == 1 + BuiltinFunctionIndex::len() => Self::ComponentLowerImport, + #[cfg(feature = "component-model")] + _ if index < 2 + BuiltinFunctionIndex::len() + ComponentBuiltinFunctionIndex::len() => { + Self::ComponentBuiltin(ComponentBuiltinFunctionIndex::from_u32( + index - 2 - BuiltinFunctionIndex::len(), + )) + } + _ => panic!("bad host call index: {index}"), + }; + debug_assert_eq!(index, host_call.index()); + host_call + } } impl From for HostCall { diff --git a/crates/environ/src/module_artifacts.rs b/crates/environ/src/module_artifacts.rs index 0d41a68f8..974b4f0fc 100644 --- a/crates/environ/src/module_artifacts.rs +++ b/crates/environ/src/module_artifacts.rs @@ -9,7 +9,7 @@ use core::str; use serde_derive::{Deserialize, Serialize}; /// Secondary in-memory results of function compilation. -#[derive(Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize)] pub struct CompiledFunctionInfo { /// Where this function was found in the original wasm file. pub start_srcloc: FilePos, diff --git a/crates/wasmtime/src/compile.rs b/crates/wasmtime/src/compile.rs index 8325c6eaa..d6bc799de 100644 --- a/crates/wasmtime/src/compile.rs +++ b/crates/wasmtime/src/compile.rs @@ -29,25 +29,20 @@ use crate::prelude::*; use std::{ any::Any, borrow::Cow, - collections::{BTreeMap, BTreeSet, btree_map}, + collections::{BTreeMap, BTreeSet}, mem, ops::Range, }; use call_graph::CallGraph; -use wasmtime_environ::CompiledFunctionBody; -use wasmtime_environ::FuncIndex; -use wasmtime_environ::InliningCompiler; -use wasmtime_environ::IntraModuleInlining; -use wasmtime_environ::Tunables; -#[cfg(feature = "component-model")] -use wasmtime_environ::component::Translator; use wasmtime_environ::{ - BuiltinFunctionIndex, CompiledFunctionInfo, CompiledModuleInfo, Compiler, DefinedFuncIndex, - FilePos, FinishedObject, FunctionBodyData, ModuleEnvironment, ModuleInternedTypeIndex, - ModuleTranslation, ModuleTypes, ModuleTypesBuilder, ObjectKind, PrimaryMap, RelocationTarget, - StaticModuleIndex, + BuiltinFunctionIndex, CompiledFunctionBody, CompiledFunctionInfo, CompiledModuleInfo, Compiler, + DefinedFuncIndex, FilePos, FinishedObject, FuncKey, FunctionBodyData, InliningCompiler, + IntraModuleInlining, ModuleEnvironment, ModuleTranslation, ModuleTypes, ModuleTypesBuilder, + ObjectKind, PrimaryMap, SecondaryMap, StaticModuleIndex, Tunables, }; +#[cfg(feature = "component-model")] +use wasmtime_environ::{FunctionLoc, component::Translator}; mod call_graph; mod scc; @@ -87,9 +82,14 @@ pub(crate) fn build_artifacts( let mut validator = wasmparser::Validator::new_with_features(engine.features()); parser.set_features(*validator.features()); let mut types = ModuleTypesBuilder::new(&validator); - let mut translation = ModuleEnvironment::new(tunables, &mut validator, &mut types) - .translate(parser, wasm) - .context("failed to parse WebAssembly module")?; + let mut translation = ModuleEnvironment::new( + tunables, + &mut validator, + &mut types, + StaticModuleIndex::from_u32(0), + ) + .translate(parser, wasm) + .context("failed to parse WebAssembly module")?; let functions = mem::take(&mut translation.function_body_inputs); let compile_inputs = CompileInputs::for_module(&types, &translation, functions); @@ -200,8 +200,7 @@ pub(crate) fn build_component_artifacts( let info = CompiledComponentInfo { component: component.component, trampolines: compilation_artifacts.trampolines, - resource_drop_wasm_to_array_trampoline: compilation_artifacts - .resource_drop_wasm_to_array_trampoline, + resource_drop_wasm_to_array_trampoline: compilation_artifacts.resource_drop_trampoline, }; let artifacts = ComponentArtifacts { info, @@ -217,145 +216,6 @@ pub(crate) fn build_component_artifacts( type CompileInput<'a> = Box Result> + Send + 'a>; -/// A sortable, comparable key for a compilation output. -/// -/// Two `u32`s to align with `cranelift_codegen::ir::UserExternalName`. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -struct CompileKey { - // The namespace field is bitpacked like: - // - // [ kind:i3 module:i29 ] - namespace: u32, - - index: u32, -} - -#[repr(u32)] -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -enum CompileKind { - WasmFunction = CompileKey::new_kind(0), - ArrayToWasmTrampoline = CompileKey::new_kind(1), - WasmToArrayTrampoline = CompileKey::new_kind(2), - WasmToBuiltinTrampoline = CompileKey::new_kind(3), - - #[cfg(feature = "component-model")] - Trampoline = CompileKey::new_kind(4), - #[cfg(feature = "component-model")] - ResourceDropWasmToArrayTrampoline = CompileKey::new_kind(5), -} - -impl From for u32 { - fn from(kind: CompileKind) -> Self { - kind as u32 - } -} - -impl core::fmt::Debug for CompileKey { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("CompileKey") - .field("kind", &self.kind()) - .field("module", &self.module()) - .field("index", &self.index) - .finish() - } -} - -impl CompileKey { - const KIND_BITS: u32 = 3; - const KIND_OFFSET: u32 = 32 - Self::KIND_BITS; - const KIND_MASK: u32 = ((1 << Self::KIND_BITS) - 1) << Self::KIND_OFFSET; - - const fn new_kind(kind: u32) -> u32 { - assert!(kind < (1 << Self::KIND_BITS)); - kind << Self::KIND_OFFSET - } - - fn kind(&self) -> CompileKind { - let k = self.namespace & Self::KIND_MASK; - if k == u32::from(CompileKind::WasmFunction) { - return CompileKind::WasmFunction; - } - if k == u32::from(CompileKind::ArrayToWasmTrampoline) { - return CompileKind::ArrayToWasmTrampoline; - } - if k == u32::from(CompileKind::WasmToArrayTrampoline) { - return CompileKind::WasmToArrayTrampoline; - } - if k == u32::from(CompileKind::WasmToBuiltinTrampoline) { - return CompileKind::WasmToBuiltinTrampoline; - } - - #[cfg(feature = "component-model")] - { - if k == u32::from(CompileKind::Trampoline) { - return CompileKind::Trampoline; - } - if k == u32::from(CompileKind::ResourceDropWasmToArrayTrampoline) { - return CompileKind::ResourceDropWasmToArrayTrampoline; - } - } - - unreachable!() - } - - fn module(&self) -> StaticModuleIndex { - StaticModuleIndex::from_u32(self.namespace & !Self::KIND_MASK) - } - - fn defined_func_index(&self) -> DefinedFuncIndex { - DefinedFuncIndex::from_u32(self.index) - } - - // NB: more kinds in the other `impl` block. - - fn wasm_function(module: StaticModuleIndex, index: DefinedFuncIndex) -> Self { - debug_assert_eq!(module.as_u32() & Self::KIND_MASK, 0); - Self { - namespace: u32::from(CompileKind::WasmFunction) | module.as_u32(), - index: index.as_u32(), - } - } - - fn array_to_wasm_trampoline(module: StaticModuleIndex, index: DefinedFuncIndex) -> Self { - debug_assert_eq!(module.as_u32() & Self::KIND_MASK, 0); - Self { - namespace: u32::from(CompileKind::ArrayToWasmTrampoline) | module.as_u32(), - index: index.as_u32(), - } - } - - fn wasm_to_array_trampoline(index: ModuleInternedTypeIndex) -> Self { - Self { - namespace: CompileKind::WasmToArrayTrampoline.into(), - index: index.as_u32(), - } - } - - fn wasm_to_builtin_trampoline(index: BuiltinFunctionIndex) -> Self { - Self { - namespace: CompileKind::WasmToBuiltinTrampoline.into(), - index: index.index(), - } - } -} - -#[cfg(feature = "component-model")] -impl CompileKey { - fn trampoline(index: wasmtime_environ::component::TrampolineIndex) -> Self { - Self { - namespace: CompileKind::Trampoline.into(), - index: index.as_u32(), - } - } - - fn resource_drop_wasm_to_array_trampoline() -> Self { - Self { - namespace: CompileKind::ResourceDropWasmToArrayTrampoline.into(), - index: 0, - } - } -} - #[derive(Clone, Copy)] enum CompiledFunction { Function(T), @@ -405,11 +265,15 @@ impl From> for CompiledFunction { - key: CompileKey, + key: FuncKey, symbol: String, function: CompiledFunction, start_srcloc: FilePos, + + // Only present when `self.key` is a `FuncKey::DefinedWasmFunction(..)`. translation: Option<&'a ModuleTranslation<'a>>, + + // Only present when `self.key` is a `FuncKey::DefinedWasmFunction(..)`. func_body: Option>, } @@ -475,12 +339,13 @@ impl<'a> CompileInputs<'a> { for (idx, trampoline) in component.trampolines.iter() { ret.push_input(move |compiler| { + let key = FuncKey::ComponentTrampoline(idx); let symbol = trampoline.symbol_name(); Ok(CompileOutput { - key: CompileKey::trampoline(idx), + key, function: compiler .component_compiler() - .compile_trampoline(component, types, idx, tunables, &symbol) + .compile_trampoline(component, types, key, tunables, &symbol) .with_context(|| format!("failed to compile {symbol}"))? .into(), symbol, @@ -500,12 +365,13 @@ impl<'a> CompileInputs<'a> { if component.component.num_resources > 0 { if let Some(sig) = types.find_resource_drop_signature() { ret.push_input(move |compiler| { + let key = FuncKey::ResourceDropTrampoline; let symbol = "resource_drop_trampoline".to_string(); let function = compiler - .compile_wasm_to_array_trampoline(types[sig].unwrap_func(), &symbol) + .compile_wasm_to_array_trampoline(types[sig].unwrap_func(), key, &symbol) .with_context(|| format!("failed to compile `{symbol}`"))?; Ok(CompileOutput { - key: CompileKey::resource_drop_wasm_to_array_trampoline(), + key, function: CompiledFunction::Function(function), symbol, start_srcloc: FilePos::default(), @@ -563,6 +429,7 @@ impl<'a> CompileInputs<'a> { for (module, translation, functions) in translations { for (def_func_index, func_body_data) in functions { self.push_input(move |compiler| { + let key = FuncKey::DefinedWasmFunction(module, def_func_index); let func_index = translation.module.func_index(def_func_index); let symbol = match translation .debuginfo @@ -587,17 +454,11 @@ impl<'a> CompileInputs<'a> { let offset = data.original_position(); let start_srcloc = FilePos::new(u32::try_from(offset).unwrap()); let function = compiler - .compile_function( - translation, - def_func_index, - func_body_data, - types, - &symbol, - ) + .compile_function(translation, key, func_body_data, types, &symbol) .with_context(|| format!("failed to compile: {symbol}"))?; Ok(CompileOutput { - key: CompileKey::wasm_function(module, def_func_index), + key, symbol, function: CompiledFunction::Function(function), start_srcloc, @@ -609,6 +470,7 @@ impl<'a> CompileInputs<'a> { let func_index = translation.module.func_index(def_func_index); if translation.module.functions[func_index].is_escaping() { self.push_input(move |compiler| { + let key = FuncKey::ArrayToWasmTrampoline(module, def_func_index); let func_index = translation.module.func_index(def_func_index); let symbol = format!( "wasm[{}]::array_to_wasm_trampoline[{}]", @@ -616,15 +478,10 @@ impl<'a> CompileInputs<'a> { func_index.as_u32() ); let trampoline = compiler - .compile_array_to_wasm_trampoline( - translation, - types, - def_func_index, - &symbol, - ) + .compile_array_to_wasm_trampoline(translation, types, key, &symbol) .with_context(|| format!("failed to compile: {symbol}"))?; Ok(CompileOutput { - key: CompileKey::array_to_wasm_trampoline(module, def_func_index), + key, symbol, function: CompiledFunction::Function(trampoline), start_srcloc: FilePos::default(), @@ -644,15 +501,16 @@ impl<'a> CompileInputs<'a> { } let trampoline_func_ty = types[trampoline_type_index].unwrap_func(); self.push_input(move |compiler| { + let key = FuncKey::WasmToArrayTrampoline(trampoline_type_index); let symbol = format!( "signatures[{}]::wasm_to_array_trampoline", trampoline_type_index.as_u32() ); let trampoline = compiler - .compile_wasm_to_array_trampoline(trampoline_func_ty, &symbol) + .compile_wasm_to_array_trampoline(trampoline_func_ty, key, &symbol) .with_context(|| format!("failed to compile: {symbol}"))?; Ok(CompileOutput { - key: CompileKey::wasm_to_array_trampoline(trampoline_type_index), + key, function: CompiledFunction::Function(trampoline), symbol, start_srcloc: FilePos::default(), @@ -731,9 +589,9 @@ the use case. compile_required_builtins(engine, &mut raw_outputs)?; // Bucket the outputs by kind. - let mut outputs: BTreeMap> = BTreeMap::new(); + let mut outputs: BTreeMap = BTreeMap::new(); for output in raw_outputs { - outputs.entry(output.key.kind()).or_default().push(output); + outputs.insert(output.key, output); } Ok(UnlinkedCompileOutputs { outputs }) @@ -761,12 +619,9 @@ the use case. fn wasm_functions<'a>( outputs: &'a PrimaryMap>>, ) -> impl Iterator + 'a { - outputs.iter().filter_map(|(i, o)| { - if o.as_ref()?.key.kind() == CompileKind::WasmFunction { - Some(i) - } else { - None - } + outputs.iter().filter_map(|(i, o)| match o.as_ref()?.key { + FuncKey::DefinedWasmFunction(..) => Some(i), + _ => None, }) } @@ -780,11 +635,15 @@ the use case. // module. This map enables that translation. let pair_to_output: HashMap<(StaticModuleIndex, DefinedFuncIndex), OutputIndex> = outputs .iter() - .filter(|(_, output)| output.as_ref().unwrap().key.kind() == CompileKind::WasmFunction) + .filter(|(_, output)| { + matches!( + output.as_ref().unwrap().key, + FuncKey::DefinedWasmFunction(..) + ) + }) .map(|(output_index, output)| { let output = output.as_ref().unwrap(); - let module_index = output.key.module(); - let defined_func_index = output.key.defined_func_index(); + let (module_index, defined_func_index) = output.key.unwrap_defined_wasm_function(); ((module_index, defined_func_index), output_index) }) .collect(); @@ -795,14 +654,14 @@ the use case. // trampolines being in their own stack frame when we save the entry and // exit SP, FP, and PC for backtraces in trampolines. let call_graph = CallGraph::::new(wasm_functions(&outputs), { - let mut func_indices = IndexSet::default(); + let mut compile_keys = IndexSet::default(); let outputs = &outputs; let pair_to_output = &pair_to_output; move |output_index, calls| { debug_assert!(calls.is_empty()); let output = outputs[output_index].as_ref().unwrap(); - debug_assert_eq!(output.key.kind(), CompileKind::WasmFunction); + debug_assert!(matches!(output.key, FuncKey::DefinedWasmFunction(..))); let func = match &output.function { CompiledFunction::Function(f) => f, @@ -812,31 +671,17 @@ the use case. } }; - // Get this function's call graph edges as `FuncIndex`es. - func_indices.clear(); - inlining_compiler.calls(func, &mut func_indices)?; + // Get this function's call graph edges as `CompileKey`s. + compile_keys.clear(); + inlining_compiler.calls(func, &mut compile_keys)?; // Translate each of those to (module, defined-function-index) // pairs and then finally to output indices, which is what we // actually need. - let caller_module = output.key.module(); - let translation = output - .translation - .expect("all wasm functions have translations"); - calls.extend(func_indices.iter().copied().filter_map(|callee_func| { - if let Some(callee_def_func) = - translation.module.defined_func_index(callee_func) - { - // Call to a function in the same module. - Some(pair_to_output[&(caller_module, callee_def_func)]) - } else if let Some(pair) = translation.known_imported_functions[callee_func] { - // Call to a statically-known imported function. - Some(pair_to_output[&pair]) + calls.extend(compile_keys.iter().copied().filter_map(|key| { + if let FuncKey::DefinedWasmFunction(module, def_func) = key { + Some(pair_to_output[&(module, def_func)]) } else { - // Call to an unknown imported function or perhaps to - // multiple different functions in different - // instantiations. Can't inline these calls, so don't - // add them to the call graph. None } })); @@ -868,12 +713,12 @@ the use case. engine.run_maybe_parallel_mut( &mut layer_outputs, |output: &mut CompileOutput<'_>| { - debug_assert_eq!(output.key.kind(), CompileKind::WasmFunction); log::trace!("processing inlining for {:?}", output.key); + debug_assert!(matches!(output.key, FuncKey::DefinedWasmFunction(..))); let caller_translation = output.translation.unwrap(); - let caller_module = output.key.module(); - let caller_def_func = output.key.defined_func_index(); + let (caller_module, caller_def_func) = + output.key.unwrap_defined_wasm_function(); let caller_needs_gc_heap = caller_translation.module.needs_gc_heap; let caller = output @@ -883,40 +728,31 @@ the use case. let mut caller_size = inlining_compiler.size(caller); - inlining_compiler.inline(caller, &mut |callee: FuncIndex| { - let (callee_module, callee_def_func, callee_needs_gc_heap) = - if let Some(def_func) = - caller_translation.module.defined_func_index(callee) - { - (caller_module, def_func, Some(caller_needs_gc_heap)) - } else { - let (def_module, def_func) = caller_translation - .known_imported_functions[callee] - .unwrap_or_else(|| { - panic!( - "a direct call to an imported function must have a \ - statically-known definition, but direct call to imported \ - function {callee:?} has no statically-known definition", - ) - }); - (def_module, def_func, None) - }; - + inlining_compiler.inline(caller, &mut |callee_key: FuncKey| { + let (callee_module, callee_def_func) = + callee_key.unwrap_defined_wasm_function(); let callee_output_index: OutputIndex = pair_to_output[&(callee_module, callee_def_func)]; + + // NB: If the callee is not inside `outputs`, then it is + // in the same `Strata` layer as the caller (and + // therefore is in the same strongly-connected component + // as the caller, and they mutually recursive). In this + // case, we do not do any inlining; communicate this + // command via `?`-propagation. let callee_output = outputs[callee_output_index].as_ref()?; - let callee_needs_gc_heap = callee_needs_gc_heap.unwrap_or_else(|| { - callee_output.translation.unwrap().module.needs_gc_heap - }); - debug_assert_eq!(callee_output.key.kind(), CompileKind::WasmFunction); + debug_assert_eq!(callee_output.key, callee_key); + let callee = callee_output .function .as_function() .expect("wasm functions are not all-call functions"); - let callee_size = inlining_compiler.size(callee); + let callee_needs_gc_heap = + callee_output.translation.unwrap().module.needs_gc_heap; + if Self::should_inline(InlineHeuristicParams { tunables: engine.tunables(), caller_size, @@ -1078,15 +914,16 @@ fn compile_required_builtins(engine: &Engine, raw_outputs: &mut Vec continue, }; for reloc in compiler.compiled_function_relocation_targets(&*f.code) { - match reloc { - RelocationTarget::Builtin(i) => { - if builtins.insert(i) { - new_inputs.push(compile_builtin(i)); - } + if let FuncKey::WasmToBuiltinTrampoline(builtin) = reloc { + if builtins.insert(builtin) { + new_inputs.push(compile_builtin(builtin)); } - _ => {} } } } @@ -1120,7 +954,7 @@ fn compile_required_builtins(engine: &Engine, raw_outputs: &mut Vec { // A map from kind to `CompileOutput`. - outputs: BTreeMap>>, + outputs: BTreeMap>, } impl UnlinkedCompileOutputs<'_> { @@ -1136,7 +970,7 @@ impl UnlinkedCompileOutputs<'_> { let mut indices = FunctionIndices::default(); let mut needs_gc_heap = false; - for output in self.outputs.into_iter().flat_map(|(_kind, outs)| outs) { + for output in self.outputs.into_values() { let index = match output.function { CompiledFunction::Function(f) => { needs_gc_heap |= f.needs_gc_heap; @@ -1164,22 +998,18 @@ impl UnlinkedCompileOutputs<'_> { } }; - if output.key.kind() == CompileKind::WasmFunction - || output.key.kind() == CompileKind::ArrayToWasmTrampoline + if let FuncKey::DefinedWasmFunction(module, _) + | FuncKey::ArrayToWasmTrampoline(module, _) = output.key { indices .compiled_func_index_to_module - .insert(index.unwrap_function(), output.key.module()); + .insert(index.unwrap_function(), module); indices .start_srclocs .insert(output.key, output.start_srcloc); } - indices - .indices - .entry(output.key.kind()) - .or_default() - .insert(output.key, index); + indices.indices.insert(output.key, index); } PreLinkOutput { @@ -1209,17 +1039,17 @@ struct FunctionIndices { compiled_func_index_to_module: HashMap, // A map of wasm functions and where they're located in the original file. - start_srclocs: HashMap, + start_srclocs: HashMap, - // The index of each compiled function, bucketed by compile key kind. - indices: BTreeMap>>, + // The index of each compiled function. + indices: BTreeMap>, } impl FunctionIndices { /// Link the compiled functions together, resolving relocations, and append /// them to the given ELF file. fn link_and_append_code<'a>( - mut self, + self, types: &ModuleTypesBuilder, mut obj: object::write::Object<'static>, engine: &'a Engine, @@ -1237,36 +1067,13 @@ impl FunctionIndices { let symbol_ids_and_locs = compiler.append_code( &mut obj, &compiled_funcs, - &|caller_index: usize, callee: RelocationTarget| match callee { - RelocationTarget::Wasm(callee_index) => { - let caller_module = self - .compiled_func_index_to_module - .get(&caller_index) - .copied() - .expect("should only reloc inside wasm function callers"); - let key = if let Some(def_func_index) = translations[caller_module] - .module - .defined_func_index(callee_index) - { - CompileKey::wasm_function(caller_module, def_func_index) - } else { - let (def_module, def_func_index) = translations[caller_module] - .known_imported_functions[callee_index] - .expect( - "a direct call to an imported function must have a \ - statically-known import", - ); - CompileKey::wasm_function(def_module, def_func_index) - }; - self.indices[&CompileKind::WasmFunction][&key].unwrap_function() - } - RelocationTarget::Builtin(builtin) => self.indices - [&CompileKind::WasmToBuiltinTrampoline] - [&CompileKey::wasm_to_builtin_trampoline(builtin)] - .unwrap_function(), - RelocationTarget::PulleyHostcall(_) => { - unreachable!("relocation is resolved at runtime, not compile time"); - } + &|_caller_index: usize, callee: FuncKey| { + self.indices + .get(&callee) + .and_then(|f| f.as_function().copied()) + .unwrap_or_else(|| { + panic!("cannot resolve relocation! no index for callee {callee:?}") + }) }, )?; @@ -1276,106 +1083,124 @@ impl FunctionIndices { &mut obj, &translations, &|module, func| { - let bucket = &self.indices[&CompileKind::WasmFunction]; - let i = bucket[&CompileKey::wasm_function(module, func)].unwrap_function(); - (symbol_ids_and_locs[i].0, &*compiled_funcs[i].1) + let i = + self.indices[&FuncKey::DefinedWasmFunction(module, func)].unwrap_function(); + let (symbol, _) = symbol_ids_and_locs[i]; + let (_, compiled_func) = &compiled_funcs[i]; + (symbol, &**compiled_func) }, dwarf_package_bytes, tunables, )?; } - let mut obj = wasmtime_environ::ObjectBuilder::new(obj, tunables); - let mut artifacts = Artifacts::default(); - - // Remove this as it's not needed by anything below and we'll debug - // assert `self.indices` is empty, so this is acknowledgement that this - // is a pure runtime implementation detail and not needed in any - // metadata generated below. - self.indices.remove(&CompileKind::WasmToBuiltinTrampoline); - - // Finally, build our binary artifacts that map things like `FuncIndex` - // to a function location and all of that using the indices we saved - // earlier and the function locations we just received after appending - // the code. - - let mut wasm_functions = self - .indices - .remove(&CompileKind::WasmFunction) - .unwrap_or_default() - .into_iter() - .peekable(); - - fn wasm_functions_for_module( - wasm_functions: &mut std::iter::Peekable< - btree_map::IntoIter>, - >, - module: StaticModuleIndex, - ) -> impl Iterator)> + '_ { - std::iter::from_fn(move || { - let (key, _) = wasm_functions.peek()?; - if key.module() == module { - wasm_functions.next() - } else { - None + let mut def_funcs = SecondaryMap::< + StaticModuleIndex, + PrimaryMap, + >::new(); + + #[cfg(feature = "component-model")] + let mut trampolines = PrimaryMap::< + wasmtime_environ::component::TrampolineIndex, + wasmtime_environ::component::AllCallFunc, + >::new(); + + #[cfg(feature = "component-model")] + let mut resource_drop_trampoline = None; + + for (key, index) in &self.indices { + // NB: exhaustively match on function keys to make sure that we are + // remembering to handle everything we are compiling when doing this + // final linking and metadata-collection step. + match *key { + FuncKey::DefinedWasmFunction(module, def_func) => { + let index = index.unwrap_function(); + let (_, wasm_func_loc) = symbol_ids_and_locs[index]; + let start_srcloc = self.start_srclocs[key]; + + let array_to_wasm_trampoline = self + .indices + .get(&FuncKey::ArrayToWasmTrampoline(module, def_func)) + .map(|index| { + let index = index.unwrap_function(); + let (_, loc) = symbol_ids_and_locs[index]; + loc + }); + + debug_assert!(def_funcs[module].get(def_func).is_none()); + let def_func2 = def_funcs[module].push(CompiledFunctionInfo { + start_srcloc, + wasm_func_loc, + array_to_wasm_trampoline, + }); + debug_assert_eq!(def_func, def_func2); + } + + FuncKey::ArrayToWasmTrampoline(module, def_func) => { + // These are handled by the `DefinedWasmFunction` arm above. + debug_assert!(def_funcs[module].get(def_func).is_some()); + } + + FuncKey::WasmToArrayTrampoline(_) => { + // These are handled in `modules` creation below. } - }) - } - let mut array_to_wasm_trampolines = self - .indices - .remove(&CompileKind::ArrayToWasmTrampoline) - .unwrap_or_default(); + FuncKey::WasmToBuiltinTrampoline(_) => { + // Nothing we need to do for these: they are only called by + // Wasm functions, and we never create `funcref`s containing + // them, so we don't need to keep any metadata for them or + // anything like that. + } - // NB: unlike the above maps this is not emptied out during iteration - // since each module may reach into different portions of this map. - let wasm_to_array_trampolines = self - .indices - .remove(&CompileKind::WasmToArrayTrampoline) - .unwrap_or_default(); + FuncKey::PulleyHostCall(_) => { + unreachable!("we don't compile any artifacts for Pulley host calls") + } - artifacts.modules = translations + #[cfg(feature = "component-model")] + FuncKey::ComponentTrampoline(trampoline) => { + let index = index.unwrap_all_call_func(); + let loc = index.map(|i| { + let (_, loc) = symbol_ids_and_locs[i]; + loc + }); + debug_assert!(trampolines.get(trampoline).is_none()); + let trampoline2 = trampolines.push(loc); + debug_assert_eq!(trampoline, trampoline2); + } + + #[cfg(feature = "component-model")] + FuncKey::ResourceDropTrampoline => { + let index = index.unwrap_function(); + let (_, loc) = symbol_ids_and_locs[index]; + resource_drop_trampoline = Some(loc); + } + } + } + + let mut obj = wasmtime_environ::ObjectBuilder::new(obj, tunables); + let modules = translations .into_iter() .map(|(module, mut translation)| { - // If configured attempt to use static memory initialization which - // can either at runtime be implemented as a single memcpy to - // initialize memory or otherwise enabling virtual-memory-tricks - // such as mmap'ing from a file to get copy-on-write. + let def_funcs = mem::take(&mut def_funcs[module]); + + // If configured attempt to use static memory initialization + // which can either at runtime be implemented as a single memcpy + // to initialize memory or otherwise enabling + // virtual-memory-tricks such as mmap'ing from a file to get + // copy-on-write. if engine.tunables().memory_init_cow { let align = compiler.page_size_align(); let max_always_allowed = engine.config().memory_guaranteed_dense_image_size; translation.try_static_init(align, max_always_allowed); } - // Attempt to convert table initializer segments to - // FuncTable representation where possible, to enable - // table lazy init. + // Attempt to convert table initializer segments to FuncTable + // representation where possible, to enable table lazy init. if engine.tunables().table_lazy_init { translation.try_func_table_init(); } - let funcs: PrimaryMap = - wasm_functions_for_module(&mut wasm_functions, module) - .map(|(key, wasm_func_index)| { - let wasm_func_index = wasm_func_index.unwrap_function(); - let wasm_func_loc = symbol_ids_and_locs[wasm_func_index].1; - let start_srcloc = self.start_srclocs.remove(&key).unwrap(); - - let array_to_wasm_trampoline = array_to_wasm_trampolines - .remove(&CompileKey::array_to_wasm_trampoline( - key.module(), - DefinedFuncIndex::from_u32(key.index), - )) - .map(|x| symbol_ids_and_locs[x.unwrap_function()].1); - - CompiledFunctionInfo { - start_srcloc, - wasm_func_loc, - array_to_wasm_trampoline, - } - }) - .collect(); - + // Gather this module's trampolines. let unique_and_sorted_trampoline_sigs = translation .module .types @@ -1385,43 +1210,27 @@ impl FunctionIndices { .map(|idx| types.trampoline_type(idx)) .collect::>(); let wasm_to_array_trampolines = unique_and_sorted_trampoline_sigs - .iter() - .map(|idx| { - let trampoline = types.trampoline_type(*idx); - let key = CompileKey::wasm_to_array_trampoline(trampoline); - let compiled = wasm_to_array_trampolines[&key]; - (*idx, symbol_ids_and_locs[compiled.unwrap_function()].1) + .into_iter() + .map(|ty| { + debug_assert_eq!(ty, types.trampoline_type(ty)); + let key = FuncKey::WasmToArrayTrampoline(ty); + let index = self.indices[&key].unwrap_function(); + let (_, loc) = symbol_ids_and_locs[index]; + (ty, loc) }) .collect(); - obj.append(translation, funcs, wasm_to_array_trampolines) + obj.append(translation, def_funcs, wasm_to_array_trampolines) }) .collect::>>()?; - #[cfg(feature = "component-model")] - { - artifacts.trampolines = self - .indices - .remove(&CompileKind::Trampoline) - .unwrap_or_default() - .into_iter() - .map(|(_id, x)| x.unwrap_all_call_func().map(|i| symbol_ids_and_locs[i].1)) - .collect(); - let map = self - .indices - .remove(&CompileKind::ResourceDropWasmToArrayTrampoline) - .unwrap_or_default(); - assert!(map.len() <= 1); - artifacts.resource_drop_wasm_to_array_trampoline = map - .into_iter() - .next() - .map(|(_id, x)| symbol_ids_and_locs[x.unwrap_function()].1); - } - - debug_assert!( - self.indices.is_empty(), - "Should have processed all compile outputs" - ); + let artifacts = Artifacts { + modules, + #[cfg(feature = "component-model")] + trampolines, + #[cfg(feature = "component-model")] + resource_drop_trampoline, + }; Ok((obj, artifacts)) } @@ -1438,7 +1247,7 @@ struct Artifacts { wasmtime_environ::component::AllCallFunc, >, #[cfg(feature = "component-model")] - resource_drop_wasm_to_array_trampoline: Option, + resource_drop_trampoline: Option, } impl Artifacts { diff --git a/crates/wasmtime/src/engine/serialization.rs b/crates/wasmtime/src/engine/serialization.rs index feccd9f5d..359595822 100644 --- a/crates/wasmtime/src/engine/serialization.rs +++ b/crates/wasmtime/src/engine/serialization.rs @@ -691,6 +691,8 @@ Caused by: #[test] #[cfg_attr(miri, ignore)] fn cache_accounts_for_opt_level() -> Result<()> { + let _ = env_logger::try_init(); + let td = TempDir::new()?; let config_path = td.path().join("config.toml"); std::fs::write( diff --git a/crates/winch/Cargo.toml b/crates/winch/Cargo.toml index 42e76aeaf..5a37c7541 100644 --- a/crates/winch/Cargo.toml +++ b/crates/winch/Cargo.toml @@ -21,6 +21,7 @@ cranelift-codegen = { workspace = true } wasmtime-cranelift = { workspace = true } wasmparser = { workspace = true } gimli = { workspace = true, features = ['std'] } +log = { workspace = true } [features] component-model = [ diff --git a/crates/winch/src/compiler.rs b/crates/winch/src/compiler.rs index 1b27f9669..41fb19ff6 100644 --- a/crates/winch/src/compiler.rs +++ b/crates/winch/src/compiler.rs @@ -7,9 +7,8 @@ use std::sync::Mutex; use wasmparser::FuncValidatorAllocations; use wasmtime_cranelift::CompiledFunction; use wasmtime_environ::{ - BuiltinFunctionIndex, CompileError, CompiledFunctionBody, DefinedFuncIndex, FunctionBodyData, - FunctionLoc, ModuleTranslation, ModuleTypesBuilder, PrimaryMap, RelocationTarget, - StaticModuleIndex, Tunables, VMOffsets, + CompileError, CompiledFunctionBody, DefinedFuncIndex, FuncKey, FunctionBodyData, FunctionLoc, + ModuleTranslation, ModuleTypesBuilder, PrimaryMap, StaticModuleIndex, Tunables, VMOffsets, }; use winch_codegen::{BuiltinFunctions, CallingConvention, TargetIsa}; @@ -88,6 +87,23 @@ impl Compiler { } } +fn box_dyn_any_compiled_function(f: CompiledFunction) -> Box { + let b = box_dyn_any(f); + debug_assert!(b.is::()); + b +} + +fn box_dyn_any(x: impl Any + Send + Sync) -> Box { + log::trace!( + "making Box of {}", + std::any::type_name_of_val(&x) + ); + let b = Box::new(x); + let r: &(dyn Any + Sync + Send) = &*b; + log::trace!(" --> {r:#p}"); + b +} + impl wasmtime_environ::Compiler for Compiler { fn inlining_compiler(&self) -> Option<&dyn wasmtime_environ::InliningCompiler> { None @@ -96,12 +112,17 @@ impl wasmtime_environ::Compiler for Compiler { fn compile_function( &self, translation: &ModuleTranslation<'_>, - index: DefinedFuncIndex, + key: FuncKey, data: FunctionBodyData<'_>, types: &ModuleTypesBuilder, - _symbol: &str, + symbol: &str, ) -> Result { - let index = translation.module.func_index(index); + log::trace!("compiling function: {key:?} = {symbol:?}"); + + let (module_index, def_func_index) = key.unwrap_defined_wasm_function(); + debug_assert_eq!(module_index, translation.module_index); + + let index = translation.module.func_index(def_func_index); let sig = translation.module.functions[index] .signature .unwrap_module_type_index(); @@ -138,7 +159,7 @@ impl wasmtime_environ::Compiler for Compiler { } Ok(CompiledFunctionBody { - code: Box::new(func), + code: box_dyn_any_compiled_function(func), // TODO: Winch doesn't support GC objects and stack maps and all that yet. needs_gc_heap: false, }) @@ -148,27 +169,28 @@ impl wasmtime_environ::Compiler for Compiler { &self, translation: &ModuleTranslation<'_>, types: &ModuleTypesBuilder, - index: DefinedFuncIndex, + key: FuncKey, symbol: &str, ) -> Result { self.trampolines - .compile_array_to_wasm_trampoline(translation, types, index, symbol) + .compile_array_to_wasm_trampoline(translation, types, key, symbol) } fn compile_wasm_to_array_trampoline( &self, wasm_func_ty: &wasmtime_environ::WasmFuncType, + key: FuncKey, symbol: &str, ) -> Result { self.trampolines - .compile_wasm_to_array_trampoline(wasm_func_ty, symbol) + .compile_wasm_to_array_trampoline(wasm_func_ty, key, symbol) } fn append_code( &self, obj: &mut Object<'static>, funcs: &[(String, Box)], - resolve_reloc: &dyn Fn(usize, wasmtime_environ::RelocationTarget) -> usize, + resolve_reloc: &dyn Fn(usize, wasmtime_environ::FuncKey) -> usize, ) -> Result> { self.trampolines.append_code(obj, funcs, resolve_reloc) } @@ -214,16 +236,16 @@ impl wasmtime_environ::Compiler for Compiler { fn compile_wasm_to_builtin( &self, - index: BuiltinFunctionIndex, + key: FuncKey, symbol: &str, ) -> Result { - self.trampolines.compile_wasm_to_builtin(index, symbol) + self.trampolines.compile_wasm_to_builtin(key, symbol) } fn compiled_function_relocation_targets<'a>( &'a self, func: &'a dyn Any, - ) -> Box + 'a> { + ) -> Box + 'a> { self.trampolines.compiled_function_relocation_targets(func) } } @@ -240,7 +262,7 @@ impl wasmtime_environ::Compiler for NoInlineCompiler { fn compile_function( &self, translation: &ModuleTranslation<'_>, - index: DefinedFuncIndex, + key: FuncKey, data: FunctionBodyData<'_>, types: &ModuleTypesBuilder, symbol: &str, @@ -248,7 +270,7 @@ impl wasmtime_environ::Compiler for NoInlineCompiler { let input = data.body.clone(); let mut body = self .0 - .compile_function(translation, index, data, types, symbol)?; + .compile_function(translation, key, data, types, symbol)?; if let Some(c) = self.0.inlining_compiler() { c.finish_compiling(&mut body, Some(input), symbol) .map_err(|e| CompileError::Codegen(e.to_string()))?; @@ -260,12 +282,12 @@ impl wasmtime_environ::Compiler for NoInlineCompiler { &self, translation: &ModuleTranslation<'_>, types: &ModuleTypesBuilder, - index: DefinedFuncIndex, + key: FuncKey, symbol: &str, ) -> Result { - let mut body = - self.0 - .compile_array_to_wasm_trampoline(translation, types, index, symbol)?; + let mut body = self + .0 + .compile_array_to_wasm_trampoline(translation, types, key, symbol)?; if let Some(c) = self.0.inlining_compiler() { c.finish_compiling(&mut body, None, symbol) .map_err(|e| CompileError::Codegen(e.to_string()))?; @@ -276,11 +298,12 @@ impl wasmtime_environ::Compiler for NoInlineCompiler { fn compile_wasm_to_array_trampoline( &self, wasm_func_ty: &wasmtime_environ::WasmFuncType, + key: FuncKey, symbol: &str, ) -> Result { let mut body = self .0 - .compile_wasm_to_array_trampoline(wasm_func_ty, symbol)?; + .compile_wasm_to_array_trampoline(wasm_func_ty, key, symbol)?; if let Some(c) = self.0.inlining_compiler() { c.finish_compiling(&mut body, None, symbol) .map_err(|e| CompileError::Codegen(e.to_string()))?; @@ -290,10 +313,10 @@ impl wasmtime_environ::Compiler for NoInlineCompiler { fn compile_wasm_to_builtin( &self, - index: BuiltinFunctionIndex, + key: FuncKey, symbol: &str, ) -> Result { - let mut body = self.0.compile_wasm_to_builtin(index, symbol)?; + let mut body = self.0.compile_wasm_to_builtin(key, symbol)?; if let Some(c) = self.0.inlining_compiler() { c.finish_compiling(&mut body, None, symbol) .map_err(|e| CompileError::Codegen(e.to_string()))?; @@ -304,7 +327,7 @@ impl wasmtime_environ::Compiler for NoInlineCompiler { fn compiled_function_relocation_targets<'a>( &'a self, func: &'a dyn Any, - ) -> Box + 'a> { + ) -> Box + 'a> { self.0.compiled_function_relocation_targets(func) } @@ -312,7 +335,7 @@ impl wasmtime_environ::Compiler for NoInlineCompiler { &self, obj: &mut Object<'static>, funcs: &[(String, Box)], - resolve_reloc: &dyn Fn(usize, RelocationTarget) -> usize, + resolve_reloc: &dyn Fn(usize, FuncKey) -> usize, ) -> Result> { self.0.append_code(obj, funcs, resolve_reloc) } @@ -360,14 +383,14 @@ impl wasmtime_environ::component::ComponentCompiler for NoInlineCompiler { &self, component: &wasmtime_environ::component::ComponentTranslation, types: &wasmtime_environ::component::ComponentTypesBuilder, - trampoline: wasmtime_environ::component::TrampolineIndex, + key: FuncKey, tunables: &Tunables, symbol: &str, ) -> Result> { let mut body = self .0 .component_compiler() - .compile_trampoline(component, types, trampoline, tunables, symbol)?; + .compile_trampoline(component, types, key, tunables, symbol)?; if let Some(c) = self.0.inlining_compiler() { c.finish_compiling(&mut body.array_call, None, symbol) .map_err(|e| CompileError::Codegen(e.to_string()))?; diff --git a/tests/disas/call-indirect.wat b/tests/disas/call-indirect.wat index 794e815cc..02b046ebf 100644 --- a/tests/disas/call-indirect.wat +++ b/tests/disas/call-indirect.wat @@ -16,7 +16,7 @@ ;; gv5 = load.i64 notrap aligned gv3+56 ;; sig0 = (i64 vmctx, i64, i32) -> i32 tail ;; sig1 = (i64 vmctx, i32, i64) -> i64 tail -;; fn0 = colocated u1:9 sig1 +;; fn0 = colocated u1610612736:9 sig1 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32, v3: i32): diff --git a/tests/disas/component-model/direct-adapter-calls-inlining.wat b/tests/disas/component-model/direct-adapter-calls-inlining.wat index ea078d34e..dab7c47b3 100644 --- a/tests/disas/component-model/direct-adapter-calls-inlining.wat +++ b/tests/disas/component-model/direct-adapter-calls-inlining.wat @@ -54,7 +54,7 @@ (export "g" (func $b "g")) ) -;; function u0:1(i64 vmctx, i64) -> i32 tail { +;; function u1:0(i64 vmctx, i64) -> i32 tail { ;; gv0 = vmctx ;; gv1 = load.i64 notrap aligned readonly gv0+8 ;; gv2 = load.i64 notrap aligned gv1+16 @@ -70,7 +70,7 @@ ;; gv12 = load.i64 notrap aligned gv11+16 ;; sig0 = (i64 vmctx, i64, i32) -> i32 tail ;; sig1 = (i64 vmctx, i64, i32) -> i32 tail -;; fn0 = colocated u0:0 sig0 +;; fn0 = colocated u2:0 sig0 ;; fn1 = colocated u0:0 sig1 ;; stack_limit = gv2 ;; diff --git a/tests/disas/component-model/direct-adapter-calls.wat b/tests/disas/component-model/direct-adapter-calls.wat index 52f88c625..c342cfd0f 100644 --- a/tests/disas/component-model/direct-adapter-calls.wat +++ b/tests/disas/component-model/direct-adapter-calls.wat @@ -72,13 +72,13 @@ ;; @003b return v5 ;; } ;; -;; function u0:1(i64 vmctx, i64) -> i32 tail { +;; function u1:0(i64 vmctx, i64) -> i32 tail { ;; gv0 = vmctx ;; gv1 = load.i64 notrap aligned readonly gv0+8 ;; gv2 = load.i64 notrap aligned gv1+16 ;; gv3 = vmctx ;; sig0 = (i64 vmctx, i64, i32) -> i32 tail -;; fn0 = colocated u0:0 sig0 +;; fn0 = colocated u2:0 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64): @@ -91,7 +91,7 @@ ;; @00f0 return v6 ;; } ;; -;; function u0:1(i64 vmctx, i64, i32) -> i32 tail { +;; function u2:0(i64 vmctx, i64, i32) -> i32 tail { ;; gv0 = vmctx ;; gv1 = load.i64 notrap aligned readonly gv0+8 ;; gv2 = load.i64 notrap aligned gv1+16 diff --git a/tests/disas/component-model/enum.wat b/tests/disas/component-model/enum.wat index 04b3bc2d2..e1ad99c9c 100644 --- a/tests/disas/component-model/enum.wat +++ b/tests/disas/component-model/enum.wat @@ -31,7 +31,7 @@ (with "f" (func $i1 "f")))) ) -;; function u0:1(i64 vmctx, i64) -> i32 tail { +;; function u2:0(i64 vmctx, i64) -> i32 tail { ;; gv0 = vmctx ;; gv1 = load.i64 notrap aligned readonly gv0+8 ;; gv2 = load.i64 notrap aligned gv1+16 diff --git a/tests/disas/component-model/exported-module-makes-adapters-indirect.wat b/tests/disas/component-model/exported-module-makes-adapters-indirect.wat index afc37dd44..603bd1f9a 100644 --- a/tests/disas/component-model/exported-module-makes-adapters-indirect.wat +++ b/tests/disas/component-model/exported-module-makes-adapters-indirect.wat @@ -58,7 +58,7 @@ (export "module" (core module $b "module")) ) -;; function u0:1(i64 vmctx, i64) -> i32 tail { +;; function u1:0(i64 vmctx, i64) -> i32 tail { ;; gv0 = vmctx ;; gv1 = load.i64 notrap aligned readonly gv0+8 ;; gv2 = load.i64 notrap aligned gv1+16 diff --git a/tests/disas/component-model/inlining-bug.wat b/tests/disas/component-model/inlining-bug.wat new file mode 100644 index 000000000..9c449eac0 --- /dev/null +++ b/tests/disas/component-model/inlining-bug.wat @@ -0,0 +1,93 @@ +;;! target = "x86_64" +;;! test = "optimize" +;;! filter = "wasm[2]--function" +;;! flags = "-C inlining=y" + +(component + (core module $A + (func (export "f0") (result i32) (i32.const 0)) + (func (export "f1") (result i32) (call $not-inlined) (i32.const 1)) + (func $not-inlined ) + ) + + (core module $B + (import "a" "f0" (func $f0 (result i32))) + (import "a" "f1" (func $f1 (result i32))) + (func (export "f2") (result i32) + (call $f1) + ) + ) + + (core module $C + (import "b" "f2" (func $f2 (result i32))) + (func (export "f3") (result i32) + (call $f2) + ) + ) + + (core instance $a (instantiate $A)) + (core instance $b (instantiate $B (with "a" (instance $a)))) + (core instance $c (instantiate $C (with "b" (instance $b)))) + + (func (export "f") (result u32) + (canon lift (core func $c "f3")) + ) +) + +;; function u2:0(i64 vmctx, i64) -> i32 tail { +;; gv0 = vmctx +;; gv1 = load.i64 notrap aligned readonly gv0+8 +;; gv2 = load.i64 notrap aligned gv1+16 +;; gv3 = vmctx +;; gv4 = vmctx +;; gv5 = load.i64 notrap aligned readonly gv4+8 +;; gv6 = load.i64 notrap aligned gv5+16 +;; gv7 = vmctx +;; gv8 = vmctx +;; gv9 = load.i64 notrap aligned readonly gv8+8 +;; gv10 = load.i64 notrap aligned gv9+16 +;; gv11 = vmctx +;; gv12 = load.i64 notrap aligned readonly gv11+8 +;; gv13 = load.i64 notrap aligned gv12+16 +;; sig0 = (i64 vmctx, i64) -> i32 tail +;; sig1 = (i64 vmctx, i64) -> i32 tail +;; sig2 = (i64 vmctx, i64) tail +;; fn0 = colocated u1:0 sig0 +;; fn1 = colocated u0:1 sig1 +;; fn2 = colocated u0:2 sig2 +;; stack_limit = gv2 +;; +;; block0(v0: i64, v1: i64): +;; @00d4 jump block2 +;; +;; block2: +;; jump block4 +;; +;; block4: +;; jump block7 +;; +;; block7: +;; jump block8 +;; +;; block8: +;; jump block9 +;; +;; block9: +;; jump block5 +;; +;; block5: +;; jump block6 +;; +;; block6: +;; jump block3 +;; +;; block3: +;; jump block10 +;; +;; block10: +;; @00d6 jump block1 +;; +;; block1: +;; v11 = iconst.i32 1 +;; @00d6 return v11 ; v11 = 1 +;; } diff --git a/tests/disas/component-model/inlining-fuzz-bug.wat b/tests/disas/component-model/inlining-fuzz-bug.wat index b62cd75aa..07278ac8f 100644 --- a/tests/disas/component-model/inlining-fuzz-bug.wat +++ b/tests/disas/component-model/inlining-fuzz-bug.wat @@ -37,7 +37,7 @@ ) ) -;; function u0:1(i64 vmctx, i64) -> i32 tail { +;; function u2:0(i64 vmctx, i64) -> i32 tail { ;; gv0 = vmctx ;; gv1 = load.i64 notrap aligned readonly gv0+8 ;; gv2 = load.i64 notrap aligned gv1+16 @@ -54,7 +54,7 @@ ;; gv13 = load.i64 notrap aligned gv12+16 ;; sig0 = (i64 vmctx, i64) -> i32 tail ;; sig1 = (i64 vmctx, i64) -> i32 tail -;; fn0 = colocated u0:0 sig0 +;; fn0 = colocated u1:0 sig0 ;; fn1 = colocated u0:0 sig1 ;; fn2 = colocated u0:1 sig1 ;; stack_limit = gv2 diff --git a/tests/disas/component-model/multiple-instantiations-makes-adapters-indirect.wat b/tests/disas/component-model/multiple-instantiations-makes-adapters-indirect.wat index 4d35c83a2..89f1871c8 100644 --- a/tests/disas/component-model/multiple-instantiations-makes-adapters-indirect.wat +++ b/tests/disas/component-model/multiple-instantiations-makes-adapters-indirect.wat @@ -64,7 +64,7 @@ (export "module" (core module $b "module")) ) -;; function u0:1(i64 vmctx, i64) -> i32 tail { +;; function u1:0(i64 vmctx, i64) -> i32 tail { ;; gv0 = vmctx ;; gv1 = load.i64 notrap aligned readonly gv0+8 ;; gv2 = load.i64 notrap aligned gv1+16 diff --git a/tests/disas/duplicate-function-types.wat b/tests/disas/duplicate-function-types.wat index 7f8e8206d..cf2139672 100644 --- a/tests/disas/duplicate-function-types.wat +++ b/tests/disas/duplicate-function-types.wat @@ -26,7 +26,7 @@ ;; gv6 = load.i64 notrap aligned gv4+8 ;; sig0 = (i64 vmctx, i64) -> i32 tail ;; sig1 = (i64 vmctx, i32, i64) -> i64 tail -;; fn0 = colocated u1:9 sig1 +;; fn0 = colocated u1610612736:9 sig1 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32): diff --git a/tests/disas/epoch-interruption.wat b/tests/disas/epoch-interruption.wat index 8f09d34f1..f4dcffaa3 100644 --- a/tests/disas/epoch-interruption.wat +++ b/tests/disas/epoch-interruption.wat @@ -11,7 +11,7 @@ ;; gv3 = vmctx ;; gv4 = load.i64 notrap aligned readonly can_move gv3+8 ;; sig0 = (i64 vmctx) -> i64 tail -;; fn0 = colocated u1:16 sig0 +;; fn0 = colocated u1610612736:16 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64): diff --git a/tests/disas/gc/drc/array-new-fixed-of-gc-refs.wat b/tests/disas/gc/drc/array-new-fixed-of-gc-refs.wat index 1429607ee..4b224ed7c 100644 --- a/tests/disas/gc/drc/array-new-fixed-of-gc-refs.wat +++ b/tests/disas/gc/drc/array-new-fixed-of-gc-refs.wat @@ -21,7 +21,7 @@ ;; gv5 = load.i64 notrap aligned readonly can_move gv4+24 ;; gv6 = load.i64 notrap aligned gv4+32 ;; sig0 = (i64 vmctx, i32, i32, i32, i32) -> i32 tail -;; fn0 = colocated u1:27 sig0 +;; fn0 = colocated u1610612736:27 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32, v3: i32, v4: i32): diff --git a/tests/disas/gc/drc/array-new-fixed.wat b/tests/disas/gc/drc/array-new-fixed.wat index be8fe3776..6eac41958 100644 --- a/tests/disas/gc/drc/array-new-fixed.wat +++ b/tests/disas/gc/drc/array-new-fixed.wat @@ -17,7 +17,7 @@ ;; gv4 = load.i64 notrap aligned readonly can_move gv3+8 ;; gv5 = load.i64 notrap aligned readonly can_move gv4+24 ;; sig0 = (i64 vmctx, i32, i32, i32, i32) -> i32 tail -;; fn0 = colocated u1:27 sig0 +;; fn0 = colocated u1610612736:27 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i64, v3: i64, v4: i64): diff --git a/tests/disas/gc/drc/array-new.wat b/tests/disas/gc/drc/array-new.wat index a888392f4..d59c51d26 100644 --- a/tests/disas/gc/drc/array-new.wat +++ b/tests/disas/gc/drc/array-new.wat @@ -17,7 +17,7 @@ ;; gv4 = load.i64 notrap aligned readonly can_move gv3+8 ;; gv5 = load.i64 notrap aligned readonly can_move gv4+24 ;; sig0 = (i64 vmctx, i32, i32, i32, i32) -> i32 tail -;; fn0 = colocated u1:27 sig0 +;; fn0 = colocated u1610612736:27 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i64, v3: i32): diff --git a/tests/disas/gc/drc/br-on-cast-fail.wat b/tests/disas/gc/drc/br-on-cast-fail.wat index 1368346c7..6ca19404f 100644 --- a/tests/disas/gc/drc/br-on-cast-fail.wat +++ b/tests/disas/gc/drc/br-on-cast-fail.wat @@ -16,7 +16,7 @@ return ) ) -;; function u0:2(i64 vmctx, i64, i32) tail { +;; function u0:0(i64 vmctx, i64, i32) tail { ;; ss0 = explicit_slot 4, align = 4 ;; gv0 = vmctx ;; gv1 = load.i64 notrap aligned readonly gv0+8 @@ -27,7 +27,7 @@ ;; gv6 = load.i64 notrap aligned gv4+32 ;; sig0 = (i64 vmctx, i32, i32) -> i32 tail ;; sig1 = (i64 vmctx, i64) tail -;; fn0 = colocated u1:35 sig0 +;; fn0 = colocated u1610612736:35 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32): diff --git a/tests/disas/gc/drc/br-on-cast.wat b/tests/disas/gc/drc/br-on-cast.wat index dff0153a7..7adb9bdf2 100644 --- a/tests/disas/gc/drc/br-on-cast.wat +++ b/tests/disas/gc/drc/br-on-cast.wat @@ -16,7 +16,7 @@ return ) ) -;; function u0:2(i64 vmctx, i64, i32) tail { +;; function u0:0(i64 vmctx, i64, i32) tail { ;; ss0 = explicit_slot 4, align = 4 ;; gv0 = vmctx ;; gv1 = load.i64 notrap aligned readonly gv0+8 @@ -27,7 +27,7 @@ ;; gv6 = load.i64 notrap aligned gv4+32 ;; sig0 = (i64 vmctx, i32, i32) -> i32 tail ;; sig1 = (i64 vmctx, i64) tail -;; fn0 = colocated u1:35 sig0 +;; fn0 = colocated u1610612736:35 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32): diff --git a/tests/disas/gc/drc/call-indirect-and-subtyping.wat b/tests/disas/gc/drc/call-indirect-and-subtyping.wat index 200b8f566..9669191c5 100644 --- a/tests/disas/gc/drc/call-indirect-and-subtyping.wat +++ b/tests/disas/gc/drc/call-indirect-and-subtyping.wat @@ -16,7 +16,7 @@ (call_indirect (type $t1) (local.get 0)) ) ) -;; function u0:2(i64 vmctx, i64, i32) tail { +;; function u0:0(i64 vmctx, i64, i32) tail { ;; gv0 = vmctx ;; gv1 = load.i64 notrap aligned readonly gv0+8 ;; gv2 = load.i64 notrap aligned gv1+16 @@ -25,8 +25,8 @@ ;; sig0 = (i64 vmctx, i64) tail ;; sig1 = (i64 vmctx, i32, i64) -> i64 tail ;; sig2 = (i64 vmctx, i32, i32) -> i32 tail -;; fn0 = colocated u1:9 sig1 -;; fn1 = colocated u1:35 sig2 +;; fn0 = colocated u1610612736:9 sig1 +;; fn1 = colocated u1610612736:35 sig2 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32): diff --git a/tests/disas/gc/drc/externref-globals.wat b/tests/disas/gc/drc/externref-globals.wat index 587d540c2..b878f0902 100644 --- a/tests/disas/gc/drc/externref-globals.wat +++ b/tests/disas/gc/drc/externref-globals.wat @@ -78,7 +78,7 @@ ;; gv5 = load.i64 notrap aligned readonly can_move gv4+24 ;; gv6 = load.i64 notrap aligned gv4+32 ;; sig0 = (i64 vmctx, i32) tail -;; fn0 = colocated u1:25 sig0 +;; fn0 = colocated u1610612736:25 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32): diff --git a/tests/disas/gc/drc/funcref-in-gc-heap-get.wat b/tests/disas/gc/drc/funcref-in-gc-heap-get.wat index 32c65e647..226609b2e 100644 --- a/tests/disas/gc/drc/funcref-in-gc-heap-get.wat +++ b/tests/disas/gc/drc/funcref-in-gc-heap-get.wat @@ -18,7 +18,7 @@ ;; gv5 = load.i64 notrap aligned readonly can_move gv4+24 ;; gv6 = load.i64 notrap aligned gv4+32 ;; sig0 = (i64 vmctx, i32, i32) -> i64 tail -;; fn0 = colocated u1:29 sig0 +;; fn0 = colocated u1610612736:29 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32): diff --git a/tests/disas/gc/drc/funcref-in-gc-heap-new.wat b/tests/disas/gc/drc/funcref-in-gc-heap-new.wat index 952acf538..87e548958 100644 --- a/tests/disas/gc/drc/funcref-in-gc-heap-new.wat +++ b/tests/disas/gc/drc/funcref-in-gc-heap-new.wat @@ -19,8 +19,8 @@ ;; gv5 = load.i64 notrap aligned readonly can_move gv4+24 ;; sig0 = (i64 vmctx, i32, i32, i32, i32) -> i32 tail ;; sig1 = (i64 vmctx, i64) -> i64 tail -;; fn0 = colocated u1:27 sig0 -;; fn1 = colocated u1:28 sig1 +;; fn0 = colocated u1610612736:27 sig0 +;; fn1 = colocated u1610612736:28 sig1 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i64): diff --git a/tests/disas/gc/drc/funcref-in-gc-heap-set.wat b/tests/disas/gc/drc/funcref-in-gc-heap-set.wat index db8dd8fe9..511596b09 100644 --- a/tests/disas/gc/drc/funcref-in-gc-heap-set.wat +++ b/tests/disas/gc/drc/funcref-in-gc-heap-set.wat @@ -18,7 +18,7 @@ ;; gv5 = load.i64 notrap aligned readonly can_move gv4+24 ;; gv6 = load.i64 notrap aligned gv4+32 ;; sig0 = (i64 vmctx, i64) -> i64 tail -;; fn0 = colocated u1:28 sig0 +;; fn0 = colocated u1610612736:28 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32, v3: i64): diff --git a/tests/disas/gc/drc/ref-cast.wat b/tests/disas/gc/drc/ref-cast.wat index 6bea7387e..63d833f3f 100644 --- a/tests/disas/gc/drc/ref-cast.wat +++ b/tests/disas/gc/drc/ref-cast.wat @@ -18,7 +18,7 @@ ;; gv5 = load.i64 notrap aligned readonly can_move gv4+24 ;; gv6 = load.i64 notrap aligned gv4+32 ;; sig0 = (i64 vmctx, i32, i32) -> i32 tail -;; fn0 = colocated u1:35 sig0 +;; fn0 = colocated u1610612736:35 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32): diff --git a/tests/disas/gc/drc/ref-test-concrete-func-type.wat b/tests/disas/gc/drc/ref-test-concrete-func-type.wat index 0bcb35bf3..b1a38fbb5 100644 --- a/tests/disas/gc/drc/ref-test-concrete-func-type.wat +++ b/tests/disas/gc/drc/ref-test-concrete-func-type.wat @@ -14,7 +14,7 @@ ;; gv2 = load.i64 notrap aligned gv1+16 ;; gv3 = vmctx ;; sig0 = (i64 vmctx, i32, i32) -> i32 tail -;; fn0 = colocated u1:35 sig0 +;; fn0 = colocated u1610612736:35 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i64): diff --git a/tests/disas/gc/drc/ref-test-concrete-type.wat b/tests/disas/gc/drc/ref-test-concrete-type.wat index da3b61f53..25f7897c7 100644 --- a/tests/disas/gc/drc/ref-test-concrete-type.wat +++ b/tests/disas/gc/drc/ref-test-concrete-type.wat @@ -17,7 +17,7 @@ ;; gv5 = load.i64 notrap aligned readonly can_move gv4+24 ;; gv6 = load.i64 notrap aligned gv4+32 ;; sig0 = (i64 vmctx, i32, i32) -> i32 tail -;; fn0 = colocated u1:35 sig0 +;; fn0 = colocated u1610612736:35 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32): diff --git a/tests/disas/gc/drc/struct-new-default.wat b/tests/disas/gc/drc/struct-new-default.wat index b04f34436..feb660998 100644 --- a/tests/disas/gc/drc/struct-new-default.wat +++ b/tests/disas/gc/drc/struct-new-default.wat @@ -20,7 +20,7 @@ ;; gv5 = load.i64 notrap aligned readonly can_move gv4+24 ;; gv6 = load.i64 notrap aligned gv4+32 ;; sig0 = (i64 vmctx, i32, i32, i32, i32) -> i32 tail -;; fn0 = colocated u1:27 sig0 +;; fn0 = colocated u1610612736:27 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64): diff --git a/tests/disas/gc/drc/struct-new.wat b/tests/disas/gc/drc/struct-new.wat index f821ca8cb..c8ea45a89 100644 --- a/tests/disas/gc/drc/struct-new.wat +++ b/tests/disas/gc/drc/struct-new.wat @@ -21,7 +21,7 @@ ;; gv5 = load.i64 notrap aligned readonly can_move gv4+24 ;; gv6 = load.i64 notrap aligned gv4+32 ;; sig0 = (i64 vmctx, i32, i32, i32, i32) -> i32 tail -;; fn0 = colocated u1:27 sig0 +;; fn0 = colocated u1610612736:27 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: f32, v3: i32, v4: i32): diff --git a/tests/disas/gc/drc/struct-set.wat b/tests/disas/gc/drc/struct-set.wat index c4fd5e18e..109f0a837 100644 --- a/tests/disas/gc/drc/struct-set.wat +++ b/tests/disas/gc/drc/struct-set.wat @@ -78,7 +78,7 @@ ;; gv5 = load.i64 notrap aligned readonly can_move gv4+24 ;; gv6 = load.i64 notrap aligned gv4+32 ;; sig0 = (i64 vmctx, i32) tail -;; fn0 = colocated u1:25 sig0 +;; fn0 = colocated u1610612736:25 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32, v3: i32): diff --git a/tests/disas/gc/null/array-new-fixed-of-gc-refs.wat b/tests/disas/gc/null/array-new-fixed-of-gc-refs.wat index 12dd5fe01..963afecaf 100644 --- a/tests/disas/gc/null/array-new-fixed-of-gc-refs.wat +++ b/tests/disas/gc/null/array-new-fixed-of-gc-refs.wat @@ -21,7 +21,7 @@ ;; gv5 = load.i64 notrap aligned gv4+32 ;; gv6 = load.i64 notrap aligned readonly can_move gv4+24 ;; sig0 = (i64 vmctx, i64) -> i8 tail -;; fn0 = colocated u1:26 sig0 +;; fn0 = colocated u1610612736:26 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32, v3: i32, v4: i32): diff --git a/tests/disas/gc/null/array-new-fixed.wat b/tests/disas/gc/null/array-new-fixed.wat index e9a3fc08c..792803c24 100644 --- a/tests/disas/gc/null/array-new-fixed.wat +++ b/tests/disas/gc/null/array-new-fixed.wat @@ -18,7 +18,7 @@ ;; gv5 = load.i64 notrap aligned gv4+32 ;; gv6 = load.i64 notrap aligned readonly can_move gv4+24 ;; sig0 = (i64 vmctx, i64) -> i8 tail -;; fn0 = colocated u1:26 sig0 +;; fn0 = colocated u1610612736:26 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i64, v3: i64, v4: i64): diff --git a/tests/disas/gc/null/array-new.wat b/tests/disas/gc/null/array-new.wat index dc79a568c..9335a0478 100644 --- a/tests/disas/gc/null/array-new.wat +++ b/tests/disas/gc/null/array-new.wat @@ -18,7 +18,7 @@ ;; gv5 = load.i64 notrap aligned gv4+32 ;; gv6 = load.i64 notrap aligned readonly can_move gv4+24 ;; sig0 = (i64 vmctx, i64) -> i8 tail -;; fn0 = colocated u1:26 sig0 +;; fn0 = colocated u1610612736:26 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i64, v3: i32): diff --git a/tests/disas/gc/null/br-on-cast-fail.wat b/tests/disas/gc/null/br-on-cast-fail.wat index 5ef3653ae..e16a70c39 100644 --- a/tests/disas/gc/null/br-on-cast-fail.wat +++ b/tests/disas/gc/null/br-on-cast-fail.wat @@ -16,7 +16,7 @@ return ) ) -;; function u0:2(i64 vmctx, i64, i32) tail { +;; function u0:0(i64 vmctx, i64, i32) tail { ;; ss0 = explicit_slot 4, align = 4 ;; gv0 = vmctx ;; gv1 = load.i64 notrap aligned readonly gv0+8 @@ -27,7 +27,7 @@ ;; gv6 = load.i64 notrap aligned gv4+32 ;; sig0 = (i64 vmctx, i32, i32) -> i32 tail ;; sig1 = (i64 vmctx, i64) tail -;; fn0 = colocated u1:35 sig0 +;; fn0 = colocated u1610612736:35 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32): diff --git a/tests/disas/gc/null/br-on-cast.wat b/tests/disas/gc/null/br-on-cast.wat index 27bf38f70..b8340d637 100644 --- a/tests/disas/gc/null/br-on-cast.wat +++ b/tests/disas/gc/null/br-on-cast.wat @@ -16,7 +16,7 @@ return ) ) -;; function u0:2(i64 vmctx, i64, i32) tail { +;; function u0:0(i64 vmctx, i64, i32) tail { ;; ss0 = explicit_slot 4, align = 4 ;; gv0 = vmctx ;; gv1 = load.i64 notrap aligned readonly gv0+8 @@ -27,7 +27,7 @@ ;; gv6 = load.i64 notrap aligned gv4+32 ;; sig0 = (i64 vmctx, i32, i32) -> i32 tail ;; sig1 = (i64 vmctx, i64) tail -;; fn0 = colocated u1:35 sig0 +;; fn0 = colocated u1610612736:35 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32): diff --git a/tests/disas/gc/null/call-indirect-and-subtyping.wat b/tests/disas/gc/null/call-indirect-and-subtyping.wat index cfe055252..f1bff51d6 100644 --- a/tests/disas/gc/null/call-indirect-and-subtyping.wat +++ b/tests/disas/gc/null/call-indirect-and-subtyping.wat @@ -16,7 +16,7 @@ (call_indirect (type $t1) (local.get 0)) ) ) -;; function u0:2(i64 vmctx, i64, i32) tail { +;; function u0:0(i64 vmctx, i64, i32) tail { ;; gv0 = vmctx ;; gv1 = load.i64 notrap aligned readonly gv0+8 ;; gv2 = load.i64 notrap aligned gv1+16 @@ -25,8 +25,8 @@ ;; sig0 = (i64 vmctx, i64) tail ;; sig1 = (i64 vmctx, i32, i64) -> i64 tail ;; sig2 = (i64 vmctx, i32, i32) -> i32 tail -;; fn0 = colocated u1:9 sig1 -;; fn1 = colocated u1:35 sig2 +;; fn0 = colocated u1610612736:9 sig1 +;; fn1 = colocated u1610612736:35 sig2 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32): diff --git a/tests/disas/gc/null/funcref-in-gc-heap-get.wat b/tests/disas/gc/null/funcref-in-gc-heap-get.wat index 558aa070e..a12beba91 100644 --- a/tests/disas/gc/null/funcref-in-gc-heap-get.wat +++ b/tests/disas/gc/null/funcref-in-gc-heap-get.wat @@ -18,7 +18,7 @@ ;; gv5 = load.i64 notrap aligned readonly can_move gv4+24 ;; gv6 = load.i64 notrap aligned gv4+32 ;; sig0 = (i64 vmctx, i32, i32) -> i64 tail -;; fn0 = colocated u1:29 sig0 +;; fn0 = colocated u1610612736:29 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32): diff --git a/tests/disas/gc/null/funcref-in-gc-heap-new.wat b/tests/disas/gc/null/funcref-in-gc-heap-new.wat index 90401943f..658c4d833 100644 --- a/tests/disas/gc/null/funcref-in-gc-heap-new.wat +++ b/tests/disas/gc/null/funcref-in-gc-heap-new.wat @@ -19,8 +19,8 @@ ;; gv6 = load.i64 notrap aligned readonly can_move gv4+24 ;; sig0 = (i64 vmctx, i64) -> i8 tail ;; sig1 = (i64 vmctx, i64) -> i64 tail -;; fn0 = colocated u1:26 sig0 -;; fn1 = colocated u1:28 sig1 +;; fn0 = colocated u1610612736:26 sig0 +;; fn1 = colocated u1610612736:28 sig1 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i64): diff --git a/tests/disas/gc/null/funcref-in-gc-heap-set.wat b/tests/disas/gc/null/funcref-in-gc-heap-set.wat index 687da61ce..97dba164e 100644 --- a/tests/disas/gc/null/funcref-in-gc-heap-set.wat +++ b/tests/disas/gc/null/funcref-in-gc-heap-set.wat @@ -18,7 +18,7 @@ ;; gv5 = load.i64 notrap aligned readonly can_move gv4+24 ;; gv6 = load.i64 notrap aligned gv4+32 ;; sig0 = (i64 vmctx, i64) -> i64 tail -;; fn0 = colocated u1:28 sig0 +;; fn0 = colocated u1610612736:28 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32, v3: i64): diff --git a/tests/disas/gc/null/ref-cast.wat b/tests/disas/gc/null/ref-cast.wat index 4788cd5f2..451898878 100644 --- a/tests/disas/gc/null/ref-cast.wat +++ b/tests/disas/gc/null/ref-cast.wat @@ -18,7 +18,7 @@ ;; gv5 = load.i64 notrap aligned readonly can_move gv4+24 ;; gv6 = load.i64 notrap aligned gv4+32 ;; sig0 = (i64 vmctx, i32, i32) -> i32 tail -;; fn0 = colocated u1:35 sig0 +;; fn0 = colocated u1610612736:35 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32): diff --git a/tests/disas/gc/null/ref-test-concrete-func-type.wat b/tests/disas/gc/null/ref-test-concrete-func-type.wat index bcc6d606b..30b06b480 100644 --- a/tests/disas/gc/null/ref-test-concrete-func-type.wat +++ b/tests/disas/gc/null/ref-test-concrete-func-type.wat @@ -14,7 +14,7 @@ ;; gv2 = load.i64 notrap aligned gv1+16 ;; gv3 = vmctx ;; sig0 = (i64 vmctx, i32, i32) -> i32 tail -;; fn0 = colocated u1:35 sig0 +;; fn0 = colocated u1610612736:35 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i64): diff --git a/tests/disas/gc/null/ref-test-concrete-type.wat b/tests/disas/gc/null/ref-test-concrete-type.wat index 673e890dd..89809a375 100644 --- a/tests/disas/gc/null/ref-test-concrete-type.wat +++ b/tests/disas/gc/null/ref-test-concrete-type.wat @@ -17,7 +17,7 @@ ;; gv5 = load.i64 notrap aligned readonly can_move gv4+24 ;; gv6 = load.i64 notrap aligned gv4+32 ;; sig0 = (i64 vmctx, i32, i32) -> i32 tail -;; fn0 = colocated u1:35 sig0 +;; fn0 = colocated u1610612736:35 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32): diff --git a/tests/disas/gc/null/struct-new-default.wat b/tests/disas/gc/null/struct-new-default.wat index 957895c92..c67db4ca4 100644 --- a/tests/disas/gc/null/struct-new-default.wat +++ b/tests/disas/gc/null/struct-new-default.wat @@ -20,7 +20,7 @@ ;; gv5 = load.i64 notrap aligned gv4+32 ;; gv6 = load.i64 notrap aligned readonly can_move gv4+24 ;; sig0 = (i64 vmctx, i64) -> i8 tail -;; fn0 = colocated u1:26 sig0 +;; fn0 = colocated u1610612736:26 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64): diff --git a/tests/disas/gc/null/struct-new.wat b/tests/disas/gc/null/struct-new.wat index 247786227..36b5e1ad2 100644 --- a/tests/disas/gc/null/struct-new.wat +++ b/tests/disas/gc/null/struct-new.wat @@ -21,7 +21,7 @@ ;; gv5 = load.i64 notrap aligned gv4+32 ;; gv6 = load.i64 notrap aligned readonly can_move gv4+24 ;; sig0 = (i64 vmctx, i64) -> i8 tail -;; fn0 = colocated u1:26 sig0 +;; fn0 = colocated u1610612736:26 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: f32, v3: i32, v4: i32): diff --git a/tests/disas/gc/struct-new-default.wat b/tests/disas/gc/struct-new-default.wat index 75416dd00..3141cfb7d 100644 --- a/tests/disas/gc/struct-new-default.wat +++ b/tests/disas/gc/struct-new-default.wat @@ -21,7 +21,7 @@ ;; gv5 = load.i64 notrap aligned readonly can_move gv4+24 ;; gv6 = load.i64 notrap aligned gv4+32 ;; sig0 = (i64 vmctx, i32, i32, i32, i32) -> i32 tail -;; fn0 = colocated u1:27 sig0 +;; fn0 = colocated u1610612736:27 sig0 ;; const0 = 0x00000000000000000000000000000000 ;; stack_limit = gv2 ;; diff --git a/tests/disas/gc/struct-new.wat b/tests/disas/gc/struct-new.wat index 9756c7bff..7f59fc129 100644 --- a/tests/disas/gc/struct-new.wat +++ b/tests/disas/gc/struct-new.wat @@ -21,7 +21,7 @@ ;; gv5 = load.i64 notrap aligned readonly can_move gv4+24 ;; gv6 = load.i64 notrap aligned gv4+32 ;; sig0 = (i64 vmctx, i32, i32, i32, i32) -> i32 tail -;; fn0 = colocated u1:27 sig0 +;; fn0 = colocated u1610612736:27 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: f32, v3: i32, v4: i32): diff --git a/tests/disas/icall-loop.wat b/tests/disas/icall-loop.wat index 8107c3d71..ac63bc9be 100644 --- a/tests/disas/icall-loop.wat +++ b/tests/disas/icall-loop.wat @@ -30,7 +30,7 @@ ;; gv4 = load.i64 notrap aligned readonly can_move gv3+48 ;; sig0 = (i64 vmctx, i64) -> i32 tail ;; sig1 = (i64 vmctx, i32, i64) -> i64 tail -;; fn0 = colocated u1:9 sig1 +;; fn0 = colocated u1610612736:9 sig1 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32): @@ -78,7 +78,7 @@ ;; gv4 = load.i64 notrap aligned readonly can_move gv3+48 ;; sig0 = (i64 vmctx, i64) -> i32 tail ;; sig1 = (i64 vmctx, i32, i64) -> i64 tail -;; fn0 = colocated u1:9 sig1 +;; fn0 = colocated u1610612736:9 sig1 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64): diff --git a/tests/disas/icall-simd.wat b/tests/disas/icall-simd.wat index 64f0d37c1..6733afce4 100644 --- a/tests/disas/icall-simd.wat +++ b/tests/disas/icall-simd.wat @@ -16,7 +16,7 @@ ;; gv4 = load.i64 notrap aligned readonly can_move gv3+48 ;; sig0 = (i64 vmctx, i64, i8x16) -> i8x16 tail ;; sig1 = (i64 vmctx, i32, i64) -> i64 tail -;; fn0 = colocated u1:9 sig1 +;; fn0 = colocated u1610612736:9 sig1 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32, v3: i8x16): diff --git a/tests/disas/icall.wat b/tests/disas/icall.wat index d3df0defb..aeb4cb467 100644 --- a/tests/disas/icall.wat +++ b/tests/disas/icall.wat @@ -16,7 +16,7 @@ ;; gv4 = load.i64 notrap aligned readonly can_move gv3+48 ;; sig0 = (i64 vmctx, i64, f32) -> i32 tail ;; sig1 = (i64 vmctx, i32, i64) -> i64 tail -;; fn0 = colocated u1:9 sig1 +;; fn0 = colocated u1610612736:9 sig1 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32, v3: f32): diff --git a/tests/disas/indirect-call-no-caching.wat b/tests/disas/indirect-call-no-caching.wat index 41061d121..a30b25af5 100644 --- a/tests/disas/indirect-call-no-caching.wat +++ b/tests/disas/indirect-call-no-caching.wat @@ -70,7 +70,7 @@ ;; gv4 = load.i64 notrap aligned readonly can_move gv3+48 ;; sig0 = (i64 vmctx, i64) -> i32 tail ;; sig1 = (i64 vmctx, i32, i64) -> i64 tail -;; fn0 = colocated u1:9 sig1 +;; fn0 = colocated u1610612736:9 sig1 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32): diff --git a/tests/disas/memory-min-max-same.wat b/tests/disas/memory-min-max-same.wat index 92b80e5c5..75d433e74 100644 --- a/tests/disas/memory-min-max-same.wat +++ b/tests/disas/memory-min-max-same.wat @@ -33,7 +33,7 @@ ) ) ) -;; function u0:1(i64 vmctx, i64, i32) tail { +;; function u0:0(i64 vmctx, i64, i32) tail { ;; gv0 = vmctx ;; gv1 = load.i64 notrap aligned readonly gv0+8 ;; gv2 = load.i64 notrap aligned gv1+16 diff --git a/tests/disas/passive-data.wat b/tests/disas/passive-data.wat index d03facda0..21de22f46 100644 --- a/tests/disas/passive-data.wat +++ b/tests/disas/passive-data.wat @@ -21,7 +21,7 @@ ;; gv4 = load.i64 notrap aligned gv3+64 ;; gv5 = load.i64 notrap aligned readonly can_move checked gv3+56 ;; sig0 = (i64 vmctx, i32, i32, i64, i32, i32) -> i8 tail -;; fn0 = colocated u1:6 sig0 +;; fn0 = colocated u1610612736:6 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32, v3: i32, v4: i32): @@ -41,7 +41,7 @@ ;; gv2 = load.i64 notrap aligned gv1+16 ;; gv3 = vmctx ;; sig0 = (i64 vmctx, i32) tail -;; fn0 = colocated u1:8 sig0 +;; fn0 = colocated u1610612736:8 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64): diff --git a/tests/disas/readonly-funcrefs.wat b/tests/disas/readonly-funcrefs.wat index db3c160bc..6091c33e9 100644 --- a/tests/disas/readonly-funcrefs.wat +++ b/tests/disas/readonly-funcrefs.wat @@ -39,7 +39,7 @@ ;; gv4 = load.i64 notrap aligned readonly can_move gv3+48 ;; sig0 = (i64 vmctx, i64) tail ;; sig1 = (i64 vmctx, i32, i64) -> i64 tail -;; fn0 = colocated u1:9 sig1 +;; fn0 = colocated u1610612736:9 sig1 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32): diff --git a/tests/disas/ref-func-0.wat b/tests/disas/ref-func-0.wat index c87baad71..8ebbadbf7 100644 --- a/tests/disas/ref-func-0.wat +++ b/tests/disas/ref-func-0.wat @@ -13,7 +13,7 @@ (global (export "funcref-imported") funcref (ref.func $imported)) (global (export "funcref-local") funcref (ref.func $local))) -;; function u0:1(i64 vmctx, i64) -> i32, i32, i64, i64 tail { +;; function u0:0(i64 vmctx, i64) -> i32, i32, i64, i64 tail { ;; gv0 = vmctx ;; gv1 = load.i64 notrap aligned readonly gv0+8 ;; gv2 = load.i64 notrap aligned gv1+16 diff --git a/tests/disas/table-copy.wat b/tests/disas/table-copy.wat index 718f71168..05d8fcde4 100644 --- a/tests/disas/table-copy.wat +++ b/tests/disas/table-copy.wat @@ -68,7 +68,7 @@ ;; gv2 = load.i64 notrap aligned gv1+16 ;; gv3 = vmctx ;; sig0 = (i64 vmctx, i32, i32, i64, i64, i64) -> i8 tail -;; fn0 = colocated u1:1 sig0 +;; fn0 = colocated u1610612736:1 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32, v3: i32, v4: i32, v5: i32): @@ -90,7 +90,7 @@ ;; gv2 = load.i64 notrap aligned gv1+16 ;; gv3 = vmctx ;; sig0 = (i64 vmctx, i32, i32, i64, i64, i64) -> i8 tail -;; fn0 = colocated u1:1 sig0 +;; fn0 = colocated u1610612736:1 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32, v3: i32, v4: i32, v5: i32): diff --git a/tests/disas/table-set-fixed-size.wat b/tests/disas/table-set-fixed-size.wat index de94d4748..86e57ff33 100644 --- a/tests/disas/table-set-fixed-size.wat +++ b/tests/disas/table-set-fixed-size.wat @@ -26,7 +26,7 @@ ;; gv6 = load.i64 notrap aligned readonly can_move gv5+24 ;; gv7 = load.i64 notrap aligned gv5+32 ;; sig0 = (i64 vmctx, i32) tail -;; fn0 = colocated u1:25 sig0 +;; fn0 = colocated u1610612736:25 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32): @@ -123,7 +123,7 @@ ;; gv6 = load.i64 notrap aligned readonly can_move gv5+24 ;; gv7 = load.i64 notrap aligned gv5+32 ;; sig0 = (i64 vmctx, i32) tail -;; fn0 = colocated u1:25 sig0 +;; fn0 = colocated u1610612736:25 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32, v3: i32): diff --git a/tests/disas/table-set.wat b/tests/disas/table-set.wat index b09422f78..ee30fbc37 100644 --- a/tests/disas/table-set.wat +++ b/tests/disas/table-set.wat @@ -27,7 +27,7 @@ ;; gv7 = load.i64 notrap aligned readonly can_move gv6+24 ;; gv8 = load.i64 notrap aligned gv6+32 ;; sig0 = (i64 vmctx, i32) tail -;; fn0 = colocated u1:25 sig0 +;; fn0 = colocated u1610612736:25 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32): @@ -126,7 +126,7 @@ ;; gv7 = load.i64 notrap aligned readonly can_move gv6+24 ;; gv8 = load.i64 notrap aligned gv6+32 ;; sig0 = (i64 vmctx, i32) tail -;; fn0 = colocated u1:25 sig0 +;; fn0 = colocated u1610612736:25 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32, v3: i32): diff --git a/tests/disas/typed-funcrefs.wat b/tests/disas/typed-funcrefs.wat index 23e3545ba..310334996 100644 --- a/tests/disas/typed-funcrefs.wat +++ b/tests/disas/typed-funcrefs.wat @@ -134,7 +134,7 @@ ;; gv4 = load.i64 notrap aligned readonly can_move gv3+48 ;; sig0 = (i64 vmctx, i32, i64) -> i64 tail ;; sig1 = (i64 vmctx, i64, i32, i32, i32, i32) -> i32 tail -;; fn0 = colocated u1:9 sig0 +;; fn0 = colocated u1610612736:9 sig0 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32, v3: i32, v4: i32, v5: i32): @@ -188,7 +188,7 @@ ;; gv4 = load.i64 notrap aligned readonly can_move gv3+48 ;; sig0 = (i64 vmctx, i64, i32, i32, i32, i32) -> i32 tail ;; sig1 = (i64 vmctx, i32, i64) -> i64 tail -;; fn0 = colocated u1:9 sig1 +;; fn0 = colocated u1610612736:9 sig1 ;; stack_limit = gv2 ;; ;; block0(v0: i64, v1: i64, v2: i32, v3: i32, v4: i32, v5: i32): diff --git a/tests/disas/winch/x64/table/init_copy_drop.wat b/tests/disas/winch/x64/table/init_copy_drop.wat index b753b658d..138863dea 100644 --- a/tests/disas/winch/x64/table/init_copy_drop.wat +++ b/tests/disas/winch/x64/table/init_copy_drop.wat @@ -142,11 +142,11 @@ ;; movl $7, %ecx ;; movl $0, %r8d ;; movl $4, %r9d -;; callq 0x8a7 +;; callq 0x905 ;; movq 8(%rsp), %r14 ;; movq %r14, %rdi ;; movl $1, %esi -;; callq 0x905 +;; callq 0x963 ;; movq 8(%rsp), %r14 ;; movq %r14, %rdi ;; movl $0, %esi @@ -154,11 +154,11 @@ ;; movl $0xf, %ecx ;; movl $1, %r8d ;; movl $3, %r9d -;; callq 0x8a7 +;; callq 0x905 ;; movq 8(%rsp), %r14 ;; movq %r14, %rdi ;; movl $3, %esi -;; callq 0x905 +;; callq 0x963 ;; movq 8(%rsp), %r14 ;; movq %r14, %rdi ;; movl $0, %esi @@ -166,7 +166,7 @@ ;; movl $0x14, %ecx ;; movl $0xf, %r8d ;; movl $5, %r9d -;; callq 0x943 +;; callq 0x8a7 ;; movq 8(%rsp), %r14 ;; movq %r14, %rdi ;; movl $0, %esi @@ -174,7 +174,7 @@ ;; movl $0x15, %ecx ;; movl $0x1d, %r8d ;; movl $1, %r9d -;; callq 0x943 +;; callq 0x8a7 ;; movq 8(%rsp), %r14 ;; movq %r14, %rdi ;; movl $0, %esi @@ -182,7 +182,7 @@ ;; movl $0x18, %ecx ;; movl $0xa, %r8d ;; movl $1, %r9d -;; callq 0x943 +;; callq 0x8a7 ;; movq 8(%rsp), %r14 ;; movq %r14, %rdi ;; movl $0, %esi @@ -190,7 +190,7 @@ ;; movl $0xd, %ecx ;; movl $0xb, %r8d ;; movl $4, %r9d -;; callq 0x943 +;; callq 0x8a7 ;; movq 8(%rsp), %r14 ;; movq %r14, %rdi ;; movl $0, %esi @@ -198,7 +198,7 @@ ;; movl $0x13, %ecx ;; movl $0x14, %r8d ;; movl $5, %r9d -;; callq 0x943 +;; callq 0x8a7 ;; movq 8(%rsp), %r14 ;; addq $0x10, %rsp ;; popq %rbp diff --git a/tests/disas/x64-simd-round-without-sse41.wat b/tests/disas/x64-simd-round-without-sse41.wat index 197bce1b2..c3dd36b46 100644 --- a/tests/disas/x64-simd-round-without-sse41.wat +++ b/tests/disas/x64-simd-round-without-sse41.wat @@ -17,7 +17,7 @@ ;; gv2 = load.i64 notrap aligned gv1+16 ;; gv3 = vmctx ;; sig0 = (i64 vmctx, f32) -> f32 tail -;; fn0 = colocated u1:38 sig0 +;; fn0 = colocated u1610612736:38 sig0 ;; const0 = 0x00000000000000000000000000000000 ;; stack_limit = gv2 ;; @@ -49,7 +49,7 @@ ;; gv2 = load.i64 notrap aligned gv1+16 ;; gv3 = vmctx ;; sig0 = (i64 vmctx, f32) -> f32 tail -;; fn0 = colocated u1:40 sig0 +;; fn0 = colocated u1610612736:40 sig0 ;; const0 = 0x00000000000000000000000000000000 ;; stack_limit = gv2 ;; @@ -81,7 +81,7 @@ ;; gv2 = load.i64 notrap aligned gv1+16 ;; gv3 = vmctx ;; sig0 = (i64 vmctx, f32) -> f32 tail -;; fn0 = colocated u1:42 sig0 +;; fn0 = colocated u1610612736:42 sig0 ;; const0 = 0x00000000000000000000000000000000 ;; stack_limit = gv2 ;; @@ -113,7 +113,7 @@ ;; gv2 = load.i64 notrap aligned gv1+16 ;; gv3 = vmctx ;; sig0 = (i64 vmctx, f32) -> f32 tail -;; fn0 = colocated u1:44 sig0 +;; fn0 = colocated u1610612736:44 sig0 ;; const0 = 0x00000000000000000000000000000000 ;; stack_limit = gv2 ;; @@ -145,7 +145,7 @@ ;; gv2 = load.i64 notrap aligned gv1+16 ;; gv3 = vmctx ;; sig0 = (i64 vmctx, f64) -> f64 tail -;; fn0 = colocated u1:39 sig0 +;; fn0 = colocated u1610612736:39 sig0 ;; const0 = 0x00000000000000000000000000000000 ;; stack_limit = gv2 ;; @@ -171,7 +171,7 @@ ;; gv2 = load.i64 notrap aligned gv1+16 ;; gv3 = vmctx ;; sig0 = (i64 vmctx, f64) -> f64 tail -;; fn0 = colocated u1:41 sig0 +;; fn0 = colocated u1610612736:41 sig0 ;; const0 = 0x00000000000000000000000000000000 ;; stack_limit = gv2 ;; @@ -197,7 +197,7 @@ ;; gv2 = load.i64 notrap aligned gv1+16 ;; gv3 = vmctx ;; sig0 = (i64 vmctx, f64) -> f64 tail -;; fn0 = colocated u1:43 sig0 +;; fn0 = colocated u1610612736:43 sig0 ;; const0 = 0x00000000000000000000000000000000 ;; stack_limit = gv2 ;; @@ -223,7 +223,7 @@ ;; gv2 = load.i64 notrap aligned gv1+16 ;; gv3 = vmctx ;; sig0 = (i64 vmctx, f64) -> f64 tail -;; fn0 = colocated u1:45 sig0 +;; fn0 = colocated u1610612736:45 sig0 ;; const0 = 0x00000000000000000000000000000000 ;; stack_limit = gv2 ;; diff --git a/winch/codegen/src/codegen/call.rs b/winch/codegen/src/codegen/call.rs index 2f09c6b3e..43c544d78 100644 --- a/winch/codegen/src/codegen/call.rs +++ b/winch/codegen/src/codegen/call.rs @@ -70,7 +70,7 @@ use crate::{ stack::Val, }; use anyhow::{Result, ensure}; -use wasmtime_environ::{FuncIndex, PtrSize, VMOffsets}; +use wasmtime_environ::{DefinedFuncIndex, FuncIndex, PtrSize, VMOffsets}; /// All the information needed to emit a function call. #[derive(Copy, Clone)] @@ -148,7 +148,10 @@ impl FnCall { Callee::FuncRef(_) => { Self::lower_funcref(env.callee_sig::(callee)?, ptr, context, masm) } - Callee::Local(i) => Ok(Self::lower_local(env, *i)), + Callee::Local(i) => { + let f = env.translation.module.defined_func_index(*i).unwrap(); + Ok(Self::lower_local(env, f)) + } Callee::Import(i) => { let sig = env.callee_sig::(callee)?; Self::lower_import(*i, sig, context, masm, vmoffsets) @@ -177,7 +180,7 @@ impl FnCall { /// Lower a local function to a [`CalleeKind`] and [ContextArgs] pair. fn lower_local( env: &mut FuncEnv

, - index: FuncIndex, + index: DefinedFuncIndex, ) -> (CalleeKind, ContextArgs) { ( CalleeKind::direct(env.name_wasm(index)), diff --git a/winch/codegen/src/codegen/env.rs b/winch/codegen/src/codegen/env.rs index b58fb03a6..9f1b5e9ef 100644 --- a/winch/codegen/src/codegen/env.rs +++ b/winch/codegen/src/codegen/env.rs @@ -12,9 +12,9 @@ use std::collections::{ use std::mem; use wasmparser::BlockType; use wasmtime_environ::{ - BuiltinFunctionIndex, FuncIndex, GlobalIndex, IndexType, Memory, MemoryIndex, - ModuleTranslation, ModuleTypesBuilder, PrimaryMap, PtrSize, Table, TableIndex, TypeConvert, - TypeIndex, VMOffsets, WasmHeapType, WasmValType, + BuiltinFunctionIndex, DefinedFuncIndex, FuncIndex, FuncKey, GlobalIndex, IndexType, Memory, + MemoryIndex, ModuleTranslation, ModuleTypesBuilder, PrimaryMap, PtrSize, Table, TableIndex, + TypeConvert, TypeIndex, VMOffsets, WasmHeapType, WasmValType, }; #[derive(Debug, Clone, Copy)] @@ -354,18 +354,16 @@ impl<'a, 'translation, 'data, P: PtrSize> FuncEnv<'a, 'translation, 'data, P> { /// Creates a name to reference the `builtin` provided. pub fn name_builtin(&mut self, builtin: BuiltinFunctionIndex) -> UserExternalNameRef { - self.intern_name(UserExternalName { - namespace: wasmtime_cranelift::NS_WASMTIME_BUILTIN, - index: builtin.index(), - }) + let key = FuncKey::WasmToBuiltinTrampoline(builtin); + let (namespace, index) = key.into_raw_parts(); + self.intern_name(UserExternalName { namespace, index }) } /// Creates a name to reference the wasm function `index` provided. - pub fn name_wasm(&mut self, index: FuncIndex) -> UserExternalNameRef { - self.intern_name(UserExternalName { - namespace: wasmtime_cranelift::NS_WASM_FUNC, - index: index.as_u32(), - }) + pub fn name_wasm(&mut self, def_func: DefinedFuncIndex) -> UserExternalNameRef { + let key = FuncKey::DefinedWasmFunction(self.translation.module_index, def_func); + let (namespace, index) = key.into_raw_parts(); + self.intern_name(UserExternalName { namespace, index }) } /// Interns `name` into a `UserExternalNameRef` and ensures that duplicate