Skip to content

Commit

Permalink
Preserve pointer provenance in the Rust backend.
Browse files Browse the repository at this point in the history
Use the new `Pointer` and `Length` types in the Rust backend to emit
code that uses `*mut c_void` and `usize` instead of `i32` when working
with pointers and array lengths.

To represent `PointerOrI64`, use a `MaybeUninit<u64>`, since that type
can hold any `u64` and is documented to also preserve provenance.

This change happens to get the generated Rust code close to supporting
memory64, however it isn't complete; the abi code still emits hard-coded
`+ 4` offsets for loading the length of a pointer+length pair in memory.
  • Loading branch information
sunfishcode committed Feb 27, 2024
1 parent ec84c8e commit 407e94a
Show file tree
Hide file tree
Showing 9 changed files with 254 additions and 105 deletions.
64 changes: 32 additions & 32 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ clap = { version = "4.3.19", features = ["derive"] }
env_logger = "0.10.0"
indexmap = "2.0.0"

wasmparser = "0.200.0"
wasm-encoder = "0.200.0"
wasm-metadata = "0.200.0"
wit-parser = "0.200.0"
wit-component = "0.200.0"
wasmparser = "0.201.0"
wasm-encoder = "0.201.0"
wasm-metadata = "0.201.0"
wit-parser = "0.201.0"
wit-component = "0.201.0"

wit-bindgen-core = { path = 'crates/core', version = '0.19.2' }
wit-bindgen-c = { path = 'crates/c', version = '0.19.2' }
Expand Down
20 changes: 16 additions & 4 deletions crates/c/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2205,12 +2205,15 @@ impl Bindgen for FunctionBindgen<'_, '_> {
op
));
}
Bitcast::I32ToI64 => {
Bitcast::I32ToI64 | Bitcast::PToP64 => {
results.push(format!("(int64_t) {}", op));
}
Bitcast::I64ToI32 => {
Bitcast::I64ToI32 | Bitcast::P64ToP => {
results.push(format!("(int32_t) {}", op));
}
Bitcast::I64ToP64 | Bitcast::P64ToI64 => {
results.push(format!("{}", op));
}
Bitcast::None => results.push(op.to_string()),
}
}
Expand Down Expand Up @@ -2869,11 +2872,17 @@ impl Bindgen for FunctionBindgen<'_, '_> {
}
}

Instruction::I32Load { offset } => self.load("int32_t", *offset, operands, results),
Instruction::I32Load { offset }
| Instruction::PointerLoad { offset }
| Instruction::LengthLoad { offset } => {
self.load("int32_t", *offset, operands, results)
}
Instruction::I64Load { offset } => self.load("int64_t", *offset, operands, results),
Instruction::F32Load { offset } => self.load("float", *offset, operands, results),
Instruction::F64Load { offset } => self.load("double", *offset, operands, results),
Instruction::I32Store { offset } => self.store("int32_t", *offset, operands),
Instruction::I32Store { offset }
| Instruction::PointerStore { offset }
| Instruction::LengthStore { offset } => self.store("int32_t", *offset, operands),
Instruction::I64Store { offset } => self.store("int64_t", *offset, operands),
Instruction::F32Store { offset } => self.store("float", *offset, operands),
Instruction::F64Store { offset } => self.store("double", *offset, operands),
Expand Down Expand Up @@ -3015,6 +3024,9 @@ fn wasm_type(ty: WasmType) -> &'static str {
WasmType::I64 => "int64_t",
WasmType::F32 => "float",
WasmType::F64 => "double",
WasmType::Pointer => "uintptr_t",
WasmType::PointerOrI64 => "int64_t",
WasmType::Length => "size_t",
}
}

Expand Down
53 changes: 43 additions & 10 deletions crates/core/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ def_instruction! {
/// it, using the specified constant offset.
F64Load { offset: i32 } : [1] => [1],

/// Like `I32Load` or `I64Load`, but for loading pointer values.
PointerLoad { offset: i32 } : [1] => [1],
/// Like `I32Load` or `I64Load`, but for loading array length values.
LengthLoad { offset: i32 } : [1] => [1],

/// Pops an `i32` address from the stack and then an `i32` value.
/// Stores the value in little-endian at the pointer specified plus the
/// constant `offset`.
Expand All @@ -138,6 +143,11 @@ def_instruction! {
/// constant `offset`.
F64Store { offset: i32 } : [2] => [0],

/// Like `I32Store` or `I64Store`, but for storing pointer values.
PointerStore { offset: i32 } : [2] => [0],
/// Like `I32Store` or `I64Store`, but for storing array length values.
LengthStore { offset: i32 } : [2] => [0],

// Scalar lifting/lowering

/// Converts an interface type `char` value to a 32-bit integer
Expand Down Expand Up @@ -526,6 +536,12 @@ pub enum Bitcast {
I64ToI32,
I64ToF32,

// Pointers
P64ToI64,
I64ToP64,
P64ToP,
PToP64,

None,
}

Expand Down Expand Up @@ -1517,9 +1533,9 @@ impl<'a, B: Bindgen> Generator<'a, B> {
// and the length into the high address.
self.lower(ty);
self.stack.push(addr.clone());
self.emit(&Instruction::I32Store { offset: offset + 4 });
self.emit(&Instruction::LengthStore { offset: offset + 4 });
self.stack.push(addr);
self.emit(&Instruction::I32Store { offset });
self.emit(&Instruction::PointerStore { offset });
}

fn write_fields_to_memory<'b>(
Expand Down Expand Up @@ -1689,9 +1705,9 @@ impl<'a, B: Bindgen> Generator<'a, B> {
// Read the pointer/len and then perform the standard lifting
// proceses.
self.stack.push(addr.clone());
self.emit(&Instruction::I32Load { offset });
self.emit(&Instruction::PointerLoad { offset });
self.stack.push(addr);
self.emit(&Instruction::I32Load { offset: offset + 4 });
self.emit(&Instruction::LengthLoad { offset: offset + 4 });
self.lift(ty);
}

Expand Down Expand Up @@ -1742,9 +1758,9 @@ impl<'a, B: Bindgen> Generator<'a, B> {
match *ty {
Type::String => {
self.stack.push(addr.clone());
self.emit(&Instruction::I32Load { offset });
self.emit(&Instruction::PointerLoad { offset });
self.stack.push(addr);
self.emit(&Instruction::I32Load { offset: offset + 4 });
self.emit(&Instruction::LengthLoad { offset: offset + 4 });
self.emit(&Instruction::GuestDeallocateString);
}

Expand Down Expand Up @@ -1772,9 +1788,9 @@ impl<'a, B: Bindgen> Generator<'a, B> {
self.finish_block(0);

self.stack.push(addr.clone());
self.emit(&Instruction::I32Load { offset });
self.emit(&Instruction::PointerLoad { offset });
self.stack.push(addr);
self.emit(&Instruction::I32Load { offset: offset + 4 });
self.emit(&Instruction::LengthLoad { offset: offset + 4 });
self.emit(&Instruction::GuestDeallocateList { element });
}

Expand Down Expand Up @@ -1862,7 +1878,12 @@ fn cast(from: WasmType, to: WasmType) -> Bitcast {
use WasmType::*;

match (from, to) {
(I32, I32) | (I64, I64) | (F32, F32) | (F64, F64) => Bitcast::None,
(I32, I32)
| (I64, I64)
| (F32, F32)
| (F64, F64)
| (Pointer, Pointer)
| (Length, Length) => Bitcast::None,

(I32, I64) => Bitcast::I32ToI64,
(F32, I32) => Bitcast::F32ToI32,
Expand All @@ -1875,7 +1896,19 @@ fn cast(from: WasmType, to: WasmType) -> Bitcast {
(F32, I64) => Bitcast::F32ToI64,
(I64, F32) => Bitcast::I64ToF32,

(F32, F64) | (F64, F32) | (F64, I32) | (I32, F64) => unreachable!(),
(I64, PointerOrI64) => Bitcast::I64ToP64,
(PointerOrI64, I64) => Bitcast::P64ToI64,
(Pointer, PointerOrI64) => Bitcast::PToP64,
(PointerOrI64, Pointer) => Bitcast::P64ToP,

(Pointer | PointerOrI64 | Length, _)
| (_, Pointer | PointerOrI64 | Length)
| (F32, F64)
| (F64, F32)
| (F64, I32)
| (I32, F64) => {
unreachable!()
}
}
}

Expand Down
Loading

0 comments on commit 407e94a

Please sign in to comment.