| 225 | } |
| 226 | |
| 227 | fn return_pointer(&mut self, size: ArchitectureSize, align: Alignment) -> String { |
| 228 | let tmp = self.tmp(); |
| 229 | |
| 230 | // Imports get a per-function return area to facilitate using the |
| 231 | // stack whereas exports use a per-module return area to cut down on |
| 232 | // stack usage. Note that for imports this also facilitates "adapter |
| 233 | // modules" for components to not have data segments. |
| 234 | if size.is_empty() { |
| 235 | // If the size requested is 0 then we know it won't be written to so |
| 236 | // hand out a null pointer. This can happen with async for example |
| 237 | // when the params or results are zero-sized. |
| 238 | uwrite!(self.src, "let ptr{tmp} = core::ptr::null_mut::<u8>();"); |
| 239 | } else if self.r#gen.in_import { |
| 240 | // Import return areas are stored on the stack since this stack |
| 241 | self.import_return_pointer_area_size = self.import_return_pointer_area_size.max(size); |
| 242 | self.import_return_pointer_area_align = |
| 243 | self.import_return_pointer_area_align.max(align); |
| 244 | uwrite!( |
| 245 | self.src, |
| 246 | "let ptr{tmp} = ret_area.0.as_mut_ptr().cast::<u8>();" |
| 247 | ); |
| 248 | } else { |
| 249 | // Export return areas are stored in `static` memory as they need to |
| 250 | // persist beyond the function call itself (and are cleaned-up in |
| 251 | // `post-return`). |
| 252 | self.r#gen.return_pointer_area_size = self.r#gen.return_pointer_area_size.max(size); |
| 253 | self.r#gen.return_pointer_area_align = self.r#gen.return_pointer_area_align.max(align); |
| 254 | uwriteln!( |
| 255 | self.src, |
| 256 | "let ptr{tmp} = (&raw mut _RET_AREA.0).cast::<u8>();" |
| 257 | ); |
| 258 | } |
| 259 | format!("ptr{tmp}") |
| 260 | } |
| 261 | |
| 262 | fn sizes(&self) -> &SizeAlign { |
| 263 | &self.r#gen.sizes |