Emit the sequence of instruction for a `memory.atomic.wait*`.
(&mut self, arg: &MemArg, kind: AtomicWaitKind)
| 2393 | |
| 2394 | /// Emit the sequence of instruction for a `memory.atomic.wait*`. |
| 2395 | pub fn emit_atomic_wait(&mut self, arg: &MemArg, kind: AtomicWaitKind) -> Result<()> { |
| 2396 | // The `memory_atomic_wait*` builtins expect the following arguments: |
| 2397 | // - `memory`, as u32 |
| 2398 | // - `address`, as u64 |
| 2399 | // - `expected`, as either u64 or u32 |
| 2400 | // - `timeout`, as u64 |
| 2401 | // At this point our stack only contains the `timeout`, the `expected` and the address, so |
| 2402 | // we need to: |
| 2403 | // - insert the memory as the first argument |
| 2404 | // - compute the actual memory offset from the `MemArg`, if necessary. |
| 2405 | // Note that the builtin function performs the alignment and bounds checks for us, so we |
| 2406 | // don't need to emit that. |
| 2407 | |
| 2408 | let timeout = self.context.pop_to_reg(self.masm, None)?; |
| 2409 | let expected = self.context.pop_to_reg(self.masm, None)?; |
| 2410 | let addr = self.context.pop_to_reg(self.masm, None)?; |
| 2411 | |
| 2412 | // Put the target memory index as the first argument. |
| 2413 | let stack_len = self.context.stack.len(); |
| 2414 | let builtin = match kind { |
| 2415 | AtomicWaitKind::Wait32 => self.env.builtins.memory_atomic_wait32::<M::ABI>()?, |
| 2416 | AtomicWaitKind::Wait64 => self.env.builtins.memory_atomic_wait64::<M::ABI>()?, |
| 2417 | }; |
| 2418 | let builtin = self.prepare_builtin_defined_memory_arg( |
| 2419 | MemoryIndex::from_u32(arg.memory), |
| 2420 | stack_len, |
| 2421 | builtin, |
| 2422 | )?; |
| 2423 | |
| 2424 | if arg.offset != 0 { |
| 2425 | self.masm.checked_uadd( |
| 2426 | writable!(addr.reg), |
| 2427 | addr.reg, |
| 2428 | RegImm::i64(arg.offset as i64), |
| 2429 | OperandSize::S64, |
| 2430 | TrapCode::HEAP_OUT_OF_BOUNDS, |
| 2431 | )?; |
| 2432 | } |
| 2433 | |
| 2434 | self.context |
| 2435 | .stack |
| 2436 | .push(TypedReg::new(WasmValType::I64, addr.reg).into()); |
| 2437 | self.context.stack.push(expected.into()); |
| 2438 | self.context.stack.push(timeout.into()); |
| 2439 | |
| 2440 | FnCall::emit::<M>(&mut self.env, self.masm, &mut self.context, builtin)?; |
| 2441 | |
| 2442 | Ok(()) |
| 2443 | } |
| 2444 | |
| 2445 | pub fn emit_atomic_notify(&mut self, arg: &MemArg) -> Result<()> { |
| 2446 | // The memory `memory_atomic_notify` builtin expects the following arguments: |
no test coverage detected