| ... | ... | @@ -1591,27 +1591,34 @@ fn memcpy(cg: *CodeGen, dst: WValue, src: WValue, len: WValue) !void { |
| 1591 | 1591 | // When bulk_memory is enabled, we lower it to wasm's memcpy instruction. |
| 1592 | 1592 | // If not, we lower it ourselves manually |
| 1593 | 1593 | if (std.Target.wasm.featureSetHas(cg.target.cpu.features, .bulk_memory)) { |
| 1594 | | try cg.startBlock(.block, .empty); |
| 1595 | | |
| 1596 | | // Even if `len` is zero, the spec requires an implementation to trap if `src + len` or |
| 1597 | | // `dst + len` are out of memory bounds. This can easily happen in Zig in a case such as: |
| 1598 | | // |
| 1599 | | // const dst: [*]u8 = undefined; |
| 1600 | | // const src: [*]u8 = undefined; |
| 1601 | | // var len: usize = runtime_zero(); |
| 1602 | | // @memcpy(dst[0..len], src[0..len]); |
| 1603 | | // |
| 1604 | | // So explicitly avoid using `memory.copy` in the `len == 0` case. Lovely design. |
| 1605 | | try cg.emitWValue(len); |
| 1606 | | try cg.addTag(.i32_eqz); |
| 1607 | | try cg.addLabel(.br_if, 0); |
| 1594 | const len0_ok = std.Target.wasm.featureSetHas(cg.target.cpu.features, .nontrapping_bulk_memory_len0); |
| 1595 | |
| 1596 | if (!len0_ok) { |
| 1597 | try cg.startBlock(.block, .empty); |
| 1598 | |
| 1599 | // Even if `len` is zero, the spec requires an implementation to trap if `src + len` or |
| 1600 | // `dst + len` are out of memory bounds. This can easily happen in Zig in a case such |
| 1601 | // as: |
| 1602 | // |
| 1603 | // const dst: [*]u8 = undefined; |
| 1604 | // const src: [*]u8 = undefined; |
| 1605 | // var len: usize = runtime_zero(); |
| 1606 | // @memcpy(dst[0..len], src[0..len]); |
| 1607 | // |
| 1608 | // So explicitly avoid using `memory.copy` in the `len == 0` case. Lovely design. |
| 1609 | try cg.emitWValue(len); |
| 1610 | try cg.addTag(.i32_eqz); |
| 1611 | try cg.addLabel(.br_if, 0); |
| 1612 | } |
| 1608 | 1613 | |
| 1609 | 1614 | try cg.lowerToStack(dst); |
| 1610 | 1615 | try cg.lowerToStack(src); |
| 1611 | 1616 | try cg.emitWValue(len); |
| 1612 | 1617 | try cg.addExtended(.memory_copy); |
| 1613 | 1618 | |
| 1614 | | try cg.endBlock(); |
| 1619 | if (!len0_ok) { |
| 1620 | try cg.endBlock(); |
| 1621 | } |
| 1615 | 1622 | |
| 1616 | 1623 | return; |
| 1617 | 1624 | } |
| ... | ... | @@ -4800,26 +4807,32 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) |
| 4800 | 4807 | // When bulk_memory is enabled, we lower it to wasm's memset instruction. |
| 4801 | 4808 | // If not, we lower it ourselves. |
| 4802 | 4809 | if (std.Target.wasm.featureSetHas(cg.target.cpu.features, .bulk_memory) and abi_size == 1) { |
| 4803 | | try cg.startBlock(.block, .empty); |
| 4804 | | |
| 4805 | | // Even if `len` is zero, the spec requires an implementation to trap if `ptr + len` is |
| 4806 | | // out of memory bounds. This can easily happen in Zig in a case such as: |
| 4807 | | // |
| 4808 | | // const ptr: [*]u8 = undefined; |
| 4809 | | // var len: usize = runtime_zero(); |
| 4810 | | // @memset(ptr[0..len], 42); |
| 4811 | | // |
| 4812 | | // So explicitly avoid using `memory.fill` in the `len == 0` case. Lovely design. |
| 4813 | | try cg.emitWValue(len); |
| 4814 | | try cg.addTag(.i32_eqz); |
| 4815 | | try cg.addLabel(.br_if, 0); |
| 4810 | const len0_ok = std.Target.wasm.featureSetHas(cg.target.cpu.features, .nontrapping_bulk_memory_len0); |
| 4811 | |
| 4812 | if (!len0_ok) { |
| 4813 | try cg.startBlock(.block, .empty); |
| 4814 | |
| 4815 | // Even if `len` is zero, the spec requires an implementation to trap if `ptr + len` is |
| 4816 | // out of memory bounds. This can easily happen in Zig in a case such as: |
| 4817 | // |
| 4818 | // const ptr: [*]u8 = undefined; |
| 4819 | // var len: usize = runtime_zero(); |
| 4820 | // @memset(ptr[0..len], 42); |
| 4821 | // |
| 4822 | // So explicitly avoid using `memory.fill` in the `len == 0` case. Lovely design. |
| 4823 | try cg.emitWValue(len); |
| 4824 | try cg.addTag(.i32_eqz); |
| 4825 | try cg.addLabel(.br_if, 0); |
| 4826 | } |
| 4816 | 4827 | |
| 4817 | 4828 | try cg.lowerToStack(ptr); |
| 4818 | 4829 | try cg.emitWValue(value); |
| 4819 | 4830 | try cg.emitWValue(len); |
| 4820 | 4831 | try cg.addExtended(.memory_fill); |
| 4821 | 4832 | |
| 4822 | | try cg.endBlock(); |
| 4833 | if (!len0_ok) { |
| 4834 | try cg.endBlock(); |
| 4835 | } |
| 4823 | 4836 | |
| 4824 | 4837 | return; |
| 4825 | 4838 | } |