From d603fe610b09bc5d9f9a1f503773f32b7b4edcf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lucas?= Date: Wed, 1 Jul 2026 14:52:01 -0300 Subject: [PATCH] inflate: skip the per-match bounds check in the fast loop --- zlib-rs/src/inflate.rs | 16 +++++++- zlib-rs/src/inflate/writer.rs | 72 +++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/zlib-rs/src/inflate.rs b/zlib-rs/src/inflate.rs index 09584347..3949ba5c 100644 --- a/zlib-rs/src/inflate.rs +++ b/zlib-rs/src/inflate.rs @@ -552,7 +552,10 @@ const fn zswap32(q: u32) -> u32 { } const INFLATE_FAST_MIN_HAVE: usize = 15; -const INFLATE_FAST_MIN_LEFT: usize = 260; +// 260 = up to 2 literals from the fast-path plus one max-length (258) match. The +// unchecked match copy overshoots by up to 32 bytes (one SIMD chunk), so the +// margin covers both, letting the fast loop skip the per-match bounds check. +const INFLATE_FAST_MIN_LEFT: usize = 260 + 32; impl State<'_> { // This logic is split into its own function for two reasons @@ -2110,7 +2113,16 @@ unsafe fn inflate_fast_help_impl(state: &mut State, _star } else if extra_safe { todo!() } else { - writer.copy_match_with_features::(dist as usize, len as usize) + // SAFETY: `dist <= written` (the `else` of the window-copy + // branch) gives `offset_from_end <= filled`, and + // INFLATE_FAST_MIN_LEFT guarantees at least `len + 32` bytes of + // spare capacity for this iteration's writes. + unsafe { + writer.copy_match_unchecked_with_features::( + dist as usize, + len as usize, + ) + } } } else if (op & 64) == 0 { // 2nd level distance code diff --git a/zlib-rs/src/inflate/writer.rs b/zlib-rs/src/inflate/writer.rs index 6ff26c67..8d985f8d 100644 --- a/zlib-rs/src/inflate/writer.rs +++ b/zlib-rs/src/inflate/writer.rs @@ -252,6 +252,78 @@ impl<'a> Writer<'a> { self.copy_match_help::<8>(offset_from_end, length) } + /// Like [`copy_match_with_features`], but skips the per-match bounds check. + /// + /// The inflate fast loop guarantees `INFLATE_FAST_MIN_LEFT` bytes of spare + /// capacity, which covers the longest match plus the chunked copy's overshoot, + /// so the check `copy_match_help` performs on every match is redundant there. + /// + /// # Safety + /// + /// `offset_from_end <= self.filled` and `self.filled + length + 32 <= self.capacity()`. + /// + /// [`copy_match_with_features`]: Writer::copy_match_with_features + #[inline(always)] + pub unsafe fn copy_match_unchecked_with_features( + &mut self, + offset_from_end: usize, + length: usize, + ) { + match FEATURES { + #[cfg(target_arch = "x86_64")] + CpuFeatures::AVX2 => unsafe { + self.copy_match_unchecked::<32>(offset_from_end, length) + }, + // Other targets keep the checked path; the margin only matters for the + // unchecked copy above. + _ => self.copy_match_runtime_dispatch(offset_from_end, length), + } + } + + /// # Safety + /// + /// `offset_from_end <= self.filled` and `self.filled + length + N <= self.capacity()`. + #[inline(always)] + unsafe fn copy_match_unchecked( + &mut self, + offset_from_end: usize, + length: usize, + ) { + let current = self.filled; + self.filled += length; + let ptr = self.buf.as_mut_ptr(); + + if length > offset_from_end { + match offset_from_end { + 1 => { + // The referenced byte repeats; a slice `fill` lowers to `memset`. + // SAFETY: `current >= 1` and `current + length` is in bounds by the margin. + let element = unsafe { ptr.add(current - 1).read() }; + let dst = unsafe { core::slice::from_raw_parts_mut(ptr.add(current), length) }; + dst.fill(element); + } + _ => { + // Overlapping match with a small distance: byte-by-byte, no overshoot. + // SAFETY: reads trail writes by `offset_from_end`, all in bounds. + for i in 0..length { + let byte = unsafe { ptr.add(current - offset_from_end + i).read() }; + unsafe { ptr.add(current + i).write(byte) }; + } + } + } + } else { + // SAFETY: the caller guarantees `length + N` bytes of spare capacity, so the + // chunked copy's overshoot of at most `N` bytes stays in bounds. + unsafe { + Self::copy_chunk_unchecked::( + ptr.add(current - offset_from_end), + ptr.add(current), + length, + ) + } + } + } + #[inline(always)] fn copy_match_help(&mut self, offset_from_end: usize, length: usize) { let capacity = self.buf.len();