Emit the `memory.copy` operation.
(&mut self, dst_mem: MemoryIndex, src_mem: MemoryIndex)
| 1604 | |
| 1605 | /// Emit the `memory.copy` operation. |
| 1606 | pub fn emit_memory_copy(&mut self, dst_mem: MemoryIndex, src_mem: MemoryIndex) -> Result<()> { |
| 1607 | let dst_heap = self.env.resolve_heap(dst_mem); |
| 1608 | let src_heap = self.env.resolve_heap(src_mem); |
| 1609 | let dst_idx_size: OperandSize = dst_heap.index_type().try_into()?; |
| 1610 | let src_idx_size: OperandSize = src_heap.index_type().try_into()?; |
| 1611 | |
| 1612 | let len = self.context.pop_to_reg(self.masm, None)?; |
| 1613 | let src = self.context.pop_to_reg(self.masm, None)?; |
| 1614 | let dst = self.context.pop_to_reg(self.masm, None)?; |
| 1615 | |
| 1616 | // For 32-bit linear memories go ahead and make sure `len` is zero |
| 1617 | // extended within its register ensuring that the full 64-bits of the |
| 1618 | // register are defined. This assists in situations like cross-memory |
| 1619 | // copies where one memory is 32-bit and one is 64-bit and the same |
| 1620 | // register can be used for the length in both bounds checks below. |
| 1621 | if dst_idx_size == OperandSize::S32 || src_idx_size == OperandSize::S32 { |
| 1622 | self.masm.extend( |
| 1623 | writable!(len.reg), |
| 1624 | len.reg, |
| 1625 | Extend::<Zero>::I64Extend32.into(), |
| 1626 | )?; |
| 1627 | } |
| 1628 | |
| 1629 | let dst_raw_addr = self.context.any_gpr(self.masm)?; |
| 1630 | self.emit_bounds_check_and_compute_addr(&dst_heap, dst_raw_addr, dst.reg, len.reg)?; |
| 1631 | self.context.free_reg(dst); |
| 1632 | |
| 1633 | let src_raw_addr = self.context.any_gpr(self.masm)?; |
| 1634 | self.emit_bounds_check_and_compute_addr(&src_heap, src_raw_addr, src.reg, len.reg)?; |
| 1635 | self.context.free_reg(src); |
| 1636 | |
| 1637 | self.context |
| 1638 | .stack |
| 1639 | .push(TypedReg::new(self.env.ptr_type(), dst_raw_addr).into()); |
| 1640 | self.context |
| 1641 | .stack |
| 1642 | .push(TypedReg::new(self.env.ptr_type(), src_raw_addr).into()); |
| 1643 | self.context |
| 1644 | .stack |
| 1645 | .push(TypedReg::new(self.env.ptr_type(), len.reg).into()); |
| 1646 | |
| 1647 | let builtin = self.env.builtins.memory_copy::<M::ABI>()?; |
| 1648 | FnCall::emit::<M>( |
| 1649 | &mut self.env, |
| 1650 | self.masm, |
| 1651 | &mut self.context, |
| 1652 | Callee::Builtin(builtin), |
| 1653 | )?; |
| 1654 | Ok(()) |
| 1655 | } |
| 1656 | |
| 1657 | /// Emit the `memory.fill` operation. |
| 1658 | pub fn emit_memory_fill(&mut self, mem: MemoryIndex) -> Result<()> { |
no test coverage detected