Files
Cesarus85--mjolnir-vr/docs/object_matching_logs/props_obj.md
T

8.6 KiB

source/ai/props.obj strategy ledger

Last validated against build/split/source/ai/props.obj with the normal XDK 3911 build. Baseline closeout was 6a1e60ae9; exact-helper checkpoint was 8cd09ac34. This ledger records strict COFF results only. No result below uses inline assembly, byte patches, volatile scheduling anchors, or compiler flag changes.

Current inventory

  • Code: 9/17 strict exact.
  • Target-owned non-code: 13/13 strict exact.
  • Protected exact code: _props_initialize, _props_dispose, _props_initialize_for_new_map, _props_dispose_from_old_map, _prop_iterator_new, _prop_iterator_next, _code_00052e30, _prop_orphan_update_information, and _prop_delete.
  • _code_00052e30: 0xE0/0xE0, 6/6 exact relocations, normalized SHA-256 c99acd468ec22ffc06c4bc8833aca8bc5eefb18a362eab04043e9cad87134c16.

Accepted source controls

Function Source control Strict result
_code_00052e30 Use vector_from_points3d; capture identifier first, then owner/next/parent; restore owner/next/identifier/parent Strict exact.
_prop_get_active_by_unit_index Explicit swarm fallback plus an infinite traversal with an early next-index capture and guard exits 0x90/0x90, 5/5 relocation identities; four relocation addresses exact. Remaining difference is an ECX/EDX mirror and a one-byte _prop_data relocation drift.
_prop_new_unacknowledged Keep separate next_prop_index and prop_index, assign current from next, and test next_prop_index at the header Reduced candidate from 0x230 to target-exact padded size 0x220; kept 21/21 relocation identities and recovered January's EDI next / EBX current roles.
_prop_new_unacknowledged Nested allocation selection with an explicit initialize_prop join Moved datum_new ahead of the reuse block to the target family and retained 0x220/0x220, 21/21. Current candidate hash is 681249dad8d4...; target is 4e1ed0d47f97....
_prop_new_unacknowledged Store chosen prop index before its distance in both scan arms Recovered the target's local store order without changing exact size or relocation count.
Object ownership Keep prop_data declared only through the extern in props.h The target props.obj carries _prop_data as an undefined external (section=0, value=0). Removing the local = NULL definition eliminated an incorrect 4-byte .bss section and reproduced the target symbol exactly without changing the 9/17 strict function result. The storage is supplied by the campaign's linker_common.obj.

Measured and reverted experiments

Function/family Experiment Result / first divergence Decision
_prop_get_active_by_unit_index Natural one-variable while/for traversal Bottom-tested update and direct ESI loop index diverged before the target loop header. Reverted.
_prop_get_active_by_unit_index Combined predicate inside the infinite loop 0xA0 padding and three relocation-address regressions. Reverted; do not repeat.
_prop_get_active_by_unit_index Declaration swaps and prop_get(next_prop_index) spelling No binary change. Reverted; do not repeat.
_code_00052e30 Three component subtractions 0xE0, 6/6 identities, but x87 work was hoisted across preservation restores. Reverted.
_code_000527e0 cluster register on the third formal No private-ABI change. Reverted; do not repeat.
_code_000527e0 cluster Local alias for unit_index No private-ABI or COFF change. Reverted; do not repeat.
_prop_new_unacknowledged Declaration-order swaps No prologue or ABI change. Reverted; do not repeat alone.
_prop_new_unacknowledged Declaration initializers versus separate initialization statements Same prologue: actor index loaded before _actor_data; later allocation/reuse scheduling changed but did not close. Reverted to the cleaner accepted form.
_prop_new_unacknowledged Put actor_get declaration first Actor call moved before local initialization, candidate grew to 0x230. Reverted.
_prop_new_unacknowledged Comma-expression initializers inside actor_get Moved NONE stores after float stores and worsened the prologue. Reverted.
_prop_new_unacknowledged Branch-specific goto scan_next_prop exits VC7 still tail-folded all exits into the bottom-tested loop; no relocation improvement. Reverted.
_prop_new_unacknowledged Cast the required threshold to short Recovered the target word compare, but moved allocation/reuse relocations three bytes farther from target. Reverted.
_prop_new_unacknowledged Redundant post-selection test and explicit allocation label Compiler moved datum_new back behind the reuse block. Reverted.
_code_000527e0 cluster Reverse the player/non-player source arms and add an explicit common-tail goto VC7 still tail-duplicated the two link stores; return count stayed 3 rather than target 2. Reverted.
_code_000527e0 cluster Hoist the actor pointer declaration to function scope No code-generation change; return count stayed 3. Reverted.
_code_000527e0 cluster Early boolean has_unit = unit_index != NONE Removed the R5 3-return/2-return mismatch and triggered a two-stack-argument private convention, but VC7 promoted actor_index in EAX, not January's unit_index. Frame grew to 0x0C; helper relocs began 31,38,... versus target 22,29,.... _prop_orphan_from_friend happened to recover all relocation addresses, while _code_00052a40, transition, and prop_new regressed. Reverted; useful only as proof that an early parameter-use anchor controls the caller cluster.
_code_000527e0 cluster Combine has_unit with a unit alias Same wrong promoted parameter and frame. Reverted.
_code_000527e0 cluster Reorder private formals to unit/actor/prop and reorder all calls Optimizer still promoted semantic actor_index; no target ABI. Reverted; formal order alone is not the lever.

Current bounded residuals and park criteria

Function/family Current strict state Evidence-backed blocker Reopen when
_code_000527e0, _code_00052a40, _prop_orphan_transition, _prop_orphan_from_friend Helper 0x260/0x260, 25/25 identities; callers have exact padded sizes/counts January promotes unit_index in EAX, spills actor, and has two returns. Candidate uses a stack third parameter, keeps actor in EBX, tail-duplicates the link stores, and has three returns. Early-use testing proves the convention is interprocedurally controllable, but the only found anchor promotes the wrong semantic parameter and adds a stack boolean. A non-volatile, source-faithful use/lifetime shape that makes VC7 promote unit_index without adding code or changing the target-owned ABI.
_prop_new_unacknowledged 0x220/0x220, 21/21 identities; candidate relocations 11,51,74,81,210,353,359,375,382,409,414,419,425,447,452,457,463,477,484,500,520 versus target 8,51,77,84,205,362,368,384,391,418,423,428,434,456,461,466,472,486,493,509,528 First divergence is prologue scheduling: target loads _actor_data at 6, initializes two NONE locals with EAX, then loads actor index and inserts an alignment NOP. Candidate loads actor index first and initializes the locals through ESI. Loop rotation then folds all backedges to a bottom test. A typed actor_get source/lifetime shape that recovers the target prologue without raw datum_get, volatile, or assembly; or the correct helper ABI changes caller allocation enough to close it.
_prop_get_active_by_unit_index 0x90/0x90, 5/5 identities Only ECX/EDX mirror around prop_get; _prop_data relocation is +1 while the call is exact. A source-faithful register-lifetime distinction, not another predicate/declaration spelling.
_prop_get_base_by_unit_index 0x190/0x180, 15/15 identities Target frame 0x4C; candidate 0x44. Ordered calls agree, but the target retains a longer scratch/register lifetime. Layout evidence for the additional 8-byte lifetime or a newly identified typed scratch object.

The object remains parked at 9/17 exact until one of these explicit reopen conditions is available. The exact siblings and all target-owned non-code sections are invariants for every future experiment.

Two select-any string COMDATs ("prop" and "prop->orphan_prop_index == NONE") remain locally emitted while the split target records them as undefined external symbols owned elsewhere. They are recorded as csplit COMDAT-attribution differences, not target-owned data mismatches. The former local _prop_data BSS mismatch was not COMDAT noise and has been corrected as described above.