Skip to content

[js-api] Split the Exported GC Object cache by address kind - #2327

Open
f52985 wants to merge 1 commit into
WebAssembly:mainfrom
kaist-plrg:fix/js-api-split-gc-object-cache
Open

f52985 wants to merge 1 commit into
WebAssembly:mainfrom
kaist-plrg:fix/js-api-split-gc-object-cache

Conversation

@f52985

@f52985 f52985 commented Nov 10, 2026

Copy link
Copy Markdown
Collaborator

Structs and arrays share one cache, the Exported GC Object cache, which maps an address to its JavaScript wrapper.
But in the Core Spec struct addresses and array addresses are separate address spaces (each indexes
its own store component, structs and arrays),
So a struct and an array can have the same address, and the cache, keyed by the address alone, technically cannot tell them apart, since each is just a natural number.
Therefore, a new Exported GC Object algorithm may return a struct's wrapper for an array, or an array's for a struct.

For example, with

(module
  (type $s (struct (field i32)))
  (type $a (array i32))
  (func (export "makeStruct") (result (ref $s))
    (struct.new $s (i32.const 0)))
  (func (export "makeArray") (result (ref $a))
    (array.new $a (i32.const 0) (i32.const 1))))
const s = exports.makeStruct();  // caches s at address 0
const a = exports.makeArray();   // cache hit on address 0: returns s
s === a;                         // true (which should not be)

If these are the first struct and the first array in the store, both would get address 0.
When makeStruct() returns, converting the struct to JavaScript creates its wrapper and caches it at address 0.
When makeArray() returns, converting the array to JavaScript looks the cache up by address 0, finds the struct's entry, and returns the cached struct's wrapper.


This PR splits it into one cache per address space,
and picks the map by objectkind; the lookups stay keyed by the address:

* The Exported struct cache, mapping struct addresses to Exported GC Object objects.
* The Exported array cache, mapping array addresses to Exported GC Object objects.
...
1. If objectkind is "struct", let map be the surrounding agent's associated Exported struct cache; otherwise, let map be the surrounding agent's associated Exported array cache.

P.S. Alternatives would be keying this cache by the pair (objectkind, objectaddr),
or by the reference value itself (ref.struct a/ref.array a).
I went with separate caches to keep this one consistent with the other caches here,
each of which maps uses single kind of address as a key,
but I'm happy to switch if either is preferred.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant