feat(compress): move window clearing leaf into Rust
Keep the private ZSTD_window_t layout and pointer-difference calculation in C, then route the size_t-to-U32 conversion and paired limit writes through a small Rust ABI leaf. This removes the inline C window-clear implementation while preserving its overflow behavior at both single-threaded and multithreaded call sites. Test Plan: - cargo test --manifest-path rust/Cargo.toml --lib zstd_compress::tests (77 passed) - make -C programs -j2 zstd - rustfmt +nightly --edition 2021 rust/src/zstd_compress.rs --check - make -C tests -j2 test-cli-tests (41 passed) - make -C tests -j2 test-legacy test-invalidDictionaries test-decodecorpus test-rust-lib-smoke (passed) - git diff --check
This commit is contained in:
@@ -1486,7 +1486,8 @@ void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs)
|
||||
*/
|
||||
static void ZSTD_invalidateMatchState(ZSTD_MatchState_t* ms)
|
||||
{
|
||||
ZSTD_window_clear(&ms->window);
|
||||
ZSTD_rust_windowClear((size_t)(ms->window.nextSrc - ms->window.base),
|
||||
&ms->window.lowLimit, &ms->window.dictLimit);
|
||||
|
||||
ms->nextToUpdate = ms->window.dictLimit;
|
||||
ms->loadedDictEnd = 0;
|
||||
@@ -1893,7 +1894,11 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx,
|
||||
if (cctx->blockState.matchState.window.dictLimit < cdictEnd) {
|
||||
cctx->blockState.matchState.window.nextSrc =
|
||||
cctx->blockState.matchState.window.base + cdictEnd;
|
||||
ZSTD_window_clear(&cctx->blockState.matchState.window);
|
||||
ZSTD_rust_windowClear(
|
||||
(size_t)(cctx->blockState.matchState.window.nextSrc -
|
||||
cctx->blockState.matchState.window.base),
|
||||
&cctx->blockState.matchState.window.lowLimit,
|
||||
&cctx->blockState.matchState.window.dictLimit);
|
||||
}
|
||||
/* loadedDictEnd is expressed within the referential of the active context */
|
||||
cctx->blockState.matchState.loadedDictEnd = cctx->blockState.matchState.window.dictLimit;
|
||||
|
||||
@@ -654,6 +654,7 @@ size_t ZSTD_rust_noCompressBlock(void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize, U32 lastBlock);
|
||||
size_t ZSTD_rust_rleCompressBlock(void* dst, size_t dstCapacity, BYTE src,
|
||||
size_t srcSize, U32 lastBlock);
|
||||
void ZSTD_rust_windowClear(size_t endT, U32* lowLimit, U32* dictLimit);
|
||||
U32 ZSTD_rust_windowCorrectOverflow(U32 curr, U32 cycleLog, U32 maxDist);
|
||||
U32 ZSTD_rust_windowCanOverflowCorrect(U32 curr, U32 cycleLog, U32 maxDist,
|
||||
U32 loadedDictEnd,
|
||||
@@ -1025,19 +1026,6 @@ MEM_STATIC U64 ZSTD_rollingHash_rotate(U64 hash, BYTE toRemove, BYTE toAdd, U64
|
||||
( ((U32)-1) /* Maximum ending current index */ \
|
||||
- ZSTD_CURRENT_MAX) /* Maximum beginning lowLimit */
|
||||
|
||||
/**
|
||||
* ZSTD_window_clear():
|
||||
* Clears the window containing the history by simply setting it to empty.
|
||||
*/
|
||||
MEM_STATIC void ZSTD_window_clear(ZSTD_window_t* window)
|
||||
{
|
||||
size_t const endT = (size_t)(window->nextSrc - window->base);
|
||||
U32 const end = (U32)endT;
|
||||
|
||||
window->lowLimit = end;
|
||||
window->dictLimit = end;
|
||||
}
|
||||
|
||||
MEM_STATIC U32 ZSTD_window_isEmpty(ZSTD_window_t const window)
|
||||
{
|
||||
return window.dictLimit == ZSTD_WINDOW_START_INDEX &&
|
||||
|
||||
@@ -620,7 +620,10 @@ static void ZSTDMT_serialState_ensureFinished(SerialState* serialState,
|
||||
ZSTD_pthread_cond_broadcast(&serialState->cond);
|
||||
|
||||
ZSTD_PTHREAD_MUTEX_LOCK(&serialState->ldmWindowMutex);
|
||||
ZSTD_window_clear(&serialState->ldmWindow);
|
||||
ZSTD_rust_windowClear((size_t)(serialState->ldmWindow.nextSrc -
|
||||
serialState->ldmWindow.base),
|
||||
&serialState->ldmWindow.lowLimit,
|
||||
&serialState->ldmWindow.dictLimit);
|
||||
ZSTD_pthread_cond_signal(&serialState->ldmWindowCond);
|
||||
ZSTD_pthread_mutex_unlock(&serialState->ldmWindowMutex);
|
||||
}
|
||||
|
||||
@@ -859,6 +859,24 @@ pub unsafe extern "C" fn ZSTD_rust_invalidateRepCodes(rep: *mut u32) {
|
||||
rep.fill(0);
|
||||
}
|
||||
|
||||
/// Clear a C-owned compression window using the original `size_t`-to-`U32`
|
||||
/// conversion. The caller computes the pointer difference while the private
|
||||
/// `ZSTD_window_t` layout remains entirely on the C side.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn ZSTD_rust_windowClear(
|
||||
end_t: usize,
|
||||
low_limit: *mut u32,
|
||||
dict_limit: *mut u32,
|
||||
) {
|
||||
debug_assert!(!low_limit.is_null());
|
||||
debug_assert!(!dict_limit.is_null());
|
||||
let end = end_t as u32;
|
||||
unsafe {
|
||||
*low_limit = end;
|
||||
*dict_limit = end;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn zeroed_state() -> ZSTD_compressedBlockState_t {
|
||||
/* The state contains only integer arrays and enum fields. */
|
||||
@@ -2146,6 +2164,30 @@ mod tests {
|
||||
assert_eq!(rep, [0; ZSTD_REP_NUM]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn window_clear_writes_the_same_end_to_both_limits() {
|
||||
let mut low_limit = 11u32;
|
||||
let mut dict_limit = 22u32;
|
||||
|
||||
unsafe { ZSTD_rust_windowClear(0x1234_5678, &mut low_limit, &mut dict_limit) };
|
||||
|
||||
assert_eq!(low_limit, 0x1234_5678);
|
||||
assert_eq!(dict_limit, 0x1234_5678);
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[test]
|
||||
fn window_clear_truncates_a_large_size_t_like_c_u32_cast() {
|
||||
let mut low_limit = 11u32;
|
||||
let mut dict_limit = 22u32;
|
||||
let end_t = 0x1_0000_0000usize + 0x89ab_cdef;
|
||||
|
||||
unsafe { ZSTD_rust_windowClear(end_t, &mut low_limit, &mut dict_limit) };
|
||||
|
||||
assert_eq!(low_limit, 0x89ab_cdef);
|
||||
assert_eq!(dict_limit, 0x89ab_cdef);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sizeof_local_dict_ignores_size_without_a_buffer() {
|
||||
assert_eq!(sizeof_local_dict(0, 37, 11), 11);
|
||||
|
||||
Reference in New Issue
Block a user