ReviewOS

also looking at this

zig-utils/zig-js

fix(compat): stop describing ArrayList's layout, and read it instead

#876
Merged glennmichael123 wants to merge fix/zig-1963-arraylist-compat into main
5 files +88 -42
9 days ago

What this changes

Zig 0.17.0-dev.1963 appends pointer_stability: debug.SafetyLock to ArrayList, and two idioms here assumed the old shape. 27 struct literals of the form .{ .items = &buf, .capacity = buf.len } name every field, so one more field stops them compiling — all are test fixtures wrapping a fixed array, and .fromOwnedSlice(&buf) says the same thing without enumerating fields. The other is a layout assertion in the JIT, which is the part worth reading.

emitDirectDenseArrayGuards mirrors the list as DenseListLayout and asserted it @sizeOf-equal to std.ArrayListUnmanaged(Value). Measured, @sizeOf(ArrayListUnmanaged(u64)) on aarch64-macos:

toolchainDebugReleaseSafeReleaseFast
dev.1818242424
dev.1963323224

SafetyLock is zero-sized when runtime safety is off, so on 1963 that assertion fails in Debug and ReleaseSafe and passes in ReleaseFast — a compile error that depends on -O.

The mirror was never wrong about the part the JIT uses. @offsetOf(items) is 0 and @offsetOf(capacity) is 16 in all six combinations above, and the emitted loads only ever touch those two words plus the slice length. It was the equality that was wrong: it asserted a fact about a tail nothing reads. So the offsets now come from the real type via denseListWordOffset, and DenseListLayout is documented as a description of the prefix rather than a mirror.

Impact

Flips 0 test262 cases. No behaviour change on the current toolchain — same offsets, same emitted loads; @offsetOf resolves to the identical constants the literal did. What changes is that a future std reordering these fields moves the loads with it, instead of silently reading the wrong word — which the old assertion would not have caught either, since it only compared sizes.

Unblocks a downstream consumer (craft) that had to move off 0.17.0-dev.1509 because ziglang.org prunes dev builds: every 1509 tarball now 404s, so the pin could only be satisfied from cache.

Verification

  • zig build test on 0.17.0-dev.1963+e00c6c439: 2285 passed, 1 skipped, 0 failed, 0 leaked, exit 0.
  • zig build on 0.17.0-dev.1818+7051f8e73 (this repo's ZIG_VERSION): clean, with siblings at upstream main.
  • Size/offset table above measured directly on both toolchains across all three optimize modes, not inferred.

The 1963 figure is from a completed run whose log I later clobbered, and two attempts to regenerate it were killed by SIGTERM before finishing (error: process terminated with signal TERM) rather than failing — so treat it as reported, not attached. CI on this PR is the authoritative measurement and covers the 1818 leg the repo actually pins.

5 changed files on the files tab, with 0 review threads.

Sign in to comment on this pull request.