From 4178765a1424312c783b7f4ea76954be9b6168b6 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 20 Feb 2024 08:21:53 -0800 Subject: [PATCH 1/3] Add pointer and length types to `WasmType`. In anticipation of memory64, provenance in Rust, and guest bindings with instrumented pointers, add `Pointer` and `Length` types to `WasmType`, and use it in the ABI for list, strings, and argument/return value pointers. Consumers that don't have anything special to do with these can handle them both the same as `i32`. And, because the variant type Canonical ABI can unify pointers with integer types like `i64`, add a `Pointer64` type as well, which represents a conceptual union of a pointer and an `i64`. Consumers that don't have anything special to do with this type can handle it the same as an `i64`. --- crates/wit-component/src/dummy.rs | 3 + crates/wit-component/src/encoding.rs | 3 + crates/wit-component/src/encoding/world.rs | 3 + crates/wit-component/src/validation.rs | 3 + crates/wit-parser/src/abi.rs | 72 +++++++++++++++++++--- 5 files changed, 75 insertions(+), 9 deletions(-) diff --git a/crates/wit-component/src/dummy.rs b/crates/wit-component/src/dummy.rs index 25f6d2b706..c658165372 100644 --- a/crates/wit-component/src/dummy.rs +++ b/crates/wit-component/src/dummy.rs @@ -128,6 +128,9 @@ pub fn dummy_module(resolve: &Resolve, world: WorldId) -> Vec { WasmType::I64 => dst.push_str("i64"), WasmType::F32 => dst.push_str("f32"), WasmType::F64 => dst.push_str("f64"), + WasmType::Pointer => dst.push_str("i32"), + WasmType::Pointer64 => dst.push_str("i64"), + WasmType::Length => dst.push_str("i32"), } } dst.push(')'); diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs index cb5122a1fb..87ec147952 100644 --- a/crates/wit-component/src/encoding.rs +++ b/crates/wit-component/src/encoding.rs @@ -106,6 +106,9 @@ fn to_val_type(ty: &WasmType) -> ValType { WasmType::I64 => ValType::I64, WasmType::F32 => ValType::F32, WasmType::F64 => ValType::F64, + WasmType::Pointer => ValType::I32, + WasmType::Pointer64 => ValType::I64, + WasmType::Length => ValType::I32, } } diff --git a/crates/wit-component/src/encoding/world.rs b/crates/wit-component/src/encoding/world.rs index 47b9087876..a1914a6059 100644 --- a/crates/wit-component/src/encoding/world.rs +++ b/crates/wit-component/src/encoding/world.rs @@ -224,6 +224,9 @@ impl<'a> ComponentWorld<'a> { WasmType::I64 => ValType::I64, WasmType::F32 => ValType::F32, WasmType::F64 => ValType::F64, + WasmType::Pointer => ValType::I32, + WasmType::Pointer64 => ValType::I64, + WasmType::Length => ValType::I32, } } } diff --git a/crates/wit-component/src/validation.rs b/crates/wit-component/src/validation.rs index 0a76012419..5c3fafe189 100644 --- a/crates/wit-component/src/validation.rs +++ b/crates/wit-component/src/validation.rs @@ -23,6 +23,9 @@ fn wasm_sig_to_func_type(signature: WasmSignature) -> FuncType { WasmType::I64 => ValType::I64, WasmType::F32 => ValType::F32, WasmType::F64 => ValType::F64, + WasmType::Pointer => ValType::I32, + WasmType::Pointer64 => ValType::I64, + WasmType::Length => ValType::I32, } } diff --git a/crates/wit-parser/src/abi.rs b/crates/wit-parser/src/abi.rs index b542acf000..99282f9df1 100644 --- a/crates/wit-parser/src/abi.rs +++ b/crates/wit-parser/src/abi.rs @@ -1,6 +1,6 @@ use crate::{Function, Handle, Int, Resolve, Type, TypeDefKind}; -/// A raw WebAssembly signature with params and results. +/// A core WebAssembly signature with params and results. #[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] pub struct WasmSignature { /// The WebAssembly parameters of this function. @@ -31,6 +31,29 @@ pub enum WasmType { I64, F32, F64, + + /// A pointer type. In core Wasm this typically lowers to either `i32` or + /// `i64` depending on the index type of the exported linear memory, + /// however bindings can use different source-level types to preserve + /// provenance. + /// + /// Users that don't do anything special for pointers can treat this as + /// `i32`. + Pointer, + + /// A type for values which can be either pointers or 64-bit integers. + /// This occurs in variants, when pointers and non-pointers are unified. + /// + /// Users that don't do anything special for pointers can treat this as + /// `i64`. + Pointer64, + + /// An array length type. In core Wasm this lowers to either `i32` or `i64` + /// depending on the index type of the exported linear memory. + /// + /// Users that don't do anything special for pointers can treat this as + /// `i32`. + Length, // NOTE: we don't lower interface types to any other Wasm type, // e.g. externref, so we don't need to define them here. } @@ -39,10 +62,41 @@ fn join(a: WasmType, b: WasmType) -> WasmType { use WasmType::*; match (a, b) { - (I32, I32) | (I64, I64) | (F32, F32) | (F64, F64) => a, + (I32, I32) + | (I64, I64) + | (F32, F32) + | (F64, F64) + | (Pointer, Pointer) + | (Pointer64, Pointer64) + | (Length, Length) => a, (I32, F32) | (F32, I32) => I32, + // A length is at least an `i32`, maybe more, so it wins over + // 32-bit types. + (Length, I32 | F32) => Length, + (I32 | F32, Length) => Length, + + // A length might be an `i64`, but might not be, so if we have + // 64-bit types, they win. + (Length, I64 | F64) => I64, + (I64 | F64, Length) => I64, + + // Pointers have provenance and are at least an `i32`, so they + // win over 32-bit and length types. + (Pointer, I32 | F32 | Length) => Pointer, + (I32 | F32 | Length, Pointer) => Pointer, + + // If we need 64 bits and provenance, we need to use the special + // `Pointer64`. + (Pointer, I64 | F64) => Pointer64, + (I64 | F64, Pointer) => Pointer64, + + // Pointer64 wins over everything. + (Pointer64, _) => Pointer64, + (_, Pointer64) => Pointer64, + + // Otherwise, `i64` wins. (_, I64 | F64) | (I64 | F64, _) => I64, } } @@ -92,7 +146,7 @@ impl Resolve { if params.len() > MAX_FLAT_PARAMS { params.truncate(0); - params.push(WasmType::I32); + params.push(WasmType::Pointer); indirect_params = true; } @@ -112,10 +166,10 @@ impl Resolve { results.truncate(0); match variant { AbiVariant::GuestImport => { - params.push(WasmType::I32); + params.push(WasmType::Pointer); } AbiVariant::GuestExport => { - results.push(WasmType::I32); + results.push(WasmType::Pointer); } } } @@ -145,8 +199,8 @@ impl Resolve { Type::Float32 => result.push(WasmType::F32), Type::Float64 => result.push(WasmType::F64), Type::String => { - result.push(WasmType::I32); - result.push(WasmType::I32); + result.push(WasmType::Pointer); + result.push(WasmType::Length); } Type::Id(id) => match &self.types[*id].kind { @@ -177,8 +231,8 @@ impl Resolve { } TypeDefKind::List(_) => { - result.push(WasmType::I32); - result.push(WasmType::I32); + result.push(WasmType::Pointer); + result.push(WasmType::Length); } TypeDefKind::Variant(v) => { From 037f708372bef4a2f92213b16da266ac5c3a3951 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 20 Feb 2024 09:17:47 -0800 Subject: [PATCH 2/3] Update tests. --- .../tests/components/adapt-memory-simple/component.wat | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/wit-component/tests/components/adapt-memory-simple/component.wat b/crates/wit-component/tests/components/adapt-memory-simple/component.wat index 59e9e1636d..f05ce41802 100644 --- a/crates/wit-component/tests/components/adapt-memory-simple/component.wat +++ b/crates/wit-component/tests/components/adapt-memory-simple/component.wat @@ -23,17 +23,18 @@ ) (core module (;2;) (type (;0;) (func (param i32 i32))) + (type (;1;) (func (param i32 i32))) (func $indirect-new-log (;0;) (type 0) (param i32 i32) local.get 0 local.get 1 i32.const 0 call_indirect (type 0) ) - (func $adapt-old-log (;1;) (type 0) (param i32 i32) + (func $adapt-old-log (;1;) (type 1) (param i32 i32) local.get 0 local.get 1 i32.const 1 - call_indirect (type 0) + call_indirect (type 1) ) (table (;0;) 2 2 funcref) (export "0" (func $indirect-new-log)) @@ -45,8 +46,9 @@ ) (core module (;3;) (type (;0;) (func (param i32 i32))) + (type (;1;) (func (param i32 i32))) (import "" "0" (func (;0;) (type 0))) - (import "" "1" (func (;1;) (type 0))) + (import "" "1" (func (;1;) (type 1))) (import "" "$imports" (table (;0;) 2 2 funcref)) (elem (;0;) (i32.const 0) func 0 1) (@producers From 75456fd61edc22a035a18b6abe34a0ddb283989d Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 20 Feb 2024 13:13:24 -0800 Subject: [PATCH 3/3] Rename `Pointer64` to `PointerOrI64`. --- crates/wit-component/src/dummy.rs | 2 +- crates/wit-component/src/encoding.rs | 2 +- crates/wit-component/src/encoding/world.rs | 2 +- crates/wit-component/src/validation.rs | 2 +- crates/wit-parser/src/abi.rs | 16 ++++++++-------- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/crates/wit-component/src/dummy.rs b/crates/wit-component/src/dummy.rs index c658165372..5aba44f97c 100644 --- a/crates/wit-component/src/dummy.rs +++ b/crates/wit-component/src/dummy.rs @@ -129,7 +129,7 @@ pub fn dummy_module(resolve: &Resolve, world: WorldId) -> Vec { WasmType::F32 => dst.push_str("f32"), WasmType::F64 => dst.push_str("f64"), WasmType::Pointer => dst.push_str("i32"), - WasmType::Pointer64 => dst.push_str("i64"), + WasmType::PointerOrI64 => dst.push_str("i64"), WasmType::Length => dst.push_str("i32"), } } diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs index 87ec147952..c4bdb0fed7 100644 --- a/crates/wit-component/src/encoding.rs +++ b/crates/wit-component/src/encoding.rs @@ -107,7 +107,7 @@ fn to_val_type(ty: &WasmType) -> ValType { WasmType::F32 => ValType::F32, WasmType::F64 => ValType::F64, WasmType::Pointer => ValType::I32, - WasmType::Pointer64 => ValType::I64, + WasmType::PointerOrI64 => ValType::I64, WasmType::Length => ValType::I32, } } diff --git a/crates/wit-component/src/encoding/world.rs b/crates/wit-component/src/encoding/world.rs index a1914a6059..e9e2242c63 100644 --- a/crates/wit-component/src/encoding/world.rs +++ b/crates/wit-component/src/encoding/world.rs @@ -225,7 +225,7 @@ impl<'a> ComponentWorld<'a> { WasmType::F32 => ValType::F32, WasmType::F64 => ValType::F64, WasmType::Pointer => ValType::I32, - WasmType::Pointer64 => ValType::I64, + WasmType::PointerOrI64 => ValType::I64, WasmType::Length => ValType::I32, } } diff --git a/crates/wit-component/src/validation.rs b/crates/wit-component/src/validation.rs index 5c3fafe189..b410443d4d 100644 --- a/crates/wit-component/src/validation.rs +++ b/crates/wit-component/src/validation.rs @@ -24,7 +24,7 @@ fn wasm_sig_to_func_type(signature: WasmSignature) -> FuncType { WasmType::F32 => ValType::F32, WasmType::F64 => ValType::F64, WasmType::Pointer => ValType::I32, - WasmType::Pointer64 => ValType::I64, + WasmType::PointerOrI64 => ValType::I64, WasmType::Length => ValType::I32, } } diff --git a/crates/wit-parser/src/abi.rs b/crates/wit-parser/src/abi.rs index 99282f9df1..1c3833844c 100644 --- a/crates/wit-parser/src/abi.rs +++ b/crates/wit-parser/src/abi.rs @@ -46,7 +46,7 @@ pub enum WasmType { /// /// Users that don't do anything special for pointers can treat this as /// `i64`. - Pointer64, + PointerOrI64, /// An array length type. In core Wasm this lowers to either `i32` or `i64` /// depending on the index type of the exported linear memory. @@ -67,7 +67,7 @@ fn join(a: WasmType, b: WasmType) -> WasmType { | (F32, F32) | (F64, F64) | (Pointer, Pointer) - | (Pointer64, Pointer64) + | (PointerOrI64, PointerOrI64) | (Length, Length) => a, (I32, F32) | (F32, I32) => I32, @@ -88,13 +88,13 @@ fn join(a: WasmType, b: WasmType) -> WasmType { (I32 | F32 | Length, Pointer) => Pointer, // If we need 64 bits and provenance, we need to use the special - // `Pointer64`. - (Pointer, I64 | F64) => Pointer64, - (I64 | F64, Pointer) => Pointer64, + // `PointerOrI64`. + (Pointer, I64 | F64) => PointerOrI64, + (I64 | F64, Pointer) => PointerOrI64, - // Pointer64 wins over everything. - (Pointer64, _) => Pointer64, - (_, Pointer64) => Pointer64, + // PointerOrI64 wins over everything. + (PointerOrI64, _) => PointerOrI64, + (_, PointerOrI64) => PointerOrI64, // Otherwise, `i64` wins. (_, I64 | F64) | (I64 | F64, _) => I64,