feat(compress): move match-state invalidation leaf into Rust
Route match-state invalidation through a Rust leaf. C still computes the private window pointer difference and passes the opaque dictionary-state pointer, while Rust preserves the window-limit, next-index, dictionary, optimal-parser, and dictionary-match-state reset order. Add a focused test for all invalidated fields and use the concrete C pointer type at the ABI boundary to avoid strict-aliasing warnings. Test Plan: - cargo fmt --manifest-path rust/Cargo.toml -- --check - ulimit -v 41943040 && CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings - ulimit -v 41943040 && CARGO_BUILD_JOBS=1 cargo test --manifest-path rust/Cargo.toml zstd_compress::tests::invalidate_match_state -- --nocapture - ulimit -v 41943040 && make -j1 - ulimit -v 41943040 && make -j1 -C tests test-fuzzer FUZZERTEST=-T3s FUZZER_FLAGS=--no-big-tests
This commit is contained in:
@@ -1722,6 +1722,10 @@ size_t ZSTD_rust_buildBlockEntropyStats(
|
|||||||
void* workspace, size_t wkspSize);
|
void* workspace, size_t wkspSize);
|
||||||
void ZSTD_rust_resetCompressedBlockState(ZSTD_compressedBlockState_t* bs);
|
void ZSTD_rust_resetCompressedBlockState(ZSTD_compressedBlockState_t* bs);
|
||||||
void ZSTD_rust_invalidateRepCodes(U32 rep[ZSTD_REP_NUM]);
|
void ZSTD_rust_invalidateRepCodes(U32 rep[ZSTD_REP_NUM]);
|
||||||
|
void ZSTD_rust_invalidateMatchState(
|
||||||
|
size_t endT, U32* lowLimit, U32* dictLimit,
|
||||||
|
U32* nextToUpdate, U32* loadedDictEnd, U32* litLengthSum,
|
||||||
|
const ZSTD_MatchState_t** dictMatchState);
|
||||||
typedef char ZSTD_rust_invalidate_rep_count[(ZSTD_REP_NUM == 3) ? 1 : -1];
|
typedef char ZSTD_rust_invalidate_rep_count[(ZSTD_REP_NUM == 3) ? 1 : -1];
|
||||||
void ZSTD_rust_confirmRepcodesAndEntropyTables(
|
void ZSTD_rust_confirmRepcodesAndEntropyTables(
|
||||||
ZSTD_compressedBlockState_t** prevCBlock,
|
ZSTD_compressedBlockState_t** prevCBlock,
|
||||||
@@ -3718,21 +3722,6 @@ void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs)
|
|||||||
ZSTD_rust_resetCompressedBlockState(bs);
|
ZSTD_rust_resetCompressedBlockState(bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! ZSTD_invalidateMatchState()
|
|
||||||
* Invalidate all the matches in the match finder tables.
|
|
||||||
* Requires nextSrc and base to be set (can be NULL).
|
|
||||||
*/
|
|
||||||
static void ZSTD_invalidateMatchState(ZSTD_MatchState_t* ms)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
ms->opt.litLengthSum = 0; /* force reset of btopt stats */
|
|
||||||
ms->dictMatchState = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controls, for this matchState reset, whether the tables need to be cleared /
|
* Controls, for this matchState reset, whether the tables need to be cleared /
|
||||||
* prepared for the coming compression (ZSTDcrp_makeClean), or whether the
|
* prepared for the coming compression (ZSTDcrp_makeClean), or whether the
|
||||||
@@ -3807,7 +3796,13 @@ static void ZSTD_rust_resetMatchState_invalidate(void* opaque)
|
|||||||
{
|
{
|
||||||
ZSTD_rust_resetMatchStateContext* const context =
|
ZSTD_rust_resetMatchStateContext* const context =
|
||||||
(ZSTD_rust_resetMatchStateContext*)opaque;
|
(ZSTD_rust_resetMatchStateContext*)opaque;
|
||||||
ZSTD_invalidateMatchState(context->ms);
|
ZSTD_MatchState_t* const ms = context->ms;
|
||||||
|
ZSTD_rust_invalidateMatchState(
|
||||||
|
(size_t)(ms->window.nextSrc - ms->window.base),
|
||||||
|
&ms->window.lowLimit, &ms->window.dictLimit,
|
||||||
|
&ms->nextToUpdate, &ms->loadedDictEnd,
|
||||||
|
&ms->opt.litLengthSum,
|
||||||
|
&ms->dictMatchState);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ZSTD_rust_resetMatchState_clearTables(void* opaque)
|
static void ZSTD_rust_resetMatchState_clearTables(void* opaque)
|
||||||
|
|||||||
@@ -6916,6 +6916,34 @@ pub unsafe extern "C" fn ZSTD_rust_windowClear(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Invalidate a C-owned match-state projection after the caller computes the
|
||||||
|
/// private window pointer difference. Rust owns the paired window-limit and
|
||||||
|
/// match-state field updates while C retains the match-state layout.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn ZSTD_rust_invalidateMatchState(
|
||||||
|
end_t: usize,
|
||||||
|
low_limit: *mut u32,
|
||||||
|
dict_limit: *mut u32,
|
||||||
|
next_to_update: *mut u32,
|
||||||
|
loaded_dict_end: *mut u32,
|
||||||
|
lit_length_sum: *mut u32,
|
||||||
|
dict_match_state: *mut *const c_void,
|
||||||
|
) {
|
||||||
|
debug_assert!(!low_limit.is_null());
|
||||||
|
debug_assert!(!dict_limit.is_null());
|
||||||
|
debug_assert!(!next_to_update.is_null());
|
||||||
|
debug_assert!(!loaded_dict_end.is_null());
|
||||||
|
debug_assert!(!lit_length_sum.is_null());
|
||||||
|
debug_assert!(!dict_match_state.is_null());
|
||||||
|
unsafe {
|
||||||
|
ZSTD_rust_windowClear(end_t, low_limit, dict_limit);
|
||||||
|
*next_to_update = *dict_limit;
|
||||||
|
*loaded_dict_end = 0;
|
||||||
|
*lit_length_sum = 0;
|
||||||
|
*dict_match_state = ptr::null();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const HASH_READ_SIZE: u32 = 8;
|
const HASH_READ_SIZE: u32 = 8;
|
||||||
|
|
||||||
/// Private C window fields projected for the shared window-update policy.
|
/// Private C window fields projected for the shared window-update policy.
|
||||||
@@ -12808,6 +12836,36 @@ mod tests {
|
|||||||
assert_eq!(dict_limit, 0x89ab_cdef);
|
assert_eq!(dict_limit, 0x89ab_cdef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn invalidate_match_state_clears_window_and_private_fields() {
|
||||||
|
let mut low_limit = 11u32;
|
||||||
|
let mut dict_limit = 22u32;
|
||||||
|
let mut next_to_update = 33u32;
|
||||||
|
let mut loaded_dict_end = 44u32;
|
||||||
|
let mut lit_length_sum = 55u32;
|
||||||
|
let marker = 0x5au8;
|
||||||
|
let mut dict_match_state = (&marker as *const u8).cast::<c_void>();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
ZSTD_rust_invalidateMatchState(
|
||||||
|
0x1234_5678,
|
||||||
|
&mut low_limit,
|
||||||
|
&mut dict_limit,
|
||||||
|
&mut next_to_update,
|
||||||
|
&mut loaded_dict_end,
|
||||||
|
&mut lit_length_sum,
|
||||||
|
&mut dict_match_state,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(low_limit, 0x1234_5678);
|
||||||
|
assert_eq!(dict_limit, 0x1234_5678);
|
||||||
|
assert_eq!(next_to_update, 0x1234_5678);
|
||||||
|
assert_eq!(loaded_dict_end, 0);
|
||||||
|
assert_eq!(lit_length_sum, 0);
|
||||||
|
assert!(dict_match_state.is_null());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn window_update_leaves_empty_input_untouched() {
|
fn window_update_leaves_empty_input_untouched() {
|
||||||
let mut state = ZSTD_rust_windowUpdateState {
|
let mut state = ZSTD_rust_windowUpdateState {
|
||||||
|
|||||||
Reference in New Issue
Block a user