Emit the `memory.init` operation.
(&mut self, segment: DataIndex, mem: MemoryIndex)
| 1701 | |
| 1702 | /// Emit the `memory.init` operation. |
| 1703 | pub fn emit_memory_init(&mut self, segment: DataIndex, mem: MemoryIndex) -> Result<()> { |
| 1704 | let dst_heap = self.env.resolve_heap(mem); |
| 1705 | |
| 1706 | let len = self.context.pop_to_reg(self.masm, None)?; |
| 1707 | let src = self.context.pop_to_reg(self.masm, None)?; |
| 1708 | let dst = self.context.pop_to_reg(self.masm, None)?; |
| 1709 | |
| 1710 | // Make sure `len` is zero extended within its register ensuring that |
| 1711 | // the full 64-bits of the register are defined. This assists in |
| 1712 | // situations like cross-memory copies where one memory is 32-bit and |
| 1713 | // one is 64-bit and the same register can be used for the length in |
| 1714 | // both bounds checks below. |
| 1715 | self.masm.extend( |
| 1716 | writable!(len.reg), |
| 1717 | len.reg, |
| 1718 | Extend::<Zero>::I64Extend32.into(), |
| 1719 | )?; |
| 1720 | |
| 1721 | let dst_raw_addr = self.context.any_gpr(self.masm)?; |
| 1722 | self.emit_bounds_check_and_compute_addr(&dst_heap, dst_raw_addr, dst.reg, len.reg)?; |
| 1723 | self.context.free_reg(dst); |
| 1724 | |
| 1725 | let runtime_data_index = match self.env.translation.runtime_data_map[segment] { |
| 1726 | Some(i) => i, |
| 1727 | |
| 1728 | // Active data segments always have length zero, so this is only |
| 1729 | // valid of src and len are both zero. |
| 1730 | None => { |
| 1731 | self.masm.cmp(src.reg, RegImm::i32(0), OperandSize::S32)?; |
| 1732 | self.masm |
| 1733 | .trapif(IntCmpKind::Ne, TrapCode::HEAP_OUT_OF_BOUNDS)?; |
| 1734 | self.masm.cmp(len.reg, RegImm::i32(0), OperandSize::S32)?; |
| 1735 | self.masm |
| 1736 | .trapif(IntCmpKind::Ne, TrapCode::HEAP_OUT_OF_BOUNDS)?; |
| 1737 | self.context.free_reg(dst_raw_addr); |
| 1738 | self.context.free_reg(src); |
| 1739 | self.context.free_reg(len); |
| 1740 | return Ok(()); |
| 1741 | } |
| 1742 | }; |
| 1743 | |
| 1744 | // Bounds check this passive data segment. Load its |
| 1745 | // dynamically-specified length and see if that's in the range |
| 1746 | // of `src+len`. |
| 1747 | let data_segment_length_offset = self |
| 1748 | .env |
| 1749 | .vmoffsets |
| 1750 | .vmctx_runtime_data_length(runtime_data_index); |
| 1751 | let tmp1 = self.context.any_gpr(self.masm)?; |
| 1752 | let tmp2 = self.context.any_gpr(self.masm)?; |
| 1753 | self.masm.load( |
| 1754 | self.masm.address_at_vmctx(data_segment_length_offset)?, |
| 1755 | writable!(tmp1), |
| 1756 | OperandSize::S32, |
| 1757 | )?; |
| 1758 | self.masm |
| 1759 | .mov(writable!(tmp2), src.reg.into(), OperandSize::S32)?; |
| 1760 | self.masm.checked_uadd( |
no test coverage detected