mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-28 06:49:47 -04:00
fix(progress): the #else half of a NON_MATCHING block is LIVE — REAL was undercounting by 7
classify() consumed everything from '#ifdef NON_MATCHING' through '#endif', swallowing the #else half. But banking replaces the #else INCLUDE_ASM with the real body and leaves the old attempt in the dead half — so every function banked that way landed in NO bucket: not real, not a stub, invisible in both numerator and denominator. Measured: CdReadStateMachine, CdReadSectorReadyCB and StreamLoadStateMachine are byte-identical in the shipped build and counted as zero. REAL 873 -> 880, matchable 1911 -> 1918 (seven functions fleet-wide, not the three I first checked). Now consumes only the DEAD half, then decides from the LIVE half: an INCLUDE_ASM there still buckets as NON_MATCHING (accounting unchanged), anything else rewinds and is classified normally. THIRD coverage defect of this exact shape in this one function — the K&R-definition case (~190k instructions erased) and the '#if 0' case are both documented in its own comments, which is what pointed me at it. A scanner that walks preprocessor structure needs a test per branch, not per directive. Found by the S73 documentation audit, which I had written off as producing only doc typos.
This commit is contained in:
@@ -4,21 +4,21 @@
|
||||
# cross-binary collapsible-byte leverage: docs/duplicates.cross.md.
|
||||
|
||||
# THREE progress metrics (all matter — see the labels):
|
||||
FLEET fn-count byte-ident: 362828 / 362952 = 99.97% (REAL+LINKED+empties; FUNCTION-count, ×134-inflated — one crack counts per overlay)
|
||||
FLEET fn-count byte-ident: 362835 / 362959 = 99.97% (REAL+LINKED+empties; FUNCTION-count, ×134-inflated — one crack counts per overlay)
|
||||
FLEET instr-weighted : 13472251 / 13523865 = 99.6% (shipped .text across main + resident + 211 overlays; the decomp.dev-DISPLAY number)
|
||||
FLEET distinct-code(uniq): 5801059 / 5851972 = 99.1% (90847/90929 unique fns; the DISTINCT-RE number)
|
||||
MAIN game-code weighted : 44903 / 79510 = 56.5% (INCLUDED in the fleet numbers above since 2026-07-22 — roadmap §1 metrics contract; LINKED-excluding Ghidra sig dated 2026-08-05; caveat is R34: no independent second oracle for a PS-X EXE, NOT drift)
|
||||
(fleet EXCLUDING main, for continuity with pre-2026-07-22 readings: 13427348 / 13444355 = 99.9%)
|
||||
|
||||
FLEET REAL substantive : 360658 (of which dedup-shared 255632 via 2220 groups / 255708 instances)
|
||||
FLEET REAL substantive : 360665 (of which dedup-shared 255632 via 2220 groups / 255708 instances)
|
||||
FLEET LINKED PsyQ objs : 959
|
||||
FLEET NON_MATCHING : 0 (0 in any default build — G4)
|
||||
FLEET INCLUDE_ASM stubs : 124
|
||||
FLEET matchable : 362952
|
||||
FLEET matchable : 362959
|
||||
|
||||
| binary | REAL | shared | LINKED | byte-ident | matchable | byte-ident % |
|
||||
|---|---:|---:|---:|---:|---:|---:|
|
||||
| main | 873 | 2 | 959 | 1875 | 1911 | 98.1% |
|
||||
| main | 880 | 2 | 959 | 1882 | 1918 | 98.1% |
|
||||
| resident | 138 | 0 | 0 | 140 | 145 | 96.6% |
|
||||
| md_MAIN_001 | 11 | 0 | 0 | 11 | 11 | 100.0% |
|
||||
| md_MAIN_003 | 43 | 0 | 0 | 43 | 47 | 91.5% |
|
||||
|
||||
+5
-5
File diff suppressed because one or more lines are too long
+29
-6
@@ -595,12 +595,35 @@ def classify():
|
||||
while i < n:
|
||||
s = lines[i].strip()
|
||||
if s.startswith('#ifdef NON_MATCHING'):
|
||||
blk = []
|
||||
while i < n and not lines[i].strip().startswith('#endif'):
|
||||
blk.append(lines[i]); i += 1
|
||||
i += 1
|
||||
m = re.search(r'INCLUDE_ASM\("[^"]+",\s*(\w+)\)', '\n'.join(blk))
|
||||
if m: nonmatching.append(m.group(1))
|
||||
# THE `#else` HALF IS LIVE CODE, AND SWALLOWING IT UNDERCOUNTS REAL (P31 S73).
|
||||
# The old form consumed from `#ifdef NON_MATCHING` all the way to `#endif`, so a
|
||||
# function BANKED into the `#else` branch landed in NO bucket at all — not real,
|
||||
# not a stub, invisible, exactly like the K&R and `#if 0` defects documented below
|
||||
# and above. Measured: CdReadStateMachine, CdReadSectorReadyCB and
|
||||
# StreamLoadStateMachine were all byte-identical in the shipped build and counted
|
||||
# as zero, because banking replaces the `#else` INCLUDE_ASM with the real body and
|
||||
# leaves the old attempt in the dead half.
|
||||
# So: consume only the DEAD half, then decide from the LIVE half. If it still holds
|
||||
# an INCLUDE_ASM the function is a NON_MATCHING stub (unchanged accounting); if it
|
||||
# holds anything else, rewind and let the normal scan classify it.
|
||||
dead = []
|
||||
while i < n and not lines[i].strip().startswith(('#else', '#endif')):
|
||||
dead.append(lines[i]); i += 1
|
||||
had_else = i < n and lines[i].strip().startswith('#else')
|
||||
i += 1 # step over the `#else` / `#endif`
|
||||
live_start = i
|
||||
live = []
|
||||
if had_else:
|
||||
while i < n and not lines[i].strip().startswith('#endif'):
|
||||
live.append(lines[i]); i += 1
|
||||
i += 1 # step over the `#endif`
|
||||
m = re.search(r'INCLUDE_ASM\("[^"]+",\s*(\w+)\)', '\n'.join(dead + live))
|
||||
if m and (not had_else or re.search(r'INCLUDE_ASM\("[^"]+",\s*(\w+)\)',
|
||||
'\n'.join(live))):
|
||||
nonmatching.append(m.group(1)) # still a stub: accounting unchanged
|
||||
continue
|
||||
if had_else and live:
|
||||
i = live_start # a banked body: classify it normally
|
||||
continue
|
||||
# `#if 0` — DEAD CODE, not a match (Phase-28 T5). The scanner knew `#ifdef NON_MATCHING`
|
||||
# but not this, so a `#if 0`-preserved analysis body was read as a live definition AND its
|
||||
|
||||
Reference in New Issue
Block a user