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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

1 participant