Skip to content

WIP: Reproduce game weak data with a PCH - #130

Draft
KakarottoCake wants to merge 2 commits into
doldecomp:mainfrom
KakarottoCake:pch-j3djoint
Draft

WIP: Reproduce game weak data with a PCH#130
KakarottoCake wants to merge 2 commits into
doldecomp:mainfrom
KakarottoCake:pch-j3djoint

Conversation

@KakarottoCake

@KakarottoCake KakarottoCake commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Summary

This reproduces the MWCC precompiled-header behavior responsible for the J3DJoint weak Vec literals appearing in .data in retail game objects.

  • add an SMS PCH modeled on the equivalent zeldaret/tww fix
  • apply it selectively to 40 evidence-backed game translation units through per-object extra_cflags=["-prefix SMS.mch"]
  • keep -opt all,nostrength and -inline deferred centralized in cflags_game
  • leave the other 347 game units, JSystem, and SDK compilation without the PCH
  • replace hand-written Vec/table stand-ins in six completed-enough units
  • quote the generated PCH output path so Windows workspaces containing spaces build correctly
  • restore the retail 0x1C size of TMBindShadowBody
  • retain the small source/layout corrections found during the project sweep

TWW references:

Results

Against current main:

  • build/GMSJ01/mario.dol: OK
  • total matched code: 35.20% -> 35.50% (+10,592 bytes)
  • total matched data: 48.37% -> 50.01% (+10,528 bytes)
  • matched functions: 7,900 -> 7,921 (+21)
  • net matched gain: +21,120 bytes

Additional improvements include:

  • M3DUtil/SampleCtrlNode data: 83.33% -> 100%
  • Player/MarioParticle data: 88.24% -> 100%
  • Enemy/gesso data: 47.74% -> 100%
  • Strategic/liveinterp code: 41.69% -> 72.24%
  • Enemy/namekuri code: 40.30% -> 49.86%
  • Enemy/gatekeeper data: 16.82% -> 99.74%

The project sweep also fixes retail behavior/layout mistakes: Kumokun now initializes mSLAttackHeight instead of overwriting mSLAttackRadius, TCoasterEnemy initializes mPathDir, and TMareWallRock calls awake rather than alive.

Per review, this revision contains no manual volatile stack padding. Stack-related near-matches are intentionally left unmatched for future inline work.

Selective PCH audit

I rebuilt all 387 game units both with and without the PCH and compared every unit against retail. The final selection combines the original 28 data-layout candidates with 12 additional units whose matching results improved in the controlled A/B build. Only these 40 units receive -prefix SMS.mch; all remaining game objects compile without it.

The global experiment was useful for identifying the additional candidates, but is no longer the submitted configuration. This preserves all verified match gains without imposing PCH state on unrelated translation units.

The audit also proved three notable no-PCH cases:

  • MarioUtil/RumbleData: PCH adds 40 bytes absent from retail; no-PCH restores exact data and linked status
  • MarioUtil/gd-reinit-gx: PCH adds 64 bytes of .data and 4 bytes of .sdata absent from retail and breaks exact ReInitTransform
  • Strategic/spcinterp: PCH adds 40 bytes of .data and 4 bytes of .sdata absent from retail and breaks exact TSpcInterp::update

No padding or source fakematch is used for these results.

Known edge case

MapObjInit retains its existing stand-in literals. Its retail object owns TMapObjGeneral's vtable, getFlushTime weak body, and adjusted destructor thunk, while the current decomp does not emit the latter two there. Removing the stand-ins exposes that pre-existing ownership failure. This needs the real ownership/source correction rather than another fakematch.

Validation

  • generated metadata confirms exactly 40/387 game units use -prefix SMS.mch
  • full ninja build and retail DOL checksum
  • regenerated progress and regression reports with no lost verified gains
  • Python syntax and git diff checks
  • no manual volatile padding

@decomp-dev

decomp-dev Bot commented Jul 26, 2026

Copy link
Copy Markdown

Report for GMSJ01 (b1cfdf6 - 6854611)

📈 Matched code: 35.50% (+0.30%, +10592 bytes)
📈 Matched data: 50.01% (+1.64%, +10528 bytes)

✅ 35 new matches
Unit Item Bytes Before After
mario/Player/MarioInit .data +85 85.29% 100.00%
mario/Player/MarioRun .data +49 72.73% 100.00%
mario/System/EmitterViewObj .data +47 82.46% 100.00%
mario/GC2D/Option .data +43 82.76% 100.00%
mario/Enemy/gesso .data +42 98.02% 100.00%
mario/MSound/MSHandle .data +41 94.90% 100.00%
mario/System/RenderModeObj .data +26 75.90% 100.00%
mario/Enemy/gatekeeper .data +21 98.37% 100.00%
mario/Enemy/hinokuri2 .rodata +14 99.32% 100.00%
mario/M3DUtil/M3UJoint .data +12 85.00% 100.00%
mario/M3DUtil/SampleCtrlNode .sdata +8 0.00% 100.00%
mario/Enemy/namekuri .data +8 99.55% 100.00%
mario/Player/MarioParticle .data +7 94.00% 100.00%
mario/Enemy/gatekeeper .rodata +7 99.47% 100.00%
mario/Enemy/hinokuri2 THino2Params::THino2Params(const char*) +3 99.83% 100.00%
mario/Enemy/gesso TGessoSaveLoadParams::TGessoSaveLoadParams(const char*) +2 99.85% 100.00%
mario/Enemy/bgtentacle TBGTentacle::TTentacleParams::TTentacleParams(const char*) +2 99.84% 100.00%
mario/System/EmitterViewObj __sinit_EmitterViewObj_cpp +1 99.67% 100.00%
mario/System/RenderModeObj SMSSetupTitleRenderMode(_GXRenderModeObj*) +1 99.96% 100.00%
mario/Strategic/liveinterp linSetAnmRate(TSpcTypedInterp<TLiveActor>*, unsigned long) +1 99.98% 100.00%
mario/Strategic/liveinterp linSetSRT(TSpcTypedInterp<TLiveActor>*, unsigned long) +1 99.98% 100.00%
mario/Strategic/liveinterp linPushNerve(TSpcTypedInterp<TLiveActor>*, unsigned long) +1 99.98% 100.00%
mario/Enemy/enemyMario TEnemyMario::~TEnemyMario() +1 99.95% 100.00%
mario/Enemy/hinokuri2 THino2MtxCalc::~THino2MtxCalc() +1 99.94% 100.00%
mario/Enemy/hinokuri2 THino2Mask::THino2Mask(THinokuri2*) +1 99.91% 100.00%
mario/Enemy/hinokuri2 THinokuri2::THinokuri2(const char*) +1 99.97% 100.00%
mario/Enemy/hinokuri2 THinokuri2::setLevel(int) +1 99.96% 100.00%
mario/Enemy/namekuri TNameKuriManager::load(JSUMemoryInputStream&) +1 99.85% 100.00%
mario/Enemy/namekuri TDiffusionNameKuriManager::load(JSUMemoryInputStream&) +1 99.85% 100.00%
mario/Enemy/gatekeeper TBiancoGateKeeperManager::initJParticle() +1 99.93% 100.00%

...and 5 more new matches

📈 39 improvements in unmatched items
Unit Item Bytes Before After
mario/Enemy/enemyMario .data +415 81.18% 97.95%
mario/Enemy/bgtentacle .data +106 88.90% 98.58%
mario/Enemy/hinokuri2 .data +101 90.76% 99.01%
mario/Player/MarioDraw .data +89 90.39% 92.33%
mario/Enemy/bosseel .data +41 98.32% 99.66%
mario/Enemy/bossgesso .data +33 94.21% 96.85%
mario/System/RenderModeObj SMSSetupTitleRenderingInfo(JDrama::TDisplay*) +6 97.61% 99.92%
mario/MSound/MSHandle MSHandle::MSACos(float) +6 84.17% 91.22%
mario/Enemy/hinokuri2 .sdata +4 25.00% 50.00%
mario/System/RenderModeObj SMSSetupGameRenderingInfo(JDrama::TDisplay*, bool) +1 99.44% 99.94%
mario/Strategic/liveinterp linGetSRT(TSpcTypedInterp<TLiveActor>*, unsigned long) +1 96.03% 96.06%
mario/Player/Yoshi TYoshi::init(TMario*) +1 99.52% 99.57%
mario/GC2D/Option TOptionSoundUnit::adjustView() +1 99.64% 99.78%
mario/Enemy/enemyMario TEnemyMario::initModel() +1 99.87% 99.91%
mario/Enemy/enemyMario TEnemyMario::initEnemyValues() +1 94.70% 94.72%
mario/Enemy/gatekeeper TBiancoGateKeeper::launchNamekuri() +1 97.36% 97.38%
mario/Enemy/bgtentacle TBGTentacle::TBGTentacle(TBossGesso*, int, int) +1 97.91% 97.94%
mario/Enemy/bgtentacle TBGTentacle::calcAttackGuideAnm() +1 75.77% 75.78%
mario/System/MarNameRefGen_BossEnemy TMarNameRefGen::getNameRef_BossEnemy(const char*) const 0 16.32% 16.33%
mario/Player/MarioDraw TMario::setAnimation(int, float) 0 98.07% 98.09%
mario/Player/MarioDraw TMario::initModel() 0 95.46% 95.46%
mario/Player/MarioRun TMario::moveMain() 0 99.32% 99.33%
mario/Player/Yoshi TYoshi::movement() 0 99.38% 99.38%
mario/Player/MarioInit TMario::initValues() 0 99.94% 99.94%
mario/MoveBG/MapObjSirena TRoulette::initMapObj() 0 99.94% 99.96%
mario/MoveBG/MapObjSirena TDonchou::loadAfter() 0 99.74% 99.82%
mario/MoveBG/MapObjSirena TCloset::moveObject() 0 97.34% 97.35%
mario/Map/MapEventSink TMapEventSinkBianco::finishControl() 0 97.56% 97.59%
mario/Map/MapEventSink TMapEventSinkBianco::loadAfter() 0 56.68% 56.72%
mario/Map/MapEventDolpic TDolpicEventRiccoMammaGate::load(JSUMemoryInputStream&) 0 99.16% 99.19%

...and 9 more improvements in unmatched items

📉 5 regressions in unmatched items
Unit Item Bytes Before After
mario/System/MarNameRefGen_BossEnemy .rodata -15 27.72% 26.84%
mario/Player/MarioDraw .rodata -13 97.98% 97.57%
mario/Enemy/bossgesso .sdata -2 75.00% 50.00%
mario/Enemy/gatekeeper .sdata -1 50.00% 40.00%
mario/Enemy/coasterkiller .sdata -1 50.00% 40.00%

@KakarottoCake KakarottoCake changed the title WIP: Use a PCH for J3DJoint weak data WIP: Reproduce game weak data with a PCH Jul 26, 2026
@KakarottoCake
KakarottoCake force-pushed the pch-j3djoint branch 2 times, most recently from 2002949 to a927788 Compare July 26, 2026 16:01
Comment thread src/Camera/CameraDemo.cpp Outdated
@KakarottoCake
KakarottoCake force-pushed the pch-j3djoint branch 4 times, most recently from 533a056 to f8aa717 Compare July 26, 2026 17:36
@KakarottoCake

Copy link
Copy Markdown
Contributor Author

Follow-up commit a7e5756 centralizes the common game compiler profile in cflags_game: -opt all,nostrength, -inline deferred, and -prefix SMS.mch. The PCH build and the three evidence-backed no-PCH object exceptions retain explicit flag lists; THPPlayer remains on its separate profile. Verified with a full build (mario.dol: OK), ninja baseline/changes_all (no regressions), Python syntax validation, and git diff --check.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants