Skip to content

Commit

Permalink
Add pointer and length types to WasmType. (#1423)
Browse files Browse the repository at this point in the history
* 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`.

* Update tests.

* Rename `Pointer64` to `PointerOrI64`.
  • Loading branch information
sunfishcode authored Feb 20, 2024
1 parent 4eaf9fb commit 80ce319
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 12 deletions.
3 changes: 3 additions & 0 deletions crates/wit-component/src/dummy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ pub fn dummy_module(resolve: &Resolve, world: WorldId) -> Vec<u8> {
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::PointerOrI64 => dst.push_str("i64"),
WasmType::Length => dst.push_str("i32"),
}
}
dst.push(')');
Expand Down
3 changes: 3 additions & 0 deletions crates/wit-component/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::PointerOrI64 => ValType::I64,
WasmType::Length => ValType::I32,
}
}

Expand Down
3 changes: 3 additions & 0 deletions crates/wit-component/src/encoding/world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::PointerOrI64 => ValType::I64,
WasmType::Length => ValType::I32,
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions crates/wit-component/src/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::PointerOrI64 => ValType::I64,
WasmType::Length => ValType::I32,
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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
Expand Down
72 changes: 63 additions & 9 deletions crates/wit-parser/src/abi.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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`.
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.
///
/// 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.
}
Expand All @@ -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)
| (PointerOrI64, PointerOrI64)
| (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
// `PointerOrI64`.
(Pointer, I64 | F64) => PointerOrI64,
(I64 | F64, Pointer) => PointerOrI64,

// PointerOrI64 wins over everything.
(PointerOrI64, _) => PointerOrI64,
(_, PointerOrI64) => PointerOrI64,

// Otherwise, `i64` wins.
(_, I64 | F64) | (I64 | F64, _) => I64,
}
}
Expand Down Expand Up @@ -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;
}

Expand All @@ -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);
}
}
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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) => {
Expand Down

0 comments on commit 80ce319

Please sign in to comment.