re: close the ISL operand chain -- built-in result is special[0], via a vtable

Answers what the previous commit left open: naming the branches did not give a
clear condition, because that needs the operand chain feeding each compare.

First, a correction to my own work.  isl-bytecode.md -- which OWNS the opcode table
-- already named ops 21-24 push.i/push.f/pop.i/pop.f.  isl-branches.md, which I
wrote last iteration, said op21 and op23 were unread.  The stale file was mine.
Verified from the thunks rather than accepted: 21 pushes [phase+168] onto the deque
at phase+44, 22 pushes [phase+184] onto phase+64, and the 23/24 handlers touch only
r3+168 and r3+184.  So pop.i lands in special[1].

New: the 147-entry built-in table is a thin DISPATCH LAYER, not implementations.
Each stub resolves the local[] argument base and tail-calls a fixed ScriptPhase
vtable slot.  112 of 147 dispatch that way; 17 write [phase+164] inline; 0 write
+184.  Every named predicate is in the vtable group -- unit_state 184, unit_alive
188, hp_pct_test 64, dist_lt 56, is_engaged 252, timer_elapsed 372 -- which is the
control that the split separates engine queries from script bookkeeping.

The vtable is 0x820A84BC, derived from a known implementation rather than a stride:
MARK_LAST_PHASE is documented as [phase+300]=2; the function 0x8226B498 is exactly
that stub; it appears as a data word at exactly one address, 0x820A8570; built-in
39 uses slot 180.  The check NOT used in the derivation: built-in 40 mark_not_last
uses slot 176, and slot 176 holds the [phase+300]=1 stub.  Predicted and confirmed.
The db's own vptr_writes independently lists 0x820A84BC, written at 0x82261B80.

unit_state = slot 184 = 0x8226ADF0, which indexes [phase+324] by local[4] and writes
its answer to [phase+164] = special[0] at both exits.  The phase-3 poll loop now
reads end to end: unit_state(ADT308) -> special[0]; pop.i -> special[1]; cmp.i; beq.

isl.py names ops 21-24; the calls artefact regenerates with NO diff.

Left open and said so: the other 111 vtable slots, which comparand each site pushes,
the 35 non-vtable built-ins, and the vtable's length.
This commit is contained in:
Sylpheed RE agent
2026-08-27 05:21:10 +00:00
parent bad96eb54a
commit 142b8d7200
5 changed files with 142 additions and 17 deletions

View File

@@ -52,7 +52,7 @@ phase code bases: 0xe4 0x14aa8 0x24b4c
005834: 00000C13 call len=12 k=00,00 0000000B 00000278 end_coroutine
005840: 01021001 set.f len=16 k=01,02 00000000 406A4000 00000000 special[0] = imm 210
005850: 02020C01 set.f len=12 k=02,02 00000001 00000000 special[1] = special[0]
00585C: 02000416 op22 len=4 k=02,00
00585C: 02000416 push.f len=4 k=02,00
005860: 01020C00 set.i len=12 k=01,02 00000000 00000000 special[0] = imm 0x0
## phase 1 — builtin 6 (END_PHASE) at 0x6010
@@ -76,7 +76,7 @@ phase code bases: 0xe4 0x14aa8 0x24b4c
00601C: 00000C13 call len=12 k=00,00 0000000B 000002A5 end_coroutine
006028: 01021001 set.f len=16 k=01,02 00000000 4092C000 00000000 special[0] = imm 1200
006038: 02020C01 set.f len=12 k=02,02 00000001 00000000 special[1] = special[0]
006044: 02000416 op22 len=4 k=02,00
006044: 02000416 push.f len=4 k=02,00
006048: 01020C00 set.i len=12 k=01,02 00000000 00000000 special[0] = imm 0x0
## phase 1 — builtin 6 (END_PHASE) at 0x6260
@@ -101,7 +101,7 @@ phase code bases: 0xe4 0x14aa8 0x24b4c
006278: 00000414 ret len=4 k=00,00
00627C: 01020C00 set.i len=12 k=01,02 00000000 00000002 special[0] = imm 0x2
006288: 02020C00 set.i len=12 k=02,02 00000001 00000000 special[1] = special[0]
006294: 02000415 op21 len=4 k=02,00
006294: 02000415 push.i len=4 k=02,00
## phase 1 — builtin 62 (FORCE_END_PHASE) at 0x1482C
014770: 01020C00 set.i len=12 k=01,02 00000000 00000000 special[0] = imm 0x0
@@ -292,14 +292,14 @@ phase code bases: 0xe4 0x14aa8 0x24b4c
02C1EC: 00000C13 call len=12 k=00,00 0000000B 000002BA end_coroutine
02C1F8: 01021001 set.f len=16 k=01,02 00000000 4072C000 00000000 special[0] = imm 300
02C208: 02020C01 set.f len=12 k=02,02 00000001 00000000 special[1] = special[0]
02C214: 02000416 op22 len=4 k=02,00
02C214: 02000416 push.f len=4 k=02,00
02C218: 01020C00 set.i len=12 k=01,02 00000000 00000000 special[0] = imm 0x0
## phase 3 — builtin 6 (END_PHASE) at 0x2CF74
02CEBC: 02020C00 set.i len=12 k=02,02 00000001 00000000 special[1] = special[0]
02CEC8: 02000415 op21 len=4 k=02,00
02CEC8: 02000415 push.i len=4 k=02,00
02CECC: 00000C13 call len=12 k=00,00 00000063 00000306 builtin99
02CED8: 00020417 op23 len=4 k=00,02
02CED8: 00020417 pop.i len=4 k=00,02
02CEDC: 02020C0A cmp.i len=12 k=02,02 00000000 00000001
02CEE8: 0000080D beq len=8 k=00,00 000083B0
02CEF0: 01000C00 set.i len=12 k=01,00 00000074 00000002 global[116] = imm 0x2
@@ -316,7 +316,7 @@ phase code bases: 0xe4 0x14aa8 0x24b4c
02CF80: 00000C13 call len=12 k=00,00 0000000B 0000030E end_coroutine
02CF8C: 01021001 set.f len=16 k=01,02 00000000 4092C000 00000000 special[0] = imm 1200
02CF9C: 02020C01 set.f len=12 k=02,02 00000001 00000000 special[1] = special[0]
02CFA8: 02000416 op22 len=4 k=02,00
02CFA8: 02000416 push.f len=4 k=02,00
02CFAC: 01020C00 set.i len=12 k=01,02 00000000 00000000 special[0] = imm 0x0
## phase 3 — builtin 6 (END_PHASE) at 0x2D1DC
@@ -350,11 +350,11 @@ phase code bases: 0xe4 0x14aa8 0x24b4c
034994: 0000080E bne len=8 k=00,00 0000FEB4
03499C: 01020C00 set.i len=12 k=01,02 00000000 00000001 special[0] = imm 0x1
0349A8: 02020C00 set.i len=12 k=02,02 00000001 00000000 special[1] = special[0]
0349B4: 02000415 op21 len=4 k=02,00
0349B4: 02000415 push.i len=4 k=02,00
0349B8: 01030C00 set.i len=12 k=01,03 00000000 00000001 local[0] = imm 0x1
0349C4: 01030C00 set.i len=12 k=01,03 00000004 00000049 local[4] = imm 0x49
0349D0: 00000C13 call len=12 k=00,00 00000045 0000072C unit_state(ADT308)
0349DC: 00020417 op23 len=4 k=00,02
0349DC: 00020417 pop.i len=4 k=00,02
0349E0: 02020C0A cmp.i len=12 k=02,02 00000000 00000001
0349EC: 0000080D beq len=8 k=00,00 0000FEB4
0349F4: 00000C13 call len=12 k=00,00 0000000B 0000072D end_coroutine