Commit Graph
9 Commits
Author SHA1 Message Date
MarcelineVQ 039cec1806 luagc: 5.1 incremental GC with timing, stress tests, pre-alloc hooks (BROKEN)
Current state CRASHES on load due to pre-alloc hooks with wrong calling
conventions. pushcclosure hook is still enabled with partially disabled
others. Needs all pre-alloc hooks disabled or CCs fixed before use.

Implemented:
- Full 5.1 tri-color incremental GC
- 5.1-style singlestep budget loop (replaces chunk-based approach)
- Per-step rdtsc timing (ZGCStats returns max_step_us, atomic_us)
- Configurable gcstepsize/gcstepmul/gcpause via ZGCTune()
- Pre-alloc GC hooks for 7 API functions (5.1 luaC_checkGC pattern)
- Stress test addon: /gclife, /gcsweep, /gccompare

Broken:
- Pre-alloc hooks have CC mismatches causing immediate crash on load
- pushfstring is cdecl variadic, not fastcall (removed)
- pushstring has ambiguous CC (removed, covered by pushlstring)
- pushcclosure hook still active -- may be causing the crash
- Half-initialized objects cause garbage gcptr under heavy stress

weirdperformance: re-enabled luagc.install() + luastr + luavm
2026-04-11 13:03:37 -07:00
MarcelineVQ 8d3460cf1e luagc: per-step timing, forced GC honoring, weirdperformance compat
- Per-step rdtsc timing: ZGCStats returns max_step_us and atomic_us
- AllocBench /zgcstats frame shows step/atomic timing with color coding
- /gccompare command for timing forced GC cycles
- Honor lua_setgcthreshold forced collections (collectgarbage() with low
  threshold now triggers GC instead of being silently ignored)
- Disable luaalloc in weirdperformance when luagc is active (no conflict)
- Closures go to grayagain (covers all upvalue mutation paths)
2026-04-11 10:29:39 -07:00
MarcelineVQ ce5a2408d5 luagc: complete incremental GC -- no crashes, no addon errors on /reload
Closures, threads, and protos all go to grayagain for atomic re-traversal.
This covers all upvalue/stack/compiler mutations between mark steps without
needing to hook every individual write site.

Additional fixes this round:
- LUA_TUPVAL handling in markObject (5.1 reallymarkobject pattern)
- isCleared: strings never cleared from weak tables (5.1 lstring.c:337)
- Unified cleartable matching 5.1 (key OR value cleared removes entry)
- Clear stale weak flags when metatable is NULL
- lua_replace barrier hook (0x6F32B0) for upvalue pseudo-index writes
- Compiler barrier hooks (create_constant, finish_function) -- installed
  but superseded by proto grayagain
- fullgc abandon walks all objects with makewhite before restart
- Removed old separate clearWeakValues/clearWeakKeys

CHUNK_SIZE=5000, confirmed incremental: mark=46, sweep=184 on large heaps.
No crashes or addon errors through enter world, /reload, logout/login cycles.
2026-04-11 09:51:26 -07:00
MarcelineVQ a88d1f8411 luagc: complete Lua 5.1 incremental GC -- no crashes
Full 5.1 incremental GC port with CHUNK_SIZE=5000. All crash scenarios
resolved: enter world, logout/login, /reload, /gcstress.

Compiler barriers (verified from Ghidra):
- Hook lua_parser_create_constant (0x6FD400) and
  lua_parser_finish_function (0x6FCB00)
- ECX = LexState in all callers (not FuncState)
- Proto via: LexState+0x30 -> FuncState, FuncState+0x00 -> Proto
- Barrier-back: if proto is BLACK during mark, gray + grayagain

String/upvalue resurrection:
- Hook luaS_newlstr (0x6F9D00) -- resurrect dead strings from intern
- Hook luaF_findupval (0x6F9F10) -- resurrect dead open upvalues
- Birth mark patches for strings (0x6F9DC1) and upvalues (0x6F9F4A)

Other:
- Volatile reads/writes for all foreign memory access
- Fix upvalue traversal: dereference v pointer not inline value
- Remove bootstrap (luaC_link hook covers all objects except mainthread)
- Mainthread makewhite in markroot
- Remove 5.1 removeentry from traverseTable (5.0 tables don't expect TNONE)
- Clear stale weak flags when metatable is NULL
- fullgc abandon when lua_setgcthreshold forces GC mid-cycle

Remaining: /reload causes addon errors ("attempt to call a number value").
Not a crash -- investigation needed for the specific collection difference.
2026-04-10 23:58:50 -07:00
MarcelineVQ 72627d4123 luagc: complete 5.1 incremental GC integration -- string/upval resurrection
Critical fix: hook luaS_newlstr (0x6F9D00) for dead string resurrection
during incremental sweep. When the string intern table returns an existing
string with otherwhite (dead but not yet swept), flip its white bits to
resurrect it. Without this, code gets references to strings that sweep
will free, causing hash chain crashes. Matches 5.1 lstring.c:88.

Also:
- Upvalue resurrection: hook luaF_findupval (0x6F9F10), same pattern
- Upvalue birth mark: patch 0x6F9F4A so new open upvalues get currentwhite
- Volatile reads/writes on all memory accessors (foreign memory via @ptrFromInt)
- Fix upvalue traversal: dereference v pointer (+0x08) not inline value (+0x10)
- Fix upvalue birth mark address (0x6F9F4A not 0x6F9F48 -- immediate is last byte)
- Correct hook target: luaS_newlstr does intern lookup, not lua_create_string_object

CHUNK_SIZE=5000 (true incremental). Multi-step mark cycles confirmed working.
2026-04-10 15:30:56 -07:00
MarcelineVQ 1ec97731d5 luagc: fix upvalue value read (dereference v pointer, not inline offset)
Open upvalues have v pointing to the Lua stack. Closed upvalues have v
pointing to the inline copy at upval+0x10. Reading upval+0x10 directly
was wrong for open upvalues -- gave stale/garbage data, causing
markObject to be called with invalid pointers (e.g. 0x3).

Fix: dereference upval->v at +0x08 to get the actual TValue location.
Also: volatile reads on all readU8/readU32/writeU8/writeU32 (correct
for foreign memory access via @ptrFromInt).
2026-04-10 00:21:49 -07:00
MarcelineVQ e996796d39 luagc: Lua 5.1 tri-color GC with full forward barrier coverage
Major port of Lua 5.1 incremental GC patterns:

Tri-color system:
- Two-white (WHITE0/WHITE1) with currentwhite flip in atomic phase
- Objects born currentwhite via hooked luaC_link (0x6F7B20)
- String birth mark patched to currentwhite at each flip
- isDead: otherwhite check with FIXED exception for WoW
- makewhite on survivors (preserves KEYWEAK/VALUEWEAK/FIXED)
- Bootstrap: first cycle sets all existing objects to currentwhite

Mark system (5.1 reallymarkobject/propagatemark):
- Strings: stringmark inline (no gray stack)
- Userdata: go black inline, mark metatable
- Tables: gray2black, traverse, black2gray if weak
- Threads: NEVER black, always grayagain (re-traversed in atomic)
- Closures: go black normally

Forward barriers (5.1 luaC_barrierf at every write site):
- OP_SETUPVAL: VM patch at 0x6F8A97 with naked asm trampoline
- lua_setmetatable (0x6F4020): hooked, barrier on new metatable
- lua_setupvalue (0x6F47B0): hooked, barrier grays closure
- lua_setfenv (0x6F40D0): hooked, barrier grays object

Backward barriers (5.1 luaC_barrierback):
- lua_table_set_value (0x6FA840): black2gray + grayagain
- lua_table_set_int_key (0x6FAD80): black2gray + grayagain

Atomic phase (5.1 ordering):
- propagateall, re-traverse weak tables, mark running thread,
  grayagain drain, separateudata, marktmu, cleartable, flip white

Status: enters world successfully with CHUNK_SIZE=5000 (incremental).
Crashes on UI reload (different crash pattern -- NULL+8 deref in mark,
not the old hash chain crash). Progress from "crashes on enter world"
to "crashes on UI reload."
2026-04-09 23:50:37 -07:00
MarcelineVQ 54d1b69f0e luagc: incremental GC fixes (weak tables, isAlive, grayagain, lua_close)
- Weak tables mark strong dimension (condmarkobject pattern)
- isAlive matches WoW binary (raw marked != 0)
- Write barriers use grayagain (barrier-back, prevents livelock)
- removekey sets dead keys to LUA_TNONE
- lua_close hook resets GC state before teardown
- lua_setgcthreshold hook prevents threshold stomping
- Stack nilling in traverseThread
- Sweep order: rootudata -> strings -> rootgc
- Birth mark scoped to string sweep only
2026-04-09 17:25:13 -07:00
MarcelineVQ 1ea1d6655b luagc: from-scratch incremental GC with slab allocator
Replace WoW's stop-the-world Lua 5.0 GC with a fully custom incremental
mark+sweep. The module owns both allocation (slab allocator) and collection.

Key components:
- Slab allocator (luaalloc.zig): copied from weirdperformance, stripped of
  generational age bitmaps. Hooks memory_pool_allocate + lua_gc_step.
- Incremental mark: tri-color with gray stack, write barriers on table writes.
  Correctly handles weak table strong/weak dimensions (condmarkobject).
- From-scratch sweep: cursor-based rootgc, rootudata, chunked string buckets.
  Sweep order matches native (rootudata -> strings -> rootgc).
- Weak table detection: scans metatable for __mode, sets KEYWEAK/VALUEWEAK.
- Weak clearing: removekey semantics (nil value + TNONE dead keys).
- Birth mark scoped to string sweep only (rootgc objects prepend to head).
- Stack nilling: traverseThread nils slots above L->top matching native.
- Hooks lua_setgcthreshold to prevent external threshold stomping.

Native functions retained: lua_gc_free_object (type dispatch), luaCallUserDataGC
(__gc finalizers), luaC_separateudata (dead udata separation).
2026-04-09 16:34:16 -07:00