(fix): Use legacy N-way cache path on Julia 1.11#41
Merged
Conversation
Julia 1.11's arraylen builtin derives length from Memory.length, not prod(size). This causes setfield!(:ref)-based wrapper reuse to return arrays where length(arr) != prod(size(arr)), breaking vec(), reshape(), and downstream code. Move the modern/legacy version gate from v"1.11-" to v"1.12-" so that Julia 1.11 uses the legacy N-way set-associative cache path (which uses unsafe_wrap and computes length correctly). Julia 1.12+ continues to use the zero-alloc setfield! path where the bug is fixed. GPU extensions (CUDA, Metal) are also gated at v"1.12-" because they import modern-path-only functions (_store_arr_wrapper!) from the base package.
All references to "Julia 1.11+" in comments, docstrings, and section headers now say "Julia 1.12+" to match the version gate change. Left unchanged: factual statements about Julia 1.11 behavior (e.g. "FieldError is 1.11+", "Julia 1.11's arraylen uses Memory.length").
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #41 +/- ##
==========================================
- Coverage 96.03% 95.48% -0.56%
==========================================
Files 14 14
Lines 3232 3232
==========================================
- Hits 3104 3086 -18
- Misses 128 146 +18
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adjusts version gating so Julia 1.11 uses the legacy N-way cache path (avoiding incorrect length(::Array)/vec behavior), while keeping the modern setfield! wrapper-reuse path and GPU extensions enabled only on Julia 1.12+.
Changes:
- Moved the modern/legacy version gate from
v"1.11-"tov"1.12-"in the package entrypoint and related code paths. - Updated tests to only exercise setfield!-based invalidation/zero-allocation behavior on Julia 1.12+ and use legacy expectations on ≤1.11.
- Gated CUDA/Metal extensions and their tests to Julia 1.12+ and updated related documentation/comments.
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/AdaptiveArrayPools.jl |
Switches the include/version gate to VERSION >= v"1.12-" so Julia 1.11 loads legacy implementation. |
src/acquire.jl |
Updates documentation/comments for setfield!-based reshape/acquire path to be 1.12+. |
src/bitarray.jl |
Updates header/comments to reflect BitArray setfield-based reuse is for Julia 1.12+. |
src/convenience.jl |
Updates reshape! doc wording to 1.12+ path. |
src/debug.jl |
Gates wrapper-mutation checks to 1.12+ and updates related assumptions/comments. |
src/types.jl |
Updates type docs to describe arr_wrappers cache as 1.12+ feature. |
src/legacy/state.jl |
Updates legacy header/docs to indicate legacy applies through Julia ≤1.11. |
ext/AdaptiveArrayPoolsCUDAExt/AdaptiveArrayPoolsCUDAExt.jl |
Requires Julia 1.12+ for CUDA pooling and updates warning text/comments. |
ext/AdaptiveArrayPoolsCUDAExt/types.jl |
Updates CUDA pool type docs to match Julia 1.12+ CPU design reference. |
ext/AdaptiveArrayPoolsCUDAExt/acquire.jl |
Updates comments to reference CPU’s Julia 1.12+ approach. |
ext/AdaptiveArrayPoolsMetalExt/AdaptiveArrayPoolsMetalExt.jl |
Requires Julia 1.12+ for Metal pooling and updates warning text/comments. |
ext/AdaptiveArrayPoolsMetalExt/types.jl |
Updates Metal pool type docs to match Julia 1.12+ CPU design reference. |
test/runtests.jl |
Updates version-based test selection and helpers to gate modern-path tests on 1.12+. |
test/test_zero_allocation.jl |
Updates per-iteration allocation tolerance comment/version gate to 1.12+. |
test/test_safety.jl |
Gates setfield!-based invalidation assertions to run only on Julia 1.12+. |
test/test_reshape.jl |
Gates “zero allocation reshape” tests to Julia 1.12+. |
test/test_nway_cache.jl |
Updates comments describing unlimited-pattern zero-alloc behavior to Julia 1.12+. |
test/cuda/runtests.jl |
Skips CUDA extension tests on Julia < 1.12 and updates messaging. |
test/metal/runtests.jl |
Skips Metal extension tests on Julia < 1.12 and updates messaging. |
Comments suppressed due to low confidence (1)
src/convenience.jl:352
- This docstring still says “On Julia 1.10 and CUDA, falls back to Base.reshape”, but after moving the version gate to 1.12 the fallback behavior also applies on Julia 1.11 (since the setfield!-based reshape implementation isn’t included there). Please update the version wording here so it matches the new gating.
On Julia 1.12+:
- If `ndims(A) == length(dims)` (same dimensionality), `reshape!` mutates `A`
in-place by changing its size. This differs from `Base.reshape`, which always
returns a new wrapper.
- For cross-dimensional reshapes (`ndims(A) != length(dims)`), the returned
`Array` wrapper is taken from the pool's internal cache and may be reused
after `rewind!` or pool scope exit.
As with all pool-backed objects, the reshaped result must not escape the
surrounding `@with_pool` scope.
On Julia 1.10 and CUDA, falls back to `Base.reshape`.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- src/acquire.jl: clarify Array became mutable struct in 1.11 but setfield! reuse is only safe from 1.12 due to arraylen bug - src/debug.jl: legacy fallback covers ≤1.11 (not just 1.10) - src/legacy/state.jl: fix typo nd_wrappers → arr_wrappers - src/convenience.jl: reshape! fallback "Julia 1.10" → "Julia ≤1.11" - README.md: CUDA/Metal "1.11+" → "1.12+", reshape table updated
Update all documentation under docs/src/ to reflect the version gate change. Historical facts preserved (Julia 1.11 made Array a mutable struct) with added notes about the arraylen bug that makes the setfield! path unsafe on 1.11.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On Julia 1.11,
length(::Array)is computed from the backingMemoryobject's length (arraylenbuiltin), not fromprod(size(arr)). This was fixed in Julia 1.12.The
setfield!(:ref)-based wrapper reuse inget_array!copies the entireMemoryReffrom the backing vector. Since pool slots grow but never shrink, the backing vector can be larger thanprod(dims):This caused
DimensionMismatcherrors in production.Fix
Move the modern/legacy version gate from
v"1.11-"tov"1.12-":unsafe_wrap+ cache). Zero-alloc on cache hit (up toCACHE_WAYSpatterns per slot, default 4).setfield!(:ref, :size)path. Zero-alloc unconditionally (unlimited dimension patterns).GPU extensions (CUDA, Metal) are also gated at
v"1.12-"because they import modern-path-only functions (_store_arr_wrapper!) from the base package.Impact