Skip to content

Perf: split rare object state to reach the 256-byte GC slab #120

Description

@chrisbbreuer

Parent: #62
Related: #97, #44, #86, #87, #119

Evidence

An exact-row profile on 5100a966 sampled warmed eight-context object_churn for 20 seconds. The seven-sample screen measured exact checksum 8309369344; zig-js was 335.523 ms median versus JSC 184.239 ms. One-context zig-js remained faster (109.035 vs 115.561 ms), so the deficit was scaling under concurrent private-heap memory pressure rather than a shared runtime lock.

The profiler attributed the active worker stacks primarily to young sweeping/collection and 512-byte ordinary-object allocation/reuse. Object was 448 bytes and the zig-gc header brought each managed allocation to 496 bytes, forcing the 512-byte slab. The benchmark literal used three inline values while most of the cell was default-initialized exotic/callable/typed-array/Temporal state.

The completed refactor moved rare state behind cold sidecars, reduced ordinary objects to the 256-byte GC slab, and enlarged object chunks without exceeding the fixed reuse bitmap. The accepted order-balanced run at zig-js 0a74f7d1, published by 6c71f46f, preserved all 1,540 raw samples and beat JSC in every direct, warmed-eight, and cold-eight workload. Object-churn medians were 80.380 vs 117.343 ms direct, 170.179 vs 187.303 ms at eight warmed contexts, and 177.256 vs 189.788 ms across cold eight-context lifecycles.

Scope completed

  • Split rare callable, primitive, proxy, buffer/view, weak/finalization, module, iterator-helper, Temporal, and other exotic state behind cold typed storage while keeping ordinary shape/inline-slot/prototype and dense-array access fast.
  • Kept the ordinary managed Object plus zig-gc header within the 256-byte slab class and added a compile-time/layout regression test.
  • Routed cold storage through context/GC ownership and finalizer accounting; traced moved managed edges and preserved no-GIL synchronization.
  • Preserved prototypes, property/accessor semantics, callbacks/constructors, arrays, proxies, weak collections, typed arrays, Temporal, OOM rollback, GC tracing, and exact benchmark checksums.
  • Landed the work as reviewable, compiling slices before the batched full normal/TSan/publication gates.

Acceptance

  • Managed ordinary objects use the 256-byte GC slab with a guarded layout test.
  • Beat JSC in direct and 1/2/4/8 independent object_churn rows on an order-balanced exact-parent A/B.
  • Materially improve shared object_churn without regressing the other nine benchmark workloads.
  • Pass focused object/exotic/GC/OOM/no-GIL tests, then one batched full normal and TSan gate.
  • Publish clean report/TSV evidence and refresh README/docs with the latest scores and linked commits.

Accepted report: https://github.com/zig-utils/zig-js/blob/main/docs/.data/benchmark-comparison-2026-07-15.md

Raw samples: https://github.com/zig-utils/zig-js/blob/main/docs/.data/benchmark-comparison-2026-07-15.tsv

Final full normal/TSan verification: https://github.com/zig-utils/zig-js/actions/runs/29466730465

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions