Skip to content

Host colectable GC references#55

Draft
andreaTP wants to merge 4 commits into
bytecodealliance:mainfrom
andreaTP:gc-ref-interpreter-phase1
Draft

Host colectable GC references#55
andreaTP wants to merge 4 commits into
bytecodealliance:mainfrom
andreaTP:gc-ref-interpreter-phase1

Conversation

@andreaTP
Copy link
Copy Markdown
Contributor

@andreaTP andreaTP commented Jun 5, 2026

WIP to fix #36

andreaTP added 4 commits June 2, 2026 12:55
Replace GcRefStore integer-ID indirection with direct Java Object
references in the interpreter path. Java's GC now handles liveness
of Wasm GC structs, arrays, and i31 values naturally.

Core design: MStack gains a lazy Object[] refs array (null until
first pushRef). push()/pop() are unchanged — zero overhead for
non-GC workloads. GC refs use pushRef()/popRef() to store actual
WasmStruct/WasmArray/WasmI31Ref objects.

Key changes:
- MStack: lazy Object[] with pushRef/popRef/peekRef/clearRefsTo
- StackFrame: Object[] localRefs parallel to long[] locals
- WasmStruct/WasmArray: dual long[]+Object[] for fields/elements
- GlobalInstance: Object refValue for ref-typed globals
- TableInstance: Object[] objRefs for GC-typed tables
- ValType.isGcReference(): distinguishes any-hierarchy from func/extern
- StorageType.isReference()/isGcReference(): field type helpers
- Instance.heapTypeMatchRef(Object,...): type matching on Objects
- ConstantEvaluators: ConstantResult carries both long[] and Object
- InterpreterMachine: ~30 GC instructions updated
- Machine.call(int,long[],Object[]): overload for ref args
- WasmI31Ref: equals/hashCode for ref.eq value equality

GcRefStore is NOT yet removed — the compiler still uses it (Phase 2).
Compiler GC tests are expected to fail until Phase 2.
Add callGc/applyGc methods to Machine, ExportFunction, and
WasmFunctionHandle for passing real Java Objects as Wasm GC refs.
Users can now receive WasmStruct/WasmArray/WasmI31Ref directly
from exported functions, and Java GC manages their lifecycle.

Key changes:
- Machine.callGc(int, Object[]) / ExportFunction.applyGc(Object...)
- InterpreterMachine overrides callGc with native Object path
- WasmFunctionHandle.applyGc for GC-aware host functions
- WasmExternRef can wrap either long or Object (for extern.convert_any)
- ValType.isGcReference() cached during resolve() — zero-cost check
- isGcReference correctly classifies concrete func types as non-GC
- Table init populates objRefs for GC-typed tables
- Instance.registerGcRef/gcRef/array deprecated
- OpcodeImpl.boxForTable/unboxFromTable deprecated
- Compiler: GC refs use Object.class, call bridge threads Object[]

Compiler Phase 2: GC refs flow as Objects in generated bytecode.
CompilerUtil maps GC ref types to Object.class/OBJECT_TYPE.
Shaded helpers take/return Object for GC refs.
Generated call_N bridges accept Object[] refArgs.
BR_ON_NULL/NON_NULL checks distinguish GC (ifnull) from funcref (if_icmpeq).

Non-GC code paths are completely unchanged — zero overhead.
Delete GcRefStore and its epoch-based mark-sweep collector. Wasm GC
references (structs, arrays, i31) are now managed entirely by Java's
garbage collector through the Object[] refs arrays in MStack,
StackFrame, WasmStruct, WasmArray, GlobalInstance, and TableInstance.

Changes:
- Delete GcRefStore.java and GcRefStoreTest.java
- Instance: remove gcRefs field, gcSafePoint()
- Instance.registerGcRef/gcRef/array: throw UnsupportedOperationException
- ExportFunction.apply(long...) throws on functions with GC params/returns
  directing users to applyGc(Object...) instead
- Remove gcSafePoint() calls from Instance.Exports and initialization

Users must migrate from apply(long...) to applyGc(Object...) for
functions that use GC reference types (structs, arrays, i31, anyref).
Non-GC functions (funcref, externref, numeric types) continue to
work with apply(long...) unchanged.
Fix all remaining interpreter GC reference bugs:
- MStack.popRef/peekRef: handle null refs array gracefully
- REF_TEST/CAST_TEST/BR_ON_CAST: dispatch based on source type
  (popRef for GC refs, pop for funcref/externref)
- ARRAY_GET/SET: use isGcReference() not isReference() for field
  type checks — funcref/externref elements stay in long[] path
- ARRAY_NEW_DEFAULT: fill with REF_NULL_VALUE for non-GC ref types
- ConstantEvaluators ARRAY_NEW_DEFAULT: same fix for global init
- callGc: convert REF_NULL_VALUE to null for all ref return types
- apply(long...): throw UnsupportedOperationException only after
  execution succeeds (traps propagate correctly)
- WasmExternRef: can wrap Object for extern.convert_any round-trips

Test generator (JavaTestGen):
- Emit applyGc() for functions with GC params/returns
- Null ref assertions use assertNull() for all ref types
- WasmValue: toGcArgsValue, toGcResultValue, toGcAssertion methods
- WasmValueType.isGcReference() helper
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.

Enable host JVM GC to collect unreachable WasmGC references

1 participant