diff --git a/.github/workflows/wp24b2-inplace-gc.yml b/.github/workflows/wp24b2-inplace-gc.yml index 9e1d1dc..3731872 100644 --- a/.github/workflows/wp24b2-inplace-gc.yml +++ b/.github/workflows/wp24b2-inplace-gc.yml @@ -77,18 +77,27 @@ jobs: if not re.search(r"mov\s+esi,\s*ecx", collector): raise SystemExit("ABI validation failed: collector callback does not consume L from ECX") - # lua_close is much smaller in B2 because fragment reconstruction is gone. - # Zig may preserve ECX in any callee-saved register or a stack slot; do - # not require the B1-specific ESI allocation. + # B2 lua_close has no helper call before callOriginal: Zig can legally + # leave the incoming fastcall ECX untouched and call the trampoline + # directly. Accept either explicit preservation or verified no write + # to ECX before the first call instruction. close = callback_snippet("6f6ef0", 800) - ecx_preserved = re.search( + first_call = re.search(r"\bcall\b", close) + if not first_call: + raise SystemExit("ABI validation failed: lua_close trampoline call missing") + before_call = close[:first_call.start()] + ecx_saved = re.search( r"(?:mov\s+(?:esi|edi|ebx|ebp|eax|edx),\s*ecx|push\s+ecx|mov\s+(?:dword ptr\s*)?\[[^\]]+\],\s*ecx)", - close, + before_call, ) - if not ecx_preserved: + ecx_written = re.search( + r"\b(?:mov|lea|xor|and|or|add|sub|imul|inc|dec|pop)\s+ecx\b", + before_call, + ) + if not ecx_saved and ecx_written: print("lua_close callback snippet:") print(close) - raise SystemExit("ABI validation failed: lua_close callback does not preserve L from ECX") + raise SystemExit("ABI validation failed: lua_close clobbers incoming ECX before trampoline") # Native helper ABI observed directly in WoW 5875: # lua_gc_remove_objects: ECX=L, EDX=&list, stack arg all=0.