From ef70686be9583ceeca2d704bd38096ee15b8ccee Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Mon, 11 Dec 2023 07:17:16 -0800 Subject: [PATCH 01/14] Include Version in the export name if required (#7656) Signed-off-by: James Sturtevant --- crates/component-macro/tests/codegen/multiversion/root.wit | 1 + crates/wit-bindgen/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/component-macro/tests/codegen/multiversion/root.wit b/crates/component-macro/tests/codegen/multiversion/root.wit index 52225f02beb3..b3bb3c80d3da 100644 --- a/crates/component-macro/tests/codegen/multiversion/root.wit +++ b/crates/component-macro/tests/codegen/multiversion/root.wit @@ -3,5 +3,6 @@ package foo:bar; world foo { import my:dep/a@0.1.0; import my:dep/a@0.2.0; + export my:dep/a@0.1.0; export my:dep/a@0.2.0; } diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs index eca7fd3916cd..2c1422f597e2 100644 --- a/crates/wit-bindgen/src/lib.rs +++ b/crates/wit-bindgen/src/lib.rs @@ -474,7 +474,7 @@ impl Wasmtime { format!( "{}_{}_{snake}", pkgname.namespace.to_snake_case(), - pkgname.name.to_snake_case() + self.name_package_module(resolve, iface.package.unwrap()) ), ), None => (format!("exports::{snake}::{camel}"), snake.clone()), From 2acfb6343540b9ced1b78980006d8f81c4fb1357 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 11 Dec 2023 09:37:22 -0600 Subject: [PATCH 02/14] Update `*_badfd` methods in the adapter to return an errno (#7672) Makes them a bit more consistent with the rest of the WASI functions as opposed to returning a boolean. --- crates/test-programs/src/bin/preview2_adapter_badfd.rs | 8 ++++---- crates/wasi-preview1-component-adapter/src/lib.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/test-programs/src/bin/preview2_adapter_badfd.rs b/crates/test-programs/src/bin/preview2_adapter_badfd.rs index 7baa33717225..e437dd668dcc 100644 --- a/crates/test-programs/src/bin/preview2_adapter_badfd.rs +++ b/crates/test-programs/src/bin/preview2_adapter_badfd.rs @@ -2,15 +2,15 @@ fn main() { #[link(wasm_import_module = "wasi_snapshot_preview1")] extern "C" { #[cfg_attr(target_arch = "wasm32", link_name = "adapter_open_badfd")] - fn adapter_open_badfd(fd: *mut u32) -> bool; + fn adapter_open_badfd(fd: *mut u32) -> wasi::Errno; #[cfg_attr(target_arch = "wasm32", link_name = "adapter_close_badfd")] - fn adapter_close_badfd(fd: u32) -> bool; + fn adapter_close_badfd(fd: u32) -> wasi::Errno; } unsafe { let mut fd = 0; - assert!(adapter_open_badfd(&mut fd)); + assert_eq!(adapter_open_badfd(&mut fd), wasi::ERRNO_SUCCESS); assert_eq!(wasi::fd_close(fd), Err(wasi::ERRNO_BADF)); @@ -41,6 +41,6 @@ fn main() { Err(wasi::ERRNO_BADF) ); - assert!(adapter_close_badfd(fd)); + assert_eq!(adapter_close_badfd(fd), wasi::ERRNO_SUCCESS); } } diff --git a/crates/wasi-preview1-component-adapter/src/lib.rs b/crates/wasi-preview1-component-adapter/src/lib.rs index 59561f3ef150..8ef496d56441 100644 --- a/crates/wasi-preview1-component-adapter/src/lib.rs +++ b/crates/wasi-preview1-component-adapter/src/lib.rs @@ -152,17 +152,17 @@ impl TrappingUnwrap for Result { /// from WASI Preview 1 to Preview 2. It will use this function to reserve /// descriptors for its own use, valid only for use with libc functions. #[no_mangle] -pub unsafe extern "C" fn adapter_open_badfd(fd: *mut u32) -> bool { +pub unsafe extern "C" fn adapter_open_badfd(fd: *mut u32) -> Errno { State::with(|state| { *fd = state.descriptors_mut().open(Descriptor::Bad)?; Ok(()) - }) == wasi::ERRNO_SUCCESS + }) } /// Close a descriptor previously opened using `adapter_open_badfd`. #[no_mangle] -pub unsafe extern "C" fn adapter_close_badfd(fd: u32) -> bool { - State::with(|state| state.descriptors_mut().close(fd)) == wasi::ERRNO_SUCCESS +pub unsafe extern "C" fn adapter_close_badfd(fd: u32) -> Errno { + State::with(|state| state.descriptors_mut().close(fd)) } #[no_mangle] From e6da2f6fb2d81412909c6f621c9946dd2744d843 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Mon, 11 Dec 2023 15:18:59 -0800 Subject: [PATCH 03/14] Remove unnecessary macro argument (#7673) The `$raw:ident` in this macro was unused as far as I could tell; this change removes it. --- crates/wasmtime/src/func/typed.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/wasmtime/src/func/typed.rs b/crates/wasmtime/src/func/typed.rs index f1188faad4aa..e88eb23e769e 100644 --- a/crates/wasmtime/src/func/typed.rs +++ b/crates/wasmtime/src/func/typed.rs @@ -239,7 +239,7 @@ pub unsafe trait WasmTy: Send { } macro_rules! integers { - ($($primitive:ident/$get_primitive:ident => $ty:ident in $raw:ident)*) => ($( + ($($primitive:ident/$get_primitive:ident => $ty:ident)*) => ($( unsafe impl WasmTy for $primitive { type Abi = $primitive; #[inline] @@ -275,10 +275,10 @@ macro_rules! integers { } integers! { - i32/get_i32 => I32 in i32 - i64/get_i64 => I64 in i64 - u32/get_u32 => I32 in i32 - u64/get_u64 => I64 in i64 + i32/get_i32 => I32 + i64/get_i64 => I64 + u32/get_u32 => I32 + u64/get_u64 => I64 } macro_rules! floats { From 849b2fca96bb97d164b204d60cbf1ba5ebbb5919 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 12 Dec 2023 22:18:20 +0700 Subject: [PATCH 04/14] ci: Update to `actions/checkout@v4` from `v3`. (#7674) This mainly updates to use Node 20 rather than Node 16 internally. --- .github/workflows/cargo-audit.yml | 2 +- .github/workflows/main.yml | 36 +++++++++++------------ .github/workflows/performance.yml | 4 +-- .github/workflows/publish-artifacts.yml | 2 +- .github/workflows/publish-to-cratesio.yml | 2 +- .github/workflows/release-process.yml | 2 +- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/workflows/cargo-audit.yml b/.github/workflows/cargo-audit.yml index d17cc3674230..0f4b3bcb80ac 100644 --- a/.github/workflows/cargo-audit.yml +++ b/.github/workflows/cargo-audit.yml @@ -7,7 +7,7 @@ jobs: if: github.repository == 'bytecodealliance/wasmtime' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - uses: actions-rs/audit-check@v1 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b4cb5cfd7d80..7306556abf68 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -42,7 +42,7 @@ jobs: name: Rustfmt runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust @@ -60,7 +60,7 @@ jobs: name: Clang format runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - run: git ls-files '*.h' '*.c' '*.cpp' | xargs clang-format-15 --dry-run --Werror --verbose @@ -79,7 +79,7 @@ jobs: if: needs.determine.outputs.audit runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust @@ -103,7 +103,7 @@ jobs: if: needs.determine.outputs.audit runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust @@ -138,7 +138,7 @@ jobs: audit: ${{ steps.calculate.outputs.audit }} preview1-adapter: ${{ steps.calculate.outputs.preview1-adapter }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - id: calculate env: GH_TOKEN: ${{ github.token }} @@ -202,7 +202,7 @@ jobs: RUSTDOCFLAGS: -Dbroken_intra_doc_links --cfg nightlydoc OPENVINO_SKIP_LINKING: 1 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust @@ -269,7 +269,7 @@ jobs: env: CARGO_NDK_VERSION: 2.12.2 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust @@ -351,7 +351,7 @@ jobs: name: Check Windows ARM64 runs-on: windows-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust @@ -371,7 +371,7 @@ jobs: name: Fuzz Targets runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true # Note that building with fuzzers requires nightly since it uses unstable @@ -410,7 +410,7 @@ jobs: fail-fast: ${{ github.event_name != 'pull_request' }} matrix: ${{ fromJson(needs.determine.outputs.test-matrix) }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust @@ -529,7 +529,7 @@ jobs: name: Test wasi-nn module runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust @@ -557,7 +557,7 @@ jobs: deployments: write contents: write steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - run: rustup update stable && rustup default stable @@ -591,7 +591,7 @@ jobs: name: Run benchmarks runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust @@ -611,7 +611,7 @@ jobs: name: Meta deterministic check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust @@ -629,7 +629,7 @@ jobs: if: github.repository == 'bytecodealliance/wasmtime' && needs.determine.outputs.run-full runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - run: rustup update stable && rustup default stable @@ -667,7 +667,7 @@ jobs: env: CARGO_NEXTEST_VERSION: 0.9.51 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/actions/install-rust @@ -709,7 +709,7 @@ jobs: fail-fast: ${{ github.event_name != 'pull_request' }} matrix: ${{ fromJson(needs.determine.outputs.build-matrix) }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true @@ -824,7 +824,7 @@ jobs: && startsWith(github.ref, 'refs/heads/release-') && github.repository == 'bytecodealliance/wasmtime' steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true fetch-depth: 0 diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index 0b39524a70f6..f3544251cbfd 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -74,7 +74,7 @@ jobs: cargo build --release - name: Checkout patch from bytecodealliance/wasmtime (pushed and triggering on this perf repo) - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: true path: wasmtime_commit @@ -89,7 +89,7 @@ jobs: cp target/release/libwasmtime_bench_api.so /tmp/wasmtime_commit.so - name: Checkout main from bytecodealliance/wasmtime - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: 'main' repository: 'bytecodealliance/wasmtime' diff --git a/.github/workflows/publish-artifacts.yml b/.github/workflows/publish-artifacts.yml index 8c149003dc91..191d0cc4fd21 100644 --- a/.github/workflows/publish-artifacts.yml +++ b/.github/workflows/publish-artifacts.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest if: github.repository == 'bytecodealliance/wasmtime' steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: | sha=${{ github.sha }} run_id=$( diff --git a/.github/workflows/publish-to-cratesio.yml b/.github/workflows/publish-to-cratesio.yml index 6d05b66778a4..23af15a85785 100644 --- a/.github/workflows/publish-to-cratesio.yml +++ b/.github/workflows/publish-to-cratesio.yml @@ -14,7 +14,7 @@ jobs: if: github.repository == 'bytecodealliance/wasmtime' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - run: rustup update stable && rustup default stable diff --git a/.github/workflows/release-process.yml b/.github/workflows/release-process.yml index e2003a456d92..004c00f85ce3 100644 --- a/.github/workflows/release-process.yml +++ b/.github/workflows/release-process.yml @@ -38,7 +38,7 @@ jobs: name: Run the release process runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - name: Setup From 6bb3e5bf43464c72e866613d2038ce282cd9b069 Mon Sep 17 00:00:00 2001 From: Feilong Jiang Date: Wed, 13 Dec 2023 03:37:17 +0800 Subject: [PATCH 05/14] PCC: Fix several aarch64 check_constant failures (#7593) * PCC: Fix several aarch64 check_constant failures This patch fixes several aarch64 check_constant failures: 1. `check_subsume` for `AluRRImmLogic` failed due to the mismatch of fact width isle rule for `orr_imm` always generates fact with bit_width 64 regardless of immediate type. So when Type is I32, `check_subsume` will be failed. 2. `MovN` generates incorrect fact range value when `first_is_inverted` is true `running_value` should be calculated as !(((!imm16) & 0xffff) << shift) or !(u64::from(imm.bits) << shift) Added two test cases in cranelift/filetests/filetests/pcc/succeed/const.clif. Additional fix for `get_fact_or_default`: `trace!` treats `reg` as VirtualReg and it will panic when "reg" is RealReg and `trace-log` feature is enabled. * simplify get_fact_or_default Co-authored-by: Nick Fitzgerald * fix missing comma --------- Co-authored-by: Nick Fitzgerald --- cranelift/codegen/src/isa/aarch64/inst.isle | 6 +++++- cranelift/codegen/src/isa/aarch64/lower/isle.rs | 10 +++++++++- cranelift/codegen/src/machinst/pcc.rs | 3 +-- cranelift/filetests/filetests/pcc/succeed/const.clif | 12 ++++++++++++ 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/cranelift/codegen/src/isa/aarch64/inst.isle b/cranelift/codegen/src/isa/aarch64/inst.isle index 2d9309dd5734..15112a585763 100644 --- a/cranelift/codegen/src/isa/aarch64/inst.isle +++ b/cranelift/codegen/src/isa/aarch64/inst.isle @@ -1709,6 +1709,9 @@ (decl pure partial imm_logic_from_u64 (Type u64) ImmLogic) (extern constructor imm_logic_from_u64 imm_logic_from_u64) +(decl pure partial imm_size_from_type (Type) u16) +(extern constructor imm_size_from_type imm_size_from_type) + (decl pure partial imm_logic_from_imm64 (Type Imm64) ImmLogic) (extern constructor imm_logic_from_imm64 imm_logic_from_imm64) @@ -2938,9 +2941,10 @@ ;; we only match when we are zero-extending the value. (rule 1 (imm (integral_ty ty) (ImmExtend.Zero) k) (if-let n (imm_logic_from_u64 ty k)) + (if-let m (imm_size_from_type ty)) (add_range_fact (orr_imm ty (zero_reg) n) - 64 k k)) + m k k)) (decl load_constant64_full (Type ImmExtend u64) Reg) (extern constructor load_constant64_full load_constant64_full) diff --git a/cranelift/codegen/src/isa/aarch64/lower/isle.rs b/cranelift/codegen/src/isa/aarch64/lower/isle.rs index a70e895fbd28..91ea3a73594b 100644 --- a/cranelift/codegen/src/isa/aarch64/lower/isle.rs +++ b/cranelift/codegen/src/isa/aarch64/lower/isle.rs @@ -174,6 +174,14 @@ impl Context for IsleContext<'_, '_, MInst, AArch64Backend> { ImmLogic::maybe_from_u64(n, ty) } + fn imm_size_from_type(&mut self, ty: Type) -> Option { + match ty { + I32 => Some(32), + I64 => Some(64), + _ => None, + } + } + fn imm_logic_from_imm64(&mut self, ty: Type, n: Imm64) -> Option { let ty = if ty.bits() < 32 { I32 } else { ty }; self.imm_logic_from_u64(ty, n.bits() as u64) @@ -395,7 +403,7 @@ impl Context for IsleContext<'_, '_, MInst, AArch64Backend> { size, }); if pcc { - running_value = !(imm16 << shift); + running_value = !(u64::from(imm.bits) << shift); self.lower_ctx.add_range_fact( rd.to_reg(), 64, diff --git a/cranelift/codegen/src/machinst/pcc.rs b/cranelift/codegen/src/machinst/pcc.rs index db1bf3256533..d737d83dacc3 100644 --- a/cranelift/codegen/src/machinst/pcc.rs +++ b/cranelift/codegen/src/machinst/pcc.rs @@ -6,8 +6,7 @@ use crate::trace; pub(crate) fn get_fact_or_default(vcode: &VCode, reg: Reg, width: u16) -> Fact { trace!( - "get_fact_or_default: reg v{} -> {:?}", - reg.to_virtual_reg().unwrap().index(), + "get_fact_or_default: reg {reg:?} -> {:?}", vcode.vreg_fact(reg.into()) ); vcode diff --git a/cranelift/filetests/filetests/pcc/succeed/const.clif b/cranelift/filetests/filetests/pcc/succeed/const.clif index da0c8a08655c..d0c381c5c0ac 100644 --- a/cranelift/filetests/filetests/pcc/succeed/const.clif +++ b/cranelift/filetests/filetests/pcc/succeed/const.clif @@ -16,3 +16,15 @@ block0: v8 ! range(64, 0xffff_0000_0000_ffff, 0xffff_0000_0000_ffff) = iconst.i64 0xffff_0000_0000_ffff return } + +function %f1() -> i32 { +block0: + v0 = iconst.i32 0x10_0010 + return v0 +} + +function %f2() -> i64 { +block0: + v0 = iconst.i64 0x9_ffff_ffff + return v0 +} From 2a367f4e045623db918b3f2538f089653490ef12 Mon Sep 17 00:00:00 2001 From: scottmcm Date: Tue, 12 Dec 2023 11:57:14 -0800 Subject: [PATCH 06/14] Cranelift: Add iconst shorthand to simplify ISLE opts (#7670) * Demote `simm32` and `uimm8` to lowering ISLE only There seems to be nothing in opt ISLE that actually wanted them, just something that's more consistently done with using a 64-bit type to read from an Imm64. And `simm32` feels like it's probably wrong to me -- `simm32` can't actually match `-1_i32` -- but I'm not confident enough in my analysis to actually change it. * Cranelift: Add iconst shorthand to simplify ISLE opts * Do a manually un-currying to avoid duplicating loading the `InstructionData` * rustfmt is my nemesis --- cranelift/codegen/src/isle_prelude.rs | 12 -- cranelift/codegen/src/machinst/isle.rs | 12 ++ cranelift/codegen/src/opts.rs | 24 ++++ cranelift/codegen/src/opts/arithmetic.isle | 28 ++-- cranelift/codegen/src/opts/bitops.isle | 64 ++++----- cranelift/codegen/src/opts/extends.isle | 20 +-- cranelift/codegen/src/opts/icmp.isle | 82 ++++++----- cranelift/codegen/src/opts/selects.isle | 8 +- cranelift/codegen/src/opts/shifts.isle | 20 +-- cranelift/codegen/src/opts/spaceship.isle | 160 +++++++++------------ cranelift/codegen/src/prelude.isle | 8 -- cranelift/codegen/src/prelude_lower.isle | 12 ++ cranelift/codegen/src/prelude_opt.isle | 44 ++++-- 13 files changed, 260 insertions(+), 234 deletions(-) diff --git a/cranelift/codegen/src/isle_prelude.rs b/cranelift/codegen/src/isle_prelude.rs index a2ee1563f7a4..0ad5bfa824d3 100644 --- a/cranelift/codegen/src/isle_prelude.rs +++ b/cranelift/codegen/src/isle_prelude.rs @@ -734,18 +734,6 @@ macro_rules! isle_common_prelude_methods { Imm64::new((x & self.ty_mask(ty)) as i64) } - #[inline] - fn simm32(&mut self, x: Imm64) -> Option { - i64::from(x).try_into().ok() - } - - #[inline] - fn uimm8(&mut self, x: Imm64) -> Option { - let x64: i64 = x.into(); - let x8: u8 = x64.try_into().ok()?; - Some(x8) - } - #[inline] fn offset32(&mut self, x: Offset32) -> i32 { x.into() diff --git a/cranelift/codegen/src/machinst/isle.rs b/cranelift/codegen/src/machinst/isle.rs index 7add8208eff1..6967aa9bce82 100644 --- a/cranelift/codegen/src/machinst/isle.rs +++ b/cranelift/codegen/src/machinst/isle.rs @@ -562,6 +562,18 @@ macro_rules! isle_lower_prelude_methods { Some(value) } + #[inline] + fn simm32(&mut self, x: Imm64) -> Option { + i64::from(x).try_into().ok() + } + + #[inline] + fn uimm8(&mut self, x: Imm64) -> Option { + let x64: i64 = x.into(); + let x8: u8 = x64.try_into().ok()?; + Some(x8) + } + #[inline] fn preg_to_reg(&mut self, preg: PReg) -> Reg { preg.into() diff --git a/cranelift/codegen/src/opts.rs b/cranelift/codegen/src/opts.rs index 3ec3e116593c..8796b62e1094 100644 --- a/cranelift/codegen/src/opts.rs +++ b/cranelift/codegen/src/opts.rs @@ -27,6 +27,8 @@ const MAX_ISLE_RETURNS: usize = 8; pub type ConstructorVec = SmallVec<[T; MAX_ISLE_RETURNS]>; +type TypeAndInstructionData = (Type, InstructionData); + impl generated_code::Length for SmallVec { #[inline] fn len(&self) -> usize { @@ -128,6 +130,13 @@ impl<'a, 'b, 'c> generated_code::Context for IsleContext<'a, 'b, 'c> { *returns = InstDataEtorIter::new(eclass); } + type inst_data_tupled_etor_returns = InstDataEtorIter<'a, 'b, 'c>; + + fn inst_data_tupled_etor(&mut self, eclass: Value, returns: &mut InstDataEtorIter<'a, 'b, 'c>) { + // Literally identical to `inst_data_etor`, just a different nominal type in ISLE + self.inst_data_etor(eclass, returns); + } + fn make_inst_ctor(&mut self, ty: Type, op: &InstructionData) -> Value { let value = self .ctx @@ -149,6 +158,21 @@ impl<'a, 'b, 'c> generated_code::Context for IsleContext<'a, 'b, 'c> { self.ctx.func.dfg.value_type(val) } + fn iconst_sextend_etor( + &mut self, + (ty, inst_data): (Type, InstructionData), + ) -> Option<(Type, i64)> { + if let InstructionData::UnaryImm { + opcode: Opcode::Iconst, + imm, + } = inst_data + { + Some((ty, self.i64_sextend_imm64(ty, imm))) + } else { + None + } + } + fn remat(&mut self, value: Value) -> Value { trace!("remat: {}", value); self.ctx.remat_values.insert(value); diff --git a/cranelift/codegen/src/opts/arithmetic.isle b/cranelift/codegen/src/opts/arithmetic.isle index 3ac4381a92fd..5ed3669e7745 100644 --- a/cranelift/codegen/src/opts/arithmetic.isle +++ b/cranelift/codegen/src/opts/arithmetic.isle @@ -7,16 +7,16 @@ ;; x+0 == x. (rule (simplify (iadd ty x - (iconst ty (u64_from_imm64 0)))) + (iconst_u ty 0))) (subsume x)) ;; x-0 == x. (rule (simplify (isub ty x - (iconst ty (u64_from_imm64 0)))) + (iconst_u ty 0))) (subsume x)) ;; 0-x == (ineg x). (rule (simplify (isub ty - (iconst ty (u64_from_imm64 0)) + (iconst_u ty 0) x)) (ineg ty x)) @@ -47,51 +47,49 @@ (subsume inner)) ;; x-x == 0. -(rule (simplify (isub (fits_in_64 (ty_int ty)) x x)) (subsume (iconst ty (imm64 0)))) +(rule (simplify (isub (fits_in_64 (ty_int ty)) x x)) (subsume (iconst_u ty 0))) ;; x*1 == x. (rule (simplify (imul ty x - (iconst ty (u64_from_imm64 1)))) + (iconst_u ty 1))) (subsume x)) ;; x*0 == 0. (rule (simplify (imul ty _ - zero @ (iconst ty (u64_from_imm64 0)))) + zero @ (iconst_u ty 0))) (subsume zero)) ;; x*-1 == ineg(x). -(rule (simplify (imul ty x (iconst ty c))) - (if-let -1 (i64_sextend_imm64 ty c)) +(rule (simplify (imul ty x (iconst_s ty -1))) (ineg ty x)) ;; (!x) + 1 == ineg(x) -(rule (simplify (iadd ty (bnot ty x) (iconst ty (u64_from_imm64 1)))) +(rule (simplify (iadd ty (bnot ty x) (iconst_u ty 1))) (ineg ty x)) ;; !(x - 1) == !(x + (-1)) == ineg(x) -(rule (simplify (bnot ty (isub ty x (iconst ty (u64_from_imm64 1))))) +(rule (simplify (bnot ty (isub ty x (iconst_s ty 1)))) (ineg ty x)) -(rule (simplify (bnot ty (iadd ty x (iconst ty c)))) - (if-let -1 (i64_sextend_imm64 ty c)) +(rule (simplify (bnot ty (iadd ty x (iconst_s ty -1)))) (ineg ty x)) ;; x/1 == x. (rule (simplify (sdiv ty x - (iconst ty (u64_from_imm64 1)))) + (iconst_u ty 1))) (subsume x)) (rule (simplify (udiv ty x - (iconst ty (u64_from_imm64 1)))) + (iconst_u ty 1))) (subsume x)) ;; TODO: strength reduction: div to shifts ;; TODO: div/rem by constants -> magic multiplications ;; x*2 == x+x. -(rule (simplify (imul ty x (iconst _ (simm32 2)))) +(rule (simplify (imul ty x (iconst_u _ 2))) (iadd ty x x)) ;; x*c == x< uextend(icmp(x, y)) (rule (simplify (select ty cmp@(icmp _ cc x y) - (iconst _ (u64_from_imm64 1)) - (iconst _ (u64_from_imm64 0)))) + (iconst_u _ 1) + (iconst_u _ 0))) (uextend_from_i8 ty cmp)) ;; if icmp(x, y) { 0 } else { 1 } => uextend(!icmp(x, y)) (rule (simplify (select sty (icmp cty cc x y) - (iconst _ (u64_from_imm64 0)) - (iconst _ (u64_from_imm64 1)))) + (iconst_u _ 0) + (iconst_u _ 1))) (uextend_from_i8 sty (icmp cty (intcc_complement cc) x y))) ;; Transform select-of-icmp into {u,s}{min,max} instructions where possible. diff --git a/cranelift/codegen/src/opts/shifts.isle b/cranelift/codegen/src/opts/shifts.isle index 272c5c90bf65..0849d541ecb4 100644 --- a/cranelift/codegen/src/opts/shifts.isle +++ b/cranelift/codegen/src/opts/shifts.isle @@ -3,23 +3,23 @@ ;; x>>0 == x<<0 == x rotr 0 == x rotl 0 == x. (rule (simplify (ishl ty x - (iconst ty (u64_from_imm64 0)))) + (iconst_u ty 0))) (subsume x)) (rule (simplify (ushr ty x - (iconst ty (u64_from_imm64 0)))) + (iconst_u ty 0))) (subsume x)) (rule (simplify (sshr ty x - (iconst ty (u64_from_imm64 0)))) + (iconst_u ty 0))) (subsume x)) (rule (simplify (rotr ty x - (iconst ty (u64_from_imm64 0)))) + (iconst_u ty 0))) (subsume x)) (rule (simplify (rotl ty x - (iconst ty (u64_from_imm64 0)))) + (iconst_u ty 0))) (subsume x)) ;; `(x >> k) << k` is the same as masking off the bottom `k` bits (regardless if @@ -159,7 +159,7 @@ (u64_and k1 (ty_shift_mask ty)) (u64_and k2 (ty_shift_mask ty)))) (if-let $true (u64_lt shift_amt (ty_bits_u64 (lane_type ty)))) - (ishl ty x (iconst_u64 kty shift_amt))) + (ishl ty x (iconst_u kty shift_amt))) (rule (simplify (ushr ty (ushr ty x (iconst kty (u64_from_imm64 k1))) @@ -168,7 +168,7 @@ (u64_and k1 (ty_shift_mask ty)) (u64_and k2 (ty_shift_mask ty)))) (if-let $true (u64_lt shift_amt (ty_bits_u64 (lane_type ty)))) - (ushr ty x (iconst_u64 kty shift_amt))) + (ushr ty x (iconst_u kty shift_amt))) (rule (simplify (sshr ty (sshr ty x (iconst kty (u64_from_imm64 k1))) @@ -177,7 +177,7 @@ (u64_and k1 (ty_shift_mask ty)) (u64_and k2 (ty_shift_mask ty)))) (if-let $true (u64_lt shift_amt (ty_bits_u64 (lane_type ty)))) - (sshr ty x (iconst_u64 kty shift_amt))) + (sshr ty x (iconst_u kty shift_amt))) ;; Simliarly, if the shift amount overflows the type, then we can turn ;; it into a 0 @@ -191,7 +191,7 @@ (u64_and k1 (ty_shift_mask ty)) (u64_and k2 (ty_shift_mask ty)))) (if-let $true (u64_le (ty_bits_u64 ty) shift_amt)) - (subsume (iconst_u64 ty 0))) + (subsume (iconst_u ty 0))) (rule (simplify (ushr ty (ushr ty x (iconst _ (u64_from_imm64 k1))) @@ -200,7 +200,7 @@ (u64_and k1 (ty_shift_mask ty)) (u64_and k2 (ty_shift_mask ty)))) (if-let $true (u64_le (ty_bits_u64 ty) shift_amt)) - (subsume (iconst_u64 ty 0))) + (subsume (iconst_u ty 0))) ;; (rotl (rotr x y) y) == x ;; (rotr (rotl x y) y) == x diff --git a/cranelift/codegen/src/opts/spaceship.isle b/cranelift/codegen/src/opts/spaceship.isle index 809274317332..d7d2071528d6 100644 --- a/cranelift/codegen/src/opts/spaceship.isle +++ b/cranelift/codegen/src/opts/spaceship.isle @@ -11,92 +11,80 @@ ;; x < y ? -1 : x == y ? 0 : +1 ;; x < y ? -1 : x != y ? +1 : 0 (rule (simplify (select ty (ult rty x y) - (iconst ty neg_1) + (iconst_s ty -1) (ne rty x y))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) (sextend_from_i8 ty (spaceship_u rty x y))) (rule (simplify (select ty (ult rty x y) - (iconst ty neg_1) + (iconst_s ty -1) (uextend ty (ne rty x y)))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) (sextend_from_i8 ty (spaceship_u rty x y))) ;; x < y ? -1 : x <= y ? 0 : +1 ;; x < y ? -1 : x > y ? +1 : 0 (rule (simplify (select ty (ult rty x y) - (iconst ty neg_1) + (iconst_s ty -1) (ugt rty x y))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) (sextend_from_i8 ty (spaceship_u rty x y))) (rule (simplify (select ty (ult rty x y) - (iconst ty neg_1) + (iconst_s ty -1) (uextend ty (ugt rty x y)))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) (sextend_from_i8 ty (spaceship_u rty x y))) ;; x == y ? 0 : x < y ? -1 : +1 (rule (simplify (select ty (eq rty x y) - (iconst ty (u64_from_imm64 0)) + (iconst_s ty 0) (select ty (ult rty x y) - (iconst ty neg_1) - (iconst ty (u64_from_imm64 1))))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) + (iconst_s ty -1) + (iconst_s ty 1)))) (sextend_from_i8 ty (spaceship_u rty x y))) ;; x == y ? 0 : x <= y ? -1 : +1 (rule (simplify (select ty (eq rty x y) - (iconst ty (u64_from_imm64 0)) + (iconst_s ty 0) (select ty (ule rty x y) - (iconst ty neg_1) - (iconst ty (u64_from_imm64 1))))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) + (iconst_s ty -1) + (iconst_s ty 1)))) (sextend_from_i8 ty (spaceship_u rty x y))) ;; x == y ? 0 : x > y ? +1 : -1 (rule (simplify (select ty (eq rty x y) - (iconst ty (u64_from_imm64 0)) + (iconst_s ty 0) (select ty (ugt rty x y) - (iconst ty (u64_from_imm64 1)) - (iconst ty neg_1)))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) + (iconst_s ty 1) + (iconst_s ty -1)))) (sextend_from_i8 ty (spaceship_u rty x y))) ;; x == y ? 0 : x >= y ? +1 : -1 (rule (simplify (select ty (eq rty x y) - (iconst ty (u64_from_imm64 0)) + (iconst_s ty 0) (select ty (uge rty x y) - (iconst ty (u64_from_imm64 1)) - (iconst ty neg_1)))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) + (iconst_s ty 1) + (iconst_s ty -1)))) (sextend_from_i8 ty (spaceship_u rty x y))) ;; x > y ? 1 : x < y ? -1 : 0 (rule (simplify (select ty (ugt rty x y) - (iconst ty (u64_from_imm64 1)) + (iconst_s ty 1) (select ty (ult rty x y) - (iconst ty neg_1) - (iconst ty (u64_from_imm64 0))))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) + (iconst_s ty -1) + (iconst_s ty 0)))) (sextend_from_i8 ty (spaceship_u rty x y))) ;; x > y ? 1 : x != y ? -1 : 0 (rule (simplify (select ty (ugt rty x y) - (iconst ty (u64_from_imm64 1)) + (iconst_s ty 1) (select ty (ne rty x y) - (iconst ty neg_1) - (iconst ty (u64_from_imm64 0))))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) + (iconst_s ty -1) + (iconst_s ty 0)))) (sextend_from_i8 ty (spaceship_u rty x y))) ;; x > y ? 1 : x == y ? 0 : -1 (rule (simplify (select ty (ugt rty x y) - (iconst ty (u64_from_imm64 1)) + (iconst_s ty 1) (select ty (eq rty x y) - (iconst ty (u64_from_imm64 0)) - (iconst ty neg_1)))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) + (iconst_s ty 0) + (iconst_s ty -1)))) (sextend_from_i8 ty (spaceship_u rty x y))) ;; x > y ? 1 : x >= y ? 0 : -1 (rule (simplify (select ty (ugt rty x y) - (iconst ty (u64_from_imm64 1)) + (iconst_s ty 1) (select ty (uge rty x y) - (iconst ty (u64_from_imm64 0)) - (iconst ty neg_1)))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) + (iconst_s ty 0) + (iconst_s ty -1)))) (sextend_from_i8 ty (spaceship_u rty x y))) ;; Same, but for signed comparisons this time @@ -104,92 +92,80 @@ ;; x < y ? -1 : x == y ? 0 : +1 ;; x < y ? -1 : x != y ? +1 : 0 (rule (simplify (select ty (slt rty x y) - (iconst ty neg_1) + (iconst_s ty -1) (ne rty x y))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) (spaceship_s rty x y)) (rule (simplify (select ty (slt rty x y) - (iconst ty neg_1) + (iconst_s ty -1) (uextend ty (ne rty x y)))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) (sextend_from_i8 ty (spaceship_s rty x y))) ;; x < y ? -1 : x <= y ? 0 : +1 ;; x < y ? -1 : x > y ? +1 : 0 (rule (simplify (select ty (slt rty x y) - (iconst ty neg_1) + (iconst_s ty -1) (sgt rty x y))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) (spaceship_s rty x y)) (rule (simplify (select ty (slt rty x y) - (iconst ty neg_1) + (iconst_s ty -1) (uextend ty (sgt rty x y)))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) (sextend_from_i8 ty (spaceship_s rty x y))) ;; x == y ? 0 : x < y ? -1 : +1 (rule (simplify (select ty (eq rty x y) - (iconst ty (u64_from_imm64 0)) + (iconst_s ty 0) (select ty (slt rty x y) - (iconst ty neg_1) - (iconst ty (u64_from_imm64 1))))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) + (iconst_s ty -1) + (iconst_s ty 1)))) (sextend_from_i8 ty (spaceship_s rty x y))) ;; x == y ? 0 : x <= y ? -1 : +1 (rule (simplify (select ty (eq rty x y) - (iconst ty (u64_from_imm64 0)) + (iconst_s ty 0) (select ty (sle rty x y) - (iconst ty neg_1) - (iconst ty (u64_from_imm64 1))))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) + (iconst_s ty -1) + (iconst_s ty 1)))) (sextend_from_i8 ty (spaceship_s rty x y))) ;; x == y ? 0 : x > y ? +1 : -1 (rule (simplify (select ty (eq rty x y) - (iconst ty (u64_from_imm64 0)) + (iconst_s ty 0) (select ty (sgt rty x y) - (iconst ty (u64_from_imm64 1)) - (iconst ty neg_1)))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) + (iconst_s ty 1) + (iconst_s ty -1)))) (sextend_from_i8 ty (spaceship_s rty x y))) ;; x == y ? 0 : x >= y ? +1 : -1 (rule (simplify (select ty (eq rty x y) - (iconst ty (u64_from_imm64 0)) + (iconst_s ty 0) (select ty (sge rty x y) - (iconst ty (u64_from_imm64 1)) - (iconst ty neg_1)))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) + (iconst_s ty 1) + (iconst_s ty -1)))) (sextend_from_i8 ty (spaceship_s rty x y))) ;; x > y ? 1 : x < y ? -1 : 0 (rule (simplify (select ty (sgt rty x y) - (iconst ty (u64_from_imm64 1)) + (iconst_s ty 1) (select ty (slt rty x y) - (iconst ty neg_1) - (iconst ty (u64_from_imm64 0))))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) + (iconst_s ty -1) + (iconst_s ty 0)))) (sextend_from_i8 ty (spaceship_s rty x y))) ;; x > y ? 1 : x != y ? -1 : 0 (rule (simplify (select ty (sgt rty x y) - (iconst ty (u64_from_imm64 1)) + (iconst_s ty 1) (select ty (ne rty x y) - (iconst ty neg_1) - (iconst ty (u64_from_imm64 0))))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) + (iconst_s ty -1) + (iconst_s ty 0)))) (sextend_from_i8 ty (spaceship_s rty x y))) ;; x > y ? 1 : x == y ? 0 : -1 (rule (simplify (select ty (sgt rty x y) - (iconst ty (u64_from_imm64 1)) + (iconst_s ty 1) (select ty (eq rty x y) - (iconst ty (u64_from_imm64 0)) - (iconst ty neg_1)))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) + (iconst_s ty 0) + (iconst_s ty -1)))) (sextend_from_i8 ty (spaceship_s rty x y))) ;; x > y ? 1 : x >= y ? 0 : -1 (rule (simplify (select ty (sgt rty x y) - (iconst ty (u64_from_imm64 1)) + (iconst_s ty 1) (select ty (sge rty x y) - (iconst ty (u64_from_imm64 0)) - (iconst ty neg_1)))) - (if-let -1 (i64_sextend_imm64 ty neg_1)) + (iconst_s ty 0) + (iconst_s ty -1)))) (sextend_from_i8 ty (spaceship_s rty x y))) ;; Then once we have it normalized, we can apply some basic simplifications. @@ -199,35 +175,35 @@ ;; also matching things like `(a <=> b) < 1` or `(a <=> b) <= -1`. ;; (a <=> b) == 0 --> a == b -(rule (simplify (eq _ (spaceship_s ty x y) (iconst _ (u64_from_imm64 0)))) +(rule (simplify (eq _ (spaceship_s ty x y) (iconst_s _ 0))) (eq ty x y)) -(rule (simplify (eq _ (spaceship_u ty x y) (iconst _ (u64_from_imm64 0)))) +(rule (simplify (eq _ (spaceship_u ty x y) (iconst_s _ 0))) (eq ty x y)) ;; (a <=> b) != 0 --> a != b -(rule (simplify (ne _ (spaceship_s ty x y) (iconst _ (u64_from_imm64 0)))) +(rule (simplify (ne _ (spaceship_s ty x y) (iconst_s _ 0))) (ne ty x y)) -(rule (simplify (ne _ (spaceship_u ty x y) (iconst _ (u64_from_imm64 0)))) +(rule (simplify (ne _ (spaceship_u ty x y) (iconst_s _ 0))) (ne ty x y)) ;; (a <=> b) < 0 --> a < b -(rule (simplify (slt _ (spaceship_s ty x y) (iconst _ (u64_from_imm64 0)))) +(rule (simplify (slt _ (spaceship_s ty x y) (iconst_s _ 0))) (slt ty x y)) -(rule (simplify (slt _ (spaceship_u ty x y) (iconst _ (u64_from_imm64 0)))) +(rule (simplify (slt _ (spaceship_u ty x y) (iconst_s _ 0))) (ult ty x y)) ;; (a <=> b) <= 0 --> a <= b -(rule (simplify (sle _ (spaceship_s ty x y) (iconst _ (u64_from_imm64 0)))) +(rule (simplify (sle _ (spaceship_s ty x y) (iconst_s _ 0))) (sle ty x y)) -(rule (simplify (sle _ (spaceship_u ty x y) (iconst _ (u64_from_imm64 0)))) +(rule (simplify (sle _ (spaceship_u ty x y) (iconst_s _ 0))) (ule ty x y)) ;; (a <=> b) > 0 --> a > b -(rule (simplify (sgt _ (spaceship_s ty x y) (iconst _ (u64_from_imm64 0)))) +(rule (simplify (sgt _ (spaceship_s ty x y) (iconst_s _ 0))) (sgt ty x y)) -(rule (simplify (sgt _ (spaceship_u ty x y) (iconst _ (u64_from_imm64 0)))) +(rule (simplify (sgt _ (spaceship_u ty x y) (iconst_s _ 0))) (ugt ty x y)) ;; (a <=> b) >= 0 --> a >= b -(rule (simplify (sge _ (spaceship_s ty x y) (iconst _ (u64_from_imm64 0)))) +(rule (simplify (sge _ (spaceship_s ty x y) (iconst_s _ 0))) (sge ty x y)) -(rule (simplify (sge _ (spaceship_u ty x y) (iconst _ (u64_from_imm64 0)))) +(rule (simplify (sge _ (spaceship_u ty x y) (iconst_s _ 0))) (uge ty x y)) ;; extend from i8 to i8 is invalid CLIF, so this allows fixing that in the output diff --git a/cranelift/codegen/src/prelude.isle b/cranelift/codegen/src/prelude.isle index c4416a4f9bca..ed625559fe63 100644 --- a/cranelift/codegen/src/prelude.isle +++ b/cranelift/codegen/src/prelude.isle @@ -67,14 +67,6 @@ (decl pure partial u8_lt (u8 u8) Unit) (extern constructor u8_lt u8_lt) -;; Get a signed 32-bit immediate in an u32 from an Imm64, if possible. -(decl simm32 (i32) Imm64) -(extern extractor simm32 simm32) - -;; Get an unsigned 8-bit immediate in a u8 from an Imm64, if possible. -(decl uimm8 (u8) Imm64) -(extern extractor uimm8 uimm8) - ;;;; Primitive Type Conversions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (decl pure u8_as_i8 (u8) i8) diff --git a/cranelift/codegen/src/prelude_lower.isle b/cranelift/codegen/src/prelude_lower.isle index d90286e88a6f..54851de654ad 100644 --- a/cranelift/codegen/src/prelude_lower.isle +++ b/cranelift/codegen/src/prelude_lower.isle @@ -302,6 +302,18 @@ (decl maybe_uextend (Value) Value) (extern extractor maybe_uextend maybe_uextend) +;; Get a signed 32-bit immediate in an u32 from an Imm64, if possible. +;; Note that this checks that the raw i64 value from the Imm64 fits in i32, +;; so `-1_u32` will not actually match -- it's treated as `0xFFFF_FFFF_i64`, +;; which doesn't fit in an i32 and thus doesn't match the extractor. +;; An Imm64 of `-1_i64` *will* match, however. +(decl simm32 (i32) Imm64) +(extern extractor simm32 simm32) + +;; Get an unsigned 8-bit immediate in a u8 from an Imm64, if possible. +(decl uimm8 (u8) Imm64) +(extern extractor uimm8 uimm8) + ;; Instruction creation helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Emit an instruction. diff --git a/cranelift/codegen/src/prelude_opt.isle b/cranelift/codegen/src/prelude_opt.isle index 55dc75f0b41a..5011481afddf 100644 --- a/cranelift/codegen/src/prelude_opt.isle +++ b/cranelift/codegen/src/prelude_opt.isle @@ -6,6 +6,14 @@ (decl multi inst_data (Type InstructionData) Value) (extern extractor inst_data inst_data_etor) +;; Identical to `inst_data`, just with a different ISLE type. +;; This is basically a manual version of `curry`/`uncurry` in Haskell: +;; to compose extractors the outer one needs to be single-parameter, +;; so this combines the two parameters of `inst_data` into one. +(type TypeAndInstructionData (primitive TypeAndInstructionData)) +(decl multi inst_data_tupled (TypeAndInstructionData) Value) +(extern extractor inst_data_tupled inst_data_tupled_etor) + ;; Construct a pure node, returning a new (or deduplicated ;; already-existing) eclass ID. (decl make_inst (Type InstructionData) Value) @@ -54,13 +62,33 @@ ;;;;; constructors ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(decl iconst_u64 (Type u64) Value) +(decl iconst_sextend_etor (Type i64) TypeAndInstructionData) +(extern extractor iconst_sextend_etor iconst_sextend_etor) -;; Use a single iconst for types that fit in 64 bits. -(rule 0 (iconst_u64 (ty_int_ref_scalar_64 ty) val) - (if-let $true (u64_le val (ty_umax ty))) - (iconst ty (imm64_masked ty val))) +;; Construct an `iconst` from an `i64` or Extract an `i64` from an `iconst` +;; by treating the constant as signed. +;; When extracting, smaller types get their value sign-extended to 64-bits, +;; so that `iconst.i8 255` will give you a `-1_i64`. +;; When constructing, the rule will fail if the value cannot be represented in +;; the target type. If it fits, it'll be masked accordingly in the constant. +(decl iconst_s (Type i64) Value) +(extractor (iconst_s ty c) (inst_data_tupled (iconst_sextend_etor ty c))) +(rule 0 (iconst_s ty c) + (if-let c_masked (u64_and (i64_as_u64 c) (ty_umax ty))) + (if-let c_reextended (i64_sextend_u64 ty c_masked)) + (if-let $true (u64_eq (i64_as_u64 c) (i64_as_u64 c_reextended))) + (iconst ty (imm64 c_masked))) +(rule 1 (iconst_s $I128 c) (sextend $I128 (iconst_s $I64 c))) -;; For i128 types use a iconst, but zero extend it to i128. -(rule 1 (iconst_u64 $I128 val) - (uextend $I128 (iconst $I64 (imm64_masked $I64 val)))) +;; Construct an `iconst` from a `u64` or Extract a `u64` from an `iconst` +;; by treating the constant as unsigned. +;; When extracting, smaller types get their value zero-extended to 64-bits, +;; so that `iconst.i8 255` will give you a `255_u64`. +;; When constructing, the rule will fail if the value cannot be represented in +;; the target type. +(decl iconst_u (Type u64) Value) +(extractor (iconst_u ty c) (iconst ty (u64_from_imm64 c))) +(rule 0 (iconst_u ty c) + (if-let $true (u64_le c (ty_umax ty))) + (iconst ty (imm64 c))) +(rule 1 (iconst_u $I128 c) (uextend $I128 (iconst_u $I64 c))) From a18752c8a3efda0012fa5d6d677dc1eeb7e7e776 Mon Sep 17 00:00:00 2001 From: Trevor Elliott Date: Tue, 12 Dec 2023 14:58:49 -0800 Subject: [PATCH 07/14] Use the compilation cache for components (#7649) * Use the compilation cache for components as well Co-authored-by: Pat Hickey * Wrap artifacts in `Some` --------- Co-authored-by: Pat Hickey --- crates/wasmtime/src/component/component.rs | 48 ++++++++++++++++++++-- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/crates/wasmtime/src/component/component.rs b/crates/wasmtime/src/component/component.rs index 280b3fdef60e..6b6a90c42ea9 100644 --- a/crates/wasmtime/src/component/component.rs +++ b/crates/wasmtime/src/component/component.rs @@ -127,14 +127,54 @@ impl Component { #[cfg(any(feature = "cranelift", feature = "winch"))] #[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result { + use crate::module::HashedEngineCompileEnv; + engine .check_compatible_with_native_host() .context("compilation settings are not compatible with the native host")?; - let (mmap, artifacts) = Component::build_artifacts(engine, binary)?; - let mut code_memory = CodeMemory::new(mmap)?; - code_memory.publish()?; - Component::from_parts(engine, Arc::new(code_memory), Some(artifacts)) + cfg_if::cfg_if! { + if #[cfg(feature = "cache")] { + let state = (HashedEngineCompileEnv(engine), binary); + let (code, artifacts) = wasmtime_cache::ModuleCacheEntry::new( + "wasmtime", + engine.cache_config(), + ) + .get_data_raw( + &state, + + // Cache miss, compute the actual artifacts + |(engine, wasm)| -> Result<_> { + let (mmap, artifacts) = Component::build_artifacts(engine.0, wasm)?; + let code = publish_mmap(mmap)?; + Ok((code, Some(artifacts))) + }, + + // Implementation of how to serialize artifacts + |(_engine, _wasm), (code, _info_and_types)| { + Some(code.mmap().to_vec()) + }, + + // Cache hit, deserialize the provided artifacts + |(engine, _wasm), serialized_bytes| { + let code = engine.0.load_code_bytes(&serialized_bytes, ObjectKind::Component).ok()?; + Some((code, None)) + }, + )?; + } else { + let (mmap, artifacts) = Component::build_artifacts(engine, binary)?; + let artifacts = Some(artifacts); + let code = publish_mmap(mmap)?; + } + }; + + return Component::from_parts(engine, code, artifacts); + + fn publish_mmap(mmap: MmapVec) -> Result> { + let mut code = CodeMemory::new(mmap)?; + code.publish()?; + Ok(Arc::new(code)) + } } /// Same as [`Module::deserialize`], but for components. From 410d8bfad5efc5f0347a4c2766c481b6a1564609 Mon Sep 17 00:00:00 2001 From: Roman Volosatovs Date: Wed, 13 Dec 2023 18:27:20 +0100 Subject: [PATCH 08/14] feat(wasmtime): allow definition of dynamic resource types in the linker (#7680) Signed-off-by: Roman Volosatovs --- crates/wasmtime/src/component/linker.rs | 12 ++-- crates/wast/src/spectest.rs | 20 +++++-- crates/wit-bindgen/src/lib.rs | 6 +- tests/all/component_model/resources.rs | 78 ++++++++++++++++++------- 4 files changed, 79 insertions(+), 37 deletions(-) diff --git a/crates/wasmtime/src/component/linker.rs b/crates/wasmtime/src/component/linker.rs index 5e490fa9ae99..58e6600449f9 100644 --- a/crates/wasmtime/src/component/linker.rs +++ b/crates/wasmtime/src/component/linker.rs @@ -417,12 +417,9 @@ impl LinkerInstance<'_, T> { self.insert(name, Definition::Module(module.clone())) } - /// Defines a new host [`ResourceType`] in this linker. + /// Defines a new resource of a given [`ResourceType`] in this linker. /// - /// This function is used to specify resources defined in the host. The `U` - /// type parameter here is the type parameter to [`Resource`]. This means - /// that component types using this resource type will be visible in - /// Wasmtime as [`Resource`]. + /// This function is used to specify resources defined in the host. /// /// The `name` argument is the name to define the resource within this /// linker. @@ -442,9 +439,10 @@ impl LinkerInstance<'_, T> { /// The provided `dtor` closure returns an error if something goes wrong /// when a guest calls the `dtor` to drop a `Resource` such as /// a runtime trap or a runtime limit being exceeded. - pub fn resource( + pub fn resource( &mut self, name: &str, + ty: ResourceType, dtor: impl Fn(StoreContextMut<'_, T>, u32) -> Result<()> + Send + Sync + 'static, ) -> Result<()> { let name = self.strings.intern(name); @@ -452,7 +450,7 @@ impl LinkerInstance<'_, T> { &self.engine, move |mut cx: crate::Caller<'_, T>, param: u32| dtor(cx.as_context_mut(), param), )); - self.insert(name, Definition::Resource(ResourceType::host::(), dtor)) + self.insert(name, Definition::Resource(ty, dtor)) } /// Defines a nested instance within this instance. diff --git a/crates/wast/src/spectest.rs b/crates/wast/src/spectest.rs index 17d49b7c294d..5f00ba73ac87 100644 --- a/crates/wast/src/spectest.rs +++ b/crates/wast/src/spectest.rs @@ -59,7 +59,7 @@ pub fn link_spectest( pub fn link_component_spectest(linker: &mut component::Linker) -> Result<()> { use std::sync::atomic::{AtomicU32, Ordering::SeqCst}; use std::sync::Arc; - use wasmtime::component::Resource; + use wasmtime::component::{Resource, ResourceType}; let engine = linker.engine().clone(); linker @@ -92,7 +92,7 @@ pub fn link_component_spectest(linker: &mut component::Linker) -> Result<( let state = Arc::new(ResourceState::default()); - i.resource::("resource1", { + i.resource("resource1", ResourceType::host::(), { let state = state.clone(); move |_, rep| { state.drops.fetch_add(1, SeqCst); @@ -101,13 +101,21 @@ pub fn link_component_spectest(linker: &mut component::Linker) -> Result<( Ok(()) } })?; - i.resource::("resource2", |_, _| Ok(()))?; + i.resource( + "resource2", + ResourceType::host::(), + |_, _| Ok(()), + )?; // Currently the embedder API requires redefining the resource destructor // here despite this being the same type as before, and fixing that is left // for a future refactoring. - i.resource::("resource1-again", |_, _| { - panic!("shouldn't be destroyed"); - })?; + i.resource( + "resource1-again", + ResourceType::host::(), + |_, _| { + panic!("shouldn't be destroyed"); + }, + )?; i.func_wrap("[constructor]resource1", |_cx, (rep,): (u32,)| { Ok((Resource::::new_own(rep),)) diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs index 2c1422f597e2..a73f6bcca4e5 100644 --- a/crates/wit-bindgen/src/lib.rs +++ b/crates/wit-bindgen/src/lib.rs @@ -807,8 +807,9 @@ impl Wasmtime { let camel = name.to_upper_camel_case(); uwriteln!( self.src, - "linker.resource::<{camel}>( + "linker.resource( \"{name}\", + wasmtime::component::ResourceType::host::<{camel}>(), move |mut store, rep| -> wasmtime::Result<()> {{ Host{camel}::drop(get(store.data_mut()), wasmtime::component::Resource::new_own(rep)) }}, @@ -1604,8 +1605,9 @@ impl<'a> InterfaceGenerator<'a> { let camel = name.to_upper_camel_case(); uwriteln!( self.src, - "inst.resource::<{camel}>( + "inst.resource( \"{name}\", + wasmtime::component::ResourceType::host::<{camel}>(), move |mut store, rep| -> wasmtime::Result<()> {{ Host{camel}::drop(get(store.data_mut()), wasmtime::component::Resource::new_own(rep)) }}, diff --git a/tests/all/component_model/resources.rs b/tests/all/component_model/resources.rs index ba821251f79c..ae3893b12d19 100644 --- a/tests/all/component_model/resources.rs +++ b/tests/all/component_model/resources.rs @@ -37,8 +37,12 @@ fn host_resource_types() -> Result<()> { let mut store = Store::new(&engine, ()); let mut linker = Linker::new(&engine); - linker.root().resource::("t", |_, _| Ok(()))?; - linker.root().resource::("u", |_, _| Ok(()))?; + linker + .root() + .resource("t", ResourceType::host::(), |_, _| Ok(()))?; + linker + .root() + .resource("u", ResourceType::host::(), |_, _| Ok(()))?; let i = linker.instantiate(&mut store, &c)?; let t1 = i.get_resource(&mut store, "t1").unwrap(); let t2 = i.get_resource(&mut store, "t2").unwrap(); @@ -367,7 +371,9 @@ fn drop_host_twice() -> Result<()> { let mut store = Store::new(&engine, ()); let mut linker = Linker::new(&engine); - linker.root().resource::("t", |_, _| Ok(()))?; + linker + .root() + .resource("t", ResourceType::host::(), |_, _| Ok(()))?; let i = linker.instantiate(&mut store, &c)?; let dtor = i.get_typed_func::<(&Resource,), ()>(&mut store, "dtor")?; @@ -431,12 +437,14 @@ fn manually_destroy() -> Result<()> { let mut store = Store::new(&engine, Data::default()); let mut linker = Linker::new(&engine); - linker.root().resource::("t1", |mut cx, rep| { - let data: &mut Data = cx.data_mut(); - data.drops += 1; - data.last_drop = Some(rep); - Ok(()) - })?; + linker + .root() + .resource("t1", ResourceType::host::(), |mut cx, rep| { + let data: &mut Data = cx.data_mut(); + data.drops += 1; + data.last_drop = Some(rep); + Ok(()) + })?; let i = linker.instantiate(&mut store, &c)?; let t2_ctor = i.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "[constructor]t2")?; let t2_drops = i.get_typed_func::<(), (u32,)>(&mut store, "[static]t2.drops")?; @@ -497,7 +505,9 @@ fn dynamic_type() -> Result<()> { let mut store = Store::new(&engine, ()); let mut linker = Linker::new(&engine); - linker.root().resource::("t1", |_, _| Ok(()))?; + linker + .root() + .resource("t1", ResourceType::host::(), |_, _| Ok(()))?; let i = linker.instantiate(&mut store, &c)?; let a = i.get_func(&mut store, "a").unwrap(); @@ -548,7 +558,9 @@ fn dynamic_val() -> Result<()> { let mut store = Store::new(&engine, ()); let mut linker = Linker::new(&engine); - linker.root().resource::("t1", |_, _| Ok(()))?; + linker + .root() + .resource("t1", ResourceType::host::(), |_, _| Ok(()))?; let i = linker.instantiate(&mut store, &c)?; let a = i.get_func(&mut store, "a").unwrap(); @@ -665,7 +677,9 @@ fn active_borrows_at_end_of_call() -> Result<()> { let mut store = Store::new(&engine, ()); let mut linker = Linker::new(&engine); - linker.root().resource::("t", |_, _| Ok(()))?; + linker + .root() + .resource("t", ResourceType::host::(), |_, _| Ok(()))?; let i = linker.instantiate(&mut store, &c)?; let f = i.get_typed_func::<(&Resource,), ()>(&mut store, "f")?; @@ -720,7 +734,9 @@ fn thread_through_borrow() -> Result<()> { let mut store = Store::new(&engine, ()); let mut linker = Linker::new(&engine); - linker.root().resource::("t", |_, _| Ok(()))?; + linker + .root() + .resource("t", ResourceType::host::(), |_, _| Ok(()))?; linker .root() .func_wrap("f", |_cx, (r,): (Resource,)| { @@ -764,7 +780,9 @@ fn cannot_use_borrow_for_own() -> Result<()> { let mut store = Store::new(&engine, ()); let mut linker = Linker::new(&engine); - linker.root().resource::("t", |_, _| Ok(()))?; + linker + .root() + .resource("t", ResourceType::host::(), |_, _| Ok(()))?; let i = linker.instantiate(&mut store, &c)?; let f = i.get_typed_func::<(&Resource,), (Resource,)>(&mut store, "f")?; @@ -809,7 +827,9 @@ fn passthrough_wrong_type() -> Result<()> { let mut store = Store::new(&engine, ()); let mut linker = Linker::new(&engine); - linker.root().resource::("t", |_, _| Ok(()))?; + linker + .root() + .resource("t", ResourceType::host::(), |_, _| Ok(()))?; linker .root() .func_wrap("f", |_cx, (r,): (Resource,)| Ok((r,)))?; @@ -849,7 +869,9 @@ fn pass_moved_resource() -> Result<()> { let mut store = Store::new(&engine, ()); let mut linker = Linker::new(&engine); - linker.root().resource::("t", |_, _| Ok(()))?; + linker + .root() + .resource("t", ResourceType::host::(), |_, _| Ok(()))?; let i = linker.instantiate(&mut store, &c)?; let f = i.get_typed_func::<(&Resource, &Resource), ()>(&mut store, "f")?; @@ -980,7 +1002,9 @@ fn host_borrow_as_resource_any() -> Result<()> { // First test the above component where the host properly drops the argument { let mut linker = Linker::new(&engine); - linker.root().resource::("t", |_, _| Ok(()))?; + linker + .root() + .resource("t", ResourceType::host::(), |_, _| Ok(()))?; linker .root() .func_wrap("f", |mut cx, (r,): (ResourceAny,)| { @@ -998,7 +1022,9 @@ fn host_borrow_as_resource_any() -> Result<()> { // Then also test the case where the host forgets a drop { let mut linker = Linker::new(&engine); - linker.root().resource::("t", |_, _| Ok(()))?; + linker + .root() + .resource("t", ResourceType::host::(), |_, _| Ok(()))?; linker.root().func_wrap("f", |_cx, (_r,): (ResourceAny,)| { // ... no drop here Ok(()) @@ -1107,7 +1133,9 @@ fn pass_host_borrow_to_guest() -> Result<()> { let mut store = Store::new(&engine, ()); let mut linker = Linker::new(&engine); - linker.root().resource::("t", |_, _| Ok(()))?; + linker + .root() + .resource("t", ResourceType::host::(), |_, _| Ok(()))?; let i = linker.instantiate(&mut store, &c)?; let take = i.get_typed_func::<(&Resource,), ()>(&mut store, "take")?; @@ -1180,7 +1208,9 @@ fn drop_on_owned_resource() -> Result<()> { let mut store = Store::new(&engine, ()); let mut linker = Linker::new(&engine); - linker.root().resource::("t", |_, _| Ok(()))?; + linker + .root() + .resource("t", ResourceType::host::(), |_, _| Ok(()))?; linker.root().func_wrap("[constructor]t", |_cx, ()| { Ok((Resource::::new_own(300),)) })?; @@ -1257,8 +1287,12 @@ fn guest_different_host_same() -> Result<()> { let mut store = Store::new(&engine, ()); let mut linker = Linker::new(&engine); - linker.root().resource::("t1", |_, _| Ok(()))?; - linker.root().resource::("t2", |_, _| Ok(()))?; + linker + .root() + .resource("t1", ResourceType::host::(), |_, _| Ok(()))?; + linker + .root() + .resource("t2", ResourceType::host::(), |_, _| Ok(()))?; linker.root().func_wrap( "f", |_cx, (r1, r2): (Resource, Resource)| { From 17091e6f6cb4df20feb8f1438304e89bbf81cb90 Mon Sep 17 00:00:00 2001 From: Jeffrey Charles Date: Wed, 13 Dec 2023 10:37:22 -0800 Subject: [PATCH 09/14] Winch: Change emits to return TypedReg to put on stack (#7682) --- winch/codegen/src/codegen/context.rs | 32 +++++++++------ winch/codegen/src/stack.rs | 16 ++++++++ winch/codegen/src/visitor.rs | 40 +++++++++++++++++++ .../filetests/filetests/x64/i64_eq/locals.wat | 8 ++-- .../filetests/filetests/x64/i64_eq/params.wat | 8 ++-- .../filetests/x64/i64_eqz/spilled.wat | 25 ++++++++++++ .../filetests/x64/i64_ge_s/locals.wat | 8 ++-- .../filetests/x64/i64_ge_s/params.wat | 8 ++-- .../filetests/x64/i64_ge_u/locals.wat | 8 ++-- .../filetests/x64/i64_ge_u/params.wat | 8 ++-- .../filetests/x64/i64_gt_s/locals.wat | 8 ++-- .../filetests/x64/i64_gt_s/params.wat | 8 ++-- .../filetests/x64/i64_gt_u/locals.wat | 8 ++-- .../filetests/x64/i64_gt_u/params.wat | 8 ++-- .../filetests/x64/i64_le_s/locals.wat | 8 ++-- .../filetests/x64/i64_le_s/params.wat | 8 ++-- .../filetests/x64/i64_le_u/locals.wat | 8 ++-- .../filetests/x64/i64_le_u/params.wat | 8 ++-- .../filetests/x64/i64_lt_s/locals.wat | 8 ++-- .../filetests/x64/i64_lt_s/params.wat | 8 ++-- .../filetests/x64/i64_lt_u/locals.wat | 8 ++-- .../filetests/x64/i64_lt_u/params.wat | 8 ++-- .../filetests/filetests/x64/i64_ne/locals.wat | 8 ++-- .../filetests/filetests/x64/i64_ne/params.wat | 8 ++-- 24 files changed, 181 insertions(+), 92 deletions(-) create mode 100644 winch/filetests/filetests/x64/i64_eqz/spilled.wat diff --git a/winch/codegen/src/codegen/context.rs b/winch/codegen/src/codegen/context.rs index 28b4a25daa27..7bcedf0891c4 100644 --- a/winch/codegen/src/codegen/context.rs +++ b/winch/codegen/src/codegen/context.rs @@ -225,25 +225,29 @@ impl<'a, 'builtins> CodeGenContext<'a, 'builtins> { } /// Prepares arguments for emitting a unary operation. + /// + /// The `emit` function returns the `TypedReg` to put on the value stack. pub fn unop(&mut self, masm: &mut M, size: OperandSize, emit: &mut F) where - F: FnMut(&mut M, Reg, OperandSize), + F: FnMut(&mut M, Reg, OperandSize) -> TypedReg, M: MacroAssembler, { let typed_reg = self.pop_to_reg(masm, None); - emit(masm, typed_reg.reg, size); - self.stack.push(typed_reg.into()); + let dst = emit(masm, typed_reg.reg, size); + self.stack.push(dst.into()); } /// Prepares arguments for emitting a binary operation. + /// + /// The `emit` function returns the `TypedReg` to put on the value stack. pub fn binop(&mut self, masm: &mut M, size: OperandSize, mut emit: F) where - F: FnMut(&mut M, Reg, Reg, OperandSize), + F: FnMut(&mut M, Reg, Reg, OperandSize) -> TypedReg, M: MacroAssembler, { let src = self.pop_to_reg(masm, None); let dst = self.pop_to_reg(masm, None); - emit(masm, dst.reg, src.reg.into(), size); + let dst = emit(masm, dst.reg, src.reg.into(), size); self.free_reg(src); self.stack.push(dst.into()); } @@ -270,9 +274,11 @@ impl<'a, 'builtins> CodeGenContext<'a, 'builtins> { } /// Prepares arguments for emitting an i32 binary operation. + /// + /// The `emit` function returns the `TypedReg` to put on the value stack. pub fn i32_binop(&mut self, masm: &mut M, mut emit: F) where - F: FnMut(&mut M, Reg, RegImm, OperandSize), + F: FnMut(&mut M, Reg, RegImm, OperandSize) -> TypedReg, M: MacroAssembler, { let top = self.stack.peek().expect("value at stack top"); @@ -283,8 +289,8 @@ impl<'a, 'builtins> CodeGenContext<'a, 'builtins> { .pop_i32_const() .expect("i32 const value at stack top"); let typed_reg = self.pop_to_reg(masm, None); - emit(masm, typed_reg.reg, RegImm::i32(val), OperandSize::S32); - self.stack.push(typed_reg.into()); + let dst = emit(masm, typed_reg.reg, RegImm::i32(val), OperandSize::S32); + self.stack.push(dst.into()); } else { self.binop(masm, OperandSize::S32, |masm, dst, src, size| { emit(masm, dst, src.into(), size) @@ -293,9 +299,11 @@ impl<'a, 'builtins> CodeGenContext<'a, 'builtins> { } /// Prepares arguments for emitting an i64 binary operation. + /// + /// The `emit` function returns the `TypedReg` to put on the value stack. pub fn i64_binop(&mut self, masm: &mut M, mut emit: F) where - F: FnMut(&mut M, Reg, RegImm, OperandSize), + F: FnMut(&mut M, Reg, RegImm, OperandSize) -> TypedReg, M: MacroAssembler, { let top = self.stack.peek().expect("value at stack top"); @@ -305,13 +313,13 @@ impl<'a, 'builtins> CodeGenContext<'a, 'builtins> { .pop_i64_const() .expect("i64 const value at stack top"); let typed_reg = self.pop_to_reg(masm, None); - emit(masm, typed_reg.reg, RegImm::i64(val), OperandSize::S64); - self.stack.push(typed_reg.into()); + let dst = emit(masm, typed_reg.reg, RegImm::i64(val), OperandSize::S64); + self.stack.push(dst.into()); } else { self.binop(masm, OperandSize::S64, |masm, dst, src, size| { emit(masm, dst, src.into(), size) }); - } + }; } /// Drops the last `n` elements of the stack, calling the provided diff --git a/winch/codegen/src/stack.rs b/winch/codegen/src/stack.rs index ffdfac397c24..a8491882bedd 100644 --- a/winch/codegen/src/stack.rs +++ b/winch/codegen/src/stack.rs @@ -34,6 +34,22 @@ impl TypedReg { reg, } } + + /// Create an f64 [`TypedReg`]. + pub fn f64(reg: Reg) -> Self { + Self { + ty: WasmType::F64, + reg, + } + } + + /// Create an f32 [`TypedReg`]. + pub fn f32(reg: Reg) -> Self { + Self { + ty: WasmType::F32, + reg, + } + } } impl From for Reg { diff --git a/winch/codegen/src/visitor.rs b/winch/codegen/src/visitor.rs index 4db1150e2ca8..ca74d0ffcc6a 100644 --- a/winch/codegen/src/visitor.rs +++ b/winch/codegen/src/visitor.rs @@ -203,6 +203,7 @@ where OperandSize::S32, &mut |masm: &mut M, dst, src, size| { masm.float_add(dst, dst, src, size); + TypedReg::f32(dst) }, ); } @@ -213,6 +214,7 @@ where OperandSize::S64, &mut |masm: &mut M, dst, src, size| { masm.float_add(dst, dst, src, size); + TypedReg::f64(dst) }, ); } @@ -223,6 +225,7 @@ where OperandSize::S32, &mut |masm: &mut M, dst, src, size| { masm.float_sub(dst, dst, src, size); + TypedReg::f32(dst) }, ); } @@ -233,6 +236,7 @@ where OperandSize::S64, &mut |masm: &mut M, dst, src, size| { masm.float_sub(dst, dst, src, size); + TypedReg::f64(dst) }, ); } @@ -243,6 +247,7 @@ where OperandSize::S32, &mut |masm: &mut M, dst, src, size| { masm.float_mul(dst, dst, src, size); + TypedReg::f32(dst) }, ); } @@ -253,6 +258,7 @@ where OperandSize::S64, &mut |masm: &mut M, dst, src, size| { masm.float_mul(dst, dst, src, size); + TypedReg::f64(dst) }, ); } @@ -263,6 +269,7 @@ where OperandSize::S32, &mut |masm: &mut M, dst, src, size| { masm.float_div(dst, dst, src, size); + TypedReg::f32(dst) }, ); } @@ -273,6 +280,7 @@ where OperandSize::S64, &mut |masm: &mut M, dst, src, size| { masm.float_div(dst, dst, src, size); + TypedReg::f64(dst) }, ); } @@ -283,6 +291,7 @@ where OperandSize::S32, &mut |masm: &mut M, dst, src, size| { masm.float_min(dst, dst, src, size); + TypedReg::f32(dst) }, ); } @@ -293,6 +302,7 @@ where OperandSize::S64, &mut |masm: &mut M, dst, src, size| { masm.float_min(dst, dst, src, size); + TypedReg::f64(dst) }, ); } @@ -303,6 +313,7 @@ where OperandSize::S32, &mut |masm: &mut M, dst, src, size| { masm.float_max(dst, dst, src, size); + TypedReg::f32(dst) }, ); } @@ -313,6 +324,7 @@ where OperandSize::S64, &mut |masm: &mut M, dst, src, size| { masm.float_max(dst, dst, src, size); + TypedReg::f64(dst) }, ); } @@ -323,6 +335,7 @@ where OperandSize::S32, &mut |masm: &mut M, dst, src, size| { masm.float_copysign(dst, dst, src, size); + TypedReg::f32(dst) }, ); } @@ -333,6 +346,7 @@ where OperandSize::S64, &mut |masm: &mut M, dst, src, size| { masm.float_copysign(dst, dst, src, size); + TypedReg::f64(dst) }, ); } @@ -341,6 +355,7 @@ where self.context .unop(self.masm, OperandSize::S32, &mut |masm, reg, size| { masm.float_abs(reg, size); + TypedReg::f32(reg) }); } @@ -348,6 +363,7 @@ where self.context .unop(self.masm, OperandSize::S64, &mut |masm, reg, size| { masm.float_abs(reg, size); + TypedReg::f64(reg) }); } @@ -355,6 +371,7 @@ where self.context .unop(self.masm, OperandSize::S32, &mut |masm, reg, size| { masm.float_neg(reg, size); + TypedReg::f32(reg) }); } @@ -362,6 +379,7 @@ where self.context .unop(self.masm, OperandSize::S64, &mut |masm, reg, size| { masm.float_neg(reg, size); + TypedReg::f64(reg) }); } @@ -409,6 +427,7 @@ where self.context .unop(self.masm, OperandSize::S32, &mut |masm, reg, size| { masm.float_sqrt(reg, reg, size); + TypedReg::f32(reg) }); } @@ -416,6 +435,7 @@ where self.context .unop(self.masm, OperandSize::S64, &mut |masm, reg, size| { masm.float_sqrt(reg, reg, size); + TypedReg::f64(reg) }); } @@ -542,36 +562,42 @@ where fn visit_i32_add(&mut self) { self.context.i32_binop(self.masm, |masm, dst, src, size| { masm.add(dst, dst, src, size); + TypedReg::i32(dst) }); } fn visit_i64_add(&mut self) { self.context.i64_binop(self.masm, |masm, dst, src, size| { masm.add(dst, dst, src, size); + TypedReg::i64(dst) }); } fn visit_i32_sub(&mut self) { self.context.i32_binop(self.masm, |masm, dst, src, size| { masm.sub(dst, dst, src, size); + TypedReg::i32(dst) }); } fn visit_i64_sub(&mut self) { self.context.i64_binop(self.masm, |masm, dst, src, size| { masm.sub(dst, dst, src, size); + TypedReg::i64(dst) }); } fn visit_i32_mul(&mut self) { self.context.i32_binop(self.masm, |masm, dst, src, size| { masm.mul(dst, dst, src, size); + TypedReg::i32(dst) }); } fn visit_i64_mul(&mut self) { self.context.i64_binop(self.masm, |masm, dst, src, size| { masm.mul(dst, dst, src, size); + TypedReg::i64(dst) }); } @@ -716,6 +742,7 @@ where self.context.unop(self.masm, S32, &mut |masm, reg, size| { masm.cmp_with_set(RegImm::i32(0), reg.into(), IntCmpKind::Eq, size); + TypedReg::i32(reg) }); } @@ -724,6 +751,7 @@ where self.context.unop(self.masm, S64, &mut |masm, reg, size| { masm.cmp_with_set(RegImm::i64(0), reg.into(), IntCmpKind::Eq, size); + TypedReg::i32(reg) // Return value for `i64.eqz` is an `i32`. }); } @@ -732,6 +760,7 @@ where self.context.unop(self.masm, S32, &mut |masm, reg, size| { masm.clz(reg, reg, size); + TypedReg::i32(reg) }); } @@ -740,6 +769,7 @@ where self.context.unop(self.masm, S64, &mut |masm, reg, size| { masm.clz(reg, reg, size); + TypedReg::i64(reg) }); } @@ -748,6 +778,7 @@ where self.context.unop(self.masm, S32, &mut |masm, reg, size| { masm.ctz(reg, reg, size); + TypedReg::i32(reg) }); } @@ -756,42 +787,49 @@ where self.context.unop(self.masm, S64, &mut |masm, reg, size| { masm.ctz(reg, reg, size); + TypedReg::i64(reg) }); } fn visit_i32_and(&mut self) { self.context.i32_binop(self.masm, |masm, dst, src, size| { masm.and(dst, dst, src, size); + TypedReg::i32(dst) }); } fn visit_i64_and(&mut self) { self.context.i64_binop(self.masm, |masm, dst, src, size| { masm.and(dst, dst, src, size); + TypedReg::i64(dst) }); } fn visit_i32_or(&mut self) { self.context.i32_binop(self.masm, |masm, dst, src, size| { masm.or(dst, dst, src, size); + TypedReg::i32(dst) }); } fn visit_i64_or(&mut self) { self.context.i64_binop(self.masm, |masm, dst, src, size| { masm.or(dst, dst, src, size); + TypedReg::i64(dst) }); } fn visit_i32_xor(&mut self) { self.context.i32_binop(self.masm, |masm, dst, src, size| { masm.xor(dst, dst, src, size); + TypedReg::i32(dst) }); } fn visit_i64_xor(&mut self) { self.context.i64_binop(self.masm, |masm, dst, src, size| { masm.xor(dst, dst, src, size); + TypedReg::i64(dst) }); } @@ -1368,6 +1406,7 @@ where fn cmp_i32s(&mut self, kind: IntCmpKind) { self.context.i32_binop(self.masm, |masm, dst, src, size| { masm.cmp_with_set(src, dst, kind, size); + TypedReg::i32(dst) }); } @@ -1375,6 +1414,7 @@ where self.context .i64_binop(self.masm, move |masm, dst, src, size| { masm.cmp_with_set(src, dst, kind, size); + TypedReg::i32(dst) // Return value for comparisons is an `i32`. }); } } diff --git a/winch/filetests/filetests/x64/i64_eq/locals.wat b/winch/filetests/filetests/x64/i64_eq/locals.wat index 8884b9d68459..6761c2e7fec8 100644 --- a/winch/filetests/filetests/x64/i64_eq/locals.wat +++ b/winch/filetests/filetests/x64/i64_eq/locals.wat @@ -31,7 +31,7 @@ ;; 3b: 4839c1 cmp rcx, rax ;; 3e: b900000000 mov ecx, 0 ;; 43: 400f94c1 sete cl -;; 47: 4889c8 mov rax, rcx -;; 4a: 4883c418 add rsp, 0x18 -;; 4e: 5d pop rbp -;; 4f: c3 ret +;; 47: 89c8 mov eax, ecx +;; 49: 4883c418 add rsp, 0x18 +;; 4d: 5d pop rbp +;; 4e: c3 ret diff --git a/winch/filetests/filetests/x64/i64_eq/params.wat b/winch/filetests/filetests/x64/i64_eq/params.wat index aed5174e312f..27fa74cb6561 100644 --- a/winch/filetests/filetests/x64/i64_eq/params.wat +++ b/winch/filetests/filetests/x64/i64_eq/params.wat @@ -18,7 +18,7 @@ ;; 20: 4839c1 cmp rcx, rax ;; 23: b900000000 mov ecx, 0 ;; 28: 400f94c1 sete cl -;; 2c: 4889c8 mov rax, rcx -;; 2f: 4883c418 add rsp, 0x18 -;; 33: 5d pop rbp -;; 34: c3 ret +;; 2c: 89c8 mov eax, ecx +;; 2e: 4883c418 add rsp, 0x18 +;; 32: 5d pop rbp +;; 33: c3 ret diff --git a/winch/filetests/filetests/x64/i64_eqz/spilled.wat b/winch/filetests/filetests/x64/i64_eqz/spilled.wat new file mode 100644 index 000000000000..b2e09645c203 --- /dev/null +++ b/winch/filetests/filetests/x64/i64_eqz/spilled.wat @@ -0,0 +1,25 @@ +;;! target = "x86_64" + +(module + (func (result i32) + i64.const 1 + i64.eqz + block + end + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec08 sub rsp, 8 +;; 8: 4c893424 mov qword ptr [rsp], r14 +;; c: 48c7c001000000 mov rax, 1 +;; 13: 4883f800 cmp rax, 0 +;; 17: b800000000 mov eax, 0 +;; 1c: 400f94c0 sete al +;; 20: 4883ec04 sub rsp, 4 +;; 24: 890424 mov dword ptr [rsp], eax +;; 27: 8b0424 mov eax, dword ptr [rsp] +;; 2a: 4883c404 add rsp, 4 +;; 2e: 4883c408 add rsp, 8 +;; 32: 5d pop rbp +;; 33: c3 ret diff --git a/winch/filetests/filetests/x64/i64_ge_s/locals.wat b/winch/filetests/filetests/x64/i64_ge_s/locals.wat index 6339d2f2312c..6f91547cc333 100644 --- a/winch/filetests/filetests/x64/i64_ge_s/locals.wat +++ b/winch/filetests/filetests/x64/i64_ge_s/locals.wat @@ -31,7 +31,7 @@ ;; 3b: 4839c1 cmp rcx, rax ;; 3e: b900000000 mov ecx, 0 ;; 43: 400f9dc1 setge cl -;; 47: 4889c8 mov rax, rcx -;; 4a: 4883c418 add rsp, 0x18 -;; 4e: 5d pop rbp -;; 4f: c3 ret +;; 47: 89c8 mov eax, ecx +;; 49: 4883c418 add rsp, 0x18 +;; 4d: 5d pop rbp +;; 4e: c3 ret diff --git a/winch/filetests/filetests/x64/i64_ge_s/params.wat b/winch/filetests/filetests/x64/i64_ge_s/params.wat index 49a3ab656f81..f8b849b82278 100644 --- a/winch/filetests/filetests/x64/i64_ge_s/params.wat +++ b/winch/filetests/filetests/x64/i64_ge_s/params.wat @@ -18,7 +18,7 @@ ;; 20: 4839c1 cmp rcx, rax ;; 23: b900000000 mov ecx, 0 ;; 28: 400f9dc1 setge cl -;; 2c: 4889c8 mov rax, rcx -;; 2f: 4883c418 add rsp, 0x18 -;; 33: 5d pop rbp -;; 34: c3 ret +;; 2c: 89c8 mov eax, ecx +;; 2e: 4883c418 add rsp, 0x18 +;; 32: 5d pop rbp +;; 33: c3 ret diff --git a/winch/filetests/filetests/x64/i64_ge_u/locals.wat b/winch/filetests/filetests/x64/i64_ge_u/locals.wat index f8b2d35f9134..626a483d27fb 100644 --- a/winch/filetests/filetests/x64/i64_ge_u/locals.wat +++ b/winch/filetests/filetests/x64/i64_ge_u/locals.wat @@ -31,7 +31,7 @@ ;; 3b: 4839c1 cmp rcx, rax ;; 3e: b900000000 mov ecx, 0 ;; 43: 400f93c1 setae cl -;; 47: 4889c8 mov rax, rcx -;; 4a: 4883c418 add rsp, 0x18 -;; 4e: 5d pop rbp -;; 4f: c3 ret +;; 47: 89c8 mov eax, ecx +;; 49: 4883c418 add rsp, 0x18 +;; 4d: 5d pop rbp +;; 4e: c3 ret diff --git a/winch/filetests/filetests/x64/i64_ge_u/params.wat b/winch/filetests/filetests/x64/i64_ge_u/params.wat index 2ca43e57eba1..68d707d11b93 100644 --- a/winch/filetests/filetests/x64/i64_ge_u/params.wat +++ b/winch/filetests/filetests/x64/i64_ge_u/params.wat @@ -18,7 +18,7 @@ ;; 20: 4839c1 cmp rcx, rax ;; 23: b900000000 mov ecx, 0 ;; 28: 400f93c1 setae cl -;; 2c: 4889c8 mov rax, rcx -;; 2f: 4883c418 add rsp, 0x18 -;; 33: 5d pop rbp -;; 34: c3 ret +;; 2c: 89c8 mov eax, ecx +;; 2e: 4883c418 add rsp, 0x18 +;; 32: 5d pop rbp +;; 33: c3 ret diff --git a/winch/filetests/filetests/x64/i64_gt_s/locals.wat b/winch/filetests/filetests/x64/i64_gt_s/locals.wat index 10c5c4ec360a..a8e347eb4732 100644 --- a/winch/filetests/filetests/x64/i64_gt_s/locals.wat +++ b/winch/filetests/filetests/x64/i64_gt_s/locals.wat @@ -31,7 +31,7 @@ ;; 3b: 4839c1 cmp rcx, rax ;; 3e: b900000000 mov ecx, 0 ;; 43: 400f9fc1 setg cl -;; 47: 4889c8 mov rax, rcx -;; 4a: 4883c418 add rsp, 0x18 -;; 4e: 5d pop rbp -;; 4f: c3 ret +;; 47: 89c8 mov eax, ecx +;; 49: 4883c418 add rsp, 0x18 +;; 4d: 5d pop rbp +;; 4e: c3 ret diff --git a/winch/filetests/filetests/x64/i64_gt_s/params.wat b/winch/filetests/filetests/x64/i64_gt_s/params.wat index 5e30853e0a9a..ee6fc2953601 100644 --- a/winch/filetests/filetests/x64/i64_gt_s/params.wat +++ b/winch/filetests/filetests/x64/i64_gt_s/params.wat @@ -18,7 +18,7 @@ ;; 20: 4839c1 cmp rcx, rax ;; 23: b900000000 mov ecx, 0 ;; 28: 400f9fc1 setg cl -;; 2c: 4889c8 mov rax, rcx -;; 2f: 4883c418 add rsp, 0x18 -;; 33: 5d pop rbp -;; 34: c3 ret +;; 2c: 89c8 mov eax, ecx +;; 2e: 4883c418 add rsp, 0x18 +;; 32: 5d pop rbp +;; 33: c3 ret diff --git a/winch/filetests/filetests/x64/i64_gt_u/locals.wat b/winch/filetests/filetests/x64/i64_gt_u/locals.wat index 9890d2ca6bb1..203adfe7a5e6 100644 --- a/winch/filetests/filetests/x64/i64_gt_u/locals.wat +++ b/winch/filetests/filetests/x64/i64_gt_u/locals.wat @@ -31,7 +31,7 @@ ;; 3b: 4839c1 cmp rcx, rax ;; 3e: b900000000 mov ecx, 0 ;; 43: 400f97c1 seta cl -;; 47: 4889c8 mov rax, rcx -;; 4a: 4883c418 add rsp, 0x18 -;; 4e: 5d pop rbp -;; 4f: c3 ret +;; 47: 89c8 mov eax, ecx +;; 49: 4883c418 add rsp, 0x18 +;; 4d: 5d pop rbp +;; 4e: c3 ret diff --git a/winch/filetests/filetests/x64/i64_gt_u/params.wat b/winch/filetests/filetests/x64/i64_gt_u/params.wat index e2e9d8654c3f..d2d5e91715c3 100644 --- a/winch/filetests/filetests/x64/i64_gt_u/params.wat +++ b/winch/filetests/filetests/x64/i64_gt_u/params.wat @@ -18,7 +18,7 @@ ;; 20: 4839c1 cmp rcx, rax ;; 23: b900000000 mov ecx, 0 ;; 28: 400f97c1 seta cl -;; 2c: 4889c8 mov rax, rcx -;; 2f: 4883c418 add rsp, 0x18 -;; 33: 5d pop rbp -;; 34: c3 ret +;; 2c: 89c8 mov eax, ecx +;; 2e: 4883c418 add rsp, 0x18 +;; 32: 5d pop rbp +;; 33: c3 ret diff --git a/winch/filetests/filetests/x64/i64_le_s/locals.wat b/winch/filetests/filetests/x64/i64_le_s/locals.wat index d363621c3b18..479cab46142b 100644 --- a/winch/filetests/filetests/x64/i64_le_s/locals.wat +++ b/winch/filetests/filetests/x64/i64_le_s/locals.wat @@ -31,7 +31,7 @@ ;; 3b: 4839c1 cmp rcx, rax ;; 3e: b900000000 mov ecx, 0 ;; 43: 400f9ec1 setle cl -;; 47: 4889c8 mov rax, rcx -;; 4a: 4883c418 add rsp, 0x18 -;; 4e: 5d pop rbp -;; 4f: c3 ret +;; 47: 89c8 mov eax, ecx +;; 49: 4883c418 add rsp, 0x18 +;; 4d: 5d pop rbp +;; 4e: c3 ret diff --git a/winch/filetests/filetests/x64/i64_le_s/params.wat b/winch/filetests/filetests/x64/i64_le_s/params.wat index 1df814ef2f03..94ec67536632 100644 --- a/winch/filetests/filetests/x64/i64_le_s/params.wat +++ b/winch/filetests/filetests/x64/i64_le_s/params.wat @@ -18,7 +18,7 @@ ;; 20: 4839c1 cmp rcx, rax ;; 23: b900000000 mov ecx, 0 ;; 28: 400f9ec1 setle cl -;; 2c: 4889c8 mov rax, rcx -;; 2f: 4883c418 add rsp, 0x18 -;; 33: 5d pop rbp -;; 34: c3 ret +;; 2c: 89c8 mov eax, ecx +;; 2e: 4883c418 add rsp, 0x18 +;; 32: 5d pop rbp +;; 33: c3 ret diff --git a/winch/filetests/filetests/x64/i64_le_u/locals.wat b/winch/filetests/filetests/x64/i64_le_u/locals.wat index 85eddc58343f..fcdcde159977 100644 --- a/winch/filetests/filetests/x64/i64_le_u/locals.wat +++ b/winch/filetests/filetests/x64/i64_le_u/locals.wat @@ -31,7 +31,7 @@ ;; 3b: 4839c1 cmp rcx, rax ;; 3e: b900000000 mov ecx, 0 ;; 43: 400f96c1 setbe cl -;; 47: 4889c8 mov rax, rcx -;; 4a: 4883c418 add rsp, 0x18 -;; 4e: 5d pop rbp -;; 4f: c3 ret +;; 47: 89c8 mov eax, ecx +;; 49: 4883c418 add rsp, 0x18 +;; 4d: 5d pop rbp +;; 4e: c3 ret diff --git a/winch/filetests/filetests/x64/i64_le_u/params.wat b/winch/filetests/filetests/x64/i64_le_u/params.wat index 113b16ffacad..11dd179ef606 100644 --- a/winch/filetests/filetests/x64/i64_le_u/params.wat +++ b/winch/filetests/filetests/x64/i64_le_u/params.wat @@ -18,7 +18,7 @@ ;; 20: 4839c1 cmp rcx, rax ;; 23: b900000000 mov ecx, 0 ;; 28: 400f96c1 setbe cl -;; 2c: 4889c8 mov rax, rcx -;; 2f: 4883c418 add rsp, 0x18 -;; 33: 5d pop rbp -;; 34: c3 ret +;; 2c: 89c8 mov eax, ecx +;; 2e: 4883c418 add rsp, 0x18 +;; 32: 5d pop rbp +;; 33: c3 ret diff --git a/winch/filetests/filetests/x64/i64_lt_s/locals.wat b/winch/filetests/filetests/x64/i64_lt_s/locals.wat index 0a10518f54c9..a22f1ff7037f 100644 --- a/winch/filetests/filetests/x64/i64_lt_s/locals.wat +++ b/winch/filetests/filetests/x64/i64_lt_s/locals.wat @@ -32,7 +32,7 @@ ;; 3b: 4839c1 cmp rcx, rax ;; 3e: b900000000 mov ecx, 0 ;; 43: 400f9cc1 setl cl -;; 47: 4889c8 mov rax, rcx -;; 4a: 4883c418 add rsp, 0x18 -;; 4e: 5d pop rbp -;; 4f: c3 ret +;; 47: 89c8 mov eax, ecx +;; 49: 4883c418 add rsp, 0x18 +;; 4d: 5d pop rbp +;; 4e: c3 ret diff --git a/winch/filetests/filetests/x64/i64_lt_s/params.wat b/winch/filetests/filetests/x64/i64_lt_s/params.wat index daafe27aa99d..2de32038d091 100644 --- a/winch/filetests/filetests/x64/i64_lt_s/params.wat +++ b/winch/filetests/filetests/x64/i64_lt_s/params.wat @@ -19,7 +19,7 @@ ;; 20: 4839c1 cmp rcx, rax ;; 23: b900000000 mov ecx, 0 ;; 28: 400f9cc1 setl cl -;; 2c: 4889c8 mov rax, rcx -;; 2f: 4883c418 add rsp, 0x18 -;; 33: 5d pop rbp -;; 34: c3 ret +;; 2c: 89c8 mov eax, ecx +;; 2e: 4883c418 add rsp, 0x18 +;; 32: 5d pop rbp +;; 33: c3 ret diff --git a/winch/filetests/filetests/x64/i64_lt_u/locals.wat b/winch/filetests/filetests/x64/i64_lt_u/locals.wat index eb5197430270..cd62dc77d1e0 100644 --- a/winch/filetests/filetests/x64/i64_lt_u/locals.wat +++ b/winch/filetests/filetests/x64/i64_lt_u/locals.wat @@ -31,7 +31,7 @@ ;; 3b: 4839c1 cmp rcx, rax ;; 3e: b900000000 mov ecx, 0 ;; 43: 400f92c1 setb cl -;; 47: 4889c8 mov rax, rcx -;; 4a: 4883c418 add rsp, 0x18 -;; 4e: 5d pop rbp -;; 4f: c3 ret +;; 47: 89c8 mov eax, ecx +;; 49: 4883c418 add rsp, 0x18 +;; 4d: 5d pop rbp +;; 4e: c3 ret diff --git a/winch/filetests/filetests/x64/i64_lt_u/params.wat b/winch/filetests/filetests/x64/i64_lt_u/params.wat index c0697c6614d0..a24abe412ce7 100644 --- a/winch/filetests/filetests/x64/i64_lt_u/params.wat +++ b/winch/filetests/filetests/x64/i64_lt_u/params.wat @@ -18,7 +18,7 @@ ;; 20: 4839c1 cmp rcx, rax ;; 23: b900000000 mov ecx, 0 ;; 28: 400f92c1 setb cl -;; 2c: 4889c8 mov rax, rcx -;; 2f: 4883c418 add rsp, 0x18 -;; 33: 5d pop rbp -;; 34: c3 ret +;; 2c: 89c8 mov eax, ecx +;; 2e: 4883c418 add rsp, 0x18 +;; 32: 5d pop rbp +;; 33: c3 ret diff --git a/winch/filetests/filetests/x64/i64_ne/locals.wat b/winch/filetests/filetests/x64/i64_ne/locals.wat index 49090a56e9e7..23655ea63721 100644 --- a/winch/filetests/filetests/x64/i64_ne/locals.wat +++ b/winch/filetests/filetests/x64/i64_ne/locals.wat @@ -32,7 +32,7 @@ ;; 3b: 4839c1 cmp rcx, rax ;; 3e: b900000000 mov ecx, 0 ;; 43: 400f95c1 setne cl -;; 47: 4889c8 mov rax, rcx -;; 4a: 4883c418 add rsp, 0x18 -;; 4e: 5d pop rbp -;; 4f: c3 ret +;; 47: 89c8 mov eax, ecx +;; 49: 4883c418 add rsp, 0x18 +;; 4d: 5d pop rbp +;; 4e: c3 ret diff --git a/winch/filetests/filetests/x64/i64_ne/params.wat b/winch/filetests/filetests/x64/i64_ne/params.wat index 0d08508c8f57..a77f746376f8 100644 --- a/winch/filetests/filetests/x64/i64_ne/params.wat +++ b/winch/filetests/filetests/x64/i64_ne/params.wat @@ -19,7 +19,7 @@ ;; 20: 4839c1 cmp rcx, rax ;; 23: b900000000 mov ecx, 0 ;; 28: 400f95c1 setne cl -;; 2c: 4889c8 mov rax, rcx -;; 2f: 4883c418 add rsp, 0x18 -;; 33: 5d pop rbp -;; 34: c3 ret +;; 2c: 89c8 mov eax, ecx +;; 2e: 4883c418 add rsp, 0x18 +;; 32: 5d pop rbp +;; 33: c3 ret From 2ac2015f2a09a8a703ddbf6da57d95f12ea66523 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Wed, 13 Dec 2023 19:45:49 +0100 Subject: [PATCH 10/14] [WASI] Dynamic `SocketAddr` check for outbound socket traffic (#7662) * Add API to WasiCtx for adding dynamic SocketAddr checks The user can now specify a closure which gets run any time a connection to an external address is attempted. If the closure returns true, the address is allowed, but if it returns false, the underlying pool is then checked. In otherwords, false does not imply denied, but rather, check the underlyin pool. Signed-off-by: Ryan Levick * Get rid of Pool in favor of just a closure Signed-off-by: Ryan Levick * Add a SocketAddrUse arg to the SocketAddrCheck Signed-off-by: Ryan Levick --------- Signed-off-by: Ryan Levick --- crates/wasi/src/preview2/ctx.rs | 102 +++++------------- .../src/preview2/host/instance_network.rs | 2 +- crates/wasi/src/preview2/host/network.rs | 52 +++++---- crates/wasi/src/preview2/host/tcp.rs | 13 ++- crates/wasi/src/preview2/host/udp.rs | 30 +++--- crates/wasi/src/preview2/network.rs | 54 +++++++++- crates/wasi/src/preview2/udp.rs | 13 ++- crates/wasi/tests/all/main.rs | 3 +- src/commands/run.rs | 2 +- 9 files changed, 134 insertions(+), 137 deletions(-) diff --git a/crates/wasi/src/preview2/ctx.rs b/crates/wasi/src/preview2/ctx.rs index d3d52408dc96..a0447711adf4 100644 --- a/crates/wasi/src/preview2/ctx.rs +++ b/crates/wasi/src/preview2/ctx.rs @@ -1,18 +1,17 @@ -use super::clocks::host::{monotonic_clock, wall_clock}; use crate::preview2::{ - clocks::{self, HostMonotonicClock, HostWallClock}, + clocks::{ + host::{monotonic_clock, wall_clock}, + HostMonotonicClock, HostWallClock, + }, filesystem::Dir, + network::{SocketAddrCheck, SocketAddrUse}, pipe, random, stdio, stdio::{StdinStream, StdoutStream}, DirPerms, FilePerms, }; use cap_rand::{Rng, RngCore, SeedableRng}; -use cap_std::ipnet::{self, IpNet}; -use cap_std::net::Pool; -use cap_std::{ambient_authority, AmbientAuthority}; -use std::mem; -use std::net::{Ipv4Addr, Ipv6Addr}; use std::sync::Arc; +use std::{mem, net::SocketAddr}; use wasmtime::component::ResourceTable; pub struct WasiCtxBuilder { @@ -22,8 +21,7 @@ pub struct WasiCtxBuilder { env: Vec<(String, String)>, args: Vec, preopens: Vec<(Dir, String)>, - - pool: Pool, + socket_addr_check: SocketAddrCheck, random: Box, insecure_random: Box, insecure_random_seed: u128, @@ -73,7 +71,7 @@ impl WasiCtxBuilder { env: Vec::new(), args: Vec::new(), preopens: Vec::new(), - pool: Pool::new(), + socket_addr_check: SocketAddrCheck::default(), random: random::thread_rng(), insecure_random, insecure_random_seed, @@ -173,80 +171,36 @@ impl WasiCtxBuilder { self.insecure_random = Box::new(insecure_random); self } + pub fn insecure_random_seed(&mut self, insecure_random_seed: u128) -> &mut Self { self.insecure_random_seed = insecure_random_seed; self } - pub fn wall_clock(&mut self, clock: impl clocks::HostWallClock + 'static) -> &mut Self { + pub fn wall_clock(&mut self, clock: impl HostWallClock + 'static) -> &mut Self { self.wall_clock = Box::new(clock); self } - pub fn monotonic_clock( - &mut self, - clock: impl clocks::HostMonotonicClock + 'static, - ) -> &mut Self { + pub fn monotonic_clock(&mut self, clock: impl HostMonotonicClock + 'static) -> &mut Self { self.monotonic_clock = Box::new(clock); self } - /// Add all network addresses accessable to the host to the pool. - pub fn inherit_network(&mut self, ambient_authority: AmbientAuthority) -> &mut Self { - self.pool.insert_ip_net_port_any( - IpNet::new(Ipv4Addr::UNSPECIFIED.into(), 0).unwrap(), - ambient_authority, - ); - self.pool.insert_ip_net_port_any( - IpNet::new(Ipv6Addr::UNSPECIFIED.into(), 0).unwrap(), - ambient_authority, - ); - self - } - - /// Add network addresses to the pool. - pub fn insert_addr( - &mut self, - addrs: A, - ) -> std::io::Result<&mut Self> { - self.pool.insert(addrs, ambient_authority())?; - Ok(self) - } - - /// Add a specific [`cap_std::net::SocketAddr`] to the pool. - pub fn insert_socket_addr(&mut self, addr: cap_std::net::SocketAddr) -> &mut Self { - self.pool.insert_socket_addr(addr, ambient_authority()); - self - } - - /// Add a range of network addresses, accepting any port, to the pool. - /// - /// Unlike `insert_ip_net`, this function grants access to any requested port. - pub fn insert_ip_net_port_any(&mut self, ip_net: ipnet::IpNet) -> &mut Self { - self.pool - .insert_ip_net_port_any(ip_net, ambient_authority()); - self + /// Allow all network addresses accessible to the host + pub fn inherit_network(&mut self) -> &mut Self { + self.socket_addr_check(|_, _| true) } - /// Add a range of network addresses, accepting a range of ports, to - /// per-instance networks. + /// A check that will be called for each socket address that is used. /// - /// This grants access to the port range starting at `ports_start` and, if - /// `ports_end` is provided, ending before `ports_end`. - pub fn insert_ip_net_port_range( - &mut self, - ip_net: ipnet::IpNet, - ports_start: u16, - ports_end: Option, - ) -> &mut Self { - self.pool - .insert_ip_net_port_range(ip_net, ports_start, ports_end, ambient_authority()); - self - } - - /// Add a range of network addresses with a specific port to the pool. - pub fn insert_ip_net(&mut self, ip_net: ipnet::IpNet, port: u16) -> &mut Self { - self.pool.insert_ip_net(ip_net, port, ambient_authority()); + /// Returning `true` will permit socket connections to the `SocketAddr`, + /// while returning `false` will reject the connection. + pub fn socket_addr_check(&mut self, check: F) -> &mut Self + where + F: Fn(&SocketAddr, SocketAddrUse) -> bool + Send + Sync + 'static, + { + self.socket_addr_check = SocketAddrCheck(Arc::new(check)); self } @@ -286,7 +240,7 @@ impl WasiCtxBuilder { env, args, preopens, - pool, + socket_addr_check, random, insecure_random, insecure_random_seed, @@ -304,7 +258,7 @@ impl WasiCtxBuilder { env, args, preopens, - pool: Arc::new(pool), + socket_addr_check, random, insecure_random, insecure_random_seed, @@ -334,7 +288,7 @@ pub struct WasiCtx { pub(crate) stdin: Box, pub(crate) stdout: Box, pub(crate) stderr: Box, - pub(crate) pool: Arc, + pub(crate) socket_addr_check: SocketAddrCheck, pub(crate) allowed_network_uses: AllowedNetworkUses, } @@ -360,8 +314,7 @@ impl AllowedNetworkUses { return Err(std::io::Error::new( std::io::ErrorKind::PermissionDenied, "UDP is not allowed", - ) - .into()); + )); } Ok(()) @@ -372,8 +325,7 @@ impl AllowedNetworkUses { return Err(std::io::Error::new( std::io::ErrorKind::PermissionDenied, "TCP is not allowed", - ) - .into()); + )); } Ok(()) diff --git a/crates/wasi/src/preview2/host/instance_network.rs b/crates/wasi/src/preview2/host/instance_network.rs index 428151dcc7c4..382bae913c0e 100644 --- a/crates/wasi/src/preview2/host/instance_network.rs +++ b/crates/wasi/src/preview2/host/instance_network.rs @@ -6,7 +6,7 @@ use wasmtime::component::Resource; impl instance_network::Host for T { fn instance_network(&mut self) -> Result, anyhow::Error> { let network = Network { - pool: self.ctx().pool.clone(), + socket_addr_check: self.ctx().socket_addr_check.clone(), allow_ip_name_lookup: self.ctx().allowed_network_uses.ip_name_lookup, }; let network = self.table_mut().push(network)?; diff --git a/crates/wasi/src/preview2/host/network.rs b/crates/wasi/src/preview2/host/network.rs index ddb4b7d63b2c..55dedb1b145d 100644 --- a/crates/wasi/src/preview2/host/network.rs +++ b/crates/wasi/src/preview2/host/network.rs @@ -218,7 +218,7 @@ pub(crate) mod util { use crate::preview2::bindings::sockets::network::ErrorCode; use crate::preview2::network::SocketAddressFamily; use crate::preview2::SocketResult; - use cap_net_ext::{Blocking, TcpBinder, TcpConnecter, TcpListenerExt, UdpBinder}; + use cap_net_ext::{Blocking, TcpListenerExt}; use cap_std::net::{TcpListener, TcpStream, UdpSocket}; use rustix::fd::AsFd; use rustix::io::Errno; @@ -302,42 +302,38 @@ pub(crate) mod util { * Syscalls wrappers with (opinionated) portability fixes. */ - pub fn tcp_bind(listener: &TcpListener, binder: &TcpBinder) -> std::io::Result<()> { - binder - .bind_existing_tcp_listener(listener) - .map_err(|error| match Errno::from_io_error(&error) { - // See: https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-bind#:~:text=WSAENOBUFS - // Windows returns WSAENOBUFS when the ephemeral ports have been exhausted. - #[cfg(windows)] - Some(Errno::NOBUFS) => Errno::ADDRINUSE.into(), - _ => error, - }) + pub fn tcp_bind(listener: &TcpListener, addr: &SocketAddr) -> std::io::Result<()> { + rustix::net::bind(listener, addr).map_err(|error| match error { + // See: https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-bind#:~:text=WSAENOBUFS + // Windows returns WSAENOBUFS when the ephemeral ports have been exhausted. + #[cfg(windows)] + Errno::NOBUFS => Errno::ADDRINUSE.into(), + _ => error.into(), + }) } - pub fn udp_bind(socket: &UdpSocket, binder: &UdpBinder) -> std::io::Result<()> { - binder.bind_existing_udp_socket(socket).map_err(|error| { - match Errno::from_io_error(&error) { + pub fn udp_bind(socket: &UdpSocket, addr: &SocketAddr) -> std::io::Result<()> { + rustix::net::bind(socket, addr).map_err(|error| { + match error { // See: https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-bind#:~:text=WSAENOBUFS // Windows returns WSAENOBUFS when the ephemeral ports have been exhausted. #[cfg(windows)] - Some(Errno::NOBUFS) => Errno::ADDRINUSE.into(), - _ => error, + Errno::NOBUFS => Errno::ADDRINUSE.into(), + _ => error.into(), } }) } - pub fn tcp_connect(listener: &TcpListener, connecter: &TcpConnecter) -> std::io::Result<()> { - connecter.connect_existing_tcp_listener(listener).map_err( - |error| match Errno::from_io_error(&error) { - // On POSIX, non-blocking `connect` returns `EINPROGRESS`. - // Windows returns `WSAEWOULDBLOCK`. - // - // This normalized error code is depended upon by: tcp.rs - #[cfg(windows)] - Some(Errno::WOULDBLOCK) => Errno::INPROGRESS.into(), - _ => error, - }, - ) + pub fn tcp_connect(listener: &TcpListener, addr: &SocketAddr) -> std::io::Result<()> { + rustix::net::connect(listener, addr).map_err(|error| match error { + // On POSIX, non-blocking `connect` returns `EINPROGRESS`. + // Windows returns `WSAEWOULDBLOCK`. + // + // This normalized error code is depended upon by: tcp.rs + #[cfg(windows)] + Errno::WOULDBLOCK => Errno::INPROGRESS.into(), + _ => error.into(), + }) } pub fn tcp_listen(listener: &TcpListener, backlog: Option) -> std::io::Result<()> { diff --git a/crates/wasi/src/preview2/host/tcp.rs b/crates/wasi/src/preview2/host/tcp.rs index 436a92367010..b1d4ba31f28c 100644 --- a/crates/wasi/src/preview2/host/tcp.rs +++ b/crates/wasi/src/preview2/host/tcp.rs @@ -1,4 +1,5 @@ use crate::preview2::host::network::util; +use crate::preview2::network::SocketAddrUse; use crate::preview2::tcp::{TcpSocket, TcpState}; use crate::preview2::{ bindings::{ @@ -9,7 +10,7 @@ use crate::preview2::{ network::SocketAddressFamily, }; use crate::preview2::{Pollable, SocketResult, WasiView}; -use cap_net_ext::{Blocking, PoolExt}; +use cap_net_ext::Blocking; use cap_std::net::TcpListener; use io_lifetimes::AsSocketlike; use rustix::io::Errno; @@ -44,11 +45,12 @@ impl crate::preview2::host::tcp::tcp::HostTcpSocket for T { util::validate_address_family(&local_address, &socket.family)?; { - let binder = network.pool.tcp_binder(local_address)?; + // Ensure that we're allowed to connect to this address. + network.check_socket_addr(&local_address, SocketAddrUse::TcpBind)?; let listener = &*socket.tcp_socket().as_socketlike_view::(); // Perform the OS bind call. - util::tcp_bind(listener, &binder).map_err(|error| { + util::tcp_bind(listener, &local_address).map_err(|error| { match Errno::from_io_error(&error) { // From https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html: // > [EAFNOSUPPORT] The specified address is not a valid address for the address family of the specified socket @@ -112,11 +114,12 @@ impl crate::preview2::host::tcp::tcp::HostTcpSocket for T { util::validate_remote_address(&remote_address)?; util::validate_address_family(&remote_address, &socket.family)?; - let connecter = network.pool.tcp_connecter(remote_address)?; + // Ensure that we're allowed to connect to this address. + network.check_socket_addr(&remote_address, SocketAddrUse::TcpConnect)?; let listener = &*socket.tcp_socket().as_socketlike_view::(); // Do an OS `connect`. Our socket is non-blocking, so it'll either... - util::tcp_connect(listener, &connecter) + util::tcp_connect(listener, &remote_address) }; match r { diff --git a/crates/wasi/src/preview2/host/udp.rs b/crates/wasi/src/preview2/host/udp.rs index cd6dd62c3b93..09ca8b5b9875 100644 --- a/crates/wasi/src/preview2/host/udp.rs +++ b/crates/wasi/src/preview2/host/udp.rs @@ -1,5 +1,5 @@ use crate::preview2::host::network::util; -use crate::preview2::network::SocketAddressFamily; +use crate::preview2::network::{SocketAddrUse, SocketAddressFamily}; use crate::preview2::{ bindings::{ sockets::network::{ErrorCode, IpAddressFamily, IpSocketAddress, Network}, @@ -11,7 +11,6 @@ use crate::preview2::{ use crate::preview2::{Pollable, SocketError, SocketResult, WasiView}; use anyhow::anyhow; use async_trait::async_trait; -use cap_net_ext::PoolExt; use io_lifetimes::AsSocketlike; use rustix::io::Errno; use rustix::net::sockopt; @@ -42,9 +41,12 @@ impl udp::HostUdpSocket for T { UdpState::Bound | UdpState::Connected => return Err(ErrorCode::InvalidState.into()), } - // Set the pool on the socket so later functions have access to it through the socket handle - let pool = table.get(&network)?.pool.clone(); - table.get_mut(&this)?.pool.replace(pool.clone()); + // Set the socket addr check on the socket so later functions have access to it through the socket handle + let check = table.get(&network)?.socket_addr_check.clone(); + table + .get_mut(&this)? + .socket_addr_check + .replace(check.clone()); let socket = table.get(&this)?; let local_address: SocketAddr = local_address.into(); @@ -52,13 +54,13 @@ impl udp::HostUdpSocket for T { util::validate_address_family(&local_address, &socket.family)?; { - let binder = pool.udp_binder(local_address)?; + check.check(&local_address, SocketAddrUse::UdpBind)?; let udp_socket = &*socket .udp_socket() .as_socketlike_view::(); // Perform the OS bind call. - util::udp_bind(udp_socket, &binder).map_err(|error| { + util::udp_bind(udp_socket, &local_address).map_err(|error| { match Errno::from_io_error(&error) { // From https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html: // > [EAFNOSUPPORT] The specified address is not a valid address for the address family of the specified socket @@ -132,13 +134,12 @@ impl udp::HostUdpSocket for T { // Step #2: (Re)connect if let Some(connect_addr) = remote_address { - let Some(pool) = socket.pool.as_ref() else { + let Some(check) = socket.socket_addr_check.as_ref() else { return Err(ErrorCode::InvalidState.into()); }; util::validate_remote_address(&connect_addr)?; util::validate_address_family(&connect_addr, &socket.family)?; - // We don't actually use the connecter, we just use it to verify that `connect_addr` is allowed - let _ = pool.udp_connecter(connect_addr)?; + check.check(&connect_addr, SocketAddrUse::UdpConnect)?; rustix::net::connect(socket.udp_socket(), &connect_addr).map_err( |error| match error { @@ -162,7 +163,7 @@ impl udp::HostUdpSocket for T { remote_address, family: socket.family, send_state: SendState::Idle, - pool: socket.pool.clone(), + socket_addr_check: socket.socket_addr_check.clone(), }; Ok(( @@ -458,13 +459,10 @@ impl udp::HostOutgoingDatagramStream for T { let provided_addr = datagram.remote_address.map(SocketAddr::from); let addr = match (stream.remote_address, provided_addr) { (None, Some(addr)) => { - let Some(pool) = stream.pool.as_ref() else { + let Some(check) = stream.socket_addr_check.as_ref() else { return Err(ErrorCode::InvalidState.into()); }; - // We don't actually use the connecter, we just use it to verify that `addr` - // is allowed. We only need to check the provided addr as the stream's remote - // address was checked when the stream was created. - let _ = pool.udp_connecter(addr)?; + check.check(&addr, SocketAddrUse::UdpOutgoingDatagram)?; addr } (Some(addr), None) => addr, diff --git a/crates/wasi/src/preview2/network.rs b/crates/wasi/src/preview2/network.rs index 6384b1803981..0cd86cba8fe2 100644 --- a/crates/wasi/src/preview2/network.rs +++ b/crates/wasi/src/preview2/network.rs @@ -1,14 +1,64 @@ use crate::preview2::bindings::sockets::network::{Ipv4Address, Ipv6Address}; use crate::preview2::bindings::wasi::sockets::network::ErrorCode; use crate::preview2::TrappableError; -use cap_std::net::Pool; +use std::net::SocketAddr; use std::sync::Arc; pub struct Network { - pub pool: Arc, + pub socket_addr_check: SocketAddrCheck, pub allow_ip_name_lookup: bool, } +impl Network { + pub fn check_socket_addr( + &self, + addr: &SocketAddr, + reason: SocketAddrUse, + ) -> std::io::Result<()> { + self.socket_addr_check.check(addr, reason) + } +} + +/// A check that will be called for each socket address that is used of whether the address is permitted. +#[derive(Clone)] +pub struct SocketAddrCheck( + pub(crate) Arc bool + Send + Sync>, +); + +impl SocketAddrCheck { + pub fn check(&self, addr: &SocketAddr, reason: SocketAddrUse) -> std::io::Result<()> { + if (self.0)(addr, reason) { + Ok(()) + } else { + Err(std::io::Error::new( + std::io::ErrorKind::PermissionDenied, + "An address was not permitted by the socket address check.", + )) + } + } +} + +impl Default for SocketAddrCheck { + fn default() -> Self { + Self(Arc::new(|_, _| false)) + } +} + +/// The reason what a socket address is being used for. +#[derive(Clone, Copy, Debug)] +pub enum SocketAddrUse { + /// Binding TCP socket + TcpBind, + /// Connecting TCP socket + TcpConnect, + /// Binding UDP socket + UdpBind, + /// Connecting UDP socket + UdpConnect, + /// Sending datagram on non-connected UDP socket + UdpOutgoingDatagram, +} + pub type SocketResult = Result; pub type SocketError = TrappableError; diff --git a/crates/wasi/src/preview2/udp.rs b/crates/wasi/src/preview2/udp.rs index 13194c1f512e..70e35ba44e73 100644 --- a/crates/wasi/src/preview2/udp.rs +++ b/crates/wasi/src/preview2/udp.rs @@ -2,13 +2,12 @@ use crate::preview2::poll::Subscribe; use crate::preview2::with_ambient_tokio_runtime; use async_trait::async_trait; use cap_net_ext::{AddressFamily, Blocking, UdpSocketExt}; -use cap_std::net::Pool; use io_lifetimes::raw::{FromRawSocketlike, IntoRawSocketlike}; use std::io; use std::net::SocketAddr; use std::sync::Arc; -use super::network::SocketAddressFamily; +use super::network::{SocketAddrCheck, SocketAddressFamily}; /// The state of a UDP socket. /// @@ -44,8 +43,8 @@ pub struct UdpSocket { /// Socket address family. pub(crate) family: SocketAddressFamily, - /// The pool of allowed addresses - pub(crate) pool: Option>, + /// The check of allowed addresses + pub(crate) socket_addr_check: Option, } #[async_trait] @@ -71,7 +70,7 @@ impl UdpSocket { inner: Arc::new(socket), udp_state: UdpState::Default, family: socket_address_family, - pool: None, + socket_addr_check: None, }) } @@ -110,8 +109,8 @@ pub struct OutgoingDatagramStream { pub(crate) send_state: SendState, - /// The pool of allowed addresses - pub(crate) pool: Option>, + /// The check of allowed addresses + pub(crate) socket_addr_check: Option, } pub(crate) enum SendState { diff --git a/crates/wasi/tests/all/main.rs b/crates/wasi/tests/all/main.rs index 03cf8031b157..eaf9a766edd1 100644 --- a/crates/wasi/tests/all/main.rs +++ b/crates/wasi/tests/all/main.rs @@ -1,5 +1,4 @@ use anyhow::Result; -use cap_std::ambient_authority; use tempfile::TempDir; use wasmtime::{ component::{Component, Linker, ResourceTable}, @@ -64,7 +63,7 @@ fn store(engine: &Engine, name: &str, inherit_stdio: bool) -> Result<(Store builder .args(&[name, "."]) - .inherit_network(ambient_authority()) + .inherit_network() .allow_ip_name_lookup(true); println!("preopen: {:?}", workspace); let preopen_dir = diff --git a/src/commands/run.rs b/src/commands/run.rs index 964a50bdeb9c..81c724bd7c48 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -772,7 +772,7 @@ impl RunCommand { } if self.run.common.wasi.inherit_network == Some(true) { - builder.inherit_network(ambient_authority()); + builder.inherit_network(); } if let Some(enable) = self.run.common.wasi.allow_ip_name_lookup { builder.allow_ip_name_lookup(enable); From 3a7706675099cedd4362b572920db260b5576cf8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 13 Dec 2023 12:46:04 -0600 Subject: [PATCH 11/14] Add release notes for Wasmtime 16 (#7678) --- RELEASES.md | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 8c60992f147a..03f2b857f015 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -16,8 +16,69 @@ Unreleased. ### Added +* Add yielding support in `wasmtime_store_epoch_deadline_callback` in the C API. + [#7476](https://github.com/bytecodealliance/wasmtime/pull/7476) + +* Support for the `wasi_unstable` module ("wasi preview0" canonically) has been + added to the `-Spreview2` support in the CLI. + [#7548](https://github.com/bytecodealliance/wasmtime/pull/7548) + +* The original module can now be obtained from an "instance pre" in the C API. + [#7572](https://github.com/bytecodealliance/wasmtime/pull/7572) + +* Usage of Mach ports on macOS can now be disabled in the C API. + [#7595](https://github.com/bytecodealliance/wasmtime/pull/7595) + ### Changed +* The preview1-to-preview2 component adapters now import a smaller number of + interfaces by default. + [#7543](https://github.com/bytecodealliance/wasmtime/pull/7543) + [#7544](https://github.com/bytecodealliance/wasmtime/pull/7544) + +* Wasmtime and Cranelift now require Rust 1.72.0 to build. + [#7554](https://github.com/bytecodealliance/wasmtime/pull/7554) + +* The default `world` supported by `wasmtime serve` has been slimmed down to + exactly what `wasi:http/proxy` specifies by default. Support for other WASI + APIs can be included with the `-S common` command-line flag. + [#7597](https://github.com/bytecodealliance/wasmtime/pull/7597) + +* The `wasmtime --version` CLI output will now include date/commit information + when Wasmtime is built from a git checkout. + [#7610](https://github.com/bytecodealliance/wasmtime/pull/7610) + +### Fixed + +* MPK support is now explicitly disabled on AMD-based CPUs since the + implementation does not currently support it. + [#7513](https://github.com/bytecodealliance/wasmtime/pull/7513) + +* Initialization of a WebAssembly data segment with a negative offset is fixed + to zero-extend the offset instead of sign-extend. + [#7559](https://github.com/bytecodealliance/wasmtime/pull/7559) + +* The reported offset of `O_APPEND` files in preview1 has been fixed. + [#7586](https://github.com/bytecodealliance/wasmtime/pull/7586) + +* MPK support does a better job of compacting memories to minimize virtual + memory used. + [#7622](https://github.com/bytecodealliance/wasmtime/pull/7622) + +### Cranelift + +* Union node bitpacking has been fixed with egraph optimizations to ensure the + minimal cost node is selected. + [#7465](https://github.com/bytecodealliance/wasmtime/pull/7465) + +* Equivalent-cost expressions now have ties broken with expression depth in + egraphs to prefer "shallow" expression trees. + [#7456](https://github.com/bytecodealliance/wasmtime/pull/7456) + +* Long-and-narrow chains of expressions are now optimized into shallow-and-wide + trees. + [#7466](https://github.com/bytecodealliance/wasmtime/pull/7466) + -------------------------------------------------------------------------------- ## 15.0.1 From 3b055d4776abe826b093b5acfbd53838255ca764 Mon Sep 17 00:00:00 2001 From: Jeffrey Charles Date: Wed, 13 Dec 2023 13:54:03 -0800 Subject: [PATCH 12/14] Winch: integer conversion instructions (#7683) --- fuzz/fuzz_targets/differential.rs | 8 ++ tests/misc_testsuite/winch/conversions.wast | 38 +++++++++ tests/misc_testsuite/winch/i32.wast | 18 ++++ tests/misc_testsuite/winch/i64.wast | 30 +++++++ winch/codegen/src/isa/aarch64/masm.rs | 13 ++- winch/codegen/src/isa/x64/asm.rs | 34 +++++++- winch/codegen/src/isa/x64/masm.rs | 16 +++- winch/codegen/src/masm.rs | 26 ++++++ winch/codegen/src/visitor.rs | 84 ++++++++++++++++++- .../filetests/x64/i32_extend_16_s/const.wat | 17 ++++ .../filetests/x64/i32_extend_16_s/locals.wat | 21 +++++ .../filetests/x64/i32_extend_16_s/params.wat | 18 ++++ .../filetests/x64/i32_extend_8_s/const.wat | 17 ++++ .../filetests/x64/i32_extend_8_s/locals.wat | 21 +++++ .../filetests/x64/i32_extend_8_s/params.wat | 18 ++++ .../filetests/x64/i32_wrap_i64/const.wat | 17 ++++ .../filetests/x64/i32_wrap_i64/locals.wat | 21 +++++ .../filetests/x64/i32_wrap_i64/params.wat | 18 ++++ .../filetests/x64/i32_wrap_i64/spilled.wat | 23 +++++ .../filetests/x64/i64_extend_16_s/const.wat | 17 ++++ .../filetests/x64/i64_extend_16_s/locals.wat | 21 +++++ .../filetests/x64/i64_extend_16_s/params.wat | 18 ++++ .../filetests/x64/i64_extend_32_s/const.wat | 17 ++++ .../filetests/x64/i64_extend_32_s/locals.wat | 21 +++++ .../filetests/x64/i64_extend_32_s/params.wat | 18 ++++ .../filetests/x64/i64_extend_8_s/const.wat | 17 ++++ .../filetests/x64/i64_extend_8_s/locals.wat | 21 +++++ .../filetests/x64/i64_extend_8_s/params.wat | 18 ++++ .../filetests/x64/i64_extend_i32_s/const.wat | 17 ++++ .../filetests/x64/i64_extend_i32_s/locals.wat | 21 +++++ .../filetests/x64/i64_extend_i32_s/params.wat | 18 ++++ .../x64/i64_extend_i32_s/spilled.wat | 21 +++++ .../filetests/x64/i64_extend_i32_u/const.wat | 17 ++++ .../filetests/x64/i64_extend_i32_u/locals.wat | 21 +++++ .../filetests/x64/i64_extend_i32_u/params.wat | 18 ++++ .../x64/i64_extend_i32_u/spilled.wat | 21 +++++ 36 files changed, 773 insertions(+), 7 deletions(-) create mode 100644 tests/misc_testsuite/winch/conversions.wast create mode 100644 winch/filetests/filetests/x64/i32_extend_16_s/const.wat create mode 100644 winch/filetests/filetests/x64/i32_extend_16_s/locals.wat create mode 100644 winch/filetests/filetests/x64/i32_extend_16_s/params.wat create mode 100644 winch/filetests/filetests/x64/i32_extend_8_s/const.wat create mode 100644 winch/filetests/filetests/x64/i32_extend_8_s/locals.wat create mode 100644 winch/filetests/filetests/x64/i32_extend_8_s/params.wat create mode 100644 winch/filetests/filetests/x64/i32_wrap_i64/const.wat create mode 100644 winch/filetests/filetests/x64/i32_wrap_i64/locals.wat create mode 100644 winch/filetests/filetests/x64/i32_wrap_i64/params.wat create mode 100644 winch/filetests/filetests/x64/i32_wrap_i64/spilled.wat create mode 100644 winch/filetests/filetests/x64/i64_extend_16_s/const.wat create mode 100644 winch/filetests/filetests/x64/i64_extend_16_s/locals.wat create mode 100644 winch/filetests/filetests/x64/i64_extend_16_s/params.wat create mode 100644 winch/filetests/filetests/x64/i64_extend_32_s/const.wat create mode 100644 winch/filetests/filetests/x64/i64_extend_32_s/locals.wat create mode 100644 winch/filetests/filetests/x64/i64_extend_32_s/params.wat create mode 100644 winch/filetests/filetests/x64/i64_extend_8_s/const.wat create mode 100644 winch/filetests/filetests/x64/i64_extend_8_s/locals.wat create mode 100644 winch/filetests/filetests/x64/i64_extend_8_s/params.wat create mode 100644 winch/filetests/filetests/x64/i64_extend_i32_s/const.wat create mode 100644 winch/filetests/filetests/x64/i64_extend_i32_s/locals.wat create mode 100644 winch/filetests/filetests/x64/i64_extend_i32_s/params.wat create mode 100644 winch/filetests/filetests/x64/i64_extend_i32_s/spilled.wat create mode 100644 winch/filetests/filetests/x64/i64_extend_i32_u/const.wat create mode 100644 winch/filetests/filetests/x64/i64_extend_i32_u/locals.wat create mode 100644 winch/filetests/filetests/x64/i64_extend_i32_u/params.wat create mode 100644 winch/filetests/filetests/x64/i64_extend_i32_u/spilled.wat diff --git a/fuzz/fuzz_targets/differential.rs b/fuzz/fuzz_targets/differential.rs index 648923768915..e166fa069d03 100644 --- a/fuzz/fuzz_targets/differential.rs +++ b/fuzz/fuzz_targets/differential.rs @@ -369,6 +369,14 @@ fn winch_supports_module(module: &[u8]) -> bool { | I64Ctz { .. } | I32Popcnt { .. } | I64Popcnt { .. } + | I32WrapI64 { .. } + | I64ExtendI32S { .. } + | I64ExtendI32U { .. } + | I32Extend8S { .. } + | I32Extend16S { .. } + | I64Extend8S { .. } + | I64Extend16S { .. } + | I64Extend32S { .. } | LocalGet { .. } | LocalSet { .. } | LocalTee { .. } diff --git a/tests/misc_testsuite/winch/conversions.wast b/tests/misc_testsuite/winch/conversions.wast new file mode 100644 index 000000000000..6f84e57d2421 --- /dev/null +++ b/tests/misc_testsuite/winch/conversions.wast @@ -0,0 +1,38 @@ +(module + (func (export "i64.extend_i32_s") (param $x i32) (result i64) (i64.extend_i32_s (local.get $x))) + (func (export "i64.extend_i32_u") (param $x i32) (result i64) (i64.extend_i32_u (local.get $x))) + (func (export "i32.wrap_i64") (param $x i64) (result i32) (i32.wrap_i64 (local.get $x))) +) + +(assert_return (invoke "i64.extend_i32_s" (i32.const 0)) (i64.const 0)) +(assert_return (invoke "i64.extend_i32_s" (i32.const 10000)) (i64.const 10000)) +(assert_return (invoke "i64.extend_i32_s" (i32.const -10000)) (i64.const -10000)) +(assert_return (invoke "i64.extend_i32_s" (i32.const -1)) (i64.const -1)) +(assert_return (invoke "i64.extend_i32_s" (i32.const 0x7fffffff)) (i64.const 0x000000007fffffff)) +(assert_return (invoke "i64.extend_i32_s" (i32.const 0x80000000)) (i64.const 0xffffffff80000000)) + +(assert_return (invoke "i64.extend_i32_u" (i32.const 0)) (i64.const 0)) +(assert_return (invoke "i64.extend_i32_u" (i32.const 10000)) (i64.const 10000)) +(assert_return (invoke "i64.extend_i32_u" (i32.const -10000)) (i64.const 0x00000000ffffd8f0)) +(assert_return (invoke "i64.extend_i32_u" (i32.const -1)) (i64.const 0xffffffff)) +(assert_return (invoke "i64.extend_i32_u" (i32.const 0x7fffffff)) (i64.const 0x000000007fffffff)) +(assert_return (invoke "i64.extend_i32_u" (i32.const 0x80000000)) (i64.const 0x0000000080000000)) + +(assert_return (invoke "i32.wrap_i64" (i64.const -1)) (i32.const -1)) +(assert_return (invoke "i32.wrap_i64" (i64.const -100000)) (i32.const -100000)) +(assert_return (invoke "i32.wrap_i64" (i64.const 0x80000000)) (i32.const 0x80000000)) +(assert_return (invoke "i32.wrap_i64" (i64.const 0xffffffff7fffffff)) (i32.const 0x7fffffff)) +(assert_return (invoke "i32.wrap_i64" (i64.const 0xffffffff00000000)) (i32.const 0x00000000)) +(assert_return (invoke "i32.wrap_i64" (i64.const 0xfffffffeffffffff)) (i32.const 0xffffffff)) +(assert_return (invoke "i32.wrap_i64" (i64.const 0xffffffff00000001)) (i32.const 0x00000001)) +(assert_return (invoke "i32.wrap_i64" (i64.const 0)) (i32.const 0)) +(assert_return (invoke "i32.wrap_i64" (i64.const 1311768467463790320)) (i32.const 0x9abcdef0)) +(assert_return (invoke "i32.wrap_i64" (i64.const 0x00000000ffffffff)) (i32.const 0xffffffff)) +(assert_return (invoke "i32.wrap_i64" (i64.const 0x0000000100000000)) (i32.const 0x00000000)) +(assert_return (invoke "i32.wrap_i64" (i64.const 0x0000000100000001)) (i32.const 0x00000001)) + +;; Type check + +(assert_invalid (module (func (result i32) (i32.wrap_i64 (f32.const 0)))) "type mismatch") +(assert_invalid (module (func (result i64) (i64.extend_i32_s (f32.const 0)))) "type mismatch") +(assert_invalid (module (func (result i64) (i64.extend_i32_u (f32.const 0)))) "type mismatch") diff --git a/tests/misc_testsuite/winch/i32.wast b/tests/misc_testsuite/winch/i32.wast index 8a06d0914500..e4084be3fa8d 100644 --- a/tests/misc_testsuite/winch/i32.wast +++ b/tests/misc_testsuite/winch/i32.wast @@ -19,6 +19,8 @@ (func (export "clz") (param $x i32) (result i32) (i32.clz (local.get $x))) (func (export "ctz") (param $x i32) (result i32) (i32.ctz (local.get $x))) (func (export "popcnt") (param $x i32) (result i32) (i32.popcnt (local.get $x))) + (func (export "extend8_s") (param $x i32) (result i32) (i32.extend8_s (local.get $x))) + (func (export "extend16_s") (param $x i32) (result i32) (i32.extend16_s (local.get $x))) (func (export "eqz") (param $x i32) (result i32) (i32.eqz (local.get $x))) (func (export "eq") (param $x i32) (param $y i32) (result i32) (i32.eq (local.get $x) (local.get $y))) (func (export "ne") (param $x i32) (param $y i32) (result i32) (i32.ne (local.get $x) (local.get $y))) @@ -265,6 +267,22 @@ (assert_return (invoke "popcnt" (i32.const 0x55555555)) (i32.const 16)) (assert_return (invoke "popcnt" (i32.const 0xDEADBEEF)) (i32.const 24)) +(assert_return (invoke "extend8_s" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "extend8_s" (i32.const 0x7f)) (i32.const 127)) +(assert_return (invoke "extend8_s" (i32.const 0x80)) (i32.const -128)) +(assert_return (invoke "extend8_s" (i32.const 0xff)) (i32.const -1)) +(assert_return (invoke "extend8_s" (i32.const 0x012345_00)) (i32.const 0)) +(assert_return (invoke "extend8_s" (i32.const 0xfedcba_80)) (i32.const -0x80)) +(assert_return (invoke "extend8_s" (i32.const -1)) (i32.const -1)) + +(assert_return (invoke "extend16_s" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "extend16_s" (i32.const 0x7fff)) (i32.const 32767)) +(assert_return (invoke "extend16_s" (i32.const 0x8000)) (i32.const -32768)) +(assert_return (invoke "extend16_s" (i32.const 0xffff)) (i32.const -1)) +(assert_return (invoke "extend16_s" (i32.const 0x0123_0000)) (i32.const 0)) +(assert_return (invoke "extend16_s" (i32.const 0xfedc_8000)) (i32.const -0x8000)) +(assert_return (invoke "extend16_s" (i32.const -1)) (i32.const -1)) + (assert_return (invoke "eqz" (i32.const 0)) (i32.const 1)) (assert_return (invoke "eqz" (i32.const 1)) (i32.const 0)) (assert_return (invoke "eqz" (i32.const 0x80000000)) (i32.const 0)) diff --git a/tests/misc_testsuite/winch/i64.wast b/tests/misc_testsuite/winch/i64.wast index 1783c61782d1..73aa4c19cd27 100644 --- a/tests/misc_testsuite/winch/i64.wast +++ b/tests/misc_testsuite/winch/i64.wast @@ -19,6 +19,9 @@ (func (export "clz") (param $x i64) (result i64) (i64.clz (local.get $x))) (func (export "ctz") (param $x i64) (result i64) (i64.ctz (local.get $x))) (func (export "popcnt") (param $x i64) (result i64) (i64.popcnt (local.get $x))) + (func (export "extend8_s") (param $x i64) (result i64) (i64.extend8_s (local.get $x))) + (func (export "extend16_s") (param $x i64) (result i64) (i64.extend16_s (local.get $x))) + (func (export "extend32_s") (param $x i64) (result i64) (i64.extend32_s (local.get $x))) (func (export "eqz") (param $x i64) (result i32) (i64.eqz (local.get $x))) (func (export "eq") (param $x i64) (param $y i64) (result i32) (i64.eq (local.get $x) (local.get $y))) (func (export "ne") (param $x i64) (param $y i64) (result i32) (i64.ne (local.get $x) (local.get $y))) @@ -265,6 +268,33 @@ (assert_return (invoke "popcnt" (i64.const 0x99999999AAAAAAAA)) (i64.const 32)) (assert_return (invoke "popcnt" (i64.const 0xDEADBEEFDEADBEEF)) (i64.const 48)) +(assert_return (invoke "extend8_s" (i64.const 0)) (i64.const 0)) +(assert_return (invoke "extend8_s" (i64.const 0x7f)) (i64.const 127)) +(assert_return (invoke "extend8_s" (i64.const 0x80)) (i64.const -128)) +(assert_return (invoke "extend8_s" (i64.const 0xff)) (i64.const -1)) +(assert_return (invoke "extend8_s" (i64.const 0x01234567_89abcd_00)) (i64.const 0)) +(assert_return (invoke "extend8_s" (i64.const 0xfedcba98_765432_80)) (i64.const -0x80)) +(assert_return (invoke "extend8_s" (i64.const -1)) (i64.const -1)) + +(assert_return (invoke "extend16_s" (i64.const 0)) (i64.const 0)) +(assert_return (invoke "extend16_s" (i64.const 0x7fff)) (i64.const 32767)) +(assert_return (invoke "extend16_s" (i64.const 0x8000)) (i64.const -32768)) +(assert_return (invoke "extend16_s" (i64.const 0xffff)) (i64.const -1)) +(assert_return (invoke "extend16_s" (i64.const 0x12345678_9abc_0000)) (i64.const 0)) +(assert_return (invoke "extend16_s" (i64.const 0xfedcba98_7654_8000)) (i64.const -0x8000)) +(assert_return (invoke "extend16_s" (i64.const -1)) (i64.const -1)) + +(assert_return (invoke "extend32_s" (i64.const 0)) (i64.const 0)) +(assert_return (invoke "extend32_s" (i64.const 0x7fff)) (i64.const 32767)) +(assert_return (invoke "extend32_s" (i64.const 0x8000)) (i64.const 32768)) +(assert_return (invoke "extend32_s" (i64.const 0xffff)) (i64.const 65535)) +(assert_return (invoke "extend32_s" (i64.const 0x7fffffff)) (i64.const 0x7fffffff)) +(assert_return (invoke "extend32_s" (i64.const 0x80000000)) (i64.const -0x80000000)) +(assert_return (invoke "extend32_s" (i64.const 0xffffffff)) (i64.const -1)) +(assert_return (invoke "extend32_s" (i64.const 0x01234567_00000000)) (i64.const 0)) +(assert_return (invoke "extend32_s" (i64.const 0xfedcba98_80000000)) (i64.const -0x80000000)) +(assert_return (invoke "extend32_s" (i64.const -1)) (i64.const -1)) + (assert_return (invoke "eqz" (i64.const 0)) (i32.const 1)) (assert_return (invoke "eqz" (i64.const 1)) (i32.const 0)) (assert_return (invoke "eqz" (i64.const 0x8000000000000000)) (i32.const 0)) diff --git a/winch/codegen/src/isa/aarch64/masm.rs b/winch/codegen/src/isa/aarch64/masm.rs index 06dfef32601b..74ce2d96e093 100644 --- a/winch/codegen/src/isa/aarch64/masm.rs +++ b/winch/codegen/src/isa/aarch64/masm.rs @@ -4,8 +4,9 @@ use crate::{ codegen::{ptr_type_from_ptr_size, CodeGenContext, TableData}, isa::reg::Reg, masm::{ - CalleeKind, DivKind, FloatCmpKind, Imm as I, IntCmpKind, MacroAssembler as Masm, - OperandSize, RegImm, RemKind, RoundingMode, SPOffset, ShiftKind, StackSlot, TrapCode, + CalleeKind, DivKind, ExtendKind, FloatCmpKind, Imm as I, IntCmpKind, + MacroAssembler as Masm, OperandSize, RegImm, RemKind, RoundingMode, SPOffset, ShiftKind, + StackSlot, TrapCode, }, }; use cranelift_codegen::{settings, Final, MachBufferFinalized, MachLabel}; @@ -382,6 +383,14 @@ impl Masm for MacroAssembler { todo!() } + fn wrap(&mut self, _src: Reg, _dst: Reg) { + todo!() + } + + fn extend(&mut self, _src: Reg, _dst: Reg, _kind: ExtendKind) { + todo!() + } + fn get_label(&mut self) -> MachLabel { self.asm.get_label() } diff --git a/winch/codegen/src/isa/x64/asm.rs b/winch/codegen/src/isa/x64/asm.rs index f4ce1be6d40e..9fa1d1cb51dd 100644 --- a/winch/codegen/src/isa/x64/asm.rs +++ b/winch/codegen/src/isa/x64/asm.rs @@ -2,7 +2,7 @@ use crate::{ isa::reg::Reg, - masm::{DivKind, IntCmpKind, OperandSize, RemKind, RoundingMode, ShiftKind}, + masm::{DivKind, ExtendKind, IntCmpKind, OperandSize, RemKind, RoundingMode, ShiftKind}, }; use cranelift_codegen::{ entity::EntityRef, @@ -132,6 +132,20 @@ impl From for CraneliftShiftKind { } } +impl From for ExtMode { + fn from(value: ExtendKind) -> Self { + match value { + ExtendKind::I64ExtendI32S | ExtendKind::I64ExtendI32U | ExtendKind::I64Extend32S => { + ExtMode::LQ + } + ExtendKind::I32Extend8S => ExtMode::BL, + ExtendKind::I32Extend16S => ExtMode::WL, + ExtendKind::I64Extend8S => ExtMode::BQ, + ExtendKind::I64Extend16S => ExtMode::WQ, + } + } +} + /// Low level assembler implementation for x64. pub(crate) struct Assembler { /// The machine instruction buffer. @@ -301,6 +315,24 @@ impl Assembler { } } + /// Register-to-register move with zero extension. + pub fn movzx_rr(&mut self, src: Reg, dst: Reg, kind: ExtendKind) { + self.emit(Inst::MovzxRmR { + ext_mode: kind.into(), + src: src.into(), + dst: dst.into(), + }) + } + + /// Register-to-register move with sign extension. + pub fn movsx_rr(&mut self, src: Reg, dst: Reg, kind: ExtendKind) { + self.emit(Inst::MovsxRmR { + ext_mode: kind.into(), + src: src.into(), + dst: dst.into(), + }); + } + /// Integer register conditional move. pub fn cmov(&mut self, src: Reg, dst: Reg, cc: IntCmpKind, size: OperandSize) { self.emit(Inst::Cmove { diff --git a/winch/codegen/src/isa/x64/masm.rs b/winch/codegen/src/isa/x64/masm.rs index 15c108aaeb09..c5ea1ac886e2 100644 --- a/winch/codegen/src/isa/x64/masm.rs +++ b/winch/codegen/src/isa/x64/masm.rs @@ -6,8 +6,8 @@ use super::{ }; use crate::masm::{ - DivKind, FloatCmpKind, Imm as I, IntCmpKind, MacroAssembler as Masm, OperandSize, RegImm, - RemKind, RoundingMode, ShiftKind, TrapCode, + DivKind, ExtendKind, FloatCmpKind, Imm as I, IntCmpKind, MacroAssembler as Masm, OperandSize, + RegImm, RemKind, RoundingMode, ShiftKind, TrapCode, }; use crate::{ abi::ABI, @@ -904,6 +904,18 @@ impl Masm for MacroAssembler { } } + fn wrap(&mut self, src: Reg, dst: Reg) { + self.asm.mov_rr(src.into(), dst.into(), OperandSize::S32); + } + + fn extend(&mut self, src: Reg, dst: Reg, kind: ExtendKind) { + if let ExtendKind::I64ExtendI32U = kind { + self.asm.movzx_rr(src, dst, kind); + } else { + self.asm.movsx_rr(src, dst, kind); + } + } + fn unreachable(&mut self) { self.asm.trap(TrapCode::UnreachableCodeReached) } diff --git a/winch/codegen/src/masm.rs b/winch/codegen/src/masm.rs index b4613635ad4e..42ea92f97420 100644 --- a/winch/codegen/src/masm.rs +++ b/winch/codegen/src/masm.rs @@ -114,6 +114,26 @@ pub(crate) enum ShiftKind { Rotr, } +/// Kinds of extends in WebAssembly. The [`masm`] implementation for each ISA +/// is responsible for emitting the correct sequence of instructions when +/// lowering to machine code. +pub(crate) enum ExtendKind { + /// Sign extends i32 to i64. + I64ExtendI32S, + /// Zero extends i32 to i64. + I64ExtendI32U, + // Sign extends the 8 least significant bits to 32 bits. + I32Extend8S, + // Sign extends the 16 least significant bits to 32 bits. + I32Extend16S, + /// Sign extends the 8 least significant bits to 64 bits. + I64Extend8S, + /// Sign extends the 16 least significant bits to 64 bits. + I64Extend16S, + /// Sign extends the 32 least significant bits to 64 bits. + I64Extend32S, +} + /// Operand size, in bits. #[derive(Copy, Debug, Clone, Eq, PartialEq)] pub(crate) enum OperandSize { @@ -580,6 +600,12 @@ pub(crate) trait MacroAssembler { /// this will emit multiple instructions if the `has_popcnt` flag is false. fn popcnt(&mut self, context: &mut CodeGenContext, size: OperandSize); + /// Converts an i64 to an i32 by discarding the high 32 bits. + fn wrap(&mut self, src: Reg, dst: Reg); + + /// Extends an integer of a given size to a larger size. + fn extend(&mut self, src: Reg, dst: Reg, kind: ExtendKind); + /// Zero a given memory range. /// /// The default implementation divides the given memory range diff --git a/winch/codegen/src/visitor.rs b/winch/codegen/src/visitor.rs index ca74d0ffcc6a..a82ecce9a39a 100644 --- a/winch/codegen/src/visitor.rs +++ b/winch/codegen/src/visitor.rs @@ -7,8 +7,8 @@ use crate::abi::ABI; use crate::codegen::{control_index, Callee, CodeGen, ControlStackFrame, FnCall}; use crate::masm::{ - DivKind, FloatCmpKind, IntCmpKind, MacroAssembler, OperandSize, RegImm, RemKind, RoundingMode, - ShiftKind, + DivKind, ExtendKind, FloatCmpKind, IntCmpKind, MacroAssembler, OperandSize, RegImm, RemKind, + RoundingMode, ShiftKind, }; use crate::stack::{TypedReg, Val}; use cranelift_codegen::ir::TrapCode; @@ -143,6 +143,14 @@ macro_rules! def_unsupported { (emit I64Ctz $($rest:tt)*) => {}; (emit I32Popcnt $($rest:tt)*) => {}; (emit I64Popcnt $($rest:tt)*) => {}; + (emit I32WrapI64 $($rest:tt)*) => {}; + (emit I64ExtendI32S $($rest:tt)*) => {}; + (emit I64ExtendI32U $($rest:tt)*) => {}; + (emit I32Extend8S $($rest:tt)*) => {}; + (emit I32Extend16S $($rest:tt)*) => {}; + (emit I64Extend8S $($rest:tt)*) => {}; + (emit I64Extend16S $($rest:tt)*) => {}; + (emit I64Extend32S $($rest:tt)*) => {}; (emit LocalGet $($rest:tt)*) => {}; (emit LocalSet $($rest:tt)*) => {}; (emit Call $($rest:tt)*) => {}; @@ -935,6 +943,78 @@ where self.masm.popcnt(&mut self.context, S64); } + fn visit_i32_wrap_i64(&mut self) { + use OperandSize::*; + + self.context.unop(self.masm, S64, &mut |masm, reg, _size| { + masm.wrap(reg, reg); + TypedReg::i32(reg) + }); + } + + fn visit_i64_extend_i32_s(&mut self) { + use OperandSize::*; + + self.context.unop(self.masm, S32, &mut |masm, reg, _size| { + masm.extend(reg, reg, ExtendKind::I64ExtendI32S); + TypedReg::i64(reg) + }); + } + + fn visit_i64_extend_i32_u(&mut self) { + use OperandSize::*; + + self.context.unop(self.masm, S32, &mut |masm, reg, _size| { + masm.extend(reg, reg, ExtendKind::I64ExtendI32U); + TypedReg::i64(reg) + }); + } + + fn visit_i32_extend8_s(&mut self) { + use OperandSize::*; + + self.context.unop(self.masm, S32, &mut |masm, reg, _size| { + masm.extend(reg, reg, ExtendKind::I32Extend8S); + TypedReg::i32(reg) + }); + } + + fn visit_i32_extend16_s(&mut self) { + use OperandSize::*; + + self.context.unop(self.masm, S32, &mut |masm, reg, _size| { + masm.extend(reg, reg, ExtendKind::I32Extend16S); + TypedReg::i32(reg) + }); + } + + fn visit_i64_extend8_s(&mut self) { + use OperandSize::*; + + self.context.unop(self.masm, S64, &mut |masm, reg, _size| { + masm.extend(reg, reg, ExtendKind::I64Extend8S); + TypedReg::i64(reg) + }); + } + + fn visit_i64_extend16_s(&mut self) { + use OperandSize::*; + + self.context.unop(self.masm, S64, &mut |masm, reg, _size| { + masm.extend(reg, reg, ExtendKind::I64Extend16S); + TypedReg::i64(reg) + }); + } + + fn visit_i64_extend32_s(&mut self) { + use OperandSize::*; + + self.context.unop(self.masm, S64, &mut |masm, reg, _size| { + masm.extend(reg, reg, ExtendKind::I64Extend32S); + TypedReg::i64(reg) + }); + } + fn visit_local_get(&mut self, index: u32) { use WasmType::*; let context = &mut self.context; diff --git a/winch/filetests/filetests/x64/i32_extend_16_s/const.wat b/winch/filetests/filetests/x64/i32_extend_16_s/const.wat new file mode 100644 index 000000000000..fa454fd9348a --- /dev/null +++ b/winch/filetests/filetests/x64/i32_extend_16_s/const.wat @@ -0,0 +1,17 @@ +;;! target = "x86_64" + +(module + (func (result i32) + (i32.const 1) + (i32.extend16_s) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec08 sub rsp, 8 +;; 8: 4c893424 mov qword ptr [rsp], r14 +;; c: b801000000 mov eax, 1 +;; 11: 0fbfc0 movsx eax, ax +;; 14: 4883c408 add rsp, 8 +;; 18: 5d pop rbp +;; 19: c3 ret diff --git a/winch/filetests/filetests/x64/i32_extend_16_s/locals.wat b/winch/filetests/filetests/x64/i32_extend_16_s/locals.wat new file mode 100644 index 000000000000..d68af51408ce --- /dev/null +++ b/winch/filetests/filetests/x64/i32_extend_16_s/locals.wat @@ -0,0 +1,21 @@ +;;! target = "x86_64" + +(module + (func (result i32) + (local i32) + + (local.get 0) + (i32.extend16_s) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec10 sub rsp, 0x10 +;; 8: 48c744240800000000 +;; mov qword ptr [rsp + 8], 0 +;; 11: 4c893424 mov qword ptr [rsp], r14 +;; 15: 8b44240c mov eax, dword ptr [rsp + 0xc] +;; 19: 0fbfc0 movsx eax, ax +;; 1c: 4883c410 add rsp, 0x10 +;; 20: 5d pop rbp +;; 21: c3 ret diff --git a/winch/filetests/filetests/x64/i32_extend_16_s/params.wat b/winch/filetests/filetests/x64/i32_extend_16_s/params.wat new file mode 100644 index 000000000000..e38a190fb825 --- /dev/null +++ b/winch/filetests/filetests/x64/i32_extend_16_s/params.wat @@ -0,0 +1,18 @@ +;;! target = "x86_64" + +(module + (func (param i32) (result i32) + (local.get 0) + (i32.extend16_s) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec10 sub rsp, 0x10 +;; 8: 897c240c mov dword ptr [rsp + 0xc], edi +;; c: 4c893424 mov qword ptr [rsp], r14 +;; 10: 8b44240c mov eax, dword ptr [rsp + 0xc] +;; 14: 0fbfc0 movsx eax, ax +;; 17: 4883c410 add rsp, 0x10 +;; 1b: 5d pop rbp +;; 1c: c3 ret diff --git a/winch/filetests/filetests/x64/i32_extend_8_s/const.wat b/winch/filetests/filetests/x64/i32_extend_8_s/const.wat new file mode 100644 index 000000000000..e4de257fa8ef --- /dev/null +++ b/winch/filetests/filetests/x64/i32_extend_8_s/const.wat @@ -0,0 +1,17 @@ +;;! target = "x86_64" + +(module + (func (result i32) + (i32.const 1) + (i32.extend8_s) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec08 sub rsp, 8 +;; 8: 4c893424 mov qword ptr [rsp], r14 +;; c: b801000000 mov eax, 1 +;; 11: 0fbec0 movsx eax, al +;; 14: 4883c408 add rsp, 8 +;; 18: 5d pop rbp +;; 19: c3 ret diff --git a/winch/filetests/filetests/x64/i32_extend_8_s/locals.wat b/winch/filetests/filetests/x64/i32_extend_8_s/locals.wat new file mode 100644 index 000000000000..d6149375d2f0 --- /dev/null +++ b/winch/filetests/filetests/x64/i32_extend_8_s/locals.wat @@ -0,0 +1,21 @@ +;;! target = "x86_64" + +(module + (func (result i32) + (local i32) + + (local.get 0) + (i32.extend8_s) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec10 sub rsp, 0x10 +;; 8: 48c744240800000000 +;; mov qword ptr [rsp + 8], 0 +;; 11: 4c893424 mov qword ptr [rsp], r14 +;; 15: 8b44240c mov eax, dword ptr [rsp + 0xc] +;; 19: 0fbec0 movsx eax, al +;; 1c: 4883c410 add rsp, 0x10 +;; 20: 5d pop rbp +;; 21: c3 ret diff --git a/winch/filetests/filetests/x64/i32_extend_8_s/params.wat b/winch/filetests/filetests/x64/i32_extend_8_s/params.wat new file mode 100644 index 000000000000..33ffb463f3e5 --- /dev/null +++ b/winch/filetests/filetests/x64/i32_extend_8_s/params.wat @@ -0,0 +1,18 @@ +;;! target = "x86_64" + +(module + (func (param i32) (result i32) + (local.get 0) + (i32.extend8_s) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec10 sub rsp, 0x10 +;; 8: 897c240c mov dword ptr [rsp + 0xc], edi +;; c: 4c893424 mov qword ptr [rsp], r14 +;; 10: 8b44240c mov eax, dword ptr [rsp + 0xc] +;; 14: 0fbec0 movsx eax, al +;; 17: 4883c410 add rsp, 0x10 +;; 1b: 5d pop rbp +;; 1c: c3 ret diff --git a/winch/filetests/filetests/x64/i32_wrap_i64/const.wat b/winch/filetests/filetests/x64/i32_wrap_i64/const.wat new file mode 100644 index 000000000000..70e76e0411c4 --- /dev/null +++ b/winch/filetests/filetests/x64/i32_wrap_i64/const.wat @@ -0,0 +1,17 @@ +;;! target = "x86_64" + +(module + (func (result i32) + (i64.const 1) + (i32.wrap_i64) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec08 sub rsp, 8 +;; 8: 4c893424 mov qword ptr [rsp], r14 +;; c: 48c7c001000000 mov rax, 1 +;; 13: 89c0 mov eax, eax +;; 15: 4883c408 add rsp, 8 +;; 19: 5d pop rbp +;; 1a: c3 ret diff --git a/winch/filetests/filetests/x64/i32_wrap_i64/locals.wat b/winch/filetests/filetests/x64/i32_wrap_i64/locals.wat new file mode 100644 index 000000000000..264365c166ce --- /dev/null +++ b/winch/filetests/filetests/x64/i32_wrap_i64/locals.wat @@ -0,0 +1,21 @@ +;;! target = "x86_64" + +(module + (func (result i32) + (local i64) + + (local.get 0) + (i32.wrap_i64) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec10 sub rsp, 0x10 +;; 8: 48c744240800000000 +;; mov qword ptr [rsp + 8], 0 +;; 11: 4c893424 mov qword ptr [rsp], r14 +;; 15: 488b442408 mov rax, qword ptr [rsp + 8] +;; 1a: 89c0 mov eax, eax +;; 1c: 4883c410 add rsp, 0x10 +;; 20: 5d pop rbp +;; 21: c3 ret diff --git a/winch/filetests/filetests/x64/i32_wrap_i64/params.wat b/winch/filetests/filetests/x64/i32_wrap_i64/params.wat new file mode 100644 index 000000000000..5707ffb24aa9 --- /dev/null +++ b/winch/filetests/filetests/x64/i32_wrap_i64/params.wat @@ -0,0 +1,18 @@ +;;! target = "x86_64" + +(module + (func (param i64) (result i32) + (local.get 0) + (i32.wrap_i64) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec10 sub rsp, 0x10 +;; 8: 48897c2408 mov qword ptr [rsp + 8], rdi +;; d: 4c893424 mov qword ptr [rsp], r14 +;; 11: 488b442408 mov rax, qword ptr [rsp + 8] +;; 16: 89c0 mov eax, eax +;; 18: 4883c410 add rsp, 0x10 +;; 1c: 5d pop rbp +;; 1d: c3 ret diff --git a/winch/filetests/filetests/x64/i32_wrap_i64/spilled.wat b/winch/filetests/filetests/x64/i32_wrap_i64/spilled.wat new file mode 100644 index 000000000000..bf3bc1004af1 --- /dev/null +++ b/winch/filetests/filetests/x64/i32_wrap_i64/spilled.wat @@ -0,0 +1,23 @@ +;;! target = "x86_64" + +(module + (func (result i32) + i64.const 1 + i32.wrap_i64 + block + end + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec08 sub rsp, 8 +;; 8: 4c893424 mov qword ptr [rsp], r14 +;; c: 48c7c001000000 mov rax, 1 +;; 13: 89c0 mov eax, eax +;; 15: 4883ec04 sub rsp, 4 +;; 19: 890424 mov dword ptr [rsp], eax +;; 1c: 8b0424 mov eax, dword ptr [rsp] +;; 1f: 4883c404 add rsp, 4 +;; 23: 4883c408 add rsp, 8 +;; 27: 5d pop rbp +;; 28: c3 ret diff --git a/winch/filetests/filetests/x64/i64_extend_16_s/const.wat b/winch/filetests/filetests/x64/i64_extend_16_s/const.wat new file mode 100644 index 000000000000..5ab076bd30a2 --- /dev/null +++ b/winch/filetests/filetests/x64/i64_extend_16_s/const.wat @@ -0,0 +1,17 @@ +;;! target = "x86_64" + +(module + (func (result i64) + (i64.const 1) + (i64.extend16_s) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec08 sub rsp, 8 +;; 8: 4c893424 mov qword ptr [rsp], r14 +;; c: 48c7c001000000 mov rax, 1 +;; 13: 480fbfc0 movsx rax, ax +;; 17: 4883c408 add rsp, 8 +;; 1b: 5d pop rbp +;; 1c: c3 ret diff --git a/winch/filetests/filetests/x64/i64_extend_16_s/locals.wat b/winch/filetests/filetests/x64/i64_extend_16_s/locals.wat new file mode 100644 index 000000000000..a39a9990e4aa --- /dev/null +++ b/winch/filetests/filetests/x64/i64_extend_16_s/locals.wat @@ -0,0 +1,21 @@ +;;! target = "x86_64" + +(module + (func (result i64) + (local i64) + + (local.get 0) + (i64.extend16_s) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec10 sub rsp, 0x10 +;; 8: 48c744240800000000 +;; mov qword ptr [rsp + 8], 0 +;; 11: 4c893424 mov qword ptr [rsp], r14 +;; 15: 488b442408 mov rax, qword ptr [rsp + 8] +;; 1a: 480fbfc0 movsx rax, ax +;; 1e: 4883c410 add rsp, 0x10 +;; 22: 5d pop rbp +;; 23: c3 ret diff --git a/winch/filetests/filetests/x64/i64_extend_16_s/params.wat b/winch/filetests/filetests/x64/i64_extend_16_s/params.wat new file mode 100644 index 000000000000..98a61767a66c --- /dev/null +++ b/winch/filetests/filetests/x64/i64_extend_16_s/params.wat @@ -0,0 +1,18 @@ +;;! target = "x86_64" + +(module + (func (param i64) (result i64) + (local.get 0) + (i64.extend16_s) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec10 sub rsp, 0x10 +;; 8: 48897c2408 mov qword ptr [rsp + 8], rdi +;; d: 4c893424 mov qword ptr [rsp], r14 +;; 11: 488b442408 mov rax, qword ptr [rsp + 8] +;; 16: 480fbfc0 movsx rax, ax +;; 1a: 4883c410 add rsp, 0x10 +;; 1e: 5d pop rbp +;; 1f: c3 ret diff --git a/winch/filetests/filetests/x64/i64_extend_32_s/const.wat b/winch/filetests/filetests/x64/i64_extend_32_s/const.wat new file mode 100644 index 000000000000..666ebd52ca49 --- /dev/null +++ b/winch/filetests/filetests/x64/i64_extend_32_s/const.wat @@ -0,0 +1,17 @@ +;;! target = "x86_64" + +(module + (func (result i64) + (i64.const 1) + (i64.extend32_s) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec08 sub rsp, 8 +;; 8: 4c893424 mov qword ptr [rsp], r14 +;; c: 48c7c001000000 mov rax, 1 +;; 13: 4863c0 movsxd rax, eax +;; 16: 4883c408 add rsp, 8 +;; 1a: 5d pop rbp +;; 1b: c3 ret diff --git a/winch/filetests/filetests/x64/i64_extend_32_s/locals.wat b/winch/filetests/filetests/x64/i64_extend_32_s/locals.wat new file mode 100644 index 000000000000..d6cfac6d128d --- /dev/null +++ b/winch/filetests/filetests/x64/i64_extend_32_s/locals.wat @@ -0,0 +1,21 @@ +;;! target = "x86_64" + +(module + (func (result i64) + (local i64) + + (local.get 0) + (i64.extend32_s) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec10 sub rsp, 0x10 +;; 8: 48c744240800000000 +;; mov qword ptr [rsp + 8], 0 +;; 11: 4c893424 mov qword ptr [rsp], r14 +;; 15: 488b442408 mov rax, qword ptr [rsp + 8] +;; 1a: 4863c0 movsxd rax, eax +;; 1d: 4883c410 add rsp, 0x10 +;; 21: 5d pop rbp +;; 22: c3 ret diff --git a/winch/filetests/filetests/x64/i64_extend_32_s/params.wat b/winch/filetests/filetests/x64/i64_extend_32_s/params.wat new file mode 100644 index 000000000000..0cf607420ce8 --- /dev/null +++ b/winch/filetests/filetests/x64/i64_extend_32_s/params.wat @@ -0,0 +1,18 @@ +;;! target = "x86_64" + +(module + (func (param i64) (result i64) + (local.get 0) + (i64.extend32_s) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec10 sub rsp, 0x10 +;; 8: 48897c2408 mov qword ptr [rsp + 8], rdi +;; d: 4c893424 mov qword ptr [rsp], r14 +;; 11: 488b442408 mov rax, qword ptr [rsp + 8] +;; 16: 4863c0 movsxd rax, eax +;; 19: 4883c410 add rsp, 0x10 +;; 1d: 5d pop rbp +;; 1e: c3 ret diff --git a/winch/filetests/filetests/x64/i64_extend_8_s/const.wat b/winch/filetests/filetests/x64/i64_extend_8_s/const.wat new file mode 100644 index 000000000000..a77763091c36 --- /dev/null +++ b/winch/filetests/filetests/x64/i64_extend_8_s/const.wat @@ -0,0 +1,17 @@ +;;! target = "x86_64" + +(module + (func (result i64) + (i64.const 1) + (i64.extend8_s) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec08 sub rsp, 8 +;; 8: 4c893424 mov qword ptr [rsp], r14 +;; c: 48c7c001000000 mov rax, 1 +;; 13: 480fbec0 movsx rax, al +;; 17: 4883c408 add rsp, 8 +;; 1b: 5d pop rbp +;; 1c: c3 ret diff --git a/winch/filetests/filetests/x64/i64_extend_8_s/locals.wat b/winch/filetests/filetests/x64/i64_extend_8_s/locals.wat new file mode 100644 index 000000000000..62b51071b8ed --- /dev/null +++ b/winch/filetests/filetests/x64/i64_extend_8_s/locals.wat @@ -0,0 +1,21 @@ +;;! target = "x86_64" + +(module + (func (result i64) + (local i64) + + (local.get 0) + (i64.extend8_s) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec10 sub rsp, 0x10 +;; 8: 48c744240800000000 +;; mov qword ptr [rsp + 8], 0 +;; 11: 4c893424 mov qword ptr [rsp], r14 +;; 15: 488b442408 mov rax, qword ptr [rsp + 8] +;; 1a: 480fbec0 movsx rax, al +;; 1e: 4883c410 add rsp, 0x10 +;; 22: 5d pop rbp +;; 23: c3 ret diff --git a/winch/filetests/filetests/x64/i64_extend_8_s/params.wat b/winch/filetests/filetests/x64/i64_extend_8_s/params.wat new file mode 100644 index 000000000000..4ad6018bd995 --- /dev/null +++ b/winch/filetests/filetests/x64/i64_extend_8_s/params.wat @@ -0,0 +1,18 @@ +;;! target = "x86_64" + +(module + (func (param i64) (result i64) + (local.get 0) + (i64.extend8_s) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec10 sub rsp, 0x10 +;; 8: 48897c2408 mov qword ptr [rsp + 8], rdi +;; d: 4c893424 mov qword ptr [rsp], r14 +;; 11: 488b442408 mov rax, qword ptr [rsp + 8] +;; 16: 480fbec0 movsx rax, al +;; 1a: 4883c410 add rsp, 0x10 +;; 1e: 5d pop rbp +;; 1f: c3 ret diff --git a/winch/filetests/filetests/x64/i64_extend_i32_s/const.wat b/winch/filetests/filetests/x64/i64_extend_i32_s/const.wat new file mode 100644 index 000000000000..363d69902e72 --- /dev/null +++ b/winch/filetests/filetests/x64/i64_extend_i32_s/const.wat @@ -0,0 +1,17 @@ +;;! target = "x86_64" + +(module + (func (result i64) + (i32.const 1) + (i64.extend_i32_s) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec08 sub rsp, 8 +;; 8: 4c893424 mov qword ptr [rsp], r14 +;; c: b801000000 mov eax, 1 +;; 11: 4863c0 movsxd rax, eax +;; 14: 4883c408 add rsp, 8 +;; 18: 5d pop rbp +;; 19: c3 ret diff --git a/winch/filetests/filetests/x64/i64_extend_i32_s/locals.wat b/winch/filetests/filetests/x64/i64_extend_i32_s/locals.wat new file mode 100644 index 000000000000..ab2629b14194 --- /dev/null +++ b/winch/filetests/filetests/x64/i64_extend_i32_s/locals.wat @@ -0,0 +1,21 @@ +;;! target = "x86_64" + +(module + (func (result i64) + (local i32) + + (local.get 0) + (i64.extend_i32_s) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec10 sub rsp, 0x10 +;; 8: 48c744240800000000 +;; mov qword ptr [rsp + 8], 0 +;; 11: 4c893424 mov qword ptr [rsp], r14 +;; 15: 8b44240c mov eax, dword ptr [rsp + 0xc] +;; 19: 4863c0 movsxd rax, eax +;; 1c: 4883c410 add rsp, 0x10 +;; 20: 5d pop rbp +;; 21: c3 ret diff --git a/winch/filetests/filetests/x64/i64_extend_i32_s/params.wat b/winch/filetests/filetests/x64/i64_extend_i32_s/params.wat new file mode 100644 index 000000000000..2d4ad7213380 --- /dev/null +++ b/winch/filetests/filetests/x64/i64_extend_i32_s/params.wat @@ -0,0 +1,18 @@ +;;! target = "x86_64" + +(module + (func (param i32) (result i64) + (local.get 0) + (i64.extend_i32_s) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec10 sub rsp, 0x10 +;; 8: 897c240c mov dword ptr [rsp + 0xc], edi +;; c: 4c893424 mov qword ptr [rsp], r14 +;; 10: 8b44240c mov eax, dword ptr [rsp + 0xc] +;; 14: 4863c0 movsxd rax, eax +;; 17: 4883c410 add rsp, 0x10 +;; 1b: 5d pop rbp +;; 1c: c3 ret diff --git a/winch/filetests/filetests/x64/i64_extend_i32_s/spilled.wat b/winch/filetests/filetests/x64/i64_extend_i32_s/spilled.wat new file mode 100644 index 000000000000..20ba1a2c40e2 --- /dev/null +++ b/winch/filetests/filetests/x64/i64_extend_i32_s/spilled.wat @@ -0,0 +1,21 @@ +;;! target = "x86_64" + +(module + (func (result i64) + i32.const 1 + i64.extend_i32_s + block + end + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec08 sub rsp, 8 +;; 8: 4c893424 mov qword ptr [rsp], r14 +;; c: b801000000 mov eax, 1 +;; 11: 4863c0 movsxd rax, eax +;; 14: 50 push rax +;; 15: 58 pop rax +;; 16: 4883c408 add rsp, 8 +;; 1a: 5d pop rbp +;; 1b: c3 ret diff --git a/winch/filetests/filetests/x64/i64_extend_i32_u/const.wat b/winch/filetests/filetests/x64/i64_extend_i32_u/const.wat new file mode 100644 index 000000000000..6f1c21f93b14 --- /dev/null +++ b/winch/filetests/filetests/x64/i64_extend_i32_u/const.wat @@ -0,0 +1,17 @@ +;;! target = "x86_64" + +(module + (func (result i64) + (i32.const 1) + (i64.extend_i32_u) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec08 sub rsp, 8 +;; 8: 4c893424 mov qword ptr [rsp], r14 +;; c: b801000000 mov eax, 1 +;; 11: 8bc0 mov eax, eax +;; 13: 4883c408 add rsp, 8 +;; 17: 5d pop rbp +;; 18: c3 ret diff --git a/winch/filetests/filetests/x64/i64_extend_i32_u/locals.wat b/winch/filetests/filetests/x64/i64_extend_i32_u/locals.wat new file mode 100644 index 000000000000..364d40325ee2 --- /dev/null +++ b/winch/filetests/filetests/x64/i64_extend_i32_u/locals.wat @@ -0,0 +1,21 @@ +;;! target = "x86_64" + +(module + (func (result i64) + (local i32) + + (local.get 0) + (i64.extend_i32_u) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec10 sub rsp, 0x10 +;; 8: 48c744240800000000 +;; mov qword ptr [rsp + 8], 0 +;; 11: 4c893424 mov qword ptr [rsp], r14 +;; 15: 8b44240c mov eax, dword ptr [rsp + 0xc] +;; 19: 8bc0 mov eax, eax +;; 1b: 4883c410 add rsp, 0x10 +;; 1f: 5d pop rbp +;; 20: c3 ret diff --git a/winch/filetests/filetests/x64/i64_extend_i32_u/params.wat b/winch/filetests/filetests/x64/i64_extend_i32_u/params.wat new file mode 100644 index 000000000000..3dbdc85983bd --- /dev/null +++ b/winch/filetests/filetests/x64/i64_extend_i32_u/params.wat @@ -0,0 +1,18 @@ +;;! target = "x86_64" + +(module + (func (param i32) (result i64) + (local.get 0) + (i64.extend_i32_u) + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec10 sub rsp, 0x10 +;; 8: 897c240c mov dword ptr [rsp + 0xc], edi +;; c: 4c893424 mov qword ptr [rsp], r14 +;; 10: 8b44240c mov eax, dword ptr [rsp + 0xc] +;; 14: 8bc0 mov eax, eax +;; 16: 4883c410 add rsp, 0x10 +;; 1a: 5d pop rbp +;; 1b: c3 ret diff --git a/winch/filetests/filetests/x64/i64_extend_i32_u/spilled.wat b/winch/filetests/filetests/x64/i64_extend_i32_u/spilled.wat new file mode 100644 index 000000000000..4722e1b826b6 --- /dev/null +++ b/winch/filetests/filetests/x64/i64_extend_i32_u/spilled.wat @@ -0,0 +1,21 @@ +;;! target = "x86_64" + +(module + (func (result i64) + i32.const 1 + i64.extend_i32_u + block + end + ) +) +;; 0: 55 push rbp +;; 1: 4889e5 mov rbp, rsp +;; 4: 4883ec08 sub rsp, 8 +;; 8: 4c893424 mov qword ptr [rsp], r14 +;; c: b801000000 mov eax, 1 +;; 11: 8bc0 mov eax, eax +;; 13: 50 push rax +;; 14: 58 pop rax +;; 15: 4883c408 add rsp, 8 +;; 19: 5d pop rbp +;; 1a: c3 ret From b411c2133a72ffa068a8f550b785614ca5d2ee88 Mon Sep 17 00:00:00 2001 From: Dave Bakker Date: Thu, 14 Dec 2023 17:03:06 +0100 Subject: [PATCH 13/14] wasi-sockets: Factor out cap-std (#7687) * Remove unnecessary conversions * Refactor: demote cap-std to an implementation detail of network::util --- crates/wasi/src/preview2/host/network.rs | 85 ++++++++++++++++-------- crates/wasi/src/preview2/host/tcp.rs | 53 ++++++--------- crates/wasi/src/preview2/host/udp.rs | 25 +++---- crates/wasi/src/preview2/tcp.rs | 32 ++++----- crates/wasi/src/preview2/udp.rs | 25 ++++--- 5 files changed, 116 insertions(+), 104 deletions(-) diff --git a/crates/wasi/src/preview2/host/network.rs b/crates/wasi/src/preview2/host/network.rs index 55dedb1b145d..e7e025e8eb90 100644 --- a/crates/wasi/src/preview2/host/network.rs +++ b/crates/wasi/src/preview2/host/network.rs @@ -218,9 +218,9 @@ pub(crate) mod util { use crate::preview2::bindings::sockets::network::ErrorCode; use crate::preview2::network::SocketAddressFamily; use crate::preview2::SocketResult; - use cap_net_ext::{Blocking, TcpListenerExt}; - use cap_std::net::{TcpListener, TcpStream, UdpSocket}; - use rustix::fd::AsFd; + use cap_net_ext::{AddressFamily, Blocking, TcpListenerExt, UdpSocketExt}; + use io_lifetimes::AsSocketlike; + use rustix::fd::{AsFd, OwnedFd}; use rustix::io::Errno; use rustix::net::sockopt; @@ -302,42 +302,64 @@ pub(crate) mod util { * Syscalls wrappers with (opinionated) portability fixes. */ - pub fn tcp_bind(listener: &TcpListener, addr: &SocketAddr) -> std::io::Result<()> { - rustix::net::bind(listener, addr).map_err(|error| match error { + pub fn tcp_socket(family: AddressFamily, blocking: Blocking) -> std::io::Result { + // Delegate socket creation to cap_net_ext. They handle a couple of things for us: + // - On Windows: call WSAStartup if not done before. + // - Set the NONBLOCK and CLOEXEC flags. Either immediately during socket creation, + // or afterwards using ioctl or fcntl. Exact method depends on the platform. + + let listener = cap_std::net::TcpListener::new(family, blocking)?; + Ok(OwnedFd::from(listener)) + } + + pub fn udp_socket(family: AddressFamily, blocking: Blocking) -> std::io::Result { + // Delegate socket creation to cap_net_ext. They handle a couple of things for us: + // - On Windows: call WSAStartup if not done before. + // - Set the NONBLOCK and CLOEXEC flags. Either immediately during socket creation, + // or afterwards using ioctl or fcntl. Exact method depends on the platform. + + let socket = cap_std::net::UdpSocket::new(family, blocking)?; + Ok(OwnedFd::from(socket)) + } + + pub fn tcp_bind(sockfd: Fd, addr: &SocketAddr) -> rustix::io::Result<()> { + rustix::net::bind(sockfd, addr).map_err(|error| match error { // See: https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-bind#:~:text=WSAENOBUFS // Windows returns WSAENOBUFS when the ephemeral ports have been exhausted. #[cfg(windows)] - Errno::NOBUFS => Errno::ADDRINUSE.into(), - _ => error.into(), + Errno::NOBUFS => Errno::ADDRINUSE, + _ => error, }) } - pub fn udp_bind(socket: &UdpSocket, addr: &SocketAddr) -> std::io::Result<()> { - rustix::net::bind(socket, addr).map_err(|error| { - match error { - // See: https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-bind#:~:text=WSAENOBUFS - // Windows returns WSAENOBUFS when the ephemeral ports have been exhausted. - #[cfg(windows)] - Errno::NOBUFS => Errno::ADDRINUSE.into(), - _ => error.into(), - } + pub fn udp_bind(sockfd: Fd, addr: &SocketAddr) -> rustix::io::Result<()> { + rustix::net::bind(sockfd, addr).map_err(|error| match error { + // See: https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-bind#:~:text=WSAENOBUFS + // Windows returns WSAENOBUFS when the ephemeral ports have been exhausted. + #[cfg(windows)] + Errno::NOBUFS => Errno::ADDRINUSE, + _ => error, }) } - pub fn tcp_connect(listener: &TcpListener, addr: &SocketAddr) -> std::io::Result<()> { - rustix::net::connect(listener, addr).map_err(|error| match error { + pub fn tcp_connect(sockfd: Fd, addr: &SocketAddr) -> rustix::io::Result<()> { + rustix::net::connect(sockfd, addr).map_err(|error| match error { // On POSIX, non-blocking `connect` returns `EINPROGRESS`. // Windows returns `WSAEWOULDBLOCK`. // // This normalized error code is depended upon by: tcp.rs #[cfg(windows)] - Errno::WOULDBLOCK => Errno::INPROGRESS.into(), - _ => error.into(), + Errno::WOULDBLOCK => Errno::INPROGRESS, + _ => error, }) } - pub fn tcp_listen(listener: &TcpListener, backlog: Option) -> std::io::Result<()> { - listener + pub fn tcp_listen(sockfd: Fd, backlog: Option) -> std::io::Result<()> { + // Delegate `listen` to cap_net_ext. That is a thin wrapper around rustix::net::listen, + // with a platform-dependent default value for the backlog size. + sockfd + .as_fd() + .as_socketlike_view::() .listen(backlog) .map_err(|error| match Errno::from_io_error(&error) { // See: https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-listen#:~:text=WSAEMFILE @@ -351,15 +373,22 @@ pub(crate) mod util { // on Microsoft's documentation here. #[cfg(windows)] Some(Errno::MFILE) => Errno::NOBUFS.into(), + _ => error, }) } - pub fn tcp_accept( - listener: &TcpListener, + pub fn tcp_accept( + sockfd: Fd, blocking: Blocking, - ) -> std::io::Result<(TcpStream, SocketAddr)> { - listener + ) -> std::io::Result<(OwnedFd, SocketAddr)> { + // Delegate `accept` to cap_net_ext. They set the NONBLOCK and CLOEXEC flags + // for us. Either immediately as a flag to `accept`, or afterwards using + // ioctl or fcntl. Exact method depends on the platform. + + let (client, addr) = sockfd + .as_fd() + .as_socketlike_view::() .accept_with(blocking) .map_err(|error| match Errno::from_io_error(&error) { // From: https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-accept#:~:text=WSAEINPROGRESS @@ -393,7 +422,9 @@ pub(crate) mod util { ) => Errno::CONNABORTED.into(), _ => error, - }) + })?; + + Ok((client.into(), addr)) } pub fn udp_disconnect(sockfd: Fd) -> rustix::io::Result<()> { diff --git a/crates/wasi/src/preview2/host/tcp.rs b/crates/wasi/src/preview2/host/tcp.rs index b1d4ba31f28c..1fe8bc5a6771 100644 --- a/crates/wasi/src/preview2/host/tcp.rs +++ b/crates/wasi/src/preview2/host/tcp.rs @@ -11,7 +11,6 @@ use crate::preview2::{ }; use crate::preview2::{Pollable, SocketResult, WasiView}; use cap_net_ext::Blocking; -use cap_std::net::TcpListener; use io_lifetimes::AsSocketlike; use rustix::io::Errno; use rustix::net::sockopt; @@ -47,21 +46,18 @@ impl crate::preview2::host::tcp::tcp::HostTcpSocket for T { { // Ensure that we're allowed to connect to this address. network.check_socket_addr(&local_address, SocketAddrUse::TcpBind)?; - let listener = &*socket.tcp_socket().as_socketlike_view::(); // Perform the OS bind call. - util::tcp_bind(listener, &local_address).map_err(|error| { - match Errno::from_io_error(&error) { - // From https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html: - // > [EAFNOSUPPORT] The specified address is not a valid address for the address family of the specified socket - // - // The most common reasons for this error should have already - // been handled by our own validation slightly higher up in this - // function. This error mapping is here just in case there is - // an edge case we didn't catch. - Some(Errno::AFNOSUPPORT) => ErrorCode::InvalidArgument, - _ => ErrorCode::from(error), - } + util::tcp_bind(socket.tcp_socket(), &local_address).map_err(|error| match error { + // From https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html: + // > [EAFNOSUPPORT] The specified address is not a valid address for the address family of the specified socket + // + // The most common reasons for this error should have already + // been handled by our own validation slightly higher up in this + // function. This error mapping is here just in case there is + // an edge case we didn't catch. + Errno::AFNOSUPPORT => ErrorCode::InvalidArgument, + _ => ErrorCode::from(error), })?; } @@ -116,10 +112,9 @@ impl crate::preview2::host::tcp::tcp::HostTcpSocket for T { // Ensure that we're allowed to connect to this address. network.check_socket_addr(&remote_address, SocketAddrUse::TcpConnect)?; - let listener = &*socket.tcp_socket().as_socketlike_view::(); // Do an OS `connect`. Our socket is non-blocking, so it'll either... - util::tcp_connect(listener, &remote_address) + util::tcp_connect(socket.tcp_socket(), &remote_address) }; match r { @@ -130,11 +125,11 @@ impl crate::preview2::host::tcp::tcp::HostTcpSocket for T { return Ok(()); } // continue in progress, - Err(err) if Errno::from_io_error(&err) == Some(Errno::INPROGRESS) => {} + Err(err) if err == Errno::INPROGRESS => {} // or fail immediately. Err(err) => { - return Err(match Errno::from_io_error(&err) { - Some(Errno::AFNOSUPPORT) => ErrorCode::InvalidArgument.into(), // See `bind` implementation. + return Err(match err { + Errno::AFNOSUPPORT => ErrorCode::InvalidArgument.into(), // See `bind` implementation. _ => err.into(), }); } @@ -207,10 +202,7 @@ impl crate::preview2::host::tcp::tcp::HostTcpSocket for T { | TcpState::BindStarted => return Err(ErrorCode::ConcurrencyConflict.into()), } - { - let listener = &*socket.tcp_socket().as_socketlike_view::(); - util::tcp_listen(listener, socket.listen_backlog_size)?; - } + util::tcp_listen(socket.tcp_socket(), socket.listen_backlog_size)?; socket.tcp_state = TcpState::ListenStarted; @@ -250,9 +242,8 @@ impl crate::preview2::host::tcp::tcp::HostTcpSocket for T { // Do the OS accept call. let tcp_socket = socket.tcp_socket(); - let (connection, _addr) = tcp_socket.try_io(Interest::READABLE, || { - let listener = &*tcp_socket.as_socketlike_view::(); - util::tcp_accept(listener, Blocking::No) + let (client_fd, _addr) = tcp_socket.try_io(Interest::READABLE, || { + util::tcp_accept(tcp_socket, Blocking::No) })?; #[cfg(target_os = "macos")] @@ -262,25 +253,25 @@ impl crate::preview2::host::tcp::tcp::HostTcpSocket for T { // and only if a specific value was explicitly set on the listener. if let Some(size) = socket.receive_buffer_size { - _ = util::set_socket_recv_buffer_size(&connection, size); // Ignore potential error. + _ = util::set_socket_recv_buffer_size(&client_fd, size); // Ignore potential error. } if let Some(size) = socket.send_buffer_size { - _ = util::set_socket_send_buffer_size(&connection, size); // Ignore potential error. + _ = util::set_socket_send_buffer_size(&client_fd, size); // Ignore potential error. } // For some reason, IP_TTL is inherited, but IPV6_UNICAST_HOPS isn't. if let (SocketAddressFamily::Ipv6 { .. }, Some(ttl)) = (socket.family, socket.hop_limit) { - _ = util::set_ipv6_unicast_hops(&connection, ttl); // Ignore potential error. + _ = util::set_ipv6_unicast_hops(&client_fd, ttl); // Ignore potential error. } if let Some(value) = socket.keep_alive_idle_time { - _ = util::set_tcp_keepidle(&connection, value); // Ignore potential error. + _ = util::set_tcp_keepidle(&client_fd, value); // Ignore potential error. } } - let mut tcp_socket = TcpSocket::from_tcp_stream(connection, socket.family)?; + let mut tcp_socket = TcpSocket::from_fd(client_fd, socket.family)?; // Mark the socket as connected so that we can exit early from methods like `start-bind`. tcp_socket.tcp_state = TcpState::Connected; diff --git a/crates/wasi/src/preview2/host/udp.rs b/crates/wasi/src/preview2/host/udp.rs index 09ca8b5b9875..b256fd861760 100644 --- a/crates/wasi/src/preview2/host/udp.rs +++ b/crates/wasi/src/preview2/host/udp.rs @@ -55,23 +55,18 @@ impl udp::HostUdpSocket for T { { check.check(&local_address, SocketAddrUse::UdpBind)?; - let udp_socket = &*socket - .udp_socket() - .as_socketlike_view::(); // Perform the OS bind call. - util::udp_bind(udp_socket, &local_address).map_err(|error| { - match Errno::from_io_error(&error) { - // From https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html: - // > [EAFNOSUPPORT] The specified address is not a valid address for the address family of the specified socket - // - // The most common reasons for this error should have already - // been handled by our own validation slightly higher up in this - // function. This error mapping is here just in case there is - // an edge case we didn't catch. - Some(Errno::AFNOSUPPORT) => ErrorCode::InvalidArgument, - _ => ErrorCode::from(error), - } + util::udp_bind(socket.udp_socket(), &local_address).map_err(|error| match error { + // From https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html: + // > [EAFNOSUPPORT] The specified address is not a valid address for the address family of the specified socket + // + // The most common reasons for this error should have already + // been handled by our own validation slightly higher up in this + // function. This error mapping is here just in case there is + // an edge case we didn't catch. + Errno::AFNOSUPPORT => ErrorCode::InvalidArgument, + _ => ErrorCode::from(error), })?; } diff --git a/crates/wasi/src/preview2/tcp.rs b/crates/wasi/src/preview2/tcp.rs index 23061760c27b..fe803306fc3a 100644 --- a/crates/wasi/src/preview2/tcp.rs +++ b/crates/wasi/src/preview2/tcp.rs @@ -1,11 +1,11 @@ use super::network::SocketAddressFamily; use super::{HostInputStream, HostOutputStream, StreamError}; +use crate::preview2::host::network::util; use crate::preview2::{ with_ambient_tokio_runtime, AbortOnDropJoinHandle, InputStream, OutputStream, Subscribe, }; use anyhow::{Error, Result}; -use cap_net_ext::{AddressFamily, Blocking, TcpListenerExt}; -use cap_std::net::TcpListener; +use cap_net_ext::{AddressFamily, Blocking}; use io_lifetimes::raw::{FromRawSocketlike, IntoRawSocketlike}; use rustix::net::sockopt; use std::io; @@ -261,36 +261,26 @@ impl TcpSocket { pub fn new(family: AddressFamily) -> io::Result { // Create a new host socket and set it to non-blocking, which is needed // by our async implementation. - let tcp_listener = TcpListener::new(family, Blocking::No)?; + let fd = util::tcp_socket(family, Blocking::No)?; let socket_address_family = match family { AddressFamily::Ipv4 => SocketAddressFamily::Ipv4, AddressFamily::Ipv6 => SocketAddressFamily::Ipv6 { - v6only: sockopt::get_ipv6_v6only(&tcp_listener)?, + v6only: sockopt::get_ipv6_v6only(&fd)?, }, }; - Self::from_tcp_listener(tcp_listener, socket_address_family) + Self::from_fd(fd, socket_address_family) } /// Create a `TcpSocket` from an existing socket. /// /// The socket must be in non-blocking mode. - pub(crate) fn from_tcp_stream( - tcp_socket: cap_std::net::TcpStream, + pub(crate) fn from_fd( + fd: rustix::fd::OwnedFd, family: SocketAddressFamily, ) -> io::Result { - let tcp_listener = TcpListener::from(rustix::fd::OwnedFd::from(tcp_socket)); - Self::from_tcp_listener(tcp_listener, family) - } - - pub(crate) fn from_tcp_listener( - tcp_listener: cap_std::net::TcpListener, - family: SocketAddressFamily, - ) -> io::Result { - let fd = tcp_listener.into_raw_socketlike(); - let std_stream = unsafe { std::net::TcpStream::from_raw_socketlike(fd) }; - let stream = with_ambient_tokio_runtime(|| tokio::net::TcpStream::try_from(std_stream))?; + let stream = Self::setup_tokio_tcp_stream(fd)?; Ok(Self { inner: Arc::new(stream), @@ -308,6 +298,12 @@ impl TcpSocket { }) } + fn setup_tokio_tcp_stream(fd: rustix::fd::OwnedFd) -> io::Result { + let std_stream = + unsafe { std::net::TcpStream::from_raw_socketlike(fd.into_raw_socketlike()) }; + with_ambient_tokio_runtime(|| tokio::net::TcpStream::try_from(std_stream)) + } + pub fn tcp_socket(&self) -> &tokio::net::TcpStream { &self.inner } diff --git a/crates/wasi/src/preview2/udp.rs b/crates/wasi/src/preview2/udp.rs index 70e35ba44e73..34d46402475b 100644 --- a/crates/wasi/src/preview2/udp.rs +++ b/crates/wasi/src/preview2/udp.rs @@ -1,7 +1,8 @@ +use crate::preview2::host::network::util; use crate::preview2::poll::Subscribe; use crate::preview2::with_ambient_tokio_runtime; use async_trait::async_trait; -use cap_net_ext::{AddressFamily, Blocking, UdpSocketExt}; +use cap_net_ext::{AddressFamily, Blocking}; use io_lifetimes::raw::{FromRawSocketlike, IntoRawSocketlike}; use std::io; use std::net::SocketAddr; @@ -57,15 +58,19 @@ impl Subscribe for UdpSocket { impl UdpSocket { /// Create a new socket in the given family. pub fn new(family: AddressFamily) -> io::Result { - let socket = Self::new_tokio_socket(family)?; + // Create a new host socket and set it to non-blocking, which is needed + // by our async implementation. + let fd = util::udp_socket(family, Blocking::No)?; let socket_address_family = match family { AddressFamily::Ipv4 => SocketAddressFamily::Ipv4, AddressFamily::Ipv6 => SocketAddressFamily::Ipv6 { - v6only: rustix::net::sockopt::get_ipv6_v6only(&socket)?, + v6only: rustix::net::sockopt::get_ipv6_v6only(&fd)?, }, }; + let socket = Self::setup_tokio_udp_socket(fd)?; + Ok(UdpSocket { inner: Arc::new(socket), udp_state: UdpState::Default, @@ -74,16 +79,10 @@ impl UdpSocket { }) } - fn new_tokio_socket(family: AddressFamily) -> io::Result { - // Create a new host socket and set it to non-blocking, which is needed - // by our async implementation. - let cap_std_socket = cap_std::net::UdpSocket::new(family, Blocking::No)?; - let fd = cap_std_socket.into_raw_socketlike(); - let std_socket = unsafe { std::net::UdpSocket::from_raw_socketlike(fd) }; - let tokio_socket = - with_ambient_tokio_runtime(|| tokio::net::UdpSocket::try_from(std_socket))?; - - Ok(tokio_socket) + fn setup_tokio_udp_socket(fd: rustix::fd::OwnedFd) -> io::Result { + let std_socket = + unsafe { std::net::UdpSocket::from_raw_socketlike(fd.into_raw_socketlike()) }; + with_ambient_tokio_runtime(|| tokio::net::UdpSocket::try_from(std_socket)) } pub fn udp_socket(&self) -> &tokio::net::UdpSocket { From 81e383f5c097a55d54cac8ad3043b147fd64eea2 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Thu, 14 Dec 2023 17:07:54 +0100 Subject: [PATCH 14/14] fix(wasi-common): convert `ErrorKind::WouldBlock` instead of trapping (#7686) Signed-off-by: Harald Hoyer --- crates/wasi-common/src/snapshots/preview_1/error.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/wasi-common/src/snapshots/preview_1/error.rs b/crates/wasi-common/src/snapshots/preview_1/error.rs index f0b7cdf4ad94..f5b8afcfcce0 100644 --- a/crates/wasi-common/src/snapshots/preview_1/error.rs +++ b/crates/wasi-common/src/snapshots/preview_1/error.rs @@ -216,6 +216,7 @@ impl From for Error { std::io::ErrorKind::PermissionDenied => Errno::Perm.into(), std::io::ErrorKind::AlreadyExists => Errno::Exist.into(), std::io::ErrorKind::InvalidInput => Errno::Inval.into(), + std::io::ErrorKind::WouldBlock => Errno::Again.into(), _ => Error::trap(anyhow::anyhow!(err).context("Unknown OS error")), }, }