Emit the `table.copy` operation.
(&mut self, dst_table: TableIndex, src_table: TableIndex)
| 897 | |
| 898 | /// Emit the `table.copy` operation. |
| 899 | pub fn emit_table_copy(&mut self, dst_table: TableIndex, src_table: TableIndex) -> Result<()> { |
| 900 | let dst_data = self.env.resolve_table_data(dst_table); |
| 901 | let src_data = self.env.resolve_table_data(src_table); |
| 902 | |
| 903 | // The value stack contains `[dst, src, len]` (top is `len`). |
| 904 | let len = self.context.pop_to_reg(self.masm, None)?; |
| 905 | let src = self.context.pop_to_reg(self.masm, None)?; |
| 906 | let dst = self.context.pop_to_reg(self.masm, None)?; |
| 907 | |
| 908 | // Zero-extend each operand to a full 64-bit value so that the |
| 909 | // arithmetic and bounds checks below can uniformly operate on 64-bit |
| 910 | // quantities regardless of the table's index type. |
| 911 | for op in [&len, &src, &dst] { |
| 912 | if op.ty == WasmValType::I32 { |
| 913 | self.masm.extend( |
| 914 | writable!(op.reg), |
| 915 | op.reg, |
| 916 | Extend::<Zero>::I64Extend32.into(), |
| 917 | )?; |
| 918 | } |
| 919 | } |
| 920 | |
| 921 | // Bounds check both ranges up-front; `table.copy` traps without |
| 922 | // copying anything if either range is out-of-bounds. |
| 923 | self.emit_table_range_bounds_check(&src_data, src.reg, len.reg)?; |
| 924 | self.emit_table_range_bounds_check(&dst_data, dst.reg, len.reg)?; |
| 925 | |
| 926 | // Decide the copy direction. If `dst <= src` then do a forwards copy |
| 927 | // and otherwise it's backwards. |
| 928 | let step = self.context.any_gpr(self.masm)?; |
| 929 | let forward = self.masm.get_label()?; |
| 930 | let setup_done = self.masm.get_label()?; |
| 931 | self.masm.branch( |
| 932 | IntCmpKind::LeU, |
| 933 | dst.reg, |
| 934 | src.reg.into(), |
| 935 | forward, |
| 936 | OperandSize::S64, |
| 937 | )?; |
| 938 | // Backwards: start at the last element and walk down. |
| 939 | { |
| 940 | self.masm |
| 941 | .mov(writable!(step), RegImm::i64(-1), OperandSize::S64)?; |
| 942 | self.masm.add( |
| 943 | writable!(src.reg), |
| 944 | src.reg, |
| 945 | len.reg.into(), |
| 946 | OperandSize::S64, |
| 947 | )?; |
| 948 | self.masm.sub( |
| 949 | writable!(src.reg), |
| 950 | src.reg, |
| 951 | RegImm::i64(1), |
| 952 | OperandSize::S64, |
| 953 | )?; |
| 954 | self.masm.add( |
| 955 | writable!(dst.reg), |
| 956 | dst.reg, |
no test coverage detected