From 407e94a47cf24b8ea7644f993f1b00d8ee83bf07 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 13 Feb 2024 10:20:41 -0800 Subject: [PATCH 1/6] Preserve pointer provenance in the Rust backend. 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`, 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. --- Cargo.lock | 64 ++++++++--------- Cargo.toml | 10 +-- crates/c/src/lib.rs | 20 ++++-- crates/core/src/abi.rs | 53 +++++++++++--- crates/csharp/src/lib.rs | 14 +++- crates/rust/src/bindgen.rs | 135 +++++++++++++++++++++++------------ crates/rust/src/interface.rs | 8 +-- crates/rust/src/lib.rs | 37 +++++++++- crates/teavm-java/src/lib.rs | 18 ++++- 9 files changed, 254 insertions(+), 105 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3cdb0ed13..9503fcc73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1375,10 +1375,10 @@ name = "test-helpers" version = "0.0.0" dependencies = [ "codegen-macro", - "wasm-encoder 0.200.0", + "wasm-encoder 0.201.0", "wit-bindgen-core", "wit-component", - "wit-parser 0.200.0", + "wit-parser 0.201.0", ] [[package]] @@ -1677,18 +1677,18 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.200.0" +version = "0.201.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e3fb0c8fbddd78aa6095b850dfeedbc7506cf5f81e633f69cf8f2333ab84b9" +checksum = "b9c7d2731df60006819b013f64ccc2019691deccf6e11a1804bc850cd6748f1a" dependencies = [ "leb128", ] [[package]] name = "wasm-metadata" -version = "0.200.0" +version = "0.201.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b8cc0c21f46d55b0aaa419cacce1eadcf28eaebd0e1488d6a6313ee71a586" +checksum = "0fd83062c17b9f4985d438603cde0a5e8c5c8198201a6937f778b607924c7da2" dependencies = [ "anyhow", "indexmap", @@ -1696,8 +1696,8 @@ dependencies = [ "serde_derive", "serde_json", "spdx", - "wasm-encoder 0.200.0", - "wasmparser 0.200.0", + "wasm-encoder 0.201.0", + "wasmparser 0.201.0", ] [[package]] @@ -1723,9 +1723,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.200.0" +version = "0.201.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a03f65ac876612140c57ff6c3b8fe4990067cce97c2cfdb07368a3cc3354b062" +checksum = "84e5df6dba6c0d7fafc63a450f1738451ed7a0b52295d83e868218fa286bf708" dependencies = [ "bitflags 2.4.2", "indexmap", @@ -2095,24 +2095,24 @@ dependencies = [ [[package]] name = "wast" -version = "200.0.0" +version = "201.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1810d14e6b03ebb8fb05eef4009ad5749c989b65197d83bce7de7172ed91366" +checksum = "1ef6e1ef34d7da3e2b374fd2b1a9c0227aff6cad596e1b24df9b58d0f6222faa" dependencies = [ "bumpalo", "leb128", "memchr", "unicode-width", - "wasm-encoder 0.200.0", + "wasm-encoder 0.201.0", ] [[package]] name = "wat" -version = "1.200.0" +version = "1.201.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "776cbd10e217f83869beaa3f40e312bb9e91d5eee29bbf6f560db1261b6a4c3d" +checksum = "453d5b37a45b98dee4f4cb68015fc73634d7883bbef1c65e6e9c78d454cf3f32" dependencies = [ - "wast 200.0.0", + "wast 201.0.0", ] [[package]] @@ -2362,11 +2362,11 @@ dependencies = [ "clap", "heck", "test-helpers", - "wasm-encoder 0.200.0", + "wasm-encoder 0.201.0", "wasm-metadata", "wit-bindgen-core", "wit-component", - "wit-parser 0.200.0", + "wit-parser 0.201.0", ] [[package]] @@ -2377,8 +2377,8 @@ dependencies = [ "clap", "heck", "test-artifacts", - "wasm-encoder 0.200.0", - "wasmparser 0.200.0", + "wasm-encoder 0.201.0", + "wasmparser 0.201.0", "wasmtime", "wasmtime-wasi", "wit-bindgen-c", @@ -2389,7 +2389,7 @@ dependencies = [ "wit-bindgen-rust", "wit-bindgen-teavm-java", "wit-component", - "wit-parser 0.200.0", + "wit-parser 0.201.0", ] [[package]] @@ -2397,7 +2397,7 @@ name = "wit-bindgen-core" version = "0.19.2" dependencies = [ "anyhow", - "wit-parser 0.200.0", + "wit-parser 0.201.0", ] [[package]] @@ -2408,9 +2408,9 @@ dependencies = [ "clap", "heck", "test-helpers", - "wasm-encoder 0.200.0", + "wasm-encoder 0.201.0", "wasm-metadata", - "wasmparser 0.200.0", + "wasmparser 0.201.0", "wit-bindgen-core", "wit-component", ] @@ -2483,9 +2483,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.200.0" +version = "0.201.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39979723340baea490b87b11b2abae05f149d86f2b55c18d41d78a2a2b284c16" +checksum = "421c0c848a0660a8c22e2fd217929a0191f14476b68962afd2af89fd22e39825" dependencies = [ "anyhow", "bitflags 2.4.2", @@ -2494,11 +2494,11 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder 0.200.0", + "wasm-encoder 0.201.0", "wasm-metadata", - "wasmparser 0.200.0", + "wasmparser 0.201.0", "wat", - "wit-parser 0.200.0", + "wit-parser 0.201.0", ] [[package]] @@ -2520,9 +2520,9 @@ dependencies = [ [[package]] name = "wit-parser" -version = "0.200.0" +version = "0.201.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f717576b37f01c15696bda7f6f13868367b9c5913485f9f0ec8e59fd28c8e13" +checksum = "196d3ecfc4b759a8573bf86a9b3f8996b304b3732e4c7de81655f875f6efdca6" dependencies = [ "anyhow", "id-arena", @@ -2533,7 +2533,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.200.0", + "wasmparser 0.201.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8d5602bb4..88213e5d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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' } diff --git a/crates/c/src/lib.rs b/crates/c/src/lib.rs index 0f8dcea7e..222d987d3 100644 --- a/crates/c/src/lib.rs +++ b/crates/c/src/lib.rs @@ -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()), } } @@ -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), @@ -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", } } diff --git a/crates/core/src/abi.rs b/crates/core/src/abi.rs index 83fe4d39d..a65d1a655 100644 --- a/crates/core/src/abi.rs +++ b/crates/core/src/abi.rs @@ -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`. @@ -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 @@ -526,6 +536,12 @@ pub enum Bitcast { I64ToI32, I64ToF32, + // Pointers + P64ToI64, + I64ToP64, + P64ToP, + PToP64, + None, } @@ -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>( @@ -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); } @@ -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); } @@ -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 }); } @@ -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, @@ -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!() + } } } diff --git a/crates/csharp/src/lib.rs b/crates/csharp/src/lib.rs index efc51f522..2d66d2b60 100644 --- a/crates/csharp/src/lib.rs +++ b/crates/csharp/src/lib.rs @@ -1696,10 +1696,15 @@ impl Bindgen for FunctionBindgen<'_, '_> { WasmType::I64 => "0L", WasmType::F32 => "0.0F", WasmType::F64 => "0.0D", + WasmType::Pointer => "0", + WasmType::PointerOrI64 => "0L", + WasmType::Length => "0", } .to_owned() })), - Instruction::I32Load { offset } => match self.gen.direction { + Instruction::I32Load { offset } + | Instruction::PointerLoad { offset } + | Instruction::LengthLoad { offset } => match self.gen.direction { Direction::Import => results.push(format!("ReturnArea.GetS32(ptr + {offset})")), Direction::Export => results.push(format!("returnArea.GetS32({offset})")), }, @@ -1723,7 +1728,9 @@ impl Bindgen for FunctionBindgen<'_, '_> { } Instruction::F64Load { offset } => results.push(format!("ReturnArea.GetF64({offset})")), - Instruction::I32Store { offset } => { + Instruction::I32Store { offset } + | Instruction::PointerStore { offset } + | Instruction::LengthStore { offset } => { uwriteln!(self.src, "returnArea.SetS32({}, {});", offset, operands[0]) } Instruction::I32Store8 { offset } => { @@ -2223,6 +2230,9 @@ fn wasm_type(ty: WasmType) -> &'static str { WasmType::I64 => "long", WasmType::F32 => "float", WasmType::F64 => "double", + WasmType::Pointer => "int", + WasmType::PointerOrI64 => "long", + WasmType::Length => "int", } } diff --git a/crates/rust/src/bindgen.rs b/crates/rust/src/bindgen.rs index 352c43bcb..e2e822a5b 100644 --- a/crates/rust/src/bindgen.rs +++ b/crates/rust/src/bindgen.rs @@ -43,7 +43,7 @@ impl<'a, 'b> FunctionBindgen<'a, 'b> { for (ptr, layout) in mem::take(&mut self.cleanup) { let alloc = self.gen.path_to_std_alloc_module(); self.push_str(&format!( - "if {layout}.size() != 0 {{\n{alloc}::dealloc({ptr}, {layout});\n}}\n" + "if {layout}.size() != 0 {{\n{alloc}::dealloc({ptr}.cast(), {layout});\n}}\n" )); } if self.needs_cleanup_list { @@ -51,7 +51,7 @@ impl<'a, 'b> FunctionBindgen<'a, 'b> { self.push_str(&format!( "for (ptr, layout) in cleanup_list {{\n if layout.size() != 0 {{\n - {alloc}::dealloc(ptr, layout);\n + {alloc}::dealloc(ptr.cast(), layout);\n }}\n }}\n", )); @@ -268,11 +268,17 @@ impl Bindgen for FunctionBindgen<'_, '_> { self.import_return_pointer_area_size = self.import_return_pointer_area_size.max(size); self.import_return_pointer_area_align = self.import_return_pointer_area_align.max(align); - uwrite!(self.src, "let ptr{tmp} = ret_area.as_mut_ptr() as i32;"); + uwrite!( + self.src, + "let ptr{tmp} = ret_area.0.as_mut_ptr().cast::();" + ); } else { self.gen.return_pointer_area_size = self.gen.return_pointer_area_size.max(size); self.gen.return_pointer_area_align = self.gen.return_pointer_area_align.max(align); - uwriteln!(self.src, "let ptr{tmp} = _RET_AREA.0.as_mut_ptr() as i32;"); + uwriteln!( + self.src, + "let ptr{tmp} = _RET_AREA.0.as_mut_ptr().cast::();" + ); } format!("ptr{}", tmp) } @@ -315,6 +321,11 @@ impl Bindgen for FunctionBindgen<'_, '_> { WasmType::I64 => results.push("0i64".to_string()), WasmType::F32 => results.push("0.0f32".to_string()), WasmType::F64 => results.push("0.0f64".to_string()), + WasmType::Pointer => results.push("core::ptr::null_mut()".to_string()), + WasmType::PointerOrI64 => { + results.push("core::mem::MaybeUninit::::zeroed()".to_string()) + } + WasmType::Length => results.push("0usize".to_string()), } } } @@ -647,22 +658,25 @@ impl Bindgen for FunctionBindgen<'_, '_> { let op0 = operands.pop().unwrap(); self.push_str(&format!("let {} = ({}).into_boxed_slice();\n", val, op0)); } - self.push_str(&format!("let {} = {}.as_ptr() as i32;\n", ptr, val)); - self.push_str(&format!("let {} = {}.len() as i32;\n", len, val)); + self.push_str(&format!( + "let {} = {}.as_ptr().cast::();\n", + ptr, val + )); + self.push_str(&format!("let {} = {}.len();\n", len, val)); if realloc.is_some() { self.push_str(&format!("::core::mem::forget({});\n", val)); } - results.push(ptr); + results.push(format!("{ptr}.cast_mut()")); results.push(len); } Instruction::ListCanonLift { .. } => { let tmp = self.tmp(); let len = format!("len{}", tmp); - self.push_str(&format!("let {} = {} as usize;\n", len, operands[1])); + self.push_str(&format!("let {} = {};\n", len, operands[1])); let vec = self.gen.path_to_vec(); let result = format!( - "{vec}::from_raw_parts({} as *mut _, {1}, {1})", + "{vec}::from_raw_parts({}.cast(), {1}, {1})", operands[0], len ); results.push(result); @@ -679,12 +693,15 @@ impl Bindgen for FunctionBindgen<'_, '_> { let op0 = format!("{}.into_bytes()", operands[0]); self.push_str(&format!("let {} = ({}).into_boxed_slice();\n", val, op0)); } - self.push_str(&format!("let {} = {}.as_ptr() as i32;\n", ptr, val)); - self.push_str(&format!("let {} = {}.len() as i32;\n", len, val)); + self.push_str(&format!( + "let {} = {}.as_ptr().cast::();\n", + ptr, val + )); + self.push_str(&format!("let {} = {}.len();\n", len, val)); if realloc.is_some() { self.push_str(&format!("::core::mem::forget({});\n", val)); } - results.push(ptr); + results.push(format!("{ptr}.cast_mut()")); results.push(len); } @@ -692,10 +709,10 @@ impl Bindgen for FunctionBindgen<'_, '_> { let vec = self.gen.path_to_vec(); let tmp = self.tmp(); let len = format!("len{}", tmp); - uwriteln!(self.src, "let {len} = {} as usize;", operands[1]); + uwriteln!(self.src, "let {len} = {};", operands[1]); uwriteln!( self.src, - "let bytes{tmp} = {vec}::from_raw_parts({} as *mut _, {len}, {len});", + "let bytes{tmp} = {vec}::from_raw_parts({}.cast(), {len}, {len});", operands[0], ); if self.gen.gen.opts.raw_strings { @@ -717,26 +734,25 @@ impl Bindgen for FunctionBindgen<'_, '_> { "let {vec} = {operand0};\n", operand0 = operands[0] )); - self.push_str(&format!("let {len} = {vec}.len() as i32;\n")); + self.push_str(&format!("let {len} = {vec}.len();\n")); let size = self.gen.sizes.size(element); let align = self.gen.sizes.align(element); self.push_str(&format!( "let {layout} = {alloc}::Layout::from_size_align_unchecked({vec}.len() * {size}, {align});\n", )); + self.push_str(&format!("let {result} = if {layout}.size() != 0 {{\n")); self.push_str(&format!( - "let {result} = if {layout}.size() != 0 {{\nlet ptr = {alloc}::alloc({layout});\n", + "let ptr = {alloc}::alloc({layout}).cast::();\n", )); self.push_str(&format!( "if ptr.is_null()\n{{\n{alloc}::handle_alloc_error({layout});\n}}\nptr\n}}", )); self.push_str("else {{\n::core::ptr::null_mut()\n}};\n"); self.push_str(&format!("for (i, e) in {vec}.into_iter().enumerate() {{\n",)); - self.push_str(&format!( - "let base = {result} as i32 + (i as i32) * {size};\n", - )); + self.push_str(&format!("let base = {result}.byte_add(i * {size});\n",)); self.push_str(&body); self.push_str("\n}\n"); - results.push(format!("{result} as i32")); + results.push(format!("{result}")); results.push(len); if realloc.is_none() { @@ -765,19 +781,17 @@ impl Bindgen for FunctionBindgen<'_, '_> { )); let vec = self.gen.path_to_vec(); self.push_str(&format!( - "let mut {result} = {vec}::with_capacity({len} as usize);\n", + "let mut {result} = {vec}::with_capacity({len});\n", )); uwriteln!(self.src, "for i in 0..{len} {{"); - uwriteln!(self.src, "let base = {base} + i * {size};"); + uwriteln!(self.src, "let base = {base}.byte_add(i * {size});"); uwriteln!(self.src, "let e{tmp} = {body};"); uwriteln!(self.src, "{result}.push(e{tmp});"); uwriteln!(self.src, "}}"); results.push(result); let dealloc = self.gen.path_to_cabi_dealloc(); - self.push_str(&format!( - "{dealloc}({base}, ({len} as usize) * {size}, {align});\n", - )); + self.push_str(&format!("{dealloc}({base}, {len} * {size}, {align});\n",)); } Instruction::IterElem { .. } => results.push("e".to_string()), @@ -863,7 +877,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = *(({} + {offset}) as *const i32);", + "let l{tmp} = *{}.byte_add({offset}).cast::();", operands[0] ); results.push(format!("l{tmp}")); @@ -872,7 +886,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = i32::from(*(({} + {offset}) as *const u8));", + "let l{tmp} = i32::from(*{}.byte_add({offset}).cast::());", operands[0] ); results.push(format!("l{tmp}")); @@ -881,7 +895,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = i32::from(*(({} + {offset}) as *const i8));", + "let l{tmp} = i32::from(*{}.byte_add({offset}).cast::());", operands[0] ); results.push(format!("l{tmp}")); @@ -890,7 +904,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = i32::from(*(({} + {offset}) as *const u16));", + "let l{tmp} = i32::from(*{}.byte_add({offset}).cast::());", operands[0] ); results.push(format!("l{tmp}")); @@ -899,7 +913,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = i32::from(*(({} + {offset}) as *const i16));", + "let l{tmp} = i32::from(*{}.byte_add({offset}).cast::());", operands[0] ); results.push(format!("l{tmp}")); @@ -908,7 +922,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = *(({} + {offset}) as *const i64);", + "let l{tmp} = *{}.byte_add({offset}).cast::();", operands[0] ); results.push(format!("l{tmp}")); @@ -917,7 +931,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = *(({} + {offset}) as *const f32);", + "let l{tmp} = *{}.byte_add({offset}).cast::();", operands[0] ); results.push(format!("l{tmp}")); @@ -926,44 +940,77 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = *(({} + {offset}) as *const f64);", + "let l{tmp} = *{}.byte_add({offset}).cast::();", + operands[0] + ); + results.push(format!("l{tmp}")); + } + + Instruction::PointerLoad { offset } => { + let tmp = self.tmp(); + uwriteln!( + self.src, + "let l{tmp} = *{}.byte_add({offset}).cast::<*mut core::ffi::c_void>();", + operands[0] + ); + results.push(format!("l{tmp}")); + } + Instruction::LengthLoad { offset } => { + let tmp = self.tmp(); + uwriteln!( + self.src, + "let l{tmp} = *{}.byte_add({offset}).cast::();", operands[0] ); results.push(format!("l{tmp}")); } + Instruction::I32Store { offset } => { self.push_str(&format!( - "*(({} + {}) as *mut i32) = {};\n", + "*{}.byte_add({}).cast::() = {};\n", operands[1], offset, operands[0] )); } Instruction::I32Store8 { offset } => { self.push_str(&format!( - "*(({} + {}) as *mut u8) = ({}) as u8;\n", + "*{}.byte_add({}).cast::() = ({}) as u8;\n", operands[1], offset, operands[0] )); } Instruction::I32Store16 { offset } => { self.push_str(&format!( - "*(({} + {}) as *mut u16) = ({}) as u16;\n", + "*{}.byte_add({}).cast::() = ({}) as u16;\n", operands[1], offset, operands[0] )); } Instruction::I64Store { offset } => { self.push_str(&format!( - "*(({} + {}) as *mut i64) = {};\n", + "*{}.byte_add({}).cast::() = {};\n", operands[1], offset, operands[0] )); } Instruction::F32Store { offset } => { self.push_str(&format!( - "*(({} + {}) as *mut f32) = {};\n", + "*{}.byte_add({}).cast::() = {};\n", operands[1], offset, operands[0] )); } Instruction::F64Store { offset } => { self.push_str(&format!( - "*(({} + {}) as *mut f64) = {};\n", + "*{}.byte_add({}).cast::() = {};\n", + operands[1], offset, operands[0] + )); + } + + Instruction::PointerStore { offset } => { + self.push_str(&format!( + "*{}.byte_add({}).cast::<*mut core::ffi::c_void>() = {};\n", + operands[1], offset, operands[0] + )); + } + Instruction::LengthStore { offset } => { + self.push_str(&format!( + "*{}.byte_add({}).cast::() = {};\n", operands[1], offset, operands[0] )); } @@ -981,7 +1028,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { Instruction::GuestDeallocateString => { let dealloc = self.gen.path_to_cabi_dealloc(); self.push_str(&format!( - "{dealloc}({op0}, ({op1}) as usize, 1);\n", + "{dealloc}({op0}, {op1}, 1);\n", op0 = operands[0], op1 = operands[1], )); @@ -1028,16 +1075,14 @@ impl Bindgen for FunctionBindgen<'_, '_> { self.push_str(" {\n"); self.push_str("let base = "); self.push_str(&base); - self.push_str(" + i *"); + self.push_str(".byte_add(i * "); self.push_str(&size.to_string()); - self.push_str(";\n"); + self.push_str(");\n"); self.push_str(&body); self.push_str("\n}\n"); } let dealloc = self.gen.path_to_cabi_dealloc(); - self.push_str(&format!( - "{dealloc}({base}, ({len} as usize) * {size}, {align});\n", - )); + self.push_str(&format!("{dealloc}({base}, {len} * {size}, {align});\n",)); } } } diff --git a/crates/rust/src/interface.rs b/crates/rust/src/interface.rs index f09067f69..e1eaf2ea8 100644 --- a/crates/rust/src/interface.rs +++ b/crates/rust/src/interface.rs @@ -269,8 +269,8 @@ impl InterfaceGenerator<'_> { self.src, " #[repr(align({align}))] - struct _RetArea([u8; {size}]); - static mut _RET_AREA: _RetArea = _RetArea([0; {size}]); + struct _RetArea([core::mem::MaybeUninit::; {size}]); + static mut _RET_AREA: _RetArea = _RetArea([core::mem::MaybeUninit::uninit(); {size}]); ", align = self.return_pointer_area_align, size = self.return_pointer_area_size, @@ -396,8 +396,8 @@ impl InterfaceGenerator<'_> { self.src, " #[repr(align({import_return_pointer_area_align}))] - struct RetArea([u8; {import_return_pointer_area_size}]); - let mut ret_area = ::core::mem::MaybeUninit::::uninit(); + struct RetArea([core::mem::MaybeUninit::; {import_return_pointer_area_size}]); + let mut ret_area = RetArea([core::mem::MaybeUninit::uninit(); {import_return_pointer_area_size}]); ", ); } diff --git a/crates/rust/src/lib.rs b/crates/rust/src/lib.rs index d750157b2..b24cdc05a 100644 --- a/crates/rust/src/lib.rs +++ b/crates/rust/src/lib.rs @@ -379,7 +379,7 @@ impl RustWasm { self.rt_module.insert(RuntimeItem::StdAllocModule); self.src.push_str( "\ -pub unsafe fn cabi_dealloc(ptr: i32, size: usize, align: usize) { +pub unsafe fn cabi_dealloc(ptr: *mut core::ffi::c_void, size: usize, align: usize) { if size == 0 { return; } @@ -1248,6 +1248,15 @@ fn wasm_type(ty: WasmType) -> &'static str { WasmType::I64 => "i64", WasmType::F32 => "f32", WasmType::F64 => "f64", + WasmType::Pointer => "*mut core::ffi::c_void", + WasmType::Length => "usize", + + // `PointerOrI64` can hold either a `u64` or a pointer with provenance. + // Neither a `u64` nor a pointer type can portably do both, so we use + // `MaybeUninit`, since `MaybeUninit` is [documented] to preserve + // provenance. + // [documented]: https://github.com/rust-lang/rfcs/blob/master/text/3559-rust-has-provenance.md#reference-level-explanation + WasmType::PointerOrI64 => "core::mem::MaybeUninit::", } } @@ -1272,6 +1281,32 @@ fn bitcast(casts: &[Bitcast], operands: &[String], results: &mut Vec) { Bitcast::I64ToF64 => format!("f64::from_bits({} as u64)", operand), Bitcast::F32ToI64 => format!("i64::from(({}).to_bits())", operand), Bitcast::I64ToF32 => format!("f32::from_bits({} as u32)", operand), + + // Convert an `i64` into a `MaybeUninit`. + Bitcast::I64ToP64 => format!("core::mem::MaybeUninit::new({} as u64)", operand), + // Convert a `MaybeUninit` holding an `i64` value back into + // the `i64` value. + Bitcast::P64ToI64 => format!("{}.assume_init() as i64", operand), + + // Convert a pointer value into a `MaybeUninit`. + Bitcast::PToP64 => { + format!( + "{{ + let mut t = core::mem::MaybeUnunit::::uninit(); + t.as_mut_ptr().cast::<*mut core::ptr::c_void>().write({}); + t + }}", + operand + ) + } + // Convert a `MaybeUninit` holding a pointer value back into + // the pointer value. + Bitcast::P64ToP => { + format!( + "{}.as_mut_ptr().cast::<*mut core::ptr::c_void>().read()", + operand + ) + } }); } } diff --git a/crates/teavm-java/src/lib.rs b/crates/teavm-java/src/lib.rs index 3b51547bc..800f5eafd 100644 --- a/crates/teavm-java/src/lib.rs +++ b/crates/teavm-java/src/lib.rs @@ -1294,6 +1294,9 @@ impl Bindgen for FunctionBindgen<'_, '_> { WasmType::I64 => "0L", WasmType::F32 => "0.0F", WasmType::F64 => "0.0D", + WasmType::Pointer => "0", + WasmType::PointerOrI64 => "0L", + WasmType::Length => "0", } .to_owned() })), @@ -1336,6 +1339,10 @@ impl Bindgen for FunctionBindgen<'_, '_> { Bitcast::F64ToI64 => format!("Double.doubleToLongBits({op})"), Bitcast::I32ToI64 => format!("(long) ({op})"), Bitcast::I64ToI32 => format!("(int) ({op})"), + Bitcast::I64ToP64 => format!("{op}"), + Bitcast::P64ToI64 => format!("{op}"), + Bitcast::PToP64 => format!("(long) ({op})"), + Bitcast::P64ToP => format!("(int) ({op})"), Bitcast::None => op.to_owned(), })) } @@ -1863,7 +1870,9 @@ impl Bindgen for FunctionBindgen<'_, '_> { } } - Instruction::I32Load { offset } => results.push(format!( + Instruction::I32Load { offset } + | Instruction::PointerLoad { offset } + | Instruction::LengthLoad { offset } => results.push(format!( "Address.fromInt(({}) + {offset}).getInt()", operands[0] )), @@ -1903,7 +1912,9 @@ impl Bindgen for FunctionBindgen<'_, '_> { operands[0] )), - Instruction::I32Store { offset } => uwriteln!( + Instruction::I32Store { offset } + | Instruction::PointerStore { offset } + | Instruction::LengthStore { offset } => uwriteln!( self.src, "Address.fromInt(({}) + {offset}).putInt({});", operands[1], @@ -2103,6 +2114,9 @@ fn wasm_type(ty: WasmType) -> &'static str { WasmType::I64 => "long", WasmType::F32 => "float", WasmType::F64 => "double", + WasmType::Pointer => "int", + WasmType::PointerOrI64 => "long", + WasmType::Length => "int", } } From d2327abfef111a1b1d1d4d1bb753f8f0d1cfe741 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 27 Feb 2024 13:19:06 -0800 Subject: [PATCH 2/6] Fully-qualify `core` in macro expansions. --- crates/rust/src/bindgen.rs | 18 +++++++++--------- crates/rust/src/interface.rs | 8 ++++---- crates/rust/src/lib.rs | 12 ++++++------ 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/crates/rust/src/bindgen.rs b/crates/rust/src/bindgen.rs index e2e822a5b..60539e3ea 100644 --- a/crates/rust/src/bindgen.rs +++ b/crates/rust/src/bindgen.rs @@ -270,14 +270,14 @@ impl Bindgen for FunctionBindgen<'_, '_> { self.import_return_pointer_area_align.max(align); uwrite!( self.src, - "let ptr{tmp} = ret_area.0.as_mut_ptr().cast::();" + "let ptr{tmp} = ret_area.0.as_mut_ptr().cast::<::core::ffi::c_void>();" ); } else { self.gen.return_pointer_area_size = self.gen.return_pointer_area_size.max(size); self.gen.return_pointer_area_align = self.gen.return_pointer_area_align.max(align); uwriteln!( self.src, - "let ptr{tmp} = _RET_AREA.0.as_mut_ptr().cast::();" + "let ptr{tmp} = _RET_AREA.0.as_mut_ptr().cast::<::core::ffi::c_void>();" ); } format!("ptr{}", tmp) @@ -321,9 +321,9 @@ impl Bindgen for FunctionBindgen<'_, '_> { WasmType::I64 => results.push("0i64".to_string()), WasmType::F32 => results.push("0.0f32".to_string()), WasmType::F64 => results.push("0.0f64".to_string()), - WasmType::Pointer => results.push("core::ptr::null_mut()".to_string()), + WasmType::Pointer => results.push("::core::ptr::null_mut()".to_string()), WasmType::PointerOrI64 => { - results.push("core::mem::MaybeUninit::::zeroed()".to_string()) + results.push("::core::mem::MaybeUninit::::zeroed()".to_string()) } WasmType::Length => results.push("0usize".to_string()), } @@ -659,7 +659,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { self.push_str(&format!("let {} = ({}).into_boxed_slice();\n", val, op0)); } self.push_str(&format!( - "let {} = {}.as_ptr().cast::();\n", + "let {} = {}.as_ptr().cast::<::core::ffi::c_void>();\n", ptr, val )); self.push_str(&format!("let {} = {}.len();\n", len, val)); @@ -694,7 +694,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { self.push_str(&format!("let {} = ({}).into_boxed_slice();\n", val, op0)); } self.push_str(&format!( - "let {} = {}.as_ptr().cast::();\n", + "let {} = {}.as_ptr().cast::<::core::ffi::c_void>();\n", ptr, val )); self.push_str(&format!("let {} = {}.len();\n", len, val)); @@ -742,7 +742,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { )); self.push_str(&format!("let {result} = if {layout}.size() != 0 {{\n")); self.push_str(&format!( - "let ptr = {alloc}::alloc({layout}).cast::();\n", + "let ptr = {alloc}::alloc({layout}).cast::<::core::ffi::c_void>();\n", )); self.push_str(&format!( "if ptr.is_null()\n{{\n{alloc}::handle_alloc_error({layout});\n}}\nptr\n}}", @@ -950,7 +950,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = *{}.byte_add({offset}).cast::<*mut core::ffi::c_void>();", + "let l{tmp} = *{}.byte_add({offset}).cast::<*mut ::core::ffi::c_void>();", operands[0] ); results.push(format!("l{tmp}")); @@ -1004,7 +1004,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { Instruction::PointerStore { offset } => { self.push_str(&format!( - "*{}.byte_add({}).cast::<*mut core::ffi::c_void>() = {};\n", + "*{}.byte_add({}).cast::<*mut ::core::ffi::c_void>() = {};\n", operands[1], offset, operands[0] )); } diff --git a/crates/rust/src/interface.rs b/crates/rust/src/interface.rs index e1eaf2ea8..f08d166bf 100644 --- a/crates/rust/src/interface.rs +++ b/crates/rust/src/interface.rs @@ -269,8 +269,8 @@ impl InterfaceGenerator<'_> { self.src, " #[repr(align({align}))] - struct _RetArea([core::mem::MaybeUninit::; {size}]); - static mut _RET_AREA: _RetArea = _RetArea([core::mem::MaybeUninit::uninit(); {size}]); + struct _RetArea([::core::mem::MaybeUninit::; {size}]); + static mut _RET_AREA: _RetArea = _RetArea([::core::mem::MaybeUninit::uninit(); {size}]); ", align = self.return_pointer_area_align, size = self.return_pointer_area_size, @@ -396,8 +396,8 @@ impl InterfaceGenerator<'_> { self.src, " #[repr(align({import_return_pointer_area_align}))] - struct RetArea([core::mem::MaybeUninit::; {import_return_pointer_area_size}]); - let mut ret_area = RetArea([core::mem::MaybeUninit::uninit(); {import_return_pointer_area_size}]); + struct RetArea([::core::mem::MaybeUninit::; {import_return_pointer_area_size}]); + let mut ret_area = RetArea([::core::mem::MaybeUninit::uninit(); {import_return_pointer_area_size}]); ", ); } diff --git a/crates/rust/src/lib.rs b/crates/rust/src/lib.rs index b24cdc05a..a20093909 100644 --- a/crates/rust/src/lib.rs +++ b/crates/rust/src/lib.rs @@ -379,7 +379,7 @@ impl RustWasm { self.rt_module.insert(RuntimeItem::StdAllocModule); self.src.push_str( "\ -pub unsafe fn cabi_dealloc(ptr: *mut core::ffi::c_void, size: usize, align: usize) { +pub unsafe fn cabi_dealloc(ptr: *mut ::core::ffi::c_void, size: usize, align: usize) { if size == 0 { return; } @@ -444,7 +444,7 @@ pub unsafe fn bool_lift(val: u8) -> bool { _ => panic!(\"invalid bool discriminant\"), } } else { - core::mem::transmute::(val) + ::core::mem::transmute::(val) } } ", @@ -1248,7 +1248,7 @@ fn wasm_type(ty: WasmType) -> &'static str { WasmType::I64 => "i64", WasmType::F32 => "f32", WasmType::F64 => "f64", - WasmType::Pointer => "*mut core::ffi::c_void", + WasmType::Pointer => "*mut ::core::ffi::c_void", WasmType::Length => "usize", // `PointerOrI64` can hold either a `u64` or a pointer with provenance. @@ -1256,7 +1256,7 @@ fn wasm_type(ty: WasmType) -> &'static str { // `MaybeUninit`, since `MaybeUninit` is [documented] to preserve // provenance. // [documented]: https://github.com/rust-lang/rfcs/blob/master/text/3559-rust-has-provenance.md#reference-level-explanation - WasmType::PointerOrI64 => "core::mem::MaybeUninit::", + WasmType::PointerOrI64 => "::core::mem::MaybeUninit::", } } @@ -1283,7 +1283,7 @@ fn bitcast(casts: &[Bitcast], operands: &[String], results: &mut Vec) { Bitcast::I64ToF32 => format!("f32::from_bits({} as u32)", operand), // Convert an `i64` into a `MaybeUninit`. - Bitcast::I64ToP64 => format!("core::mem::MaybeUninit::new({} as u64)", operand), + Bitcast::I64ToP64 => format!("::core::mem::MaybeUninit::new({} as u64)", operand), // Convert a `MaybeUninit` holding an `i64` value back into // the `i64` value. Bitcast::P64ToI64 => format!("{}.assume_init() as i64", operand), @@ -1292,7 +1292,7 @@ fn bitcast(casts: &[Bitcast], operands: &[String], results: &mut Vec) { Bitcast::PToP64 => { format!( "{{ - let mut t = core::mem::MaybeUnunit::::uninit(); + let mut t = ::core::mem::MaybeUnunit::::uninit(); t.as_mut_ptr().cast::<*mut core::ptr::c_void>().write({}); t }}", From 7fdf8ca029c71c964a67c90c4b753d8cc15ee08d Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 27 Feb 2024 14:33:29 -0800 Subject: [PATCH 3/6] Fix bitcasts between i32 and pointer. --- crates/core/src/abi.rs | 7 ++++++- crates/rust/src/lib.rs | 8 ++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/crates/core/src/abi.rs b/crates/core/src/abi.rs index a65d1a655..270389aa2 100644 --- a/crates/core/src/abi.rs +++ b/crates/core/src/abi.rs @@ -541,6 +541,8 @@ pub enum Bitcast { I64ToP64, P64ToP, PToP64, + I32ToP, + PToI32, None, } @@ -1901,13 +1903,16 @@ fn cast(from: WasmType, to: WasmType) -> Bitcast { (Pointer, PointerOrI64) => Bitcast::PToP64, (PointerOrI64, Pointer) => Bitcast::P64ToP, + (I32, Pointer) => Bitcast::I32ToP, + (Pointer, I32) => Bitcast::PToI32, + (Pointer | PointerOrI64 | Length, _) | (_, Pointer | PointerOrI64 | Length) | (F32, F64) | (F64, F32) | (F64, I32) | (I32, F64) => { - unreachable!() + unreachable!("Don't know how to bitcast from {:?} to {:?}", from, to); } } } diff --git a/crates/rust/src/lib.rs b/crates/rust/src/lib.rs index a20093909..f20d42206 100644 --- a/crates/rust/src/lib.rs +++ b/crates/rust/src/lib.rs @@ -1307,6 +1307,14 @@ fn bitcast(casts: &[Bitcast], operands: &[String], results: &mut Vec) { operand ) } + // Convert an `i32` into a pointer. + Bitcast::I32ToP => { + format!("{} as *mut ::core::ffi::c_void", operand) + } + // Convert a pointer holding an `i32` value back into the `i32`. + Bitcast::PToI32 => { + format!("{} as i32", operand) + } }); } } From 8427d4af8d05ae4b051772ce266eeff9a3d6f792 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 27 Feb 2024 14:41:22 -0800 Subject: [PATCH 4/6] Implement Bitcast::I32ToP and PToI32 in more backends. --- crates/c/src/lib.rs | 4 +++- crates/teavm-java/src/lib.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/c/src/lib.rs b/crates/c/src/lib.rs index 222d987d3..359329b56 100644 --- a/crates/c/src/lib.rs +++ b/crates/c/src/lib.rs @@ -2214,7 +2214,9 @@ impl Bindgen for FunctionBindgen<'_, '_> { Bitcast::I64ToP64 | Bitcast::P64ToI64 => { results.push(format!("{}", op)); } - Bitcast::None => results.push(op.to_string()), + Bitcast::I32ToP | Bitcast::PToI32 | Bitcast::None => { + results.push(op.to_string()) + } } } } diff --git a/crates/teavm-java/src/lib.rs b/crates/teavm-java/src/lib.rs index 800f5eafd..5376e5482 100644 --- a/crates/teavm-java/src/lib.rs +++ b/crates/teavm-java/src/lib.rs @@ -1343,7 +1343,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { Bitcast::P64ToI64 => format!("{op}"), Bitcast::PToP64 => format!("(long) ({op})"), Bitcast::P64ToP => format!("(int) ({op})"), - Bitcast::None => op.to_owned(), + Bitcast::I32ToP | Bitcast::PToI32 | Bitcast::None => op.to_owned(), })) } From d295a51b90952323a6da4eab763ba8a08e924947 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 27 Feb 2024 15:36:56 -0800 Subject: [PATCH 5/6] Use `*mut u8` instead of `*mut c_void` for pointers. And switch to `add` from `byte_add`. --- crates/rust/src/bindgen.rs | 58 +++++++++++++++++--------------------- crates/rust/src/lib.rs | 13 ++++----- 2 files changed, 31 insertions(+), 40 deletions(-) diff --git a/crates/rust/src/bindgen.rs b/crates/rust/src/bindgen.rs index 60539e3ea..607568366 100644 --- a/crates/rust/src/bindgen.rs +++ b/crates/rust/src/bindgen.rs @@ -270,14 +270,14 @@ impl Bindgen for FunctionBindgen<'_, '_> { self.import_return_pointer_area_align.max(align); uwrite!( self.src, - "let ptr{tmp} = ret_area.0.as_mut_ptr().cast::<::core::ffi::c_void>();" + "let ptr{tmp} = ret_area.0.as_mut_ptr().cast::();" ); } else { self.gen.return_pointer_area_size = self.gen.return_pointer_area_size.max(size); self.gen.return_pointer_area_align = self.gen.return_pointer_area_align.max(align); uwriteln!( self.src, - "let ptr{tmp} = _RET_AREA.0.as_mut_ptr().cast::<::core::ffi::c_void>();" + "let ptr{tmp} = _RET_AREA.0.as_mut_ptr().cast::();" ); } format!("ptr{}", tmp) @@ -658,10 +658,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let op0 = operands.pop().unwrap(); self.push_str(&format!("let {} = ({}).into_boxed_slice();\n", val, op0)); } - self.push_str(&format!( - "let {} = {}.as_ptr().cast::<::core::ffi::c_void>();\n", - ptr, val - )); + self.push_str(&format!("let {} = {}.as_ptr().cast::();\n", ptr, val)); self.push_str(&format!("let {} = {}.len();\n", len, val)); if realloc.is_some() { self.push_str(&format!("::core::mem::forget({});\n", val)); @@ -693,10 +690,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let op0 = format!("{}.into_bytes()", operands[0]); self.push_str(&format!("let {} = ({}).into_boxed_slice();\n", val, op0)); } - self.push_str(&format!( - "let {} = {}.as_ptr().cast::<::core::ffi::c_void>();\n", - ptr, val - )); + self.push_str(&format!("let {} = {}.as_ptr().cast::();\n", ptr, val)); self.push_str(&format!("let {} = {}.len();\n", len, val)); if realloc.is_some() { self.push_str(&format!("::core::mem::forget({});\n", val)); @@ -742,14 +736,14 @@ impl Bindgen for FunctionBindgen<'_, '_> { )); self.push_str(&format!("let {result} = if {layout}.size() != 0 {{\n")); self.push_str(&format!( - "let ptr = {alloc}::alloc({layout}).cast::<::core::ffi::c_void>();\n", + "let ptr = {alloc}::alloc({layout}).cast::();\n", )); self.push_str(&format!( "if ptr.is_null()\n{{\n{alloc}::handle_alloc_error({layout});\n}}\nptr\n}}", )); self.push_str("else {{\n::core::ptr::null_mut()\n}};\n"); self.push_str(&format!("for (i, e) in {vec}.into_iter().enumerate() {{\n",)); - self.push_str(&format!("let base = {result}.byte_add(i * {size});\n",)); + self.push_str(&format!("let base = {result}.add(i * {size});\n",)); self.push_str(&body); self.push_str("\n}\n"); results.push(format!("{result}")); @@ -785,7 +779,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { )); uwriteln!(self.src, "for i in 0..{len} {{"); - uwriteln!(self.src, "let base = {base}.byte_add(i * {size});"); + uwriteln!(self.src, "let base = {base}.add(i * {size});"); uwriteln!(self.src, "let e{tmp} = {body};"); uwriteln!(self.src, "{result}.push(e{tmp});"); uwriteln!(self.src, "}}"); @@ -877,7 +871,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = *{}.byte_add({offset}).cast::();", + "let l{tmp} = *{}.add({offset}).cast::();", operands[0] ); results.push(format!("l{tmp}")); @@ -886,7 +880,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = i32::from(*{}.byte_add({offset}).cast::());", + "let l{tmp} = i32::from(*{}.add({offset}).cast::());", operands[0] ); results.push(format!("l{tmp}")); @@ -895,7 +889,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = i32::from(*{}.byte_add({offset}).cast::());", + "let l{tmp} = i32::from(*{}.add({offset}).cast::());", operands[0] ); results.push(format!("l{tmp}")); @@ -904,7 +898,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = i32::from(*{}.byte_add({offset}).cast::());", + "let l{tmp} = i32::from(*{}.add({offset}).cast::());", operands[0] ); results.push(format!("l{tmp}")); @@ -913,7 +907,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = i32::from(*{}.byte_add({offset}).cast::());", + "let l{tmp} = i32::from(*{}.add({offset}).cast::());", operands[0] ); results.push(format!("l{tmp}")); @@ -922,7 +916,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = *{}.byte_add({offset}).cast::();", + "let l{tmp} = *{}.add({offset}).cast::();", operands[0] ); results.push(format!("l{tmp}")); @@ -931,7 +925,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = *{}.byte_add({offset}).cast::();", + "let l{tmp} = *{}.add({offset}).cast::();", operands[0] ); results.push(format!("l{tmp}")); @@ -940,7 +934,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = *{}.byte_add({offset}).cast::();", + "let l{tmp} = *{}.add({offset}).cast::();", operands[0] ); results.push(format!("l{tmp}")); @@ -950,7 +944,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = *{}.byte_add({offset}).cast::<*mut ::core::ffi::c_void>();", + "let l{tmp} = *{}.add({offset}).cast::<*mut u8>();", operands[0] ); results.push(format!("l{tmp}")); @@ -959,7 +953,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = *{}.byte_add({offset}).cast::();", + "let l{tmp} = *{}.add({offset}).cast::();", operands[0] ); results.push(format!("l{tmp}")); @@ -967,50 +961,50 @@ impl Bindgen for FunctionBindgen<'_, '_> { Instruction::I32Store { offset } => { self.push_str(&format!( - "*{}.byte_add({}).cast::() = {};\n", + "*{}.add({}).cast::() = {};\n", operands[1], offset, operands[0] )); } Instruction::I32Store8 { offset } => { self.push_str(&format!( - "*{}.byte_add({}).cast::() = ({}) as u8;\n", + "*{}.add({}).cast::() = ({}) as u8;\n", operands[1], offset, operands[0] )); } Instruction::I32Store16 { offset } => { self.push_str(&format!( - "*{}.byte_add({}).cast::() = ({}) as u16;\n", + "*{}.add({}).cast::() = ({}) as u16;\n", operands[1], offset, operands[0] )); } Instruction::I64Store { offset } => { self.push_str(&format!( - "*{}.byte_add({}).cast::() = {};\n", + "*{}.add({}).cast::() = {};\n", operands[1], offset, operands[0] )); } Instruction::F32Store { offset } => { self.push_str(&format!( - "*{}.byte_add({}).cast::() = {};\n", + "*{}.add({}).cast::() = {};\n", operands[1], offset, operands[0] )); } Instruction::F64Store { offset } => { self.push_str(&format!( - "*{}.byte_add({}).cast::() = {};\n", + "*{}.add({}).cast::() = {};\n", operands[1], offset, operands[0] )); } Instruction::PointerStore { offset } => { self.push_str(&format!( - "*{}.byte_add({}).cast::<*mut ::core::ffi::c_void>() = {};\n", + "*{}.add({}).cast::<*mut u8>() = {};\n", operands[1], offset, operands[0] )); } Instruction::LengthStore { offset } => { self.push_str(&format!( - "*{}.byte_add({}).cast::() = {};\n", + "*{}.add({}).cast::() = {};\n", operands[1], offset, operands[0] )); } @@ -1075,7 +1069,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { self.push_str(" {\n"); self.push_str("let base = "); self.push_str(&base); - self.push_str(".byte_add(i * "); + self.push_str(".add(i * "); self.push_str(&size.to_string()); self.push_str(");\n"); self.push_str(&body); diff --git a/crates/rust/src/lib.rs b/crates/rust/src/lib.rs index f20d42206..c73e7b5ea 100644 --- a/crates/rust/src/lib.rs +++ b/crates/rust/src/lib.rs @@ -379,7 +379,7 @@ impl RustWasm { self.rt_module.insert(RuntimeItem::StdAllocModule); self.src.push_str( "\ -pub unsafe fn cabi_dealloc(ptr: *mut ::core::ffi::c_void, size: usize, align: usize) { +pub unsafe fn cabi_dealloc(ptr: *mut u8, size: usize, align: usize) { if size == 0 { return; } @@ -1248,7 +1248,7 @@ fn wasm_type(ty: WasmType) -> &'static str { WasmType::I64 => "i64", WasmType::F32 => "f32", WasmType::F64 => "f64", - WasmType::Pointer => "*mut ::core::ffi::c_void", + WasmType::Pointer => "*mut u8", WasmType::Length => "usize", // `PointerOrI64` can hold either a `u64` or a pointer with provenance. @@ -1293,7 +1293,7 @@ fn bitcast(casts: &[Bitcast], operands: &[String], results: &mut Vec) { format!( "{{ let mut t = ::core::mem::MaybeUnunit::::uninit(); - t.as_mut_ptr().cast::<*mut core::ptr::c_void>().write({}); + t.as_mut_ptr().cast::<*mut u8>().write({}); t }}", operand @@ -1302,14 +1302,11 @@ fn bitcast(casts: &[Bitcast], operands: &[String], results: &mut Vec) { // Convert a `MaybeUninit` holding a pointer value back into // the pointer value. Bitcast::P64ToP => { - format!( - "{}.as_mut_ptr().cast::<*mut core::ptr::c_void>().read()", - operand - ) + format!("{}.as_mut_ptr().cast::<*mut u8>().read()", operand) } // Convert an `i32` into a pointer. Bitcast::I32ToP => { - format!("{} as *mut ::core::ffi::c_void", operand) + format!("{} as *mut u8", operand) } // Convert a pointer holding an `i32` value back into the `i32`. Bitcast::PToI32 => { From 4f468085a939a16ff6b85810c716ac00448d92a4 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 27 Feb 2024 16:06:46 -0800 Subject: [PATCH 6/6] Add documentation to `Bitcast` arms about provenance. --- crates/core/src/abi.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/crates/core/src/abi.rs b/crates/core/src/abi.rs index 270389aa2..9b0c37654 100644 --- a/crates/core/src/abi.rs +++ b/crates/core/src/abi.rs @@ -536,11 +536,21 @@ pub enum Bitcast { I64ToI32, I64ToF32, - // Pointers - P64ToI64, - I64ToP64, + // PointerOrI64<->Pointer conversions. These preserve provenance. + // + // These are used when pointer values are being stored in + // (PToP64) and loaded out of (P64ToP) PointerOrI64 values, so they + // always have to preserve provenance. P64ToP, PToP64, + + // Pointer<->integer conversions. These do not preserve provenance. + // + // These are used when integer values are being stored in + // (I64ToP64 and I32ToP) and loaded out of (P64ToI64 and PToI32) pointer + // or PointerOrI64 values, so they never have any provenance to preserve. + P64ToI64, + I64ToP64, I32ToP, PToI32,