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", } }