Skip to content

feat: add owned typed arrays - #68

Draft
GrapeBaBa wants to merge 6 commits into
mainfrom
fix/external-typed-array-lifecycle
Draft

feat: add owned typed arrays#68
GrapeBaBa wants to merge 6 commits into
mainfrom
fix/external-typed-array-lifecycle

Conversation

@GrapeBaBa

@GrapeBaBa GrapeBaBa commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add js.OwnedTypedArray(Element, array_type) and concrete Owned*Array aliases
  • transfer allocator-owned element storage to an external ArrayBuffer without copying
  • support owned typed arrays as return values from DSL functions and class methods
  • make ownership transfer transactional: pre-transfer failures preserve the Zig owner; successful or potentially transferred values leave the source empty
  • validate each Element against its N-API TypedArray kind at compile time
  • keep TypedArray.fromExternal unchanged from main
  • propagate NoExternalBuffersAllowed unchanged; no copy fallback

API

pub fn serialize() !js.OwnedUint8Array {
    const allocator = js.allocator();
    const data = try allocator.alloc(u8, 32);
    // Fill data...
    return js.OwnedUint8Array.fromOwnedSlice(allocator, data);
}

fromOwnedSlice takes an existing allocator-owned mutable slice without copying. fromSlice creates an owned copy when that is what the caller needs.

intoValue takes *OwnedTypedArray. Once ownership transfers, it empties the source, so a normal deferred deinit is safe. The allocator must remain valid until the ArrayBuffer finalizer runs.

Ownership boundary

  • zero length: create a normal zero-length V8 ArrayBuffer and empty the source only after TypedArray creation succeeds
  • owner heap allocation failure: leave the allocation owned by the caller
  • NoExternalBuffersAllowed, PendingException, or CannotRunJS: Node returns before finalizer registration, so restore ownership to the caller and propagate the original error
  • other external ArrayBuffer errors: leave the source empty because Node may already have installed or invoked the finalizer
  • typed-array view creation failure or success: leave the source empty; the external ArrayBuffer finalizer owns the allocation
  • DSL return conversion: defer deinit on the local owner, which frees restored/untransferred data and is a no-op after transfer

The heap finalizer context is the OwnedTypedArray itself, matching the boxed-owner model rather than duplicating ownership fields in a second context type.

Node implementation reference for the ambiguous failure boundary:

Verification

  • zig build test:zapi
  • zig build
  • pnpm test:js — 119/119
  • pnpm lint:js
  • zig fmt --check src/js/typed_arrays.zig src/js/wrap_function.zig
  • git diff --check origin/main
  • independent Zig ownership audit — PASS, 0 MUST / 0 SHOULD

Spec tests were intentionally not run.

The repository-wide zig fmt --check src still reports the pre-existing formatting issue in src/create_callback.zig; this PR does not modify that file.

Coverage limitation

The JS tests exercise non-empty and zero-length OwnedUint8Array values through the real Node addon boundary. They do not deterministically force GC to count finalizer invocations or inject NoExternalBuffersAllowed, pending/cannot-run, generic external-creation, or typed-array-view creation failures. No production test seam or compatibility branch was added for those cases.

@GrapeBaBa GrapeBaBa changed the title fix: preserve external typed array ownership feat: add owned typed arrays Jul 30, 2026
@matthewkeil matthewkeil moved this to In Progress in Lodestar Team Coordination Jul 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

2 participants