diff --git a/crates/c/src/lib.rs b/crates/c/src/lib.rs index 424cb0e8f..6d1ae0671 100644 --- a/crates/c/src/lib.rs +++ b/crates/c/src/lib.rs @@ -18,8 +18,8 @@ struct C { opts: Opts, h_includes: Vec, c_includes: Vec, - return_pointer_area_size: usize, - return_pointer_area_align: usize, + return_pointer_area_size: ArchitectureSize, + return_pointer_area_align: Alignment, names: Ns, needs_string: bool, needs_union_int32_float: bool, @@ -463,7 +463,7 @@ impl WorldGenerator for C { // Declare a statically-allocated return area, if needed. We only do // this for export bindings, because import bindings allocate their // return-area on the stack. - if self.return_pointer_area_size > 0 { + if !self.return_pointer_area_size.is_empty() { // Automatic indentation avoided due to `extern "C" {` declaration uwrite!( c_str, @@ -471,8 +471,10 @@ impl WorldGenerator for C { __attribute__((__aligned__({}))) static uint8_t RET_AREA[{}]; ", - self.return_pointer_area_align, - self.return_pointer_area_size, + self.return_pointer_area_align + .format(POINTER_SIZE_EXPRESSION), + self.return_pointer_area_size + .format(POINTER_SIZE_EXPRESSION), ); } c_str.push_str(&self.src.c_adapters); @@ -1779,12 +1781,14 @@ impl InterfaceGenerator<'_> { .. } = f; - if import_return_pointer_area_size > 0 { + if !import_return_pointer_area_size.is_empty() { self.src.c_adapters(&format!( "\ - __attribute__((__aligned__({import_return_pointer_area_align}))) - uint8_t ret_area[{import_return_pointer_area_size}]; + __attribute__((__aligned__({}))) + uint8_t ret_area[{}]; ", + import_return_pointer_area_align.format(POINTER_SIZE_EXPRESSION), + import_return_pointer_area_size.format(POINTER_SIZE_EXPRESSION), )); } @@ -2121,8 +2125,8 @@ struct FunctionBindgen<'a, 'b> { params: Vec, wasm_return: Option, ret_store_cnt: usize, - import_return_pointer_area_size: usize, - import_return_pointer_area_align: usize, + import_return_pointer_area_size: ArchitectureSize, + import_return_pointer_area_align: Alignment, /// Borrows observed during lifting an export, that will need to be dropped when the guest /// function exits. @@ -2150,8 +2154,8 @@ impl<'a, 'b> FunctionBindgen<'a, 'b> { params: Vec::new(), wasm_return: None, ret_store_cnt: 0, - import_return_pointer_area_size: 0, - import_return_pointer_area_align: 0, + import_return_pointer_area_size: Default::default(), + import_return_pointer_area_align: Default::default(), borrow_decls: Default::default(), borrows: Vec::new(), } @@ -2164,23 +2168,40 @@ impl<'a, 'b> FunctionBindgen<'a, 'b> { self.src.push_str(";\n"); } - fn load(&mut self, ty: &str, offset: i32, operands: &[String], results: &mut Vec) { - results.push(format!("*(({}*) ({} + {}))", ty, operands[0], offset)); + fn load( + &mut self, + ty: &str, + offset: ArchitectureSize, + operands: &[String], + results: &mut Vec, + ) { + results.push(format!( + "*(({}*) ({} + {}))", + ty, + operands[0], + offset.format(POINTER_SIZE_EXPRESSION) + )); } - fn load_ext(&mut self, ty: &str, offset: i32, operands: &[String], results: &mut Vec) { + fn load_ext( + &mut self, + ty: &str, + offset: ArchitectureSize, + operands: &[String], + results: &mut Vec, + ) { self.load(ty, offset, operands, results); let result = results.pop().unwrap(); results.push(format!("(int32_t) {}", result)); } - fn store(&mut self, ty: &str, offset: i32, operands: &[String]) { + fn store(&mut self, ty: &str, offset: ArchitectureSize, operands: &[String]) { uwriteln!( self.src, "*(({}*)({} + {})) = {};", ty, operands[1], - offset, + offset.format(POINTER_SIZE_EXPRESSION), operands[0] ); } @@ -2230,7 +2251,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { self.blocks.push((src.into(), mem::take(operands))); } - fn return_pointer(&mut self, size: usize, align: usize) -> String { + fn return_pointer(&mut self, size: ArchitectureSize, align: Alignment) -> String { let ptr = self.locals.tmp("ptr"); // Use a stack-based return area for imports, because exports need @@ -3034,8 +3055,12 @@ impl Bindgen for FunctionBindgen<'_, '_> { uwriteln!(self.src, "uint8_t *{ptr} = {};", operands[0]); let i = self.locals.tmp("i"); uwriteln!(self.src, "for (size_t {i} = 0; {i} < {len}; {i}++) {{"); - let size = self.gen.gen.sizes.size(element).size_wasm32(); - uwriteln!(self.src, "uint8_t *base = {ptr} + {i} * {size};"); + let size = self.gen.gen.sizes.size(element); + uwriteln!( + self.src, + "uint8_t *base = {ptr} + {i} * {};", + size.format(POINTER_SIZE_EXPRESSION) + ); uwriteln!(self.src, "(void) base;"); uwrite!(self.src, "{body}"); uwriteln!(self.src, "}}"); @@ -3272,3 +3297,5 @@ pub fn to_c_ident(name: &str) -> String { s => s.to_snake_case(), } } + +const POINTER_SIZE_EXPRESSION: &str = "sizeof(void*)"; diff --git a/crates/core/src/abi.rs b/crates/core/src/abi.rs index 9be5533df..ebb620b6c 100644 --- a/crates/core/src/abi.rs +++ b/crates/core/src/abi.rs @@ -1,7 +1,7 @@ pub use wit_parser::abi::{AbiVariant, WasmSignature, WasmType}; use wit_parser::{ - ElementInfo, Enum, Flags, FlagsRepr, Function, Handle, Int, Record, Resolve, Result_, - SizeAlign, Tuple, Type, TypeDefKind, TypeId, Variant, + align_to_arch, Alignment, ArchitectureSize, ElementInfo, Enum, Flags, FlagsRepr, Function, + Handle, Int, Record, Resolve, Result_, SizeAlign, Tuple, Type, TypeDefKind, TypeId, Variant, }; // Helper macro for defining instructions without having to have tons of @@ -86,67 +86,67 @@ def_instruction! { /// Pops a pointer from the stack and loads a little-endian `i32` from /// it, using the specified constant offset. - I32Load { offset: i32 } : [1] => [1], + I32Load { offset: ArchitectureSize } : [1] => [1], /// Pops a pointer from the stack and loads a little-endian `i8` from /// it, using the specified constant offset. The value loaded is the /// zero-extended to 32-bits - I32Load8U { offset: i32 } : [1] => [1], + I32Load8U { offset: ArchitectureSize } : [1] => [1], /// Pops a pointer from the stack and loads a little-endian `i8` from /// it, using the specified constant offset. The value loaded is the /// sign-extended to 32-bits - I32Load8S { offset: i32 } : [1] => [1], + I32Load8S { offset: ArchitectureSize } : [1] => [1], /// Pops a pointer from the stack and loads a little-endian `i16` from /// it, using the specified constant offset. The value loaded is the /// zero-extended to 32-bits - I32Load16U { offset: i32 } : [1] => [1], + I32Load16U { offset: ArchitectureSize } : [1] => [1], /// Pops a pointer from the stack and loads a little-endian `i16` from /// it, using the specified constant offset. The value loaded is the /// sign-extended to 32-bits - I32Load16S { offset: i32 } : [1] => [1], + I32Load16S { offset: ArchitectureSize } : [1] => [1], /// Pops a pointer from the stack and loads a little-endian `i64` from /// it, using the specified constant offset. - I64Load { offset: i32 } : [1] => [1], + I64Load { offset: ArchitectureSize } : [1] => [1], /// Pops a pointer from the stack and loads a little-endian `f32` from /// it, using the specified constant offset. - F32Load { offset: i32 } : [1] => [1], + F32Load { offset: ArchitectureSize } : [1] => [1], /// Pops a pointer from the stack and loads a little-endian `f64` from /// it, using the specified constant offset. - F64Load { offset: i32 } : [1] => [1], + F64Load { offset: ArchitectureSize } : [1] => [1], /// Like `I32Load` or `I64Load`, but for loading pointer values. - PointerLoad { offset: i32 } : [1] => [1], + PointerLoad { offset: ArchitectureSize } : [1] => [1], /// Like `I32Load` or `I64Load`, but for loading array length values. - LengthLoad { offset: i32 } : [1] => [1], + LengthLoad { offset: ArchitectureSize } : [1] => [1], /// Pops a pointer from the stack and then an `i32` value. /// Stores the value in little-endian at the pointer specified plus the /// constant `offset`. - I32Store { offset: i32 } : [2] => [0], + I32Store { offset: ArchitectureSize } : [2] => [0], /// Pops a pointer from the stack and then an `i32` value. /// Stores the low 8 bits of the value in little-endian at the pointer /// specified plus the constant `offset`. - I32Store8 { offset: i32 } : [2] => [0], + I32Store8 { offset: ArchitectureSize } : [2] => [0], /// Pops a pointer from the stack and then an `i32` value. /// Stores the low 16 bits of the value in little-endian at the pointer /// specified plus the constant `offset`. - I32Store16 { offset: i32 } : [2] => [0], + I32Store16 { offset: ArchitectureSize } : [2] => [0], /// Pops a pointer from the stack and then an `i64` value. /// Stores the value in little-endian at the pointer specified plus the /// constant `offset`. - I64Store { offset: i32 } : [2] => [0], + I64Store { offset: ArchitectureSize } : [2] => [0], /// Pops a pointer from the stack and then an `f32` value. /// Stores the value in little-endian at the pointer specified plus the /// constant `offset`. - F32Store { offset: i32 } : [2] => [0], + F32Store { offset: ArchitectureSize } : [2] => [0], /// Pops a pointer from the stack and then an `f64` value. /// Stores the value in little-endian at the pointer specified plus the /// constant `offset`. - F64Store { offset: i32 } : [2] => [0], + F64Store { offset: ArchitectureSize } : [2] => [0], /// Like `I32Store` or `I64Store`, but for storing pointer values. - PointerStore { offset: i32 } : [2] => [0], + PointerStore { offset: ArchitectureSize } : [2] => [0], /// Like `I32Store` or `I64Store`, but for storing array length values. - LengthStore { offset: i32 } : [2] => [0], + LengthStore { offset: ArchitectureSize } : [2] => [0], // Scalar lifting/lowering @@ -513,8 +513,8 @@ def_instruction! { /// Pushes the returned pointer onto the stack. Malloc { realloc: &'static str, - size: usize, - align: usize, + size: ArchitectureSize, + align: Alignment, } : [0] => [1], /// Used exclusively for guest-code generation this indicates that @@ -523,8 +523,8 @@ def_instruction! { /// /// This will pop a pointer from the stack and push nothing. GuestDeallocate { - size: usize, - align: usize, + size: ArchitectureSize, + align: Alignment, } : [1] => [0], /// Used exclusively for guest-code generation this indicates that @@ -678,7 +678,7 @@ pub trait Bindgen { /// Gets a operand reference to the return pointer area. /// /// The provided size and alignment is for the function's return type. - fn return_pointer(&mut self, size: usize, align: usize) -> Self::Operand; + fn return_pointer(&mut self, size: ArchitectureSize, align: Alignment) -> Self::Operand; /// Enters a new block of code to generate code for. /// @@ -757,7 +757,7 @@ pub fn lower_to_memory( true, ); generator.stack.push(value); - generator.write_to_memory(ty, address, 0); + generator.write_to_memory(ty, address, Default::default()); } pub fn lift_from_memory( @@ -774,7 +774,7 @@ pub fn lift_from_memory( bindgen, true, ); - generator.read_from_memory(ty, address, 0); + generator.read_from_memory(ty, address, Default::default()); generator.stack.pop().unwrap() } @@ -891,12 +891,12 @@ impl<'a, B: Bindgen> Generator<'a, B> { } let lower_to_memory = |self_: &mut Self, ptr: B::Operand| { - let mut offset = 0usize; + let mut offset = ArchitectureSize::default(); for (nth, (_, ty)) in func.params.iter().enumerate() { self_.emit(&Instruction::GetArg { nth }); - offset = align_to(offset, self_.bindgen.sizes().align(ty).align_wasm32()); - self_.write_to_memory(ty, ptr.clone(), offset as i32); - offset += self_.bindgen.sizes().size(ty).size_wasm32(); + offset = align_to_arch(offset, self_.bindgen.sizes().align(ty)); + self_.write_to_memory(ty, ptr.clone(), offset); + offset += self_.bindgen.sizes().size(ty); } self_.stack.push(ptr); @@ -907,9 +907,7 @@ impl<'a, B: Bindgen> Generator<'a, B> { .bindgen .sizes() .record(func.params.iter().map(|(_, ty)| ty)); - let ptr = self - .bindgen - .return_pointer(size.size_wasm32(), align.align_wasm32()); + let ptr = self.bindgen.return_pointer(size, align); lower_to_memory(self, ptr); } else { if !sig.indirect_params { @@ -924,23 +922,21 @@ impl<'a, B: Bindgen> Generator<'a, B> { // ... otherwise if parameters are indirect space is // allocated from them and each argument is lowered // individually into memory. - let info = self + let ElementInfo { size, align } = self .bindgen .sizes() .record(func.params.iter().map(|t| &t.1)); let ptr = match self.variant { // When a wasm module calls an import it will provide // space that isn't explicitly deallocated. - AbiVariant::GuestImport => self - .bindgen - .return_pointer(info.size.size_wasm32(), info.align.align_wasm32()), + AbiVariant::GuestImport => self.bindgen.return_pointer(size, align), // When calling a wasm module from the outside, though, // malloc needs to be called. AbiVariant::GuestExport => { self.emit(&Instruction::Malloc { realloc: "cabi_realloc", - size: info.size.size_wasm32(), - align: info.align.align_wasm32(), + size, + align, }); self.stack.pop().unwrap() } @@ -957,9 +953,7 @@ impl<'a, B: Bindgen> Generator<'a, B> { if self.async_ { let ElementInfo { size, align } = self.bindgen.sizes().record(func.result.iter()); - let ptr = self - .bindgen - .return_pointer(size.size_wasm32(), align.align_wasm32()); + let ptr = self.bindgen.return_pointer(size, align); self.return_pointer = Some(ptr.clone()); self.stack.push(ptr); @@ -972,9 +966,7 @@ impl<'a, B: Bindgen> Generator<'a, B> { // this ABI. if self.variant == AbiVariant::GuestImport && sig.retptr { let info = self.bindgen.sizes().params(&func.result); - let ptr = self - .bindgen - .return_pointer(info.size.size_wasm32(), info.align.align_wasm32()); + let ptr = self.bindgen.return_pointer(info.size, info.align); self.return_pointer = Some(ptr.clone()); self.stack.push(ptr); } @@ -1017,7 +1009,11 @@ impl<'a, B: Bindgen> Generator<'a, B> { } }; - self.read_results_from_memory(&func.result, ptr.clone(), 0); + self.read_results_from_memory( + &func.result, + ptr.clone(), + ArchitectureSize::default(), + ); self.emit(&Instruction::Flush { amt: usize::from(func.result.is_some()), }); @@ -1034,12 +1030,12 @@ impl<'a, B: Bindgen> Generator<'a, B> { } let read_from_memory = |self_: &mut Self| { - let mut offset = 0usize; + let mut offset = ArchitectureSize::default(); let ptr = self_.stack.pop().unwrap(); for (_, ty) in func.params.iter() { - offset = align_to(offset, self_.bindgen.sizes().align(ty).align_wasm32()); - self_.read_from_memory(ty, ptr.clone(), offset as i32); - offset += self_.bindgen.sizes().size(ty).size_wasm32(); + offset = align_to_arch(offset, self_.bindgen.sizes().align(ty)); + self_.read_from_memory(ty, ptr.clone(), offset); + offset += self_.bindgen.sizes().size(ty); } }; @@ -1089,15 +1085,12 @@ impl<'a, B: Bindgen> Generator<'a, B> { // deallocate it. if let AbiVariant::GuestExport = self.variant { if sig.indirect_params && !self.async_ { - let info = self + let ElementInfo { size, align } = self .bindgen .sizes() .record(func.params.iter().map(|t| &t.1)); self.emit(&Instruction::GetArg { nth: 0 }); - self.emit(&Instruction::GuestDeallocate { - size: info.size.size_wasm32(), - align: info.align.align_wasm32(), - }); + self.emit(&Instruction::GuestDeallocate { size, align }); } } @@ -1120,7 +1113,7 @@ impl<'a, B: Bindgen> Generator<'a, B> { nth: sig.params.len() - 1, }); let ptr = self.stack.pop().unwrap(); - self.write_params_to_memory(&func.result, ptr, 0); + self.write_params_to_memory(&func.result, ptr, Default::default()); } // For a guest import this is a function defined in @@ -1129,11 +1122,14 @@ impl<'a, B: Bindgen> Generator<'a, B> { // (statically) and then write the result into that // memory, returning the pointer at the end. AbiVariant::GuestExport => { - let info = self.bindgen.sizes().params(&func.result); - let ptr = self - .bindgen - .return_pointer(info.size.size_wasm32(), info.align.align_wasm32()); - self.write_params_to_memory(&func.result, ptr.clone(), 0); + let ElementInfo { size, align } = + self.bindgen.sizes().params(&func.result); + let ptr = self.bindgen.return_pointer(size, align); + self.write_params_to_memory( + &func.result, + ptr.clone(), + Default::default(), + ); self.stack.push(ptr); } @@ -1185,8 +1181,6 @@ impl<'a, B: Bindgen> Generator<'a, B> { self.emit(&Instruction::GetArg { nth: 0 }); let addr = self.stack.pop().unwrap(); for (offset, ty) in self.bindgen.sizes().field_offsets(&func.result) { - let offset = offset.size_wasm32(); - let offset = i32::try_from(offset).unwrap(); self.deallocate(ty, addr.clone(), offset); } self.emit(&Instruction::Return { func, amt: 0 }); @@ -1273,7 +1267,7 @@ impl<'a, B: Bindgen> Generator<'a, B> { self.emit(&IterElem { element }); self.emit(&IterBasePointer); let addr = self.stack.pop().unwrap(); - self.write_to_memory(element, addr, 0); + self.write_to_memory(element, addr, Default::default()); self.finish_block(0); self.emit(&ListLower { element, realloc }); } @@ -1469,7 +1463,7 @@ impl<'a, B: Bindgen> Generator<'a, B> { self.push_block(); self.emit(&IterBasePointer); let addr = self.stack.pop().unwrap(); - self.read_from_memory(element, addr, 0); + self.read_from_memory(element, addr, Default::default()); self.finish_block(1); self.emit(&ListLift { element, ty: id }); } @@ -1611,7 +1605,7 @@ impl<'a, B: Bindgen> Generator<'a, B> { } } - fn write_to_memory(&mut self, ty: &Type, addr: B::Operand, offset: i32) { + fn write_to_memory(&mut self, ty: &Type, addr: B::Operand, offset: ArchitectureSize) { use Instruction::*; match *ty { @@ -1671,7 +1665,7 @@ impl<'a, B: Bindgen> Generator<'a, B> { for i in (0..n).rev() { self.stack.push(addr.clone()); self.emit(&I32Store { - offset: offset + (i as i32) * 4, + offset: offset.add_bytes(i * 4), }); } } @@ -1735,24 +1729,19 @@ impl<'a, B: Bindgen> Generator<'a, B> { &mut self, params: impl IntoIterator, addr: B::Operand, - offset: i32, + offset: ArchitectureSize, ) { self.write_fields_to_memory(params, addr, offset); } fn write_variant_arms_to_memory<'b>( &mut self, - offset: i32, + offset: ArchitectureSize, addr: B::Operand, tag: Int, cases: impl IntoIterator> + Clone, ) { - let payload_offset = offset - + (self - .bindgen - .sizes() - .payload_offset(tag, cases.clone()) - .size_wasm32() as i32); + let payload_offset = offset + (self.bindgen.sizes().payload_offset(tag, cases.clone())); for (i, ty) in cases.into_iter().enumerate() { self.push_block(); self.emit(&Instruction::VariantPayloadName); @@ -1768,13 +1757,15 @@ impl<'a, B: Bindgen> Generator<'a, B> { } } - fn write_list_to_memory(&mut self, ty: &Type, addr: B::Operand, offset: i32) { + fn write_list_to_memory(&mut self, ty: &Type, addr: B::Operand, offset: ArchitectureSize) { // After lowering the list there's two i32 values on the stack // which we write into memory, writing the pointer into the low address // and the length into the high address. self.lower(ty); self.stack.push(addr.clone()); - self.emit(&Instruction::LengthStore { offset: offset + 4 }); + self.emit(&Instruction::LengthStore { + offset: offset + self.bindgen.sizes().align(ty).into(), + }); self.stack.push(addr); self.emit(&Instruction::PointerStore { offset }); } @@ -1783,7 +1774,7 @@ impl<'a, B: Bindgen> Generator<'a, B> { &mut self, tys: impl IntoIterator, addr: B::Operand, - offset: i32, + offset: ArchitectureSize, ) { let tys = tys.into_iter(); let fields = self @@ -1798,8 +1789,7 @@ impl<'a, B: Bindgen> Generator<'a, B> { .zip(fields) { self.stack.push(op); - let field_offset = field_offset.size_wasm32(); - self.write_to_memory(ty, addr.clone(), offset + (field_offset as i32)); + self.write_to_memory(ty, addr.clone(), offset + (field_offset)); } } @@ -1809,7 +1799,7 @@ impl<'a, B: Bindgen> Generator<'a, B> { self.emit(instr); } - fn read_from_memory(&mut self, ty: &Type, addr: B::Operand, offset: i32) { + fn read_from_memory(&mut self, ty: &Type, addr: B::Operand, offset: ArchitectureSize) { use Instruction::*; match *ty { @@ -1869,7 +1859,7 @@ impl<'a, B: Bindgen> Generator<'a, B> { for i in 0..n { self.stack.push(addr.clone()); self.emit(&I32Load { - offset: offset + (i as i32) * 4, + offset: offset.add_bytes(i * 4), }); } } @@ -1921,25 +1911,25 @@ impl<'a, B: Bindgen> Generator<'a, B> { } } - fn read_results_from_memory(&mut self, result: &Option, addr: B::Operand, offset: i32) { + fn read_results_from_memory( + &mut self, + result: &Option, + addr: B::Operand, + offset: ArchitectureSize, + ) { self.read_fields_from_memory(result, addr, offset) } fn read_variant_arms_from_memory<'b>( &mut self, - offset: i32, + offset: ArchitectureSize, addr: B::Operand, tag: Int, cases: impl IntoIterator> + Clone, ) { self.stack.push(addr.clone()); self.load_intrepr(offset, tag); - let payload_offset = offset - + (self - .bindgen - .sizes() - .payload_offset(tag, cases.clone()) - .size_wasm32() as i32); + let payload_offset = offset + (self.bindgen.sizes().payload_offset(tag, cases.clone())); for ty in cases { self.push_block(); if let Some(ty) = ty { @@ -1949,13 +1939,15 @@ impl<'a, B: Bindgen> Generator<'a, B> { } } - fn read_list_from_memory(&mut self, ty: &Type, addr: B::Operand, offset: i32) { + fn read_list_from_memory(&mut self, ty: &Type, addr: B::Operand, offset: ArchitectureSize) { // Read the pointer/len and then perform the standard lifting // proceses. self.stack.push(addr.clone()); self.emit(&Instruction::PointerLoad { offset }); self.stack.push(addr); - self.emit(&Instruction::LengthLoad { offset: offset + 4 }); + self.emit(&Instruction::LengthLoad { + offset: offset + self.bindgen.sizes().align(ty).into(), + }); self.lift(ty); } @@ -1963,11 +1955,10 @@ impl<'a, B: Bindgen> Generator<'a, B> { &mut self, tys: impl IntoIterator, addr: B::Operand, - offset: i32, + offset: ArchitectureSize, ) { for (field_offset, ty) in self.bindgen.sizes().field_offsets(tys).iter() { - let field_offset = field_offset.size_wasm32(); - self.read_from_memory(ty, addr.clone(), offset + (field_offset as i32)); + self.read_from_memory(ty, addr.clone(), offset + (*field_offset)); } } @@ -1977,7 +1968,7 @@ impl<'a, B: Bindgen> Generator<'a, B> { self.lift(ty); } - fn load_intrepr(&mut self, offset: i32, repr: Int) { + fn load_intrepr(&mut self, offset: ArchitectureSize, repr: Int) { self.emit(&match repr { Int::U64 => Instruction::I64Load { offset }, Int::U32 => Instruction::I32Load { offset }, @@ -1986,7 +1977,7 @@ impl<'a, B: Bindgen> Generator<'a, B> { }); } - fn store_intrepr(&mut self, offset: i32, repr: Int) { + fn store_intrepr(&mut self, offset: ArchitectureSize, repr: Int) { self.emit(&match repr { Int::U64 => Instruction::I64Store { offset }, Int::U32 => Instruction::I32Store { offset }, @@ -1995,7 +1986,7 @@ impl<'a, B: Bindgen> Generator<'a, B> { }); } - fn deallocate(&mut self, ty: &Type, addr: B::Operand, offset: i32) { + fn deallocate(&mut self, ty: &Type, addr: B::Operand, offset: ArchitectureSize) { use Instruction::*; // No need to execute any instructions if this type itself doesn't @@ -2009,7 +2000,9 @@ impl<'a, B: Bindgen> Generator<'a, B> { self.stack.push(addr.clone()); self.emit(&Instruction::PointerLoad { offset }); self.stack.push(addr); - self.emit(&Instruction::LengthLoad { offset: offset + 4 }); + self.emit(&Instruction::LengthLoad { + offset: offset + self.bindgen.sizes().align(ty).into(), + }); self.emit(&Instruction::GuestDeallocateString); } @@ -2034,12 +2027,14 @@ impl<'a, B: Bindgen> Generator<'a, B> { self.stack.push(addr.clone()); self.emit(&Instruction::PointerLoad { offset }); self.stack.push(addr); - self.emit(&Instruction::LengthLoad { offset: offset + 4 }); + self.emit(&Instruction::LengthLoad { + offset: offset + self.bindgen.sizes().align(ty).into(), + }); self.push_block(); self.emit(&IterBasePointer); let elemaddr = self.stack.pop().unwrap(); - self.deallocate(element, elemaddr, 0); + self.deallocate(element, elemaddr, Default::default()); self.finish_block(0); self.emit(&Instruction::GuestDeallocateList { element }); @@ -2100,19 +2095,14 @@ impl<'a, B: Bindgen> Generator<'a, B> { fn deallocate_variant<'b>( &mut self, - offset: i32, + offset: ArchitectureSize, addr: B::Operand, tag: Int, cases: impl IntoIterator> + Clone, ) { self.stack.push(addr.clone()); self.load_intrepr(offset, tag); - let payload_offset = offset - + (self - .bindgen - .sizes() - .payload_offset(tag, cases.clone()) - .size_wasm32() as i32); + let payload_offset = offset + (self.bindgen.sizes().payload_offset(tag, cases.clone())); for ty in cases { self.push_block(); if let Some(ty) = ty { @@ -2122,10 +2112,9 @@ impl<'a, B: Bindgen> Generator<'a, B> { } } - fn deallocate_fields(&mut self, tys: &[Type], addr: B::Operand, offset: i32) { + fn deallocate_fields(&mut self, tys: &[Type], addr: B::Operand, offset: ArchitectureSize) { for (field_offset, ty) in self.bindgen.sizes().field_offsets(tys) { - let field_offset = field_offset.size_wasm32(); - self.deallocate(ty, addr.clone(), offset + (field_offset as i32)); + self.deallocate(ty, addr.clone(), offset + (field_offset)); } } } @@ -2185,7 +2174,3 @@ fn cast(from: WasmType, to: WasmType) -> Bitcast { } } } - -fn align_to(val: usize, align: usize) -> usize { - (val + align - 1) & !(align - 1) -} diff --git a/crates/csharp/src/function.rs b/crates/csharp/src/function.rs index 383ba196c..698d19ba9 100644 --- a/crates/csharp/src/function.rs +++ b/crates/csharp/src/function.rs @@ -8,7 +8,10 @@ use std::ops::Deref; use wit_bindgen_core::abi::{Bindgen, Bitcast, Instruction}; use wit_bindgen_core::{uwrite, uwriteln, Direction, Ns}; use wit_parser::abi::WasmType; -use wit_parser::{Docs, FunctionKind, Handle, Resolve, SizeAlign, Type, TypeDefKind, TypeId}; +use wit_parser::{ + Alignment, ArchitectureSize, Docs, FunctionKind, Handle, Resolve, SizeAlign, Type, TypeDefKind, + TypeId, +}; /// FunctionBindgen generates the C# code for calling functions defined in wit pub(crate) struct FunctionBindgen<'a, 'b> { @@ -397,22 +400,22 @@ impl Bindgen for FunctionBindgen<'_, '_> { })), Instruction::I32Load { offset } | Instruction::PointerLoad { offset } - | Instruction::LengthLoad { offset } => results.push(format!("BitConverter.ToInt32(new Span((void*)({} + {offset}), 4))",operands[0])), - Instruction::I32Load8U { offset } => results.push(format!("new Span((void*)({} + {offset}), 1)[0]",operands[0])), - Instruction::I32Load8S { offset } => results.push(format!("(sbyte)new Span((void*)({} + {offset}), 1)[0]",operands[0])), - Instruction::I32Load16U { offset } => results.push(format!("BitConverter.ToUInt16(new Span((void*)({} + {offset}), 2))",operands[0])), - Instruction::I32Load16S { offset } => results.push(format!("BitConverter.ToInt16(new Span((void*)({} + {offset}), 2))",operands[0])), - Instruction::I64Load { offset } => results.push(format!("BitConverter.ToInt64(new Span((void*)({} + {offset}), 8))",operands[0])), - Instruction::F32Load { offset } => results.push(format!("BitConverter.ToSingle(new Span((void*)({} + {offset}), 4))",operands[0])), - Instruction::F64Load { offset } => results.push(format!("BitConverter.ToDouble(new Span((void*)({} + {offset}), 8))",operands[0])), + | Instruction::LengthLoad { offset } => results.push(format!("BitConverter.ToInt32(new Span((void*)({} + {offset}), 4))",operands[0],offset = offset.size_wasm32())), + Instruction::I32Load8U { offset } => results.push(format!("new Span((void*)({} + {offset}), 1)[0]",operands[0],offset = offset.size_wasm32())), + Instruction::I32Load8S { offset } => results.push(format!("(sbyte)new Span((void*)({} + {offset}), 1)[0]",operands[0],offset = offset.size_wasm32())), + Instruction::I32Load16U { offset } => results.push(format!("BitConverter.ToUInt16(new Span((void*)({} + {offset}), 2))",operands[0],offset = offset.size_wasm32())), + Instruction::I32Load16S { offset } => results.push(format!("BitConverter.ToInt16(new Span((void*)({} + {offset}), 2))",operands[0],offset = offset.size_wasm32())), + Instruction::I64Load { offset } => results.push(format!("BitConverter.ToInt64(new Span((void*)({} + {offset}), 8))",operands[0],offset = offset.size_wasm32())), + Instruction::F32Load { offset } => results.push(format!("BitConverter.ToSingle(new Span((void*)({} + {offset}), 4))",operands[0],offset = offset.size_wasm32())), + Instruction::F64Load { offset } => results.push(format!("BitConverter.ToDouble(new Span((void*)({} + {offset}), 8))",operands[0],offset = offset.size_wasm32())), Instruction::I32Store { offset } | Instruction::PointerStore { offset } - | Instruction::LengthStore { offset } => uwriteln!(self.src, "BitConverter.TryWriteBytes(new Span((void*)({} + {offset}), 4), {});", operands[1], operands[0]), - Instruction::I32Store8 { offset } => uwriteln!(self.src, "*(byte*)({} + {offset}) = (byte){};", operands[1], operands[0]), - Instruction::I32Store16 { offset } => uwriteln!(self.src, "BitConverter.TryWriteBytes(new Span((void*)({} + {offset}), 2), (short){});", operands[1], operands[0]), - Instruction::I64Store { offset } => uwriteln!(self.src, "BitConverter.TryWriteBytes(new Span((void*)({} + {offset}), 8), unchecked((long){}));", operands[1], operands[0]), - Instruction::F32Store { offset } => uwriteln!(self.src, "BitConverter.TryWriteBytes(new Span((void*)({} + {offset}), 4), unchecked((float){}));", operands[1], operands[0]), - Instruction::F64Store { offset } => uwriteln!(self.src, "BitConverter.TryWriteBytes(new Span((void*)({} + {offset}), 8), unchecked((double){}));", operands[1], operands[0]), + | Instruction::LengthStore { offset } => uwriteln!(self.src, "BitConverter.TryWriteBytes(new Span((void*)({} + {offset}), 4), {});", operands[1], operands[0],offset = offset.size_wasm32()), + Instruction::I32Store8 { offset } => uwriteln!(self.src, "*(byte*)({} + {offset}) = (byte){};", operands[1], operands[0],offset = offset.size_wasm32()), + Instruction::I32Store16 { offset } => uwriteln!(self.src, "BitConverter.TryWriteBytes(new Span((void*)({} + {offset}), 2), (short){});", operands[1], operands[0],offset = offset.size_wasm32()), + Instruction::I64Store { offset } => uwriteln!(self.src, "BitConverter.TryWriteBytes(new Span((void*)({} + {offset}), 8), unchecked((long){}));", operands[1], operands[0],offset = offset.size_wasm32()), + Instruction::F32Store { offset } => uwriteln!(self.src, "BitConverter.TryWriteBytes(new Span((void*)({} + {offset}), 4), unchecked((float){}));", operands[1], operands[0],offset = offset.size_wasm32()), + Instruction::F64Store { offset } => uwriteln!(self.src, "BitConverter.TryWriteBytes(new Span((void*)({} + {offset}), 8), unchecked((double){}));", operands[1], operands[0],offset = offset.size_wasm32()), Instruction::I64FromU64 => results.push(format!("unchecked((long)({}))", operands[0])), Instruction::I32FromChar => results.push(format!("((int){})", operands[0])), @@ -1265,15 +1268,16 @@ impl Bindgen for FunctionBindgen<'_, '_> { } } - fn return_pointer(&mut self, size: usize, align: usize) -> String { + fn return_pointer(&mut self, size: ArchitectureSize, align: Alignment) -> String { let ptr = self.locals.tmp("ptr"); match self.interface_gen.direction { Direction::Import => { 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); + self.import_return_pointer_area_size.max(size.size_wasm32()); + self.import_return_pointer_area_align = self + .import_return_pointer_area_align + .max(align.align_wasm32()); let (array_size, element_type) = crate::world_generator::dotnet_aligned_array( self.import_return_pointer_area_size, self.import_return_pointer_area_align, @@ -1289,16 +1293,23 @@ impl Bindgen for FunctionBindgen<'_, '_> { " var {ret_area} = stackalloc {element_type}[{array_size}+1]; var {ptr} = ((int){ret_area}) + ({align} - 1) & -{align}; - " + ", + align = align.align_wasm32() ); format!("{ptr}") } Direction::Export => { // exports need their return area to be live until the post-return call. - self.interface_gen.csharp_gen.return_area_size = - self.interface_gen.csharp_gen.return_area_size.max(size); - self.interface_gen.csharp_gen.return_area_align = - self.interface_gen.csharp_gen.return_area_align.max(align); + self.interface_gen.csharp_gen.return_area_size = self + .interface_gen + .csharp_gen + .return_area_size + .max(size.size_wasm32()); + self.interface_gen.csharp_gen.return_area_align = self + .interface_gen + .csharp_gen + .return_area_align + .max(align.align_wasm32()); uwrite!( self.src, diff --git a/crates/moonbit/src/lib.rs b/crates/moonbit/src/lib.rs index 449eb826d..970ffd4e7 100644 --- a/crates/moonbit/src/lib.rs +++ b/crates/moonbit/src/lib.rs @@ -6,9 +6,9 @@ use wit_bindgen_core::{ abi::{self, AbiVariant, Bindgen, Bitcast, Instruction, LiftLower, WasmType}, dealias, uwrite, uwriteln, wit_parser::{ - Docs, Enum, Flags, FlagsRepr, Function, FunctionKind, Handle, Int, InterfaceId, Record, - Resolve, Result_, SizeAlign, Tuple, Type, TypeDef, TypeDefKind, TypeId, TypeOwner, Variant, - WorldId, WorldKey, + Alignment, ArchitectureSize, Docs, Enum, Flags, FlagsRepr, Function, FunctionKind, Handle, + Int, InterfaceId, Record, Resolve, Result_, SizeAlign, Tuple, Type, TypeDef, TypeDefKind, + TypeId, TypeOwner, Variant, WorldId, WorldKey, }, Direction, Files, InterfaceGenerator as _, Ns, Source, WorldGenerator, }; @@ -280,8 +280,8 @@ pub struct MoonBit { export: HashMap, export_ns: Ns, // return area allocation - return_area_size: usize, - return_area_align: usize, + return_area_size: ArchitectureSize, + return_area_align: Alignment, } impl MoonBit { @@ -615,13 +615,13 @@ impl WorldGenerator for MoonBit { }} " ); - if self.return_area_size != 0 { + if !self.return_area_size.is_empty() { uwriteln!( &mut body, " let return_area : Int = {ffi_qualifier}malloc({}) ", - self.return_area_size, + self.return_area_size.size_wasm32(), ); } files.push( @@ -2470,49 +2470,57 @@ impl Bindgen for FunctionBindgen<'_, '_> { | Instruction::LengthLoad { offset } => results.push(format!( "{}load32(({}) + {offset})", self.gen.qualify_package(FFI_DIR), - operands[0] + operands[0], + offset = offset.size_wasm32() )), Instruction::I32Load8U { offset } => results.push(format!( "{}load8_u(({}) + {offset})", self.gen.qualify_package(FFI_DIR), - operands[0] + operands[0], + offset = offset.size_wasm32() )), Instruction::I32Load8S { offset } => results.push(format!( "{}load8(({}) + {offset})", self.gen.qualify_package(FFI_DIR), - operands[0] + operands[0], + offset = offset.size_wasm32() )), Instruction::I32Load16U { offset } => results.push(format!( "{}load16_u(({}) + {offset})", self.gen.qualify_package(FFI_DIR), - operands[0] + operands[0], + offset = offset.size_wasm32() )), Instruction::I32Load16S { offset } => results.push(format!( "{}load16(({}) + {offset})", self.gen.qualify_package(FFI_DIR), - operands[0] + operands[0], + offset = offset.size_wasm32() )), Instruction::I64Load { offset } => results.push(format!( "{}load64(({}) + {offset})", self.gen.qualify_package(FFI_DIR), - operands[0] + operands[0], + offset = offset.size_wasm32() )), Instruction::F32Load { offset } => results.push(format!( "{}loadf32(({}) + {offset})", self.gen.qualify_package(FFI_DIR), - operands[0] + operands[0], + offset = offset.size_wasm32() )), Instruction::F64Load { offset } => results.push(format!( "{}loadf64(({}) + {offset})", self.gen.qualify_package(FFI_DIR), - operands[0] + operands[0], + offset = offset.size_wasm32() )), Instruction::I32Store { offset } @@ -2522,7 +2530,8 @@ impl Bindgen for FunctionBindgen<'_, '_> { "{}store32(({}) + {offset}, {})", self.gen.qualify_package(FFI_DIR), operands[1], - operands[0] + operands[0], + offset = offset.size_wasm32() ), Instruction::I32Store8 { offset } => uwriteln!( @@ -2530,7 +2539,8 @@ impl Bindgen for FunctionBindgen<'_, '_> { "{}store8(({}) + {offset}, {})", self.gen.qualify_package(FFI_DIR), operands[1], - operands[0] + operands[0], + offset = offset.size_wasm32() ), Instruction::I32Store16 { offset } => uwriteln!( @@ -2538,7 +2548,8 @@ impl Bindgen for FunctionBindgen<'_, '_> { "{}store16(({}) + {offset}, {})", self.gen.qualify_package(FFI_DIR), operands[1], - operands[0] + operands[0], + offset = offset.size_wasm32() ), Instruction::I64Store { offset } => uwriteln!( @@ -2546,7 +2557,8 @@ impl Bindgen for FunctionBindgen<'_, '_> { "{}store64(({}) + {offset}, {})", self.gen.qualify_package(FFI_DIR), operands[1], - operands[0] + operands[0], + offset = offset.size_wasm32() ), Instruction::F32Store { offset } => uwriteln!( @@ -2554,7 +2566,8 @@ impl Bindgen for FunctionBindgen<'_, '_> { "{}storef32(({}) + {offset}, {})", self.gen.qualify_package(FFI_DIR), operands[1], - operands[0] + operands[0], + offset = offset.size_wasm32() ), Instruction::F64Store { offset } => uwriteln!( @@ -2562,7 +2575,8 @@ impl Bindgen for FunctionBindgen<'_, '_> { "{}storef64(({}) + {offset}, {})", self.gen.qualify_package(FFI_DIR), operands[1], - operands[0] + operands[0], + offset = offset.size_wasm32() ), // TODO: see what we can do with align Instruction::Malloc { size, .. } => { @@ -2570,7 +2584,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { self.src, "{}malloc({})", self.gen.qualify_package(FFI_DIR), - size + size.size_wasm32() ) } @@ -2677,15 +2691,19 @@ impl Bindgen for FunctionBindgen<'_, '_> { } } - fn return_pointer(&mut self, size: usize, align: usize) -> String { + fn return_pointer(&mut self, size: ArchitectureSize, align: Alignment) -> String { if self.gen.direction == Direction::Import { let ffi_qualifier = self.gen.qualify_package(FFI_DIR); let address = self.locals.tmp("return_area"); - uwriteln!(self.src, "let {address} = {ffi_qualifier}malloc({})", size,); + uwriteln!( + self.src, + "let {address} = {ffi_qualifier}malloc({})", + size.size_wasm32(), + ); self.cleanup.push(Cleanup::Memory { address: address.clone(), - size: size.to_string(), - align, + size: size.size_wasm32().to_string(), + align: align.align_wasm32(), }); address } else { diff --git a/crates/rust/src/bindgen.rs b/crates/rust/src/bindgen.rs index b3d15de3e..7ca7094a9 100644 --- a/crates/rust/src/bindgen.rs +++ b/crates/rust/src/bindgen.rs @@ -16,14 +16,16 @@ pub(super) struct FunctionBindgen<'a, 'b> { tmp: usize, pub needs_cleanup_list: bool, cleanup: Vec<(String, String)>, - pub import_return_pointer_area_size: usize, - pub import_return_pointer_area_align: usize, + pub import_return_pointer_area_size: ArchitectureSize, + pub import_return_pointer_area_align: Alignment, pub handle_decls: Vec, always_owned: bool, pub async_result_name: Option, emitted_cleanup: bool, } +pub const POINTER_SIZE_EXPRESSION: &str = "::core::mem::size_of::<*const u8>()"; + impl<'a, 'b> FunctionBindgen<'a, 'b> { pub(super) fn new( gen: &'b mut InterfaceGenerator<'a>, @@ -43,8 +45,8 @@ impl<'a, 'b> FunctionBindgen<'a, 'b> { tmp: 0, needs_cleanup_list: false, cleanup: Vec::new(), - import_return_pointer_area_size: 0, - import_return_pointer_area_align: 0, + import_return_pointer_area_size: Default::default(), + import_return_pointer_area_align: Default::default(), handle_decls: Vec::new(), always_owned, async_result_name: None, @@ -271,14 +273,14 @@ impl Bindgen for FunctionBindgen<'_, '_> { } } - fn return_pointer(&mut self, size: usize, align: usize) -> String { + fn return_pointer(&mut self, size: ArchitectureSize, align: Alignment) -> String { let tmp = self.tmp(); // Imports get a per-function return area to facilitate using the // stack whereas exports use a per-module return area to cut down on // stack usage. Note that for imports this also facilitates "adapter // modules" for components to not have data segments. - if size == 0 { + if size.is_empty() { // If the size requested is 0 then we know it won't be written to so // hand out a null pointer. This can happen with async for example // when the params or results are zero-sized. @@ -803,10 +805,11 @@ impl Bindgen for FunctionBindgen<'_, '_> { operand0 = operands[0] )); self.push_str(&format!("let {len} = {vec}.len();\n")); - let size = self.gen.sizes.size(element).size_wasm32(); - let align = self.gen.sizes.align(element).align_wasm32(); + 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", + "let {layout} = {alloc}::Layout::from_size_align_unchecked({vec}.len() * {}, {});\n", + size.format(POINTER_SIZE_EXPRESSION), align.format(POINTER_SIZE_EXPRESSION), )); self.push_str(&format!("let {result} = if {layout}.size() != 0 {{\n")); self.push_str(&format!( @@ -817,7 +820,10 @@ impl Bindgen for FunctionBindgen<'_, '_> { )); 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}.add(i * {size});\n",)); + self.push_str(&format!( + "let base = {result}.add(i * {});\n", + size.format(POINTER_SIZE_EXPRESSION) + )); self.push_str(&body); self.push_str("\n}\n"); results.push(format!("{result}")); @@ -834,8 +840,8 @@ impl Bindgen for FunctionBindgen<'_, '_> { Instruction::ListLift { element, .. } => { let body = self.blocks.pop().unwrap(); let tmp = self.tmp(); - let size = self.gen.sizes.size(element).size_wasm32(); - let align = self.gen.sizes.align(element).align_wasm32(); + let size = self.gen.sizes.size(element); + let align = self.gen.sizes.align(element); let len = format!("len{tmp}"); let base = format!("base{tmp}"); let result = format!("result{tmp}"); @@ -853,13 +859,21 @@ impl Bindgen for FunctionBindgen<'_, '_> { )); uwriteln!(self.src, "for i in 0..{len} {{"); - uwriteln!(self.src, "let base = {base}.add(i * {size});"); + uwriteln!( + self.src, + "let base = {base}.add(i * {size});", + size = size.format(POINTER_SIZE_EXPRESSION) + ); 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} * {size}, {align});\n",)); + self.push_str(&format!( + "{dealloc}({base}, {len} * {size}, {align});\n", + size = size.format(POINTER_SIZE_EXPRESSION), + align = align.format(POINTER_SIZE_EXPRESSION) + )); } Instruction::IterElem { .. } => results.push("e".to_string()), @@ -1042,7 +1056,8 @@ impl Bindgen for FunctionBindgen<'_, '_> { uwriteln!( self.src, "let l{tmp} = *{}.add({offset}).cast::();", - operands[0] + operands[0], + offset = offset.format_term(POINTER_SIZE_EXPRESSION, true) ); results.push(format!("l{tmp}")); } @@ -1051,7 +1066,8 @@ impl Bindgen for FunctionBindgen<'_, '_> { uwriteln!( self.src, "let l{tmp} = i32::from(*{0}.add({offset}).cast::());", - operands[0] + operands[0], + offset = offset.format_term(POINTER_SIZE_EXPRESSION, true) ); results.push(format!("l{tmp}")); } @@ -1060,7 +1076,8 @@ impl Bindgen for FunctionBindgen<'_, '_> { uwriteln!( self.src, "let l{tmp} = i32::from(*{}.add({offset}).cast::());", - operands[0] + operands[0], + offset = offset.format_term(POINTER_SIZE_EXPRESSION, true) ); results.push(format!("l{tmp}")); } @@ -1069,7 +1086,8 @@ impl Bindgen for FunctionBindgen<'_, '_> { uwriteln!( self.src, "let l{tmp} = i32::from(*{}.add({offset}).cast::());", - operands[0] + operands[0], + offset = offset.format_term(POINTER_SIZE_EXPRESSION, true) ); results.push(format!("l{tmp}")); } @@ -1078,7 +1096,8 @@ impl Bindgen for FunctionBindgen<'_, '_> { uwriteln!( self.src, "let l{tmp} = i32::from(*{}.add({offset}).cast::());", - operands[0] + operands[0], + offset = offset.format_term(POINTER_SIZE_EXPRESSION, true) ); results.push(format!("l{tmp}")); } @@ -1087,7 +1106,8 @@ impl Bindgen for FunctionBindgen<'_, '_> { uwriteln!( self.src, "let l{tmp} = *{}.add({offset}).cast::();", - operands[0] + operands[0], + offset = offset.format_term(POINTER_SIZE_EXPRESSION, true) ); results.push(format!("l{tmp}")); } @@ -1096,7 +1116,8 @@ impl Bindgen for FunctionBindgen<'_, '_> { uwriteln!( self.src, "let l{tmp} = *{}.add({offset}).cast::();", - operands[0] + operands[0], + offset = offset.format_term(POINTER_SIZE_EXPRESSION, true) ); results.push(format!("l{tmp}")); } @@ -1105,7 +1126,8 @@ impl Bindgen for FunctionBindgen<'_, '_> { uwriteln!( self.src, "let l{tmp} = *{}.add({offset}).cast::();", - operands[0] + operands[0], + offset = offset.format_term(POINTER_SIZE_EXPRESSION, true) ); results.push(format!("l{tmp}")); } @@ -1115,7 +1137,8 @@ impl Bindgen for FunctionBindgen<'_, '_> { uwriteln!( self.src, "let l{tmp} = *{}.add({offset}).cast::<*mut u8>();", - operands[0] + operands[0], + offset = offset.format_term(POINTER_SIZE_EXPRESSION, true) ); results.push(format!("l{tmp}")); } @@ -1123,8 +1146,9 @@ impl Bindgen for FunctionBindgen<'_, '_> { let tmp = self.tmp(); uwriteln!( self.src, - "let l{tmp} = *{}.add({offset}).cast::();", - operands[0] + "let l{tmp} = *{}.add({}).cast::();", + operands[0], + offset.format_term(POINTER_SIZE_EXPRESSION, true) ); results.push(format!("l{tmp}")); } @@ -1132,50 +1156,66 @@ impl Bindgen for FunctionBindgen<'_, '_> { Instruction::I32Store { offset } => { self.push_str(&format!( "*{}.add({}).cast::() = {};\n", - operands[1], offset, operands[0] + operands[1], + offset.format_term(POINTER_SIZE_EXPRESSION, true), + operands[0] )); } Instruction::I32Store8 { offset } => { self.push_str(&format!( "*{}.add({}).cast::() = ({}) as u8;\n", - operands[1], offset, operands[0] + operands[1], + offset.format_term(POINTER_SIZE_EXPRESSION, true), + operands[0] )); } Instruction::I32Store16 { offset } => { self.push_str(&format!( "*{}.add({}).cast::() = ({}) as u16;\n", - operands[1], offset, operands[0] + operands[1], + offset.format_term(POINTER_SIZE_EXPRESSION, true), + operands[0] )); } Instruction::I64Store { offset } => { self.push_str(&format!( "*{}.add({}).cast::() = {};\n", - operands[1], offset, operands[0] + operands[1], + offset.format_term(POINTER_SIZE_EXPRESSION, true), + operands[0] )); } Instruction::F32Store { offset } => { self.push_str(&format!( "*{}.add({}).cast::() = {};\n", - operands[1], offset, operands[0] + operands[1], + offset.format_term(POINTER_SIZE_EXPRESSION, true), + operands[0] )); } Instruction::F64Store { offset } => { self.push_str(&format!( "*{}.add({}).cast::() = {};\n", - operands[1], offset, operands[0] + operands[1], + offset.format_term(POINTER_SIZE_EXPRESSION, true), + operands[0] )); } Instruction::PointerStore { offset } => { self.push_str(&format!( "*{}.add({}).cast::<*mut u8>() = {};\n", - operands[1], offset, operands[0] + operands[1], + offset.format_term(POINTER_SIZE_EXPRESSION, true), + operands[0] )); } Instruction::LengthStore { offset } => { self.push_str(&format!( "*{}.add({}).cast::() = {};\n", - operands[1], offset, operands[0] + operands[1], + offset.format_term(POINTER_SIZE_EXPRESSION, true), + operands[0] )); } @@ -1185,7 +1225,9 @@ impl Bindgen for FunctionBindgen<'_, '_> { let dealloc = self.gen.path_to_cabi_dealloc(); self.push_str(&format!( "{dealloc}({op}, {size}, {align});\n", - op = operands[0] + op = operands[0], + size = size.format_term(POINTER_SIZE_EXPRESSION, true), + align = align.format(POINTER_SIZE_EXPRESSION) )); } @@ -1220,8 +1262,8 @@ impl Bindgen for FunctionBindgen<'_, '_> { Instruction::GuestDeallocateList { element } => { let body = self.blocks.pop().unwrap(); let tmp = self.tmp(); - let size = self.gen.sizes.size(element).size_wasm32(); - let align = self.gen.sizes.align(element).align_wasm32(); + let size = self.gen.sizes.size(element); + let align = self.gen.sizes.align(element); let len = format!("len{tmp}"); let base = format!("base{tmp}"); self.push_str(&format!( @@ -1240,13 +1282,17 @@ impl Bindgen for FunctionBindgen<'_, '_> { self.push_str("let base = "); self.push_str(&base); self.push_str(".add(i * "); - self.push_str(&size.to_string()); + self.push_str(&size.format(POINTER_SIZE_EXPRESSION)); 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} * {size}, {align});\n",)); + self.push_str(&format!( + "{dealloc}({base}, {len} * {size}, {align});\n", + size = size.format(POINTER_SIZE_EXPRESSION), + align = align.format(POINTER_SIZE_EXPRESSION) + )); } } } diff --git a/crates/rust/src/interface.rs b/crates/rust/src/interface.rs index 87ff5533a..bc256b717 100644 --- a/crates/rust/src/interface.rs +++ b/crates/rust/src/interface.rs @@ -1,4 +1,4 @@ -use crate::bindgen::FunctionBindgen; +use crate::bindgen::{FunctionBindgen, POINTER_SIZE_EXPRESSION}; use crate::{ full_wit_type_name, int_repr, to_rust_ident, to_upper_camel_case, wasm_type, AsyncConfig, FnSig, Identifier, InterfaceName, Ownership, RuntimeItem, RustFlagsRepr, RustWasm, @@ -22,8 +22,8 @@ pub struct InterfaceGenerator<'a> { pub(super) gen: &'a mut RustWasm, pub wasm_import_module: &'a str, pub resolve: &'a Resolve, - pub return_pointer_area_size: usize, - pub return_pointer_area_align: usize, + pub return_pointer_area_size: ArchitectureSize, + pub return_pointer_area_align: Alignment, pub(super) needs_runtime_module: bool, } @@ -377,17 +377,29 @@ macro_rules! {macro_name} {{ } } + pub fn align_area(&mut self, alignment: Alignment) { + match alignment { + Alignment::Pointer => uwriteln!( + self.src, + "#[cfg_attr(target_pointer_width=\"64\", repr(align(8)))] + #[cfg_attr(target_pointer_width=\"32\", repr(align(4)))]" + ), + Alignment::Bytes(bytes) => { + uwriteln!(self.src, "#[repr(align({align}))]", align = bytes.get()) + } + } + } + pub fn finish(&mut self) -> String { - if self.return_pointer_area_align > 0 { + if !self.return_pointer_area_size.is_empty() { + uwriteln!(self.src,); + self.align_area(self.return_pointer_area_align); uwrite!( self.src, - "\ - #[repr(align({align}))] - struct _RetArea([::core::mem::MaybeUninit::; {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, + size = self.return_pointer_area_size.format_term(POINTER_SIZE_EXPRESSION, true), ); } @@ -898,14 +910,14 @@ pub mod vtable{ordinal} {{ uwriteln!(self.src, "let mut cleanup_list = {vec}::new();"); } assert!(handle_decls.is_empty()); - if import_return_pointer_area_size > 0 { + if !import_return_pointer_area_size.is_empty() { + uwriteln!(self.src,); + self.align_area(import_return_pointer_area_align); uwrite!( self.src, - "\ - #[repr(align({import_return_pointer_area_align}))] - struct RetArea([::core::mem::MaybeUninit::; {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}]); -", +", import_return_pointer_area_size = import_return_pointer_area_size.format_term(POINTER_SIZE_EXPRESSION, true) ); } self.src.push_str(&String::from(src)); diff --git a/crates/rust/src/lib.rs b/crates/rust/src/lib.rs index 0807f11e5..6fbb44b2e 100644 --- a/crates/rust/src/lib.rs +++ b/crates/rust/src/lib.rs @@ -341,8 +341,8 @@ impl RustWasm { gen: self, sizes, resolve, - return_pointer_area_size: 0, - return_pointer_area_align: 0, + return_pointer_area_size: Default::default(), + return_pointer_area_align: Default::default(), needs_runtime_module: false, } } diff --git a/crates/teavm-java/src/lib.rs b/crates/teavm-java/src/lib.rs index 681537178..25e3732a5 100644 --- a/crates/teavm-java/src/lib.rs +++ b/crates/teavm-java/src/lib.rs @@ -10,9 +10,9 @@ use wit_bindgen_core::{ abi::{self, AbiVariant, Bindgen, Bitcast, Instruction, LiftLower, WasmType}, uwrite, uwriteln, wit_parser::{ - Docs, Enum, Flags, FlagsRepr, Function, FunctionKind, Int, InterfaceId, Record, Resolve, - Result_, SizeAlign, Tuple, Type, TypeDef, TypeDefKind, TypeId, TypeOwner, Variant, WorldId, - WorldKey, + Alignment, ArchitectureSize, Docs, Enum, Flags, FlagsRepr, Function, FunctionKind, Int, + InterfaceId, Record, Resolve, Result_, SizeAlign, Tuple, Type, TypeDef, TypeDefKind, + TypeId, TypeOwner, Variant, WorldId, WorldKey, }, Direction, Files, InterfaceGenerator as _, Ns, Source, WorldGenerator, }; @@ -53,8 +53,8 @@ struct InterfaceFragment { pub struct TeaVmJava { opts: Opts, name: String, - return_area_size: usize, - return_area_align: usize, + return_area_size: ArchitectureSize, + return_area_align: Alignment, tuple_counts: HashSet, needs_cleanup: bool, needs_result: bool, @@ -345,9 +345,9 @@ impl WorldGenerator for TeaVmJava { ); } - if self.return_area_align > 0 { - let size = self.return_area_size; - let align = self.return_area_align; + if !self.return_area_size.is_empty() { + let size = self.return_area_size.size_wasm32(); + let align = self.return_area_align.align_wasm32(); uwriteln!( src, @@ -1666,8 +1666,8 @@ impl Bindgen for FunctionBindgen<'_, '_> { assert!(block_results.is_empty()); let op = &operands[0]; - let size = self.gen.gen.sizes.size(element).size_wasm32(); - let align = self.gen.gen.sizes.align(element).align_wasm32(); + let size = self.gen.gen.sizes.size(element); + let align = self.gen.gen.sizes.align(element); let address = self.locals.tmp("address"); let ty = self.gen.type_name(element); let index = self.locals.tmp("index"); @@ -1681,14 +1681,16 @@ impl Bindgen for FunctionBindgen<'_, '_> { int {base} = {address} + ({index} * {size}); {body} }} - " + ", + align = align.align_wasm32(), + size = size.size_wasm32() ); if realloc.is_none() { self.cleanup.push(Cleanup { address: address.clone(), - size: format!("({op}).size() * {size}"), - align, + size: format!("({op}).size() * {size}", size = size.size_wasm32()), + align: align.align_wasm32(), }); } @@ -1831,42 +1833,50 @@ impl Bindgen for FunctionBindgen<'_, '_> { | Instruction::PointerLoad { offset } | Instruction::LengthLoad { offset } => results.push(format!( "org.teavm.interop.Address.fromInt(({}) + {offset}).getInt()", - operands[0] + operands[0], + offset = offset.size_wasm32() )), Instruction::I32Load8U { offset } => results.push(format!( "(((int) org.teavm.interop.Address.fromInt(({}) + {offset}).getByte()) & 0xFF)", - operands[0] + operands[0], + offset = offset.size_wasm32() )), Instruction::I32Load8S { offset } => results.push(format!( "((int) org.teavm.interop.Address.fromInt(({}) + {offset}).getByte())", - operands[0] + operands[0], + offset = offset.size_wasm32() )), Instruction::I32Load16U { offset } => results.push(format!( "(((int) org.teavm.interop.Address.fromInt(({}) + {offset}).getShort()) & 0xFFFF)", - operands[0] + operands[0], + offset = offset.size_wasm32() )), Instruction::I32Load16S { offset } => results.push(format!( "((int) org.teavm.interop.Address.fromInt(({}) + {offset}).getShort())", - operands[0] + operands[0], + offset = offset.size_wasm32() )), Instruction::I64Load { offset } => results.push(format!( "org.teavm.interop.Address.fromInt(({}) + {offset}).getLong()", - operands[0] + operands[0], + offset = offset.size_wasm32() )), Instruction::F32Load { offset } => results.push(format!( "org.teavm.interop.Address.fromInt(({}) + {offset}).getFloat()", - operands[0] + operands[0], + offset = offset.size_wasm32() )), Instruction::F64Load { offset } => results.push(format!( "org.teavm.interop.Address.fromInt(({}) + {offset}).getDouble()", - operands[0] + operands[0], + offset = offset.size_wasm32() )), Instruction::I32Store { offset } @@ -1875,42 +1885,48 @@ impl Bindgen for FunctionBindgen<'_, '_> { self.src, "org.teavm.interop.Address.fromInt(({}) + {offset}).putInt({});", operands[1], - operands[0] + operands[0], + offset = offset.size_wasm32() ), Instruction::I32Store8 { offset } => uwriteln!( self.src, "org.teavm.interop.Address.fromInt(({}) + {offset}).putByte((byte) ({}));", operands[1], - operands[0] + operands[0], + offset = offset.size_wasm32() ), Instruction::I32Store16 { offset } => uwriteln!( self.src, "org.teavm.interop.Address.fromInt(({}) + {offset}).putShort((short) ({}));", operands[1], - operands[0] + operands[0], + offset = offset.size_wasm32() ), Instruction::I64Store { offset } => uwriteln!( self.src, "org.teavm.interop.Address.fromInt(({}) + {offset}).putLong({});", operands[1], - operands[0] + operands[0], + offset = offset.size_wasm32() ), Instruction::F32Store { offset } => uwriteln!( self.src, "org.teavm.interop.Address.fromInt(({}) + {offset}).putFloat({});", operands[1], - operands[0] + operands[0], + offset = offset.size_wasm32() ), Instruction::F64Store { offset } => uwriteln!( self.src, "org.teavm.interop.Address.fromInt(({}) + {offset}).putDouble({});", operands[1], - operands[0] + operands[0], + offset = offset.size_wasm32() ), Instruction::Malloc { .. } => unimplemented!(), @@ -1919,7 +1935,9 @@ impl Bindgen for FunctionBindgen<'_, '_> { uwriteln!( self.src, "Memory.free(org.teavm.interop.Address.fromInt({}), {size}, {align});", - operands[0] + operands[0], + size = size.size_wasm32(), + align = align.align_wasm32() ) } @@ -2011,7 +2029,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { } } - fn return_pointer(&mut self, size: usize, align: usize) -> String { + fn return_pointer(&mut self, size: ArchitectureSize, align: Alignment) -> String { self.gen.gen.return_area_size = self.gen.gen.return_area_size.max(size); self.gen.gen.return_area_align = self.gen.gen.return_area_align.max(align); format!("{}RETURN_AREA", self.gen.gen.qualifier())