(&mut self, arg: &MemArg)
| 2443 | } |
| 2444 | |
| 2445 | pub fn emit_atomic_notify(&mut self, arg: &MemArg) -> Result<()> { |
| 2446 | // The memory `memory_atomic_notify` builtin expects the following arguments: |
| 2447 | // - `memory`, as u32 |
| 2448 | // - `address`, as u64 |
| 2449 | // - `count`: as u32 |
| 2450 | // At this point our stack only contains the `count` and the `address`, so we need to: |
| 2451 | // - insert the memory as the first argument |
| 2452 | // - compute the actual memory offset from the `MemArg`, if necessary. |
| 2453 | // Note that the builtin function performs the alignment and bounds checks for us, so we |
| 2454 | // don't need to emit that. |
| 2455 | |
| 2456 | // pop the arguments from the stack. |
| 2457 | let count = self.context.pop_to_reg(self.masm, None)?; |
| 2458 | let addr = self.context.pop_to_reg(self.masm, None)?; |
| 2459 | |
| 2460 | // Put the target memory index as the first argument. |
| 2461 | let builtin = self.env.builtins.memory_atomic_notify::<M::ABI>()?; |
| 2462 | let stack_len = self.context.stack.len(); |
| 2463 | let builtin = self.prepare_builtin_defined_memory_arg( |
| 2464 | MemoryIndex::from_u32(arg.memory), |
| 2465 | stack_len, |
| 2466 | builtin, |
| 2467 | )?; |
| 2468 | |
| 2469 | if arg.offset != 0 { |
| 2470 | self.masm.checked_uadd( |
| 2471 | writable!(addr.reg), |
| 2472 | addr.reg, |
| 2473 | RegImm::i64(arg.offset as i64), |
| 2474 | OperandSize::S64, |
| 2475 | TrapCode::HEAP_OUT_OF_BOUNDS, |
| 2476 | )?; |
| 2477 | } |
| 2478 | |
| 2479 | // push remaining arguments. |
| 2480 | self.context |
| 2481 | .stack |
| 2482 | .push(TypedReg::new(WasmValType::I64, addr.reg).into()); |
| 2483 | self.context.stack.push(count.into()); |
| 2484 | |
| 2485 | FnCall::emit::<M>(&mut self.env, self.masm, &mut self.context, builtin)?; |
| 2486 | |
| 2487 | Ok(()) |
| 2488 | } |
| 2489 | |
| 2490 | pub fn prepare_builtin_defined_memory_arg( |
| 2491 | &mut self, |
no test coverage detected