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..359329b56 100644 --- a/crates/c/src/lib.rs +++ b/crates/c/src/lib.rs @@ -2205,13 +2205,18 @@ 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::None => results.push(op.to_string()), + Bitcast::I64ToP64 | Bitcast::P64ToI64 => { + results.push(format!("{}", op)); + } + Bitcast::I32ToP | Bitcast::PToI32 | Bitcast::None => { + results.push(op.to_string()) + } } } } @@ -2869,11 +2874,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 +3026,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..9b0c37654 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,24 @@ pub enum Bitcast { I64ToI32, I64ToF32, + // 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, + None, } @@ -1517,9 +1545,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 +1717,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 +1770,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 +1800,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 +1890,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 +1908,22 @@ 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, + + (I32, Pointer) => Bitcast::I32ToP, + (Pointer, I32) => Bitcast::PToI32, + + (Pointer | PointerOrI64 | Length, _) + | (_, Pointer | PointerOrI64 | Length) + | (F32, F64) + | (F64, F32) + | (F64, I32) + | (I32, F64) => { + unreachable!("Don't know how to bitcast from {:?} to {:?}", from, to); + } } } 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..607568366 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,22 @@ 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 +690,12 @@ 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 +703,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 +728,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}.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 +775,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}.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 +871,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = *(({} + {offset}) as *const i32);", + "let l{tmp} = *{}.add({offset}).cast::();", operands[0] ); results.push(format!("l{tmp}")); @@ -872,7 +880,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(*{}.add({offset}).cast::());", operands[0] ); results.push(format!("l{tmp}")); @@ -881,7 +889,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(*{}.add({offset}).cast::());", operands[0] ); results.push(format!("l{tmp}")); @@ -890,7 +898,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(*{}.add({offset}).cast::());", operands[0] ); results.push(format!("l{tmp}")); @@ -899,7 +907,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(*{}.add({offset}).cast::());", operands[0] ); results.push(format!("l{tmp}")); @@ -908,7 +916,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = *(({} + {offset}) as *const i64);", + "let l{tmp} = *{}.add({offset}).cast::();", operands[0] ); results.push(format!("l{tmp}")); @@ -917,7 +925,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = *(({} + {offset}) as *const f32);", + "let l{tmp} = *{}.add({offset}).cast::();", operands[0] ); results.push(format!("l{tmp}")); @@ -926,44 +934,77 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = *(({} + {offset}) as *const f64);", + "let l{tmp} = *{}.add({offset}).cast::();", + operands[0] + ); + results.push(format!("l{tmp}")); + } + + Instruction::PointerLoad { offset } => { + let tmp = self.tmp(); + uwriteln!( + self.src, + "let l{tmp} = *{}.add({offset}).cast::<*mut u8>();", + operands[0] + ); + results.push(format!("l{tmp}")); + } + Instruction::LengthLoad { offset } => { + let tmp = self.tmp(); + uwriteln!( + self.src, + "let l{tmp} = *{}.add({offset}).cast::();", operands[0] ); results.push(format!("l{tmp}")); } + Instruction::I32Store { offset } => { self.push_str(&format!( - "*(({} + {}) as *mut i32) = {};\n", + "*{}.add({}).cast::() = {};\n", operands[1], offset, operands[0] )); } Instruction::I32Store8 { offset } => { self.push_str(&format!( - "*(({} + {}) as *mut u8) = ({}) as u8;\n", + "*{}.add({}).cast::() = ({}) as u8;\n", operands[1], offset, operands[0] )); } Instruction::I32Store16 { offset } => { self.push_str(&format!( - "*(({} + {}) as *mut u16) = ({}) as u16;\n", + "*{}.add({}).cast::() = ({}) as u16;\n", operands[1], offset, operands[0] )); } Instruction::I64Store { offset } => { self.push_str(&format!( - "*(({} + {}) as *mut i64) = {};\n", + "*{}.add({}).cast::() = {};\n", operands[1], offset, operands[0] )); } Instruction::F32Store { offset } => { self.push_str(&format!( - "*(({} + {}) as *mut f32) = {};\n", + "*{}.add({}).cast::() = {};\n", operands[1], offset, operands[0] )); } Instruction::F64Store { offset } => { self.push_str(&format!( - "*(({} + {}) as *mut f64) = {};\n", + "*{}.add({}).cast::() = {};\n", + operands[1], offset, operands[0] + )); + } + + Instruction::PointerStore { offset } => { + self.push_str(&format!( + "*{}.add({}).cast::<*mut u8>() = {};\n", + operands[1], offset, operands[0] + )); + } + Instruction::LengthStore { offset } => { + self.push_str(&format!( + "*{}.add({}).cast::() = {};\n", operands[1], offset, operands[0] )); } @@ -981,7 +1022,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 +1069,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(".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..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([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..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: i32, size: usize, align: usize) { +pub unsafe fn cabi_dealloc(ptr: *mut u8, 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,6 +1248,15 @@ fn wasm_type(ty: WasmType) -> &'static str { WasmType::I64 => "i64", WasmType::F32 => "f32", WasmType::F64 => "f64", + WasmType::Pointer => "*mut u8", + 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,37 @@ 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 u8>().write({}); + t + }}", + operand + ) + } + // Convert a `MaybeUninit` holding a pointer value back into + // the pointer value. + Bitcast::P64ToP => { + format!("{}.as_mut_ptr().cast::<*mut u8>().read()", operand) + } + // Convert an `i32` into a pointer. + Bitcast::I32ToP => { + format!("{} as *mut u8", operand) + } + // Convert a pointer holding an `i32` value back into the `i32`. + Bitcast::PToI32 => { + format!("{} as i32", operand) + } }); } } diff --git a/crates/teavm-java/src/lib.rs b/crates/teavm-java/src/lib.rs index 3b51547bc..5376e5482 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,7 +1339,11 @@ impl Bindgen for FunctionBindgen<'_, '_> { Bitcast::F64ToI64 => format!("Double.doubleToLongBits({op})"), Bitcast::I32ToI64 => format!("(long) ({op})"), Bitcast::I64ToI32 => format!("(int) ({op})"), - Bitcast::None => op.to_owned(), + Bitcast::I64ToP64 => format!("{op}"), + Bitcast::P64ToI64 => format!("{op}"), + Bitcast::PToP64 => format!("(long) ({op})"), + Bitcast::P64ToP => format!("(int) ({op})"), + Bitcast::I32ToP | Bitcast::PToI32 | 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", } }