Deemwar Monads & Abstractions

Run It to Find It

Source: PS2 Web Recomp, by snuri00

A static scan follows the jumps it can read, so it misses code a program reaches through function pointers. ps2-web-recomp fixes this by running the game, writing down what it could not find, and translating again. The same habit belongs in every dead-code report.

16 KiB units of guest code
2 games brought up
3.5 min ISO to page, 8-core laptop

The blind spot

ps2-web-recomp translates PlayStation 2 Emotion Engine machine code ahead of time into C++ and compiles it to WebAssembly. Its recompiler, eerecomp, reads the executable and follows control flow to find functions, emitting C++ in units of 16 KiB of guest code.

A direct call names its target in the instruction. A call through a pointer loads the target from memory at run time. The scanner sees the jump but not where it lands, so that function never gets translated. The README says it plainly: “Static analysis cannot see every function a game reaches through pointers.”

The loop

  1. 1

    Translate

    eerecomp

    Follow control flow from the known entry points and emit C++ for every function found.

  2. 2

    Run headless

    port.sh

    Play the game with no window: press start, then cross every five seconds, with an empty memory card in slot 1, so the run follows a player’s path.

  3. 3

    Any new addresses?

    the run’s log

    Each run writes down the addresses it jumped to but could not find in the translated code (for example 0x0012abc0, an illustrative address).

  4. yes → add them as entry points, back to 1 · stop when a run finds none
  5. 4

    Build

    port.sh

    Build the web page and the native runner. The same runs also record the vector unit microprograms, which get compiled ahead of time too.

Translate, run, collect misses, repeat until a run comes back clean.

Proof it holds

Gran Turismo 4 came first. God of War II followed through the same scripts with only generic changes, and went from ISO to page in three and a half minutes on an 8-core laptop.

Scandirect jumps
Runlog misses
Retranslatenew entries
Clean runno new addresses

The lesson for dead-code reports

Tree-shaking and “unused code” tools are static scans too. They miss callbacks, handler tables, reflection and plugin registries the same way eerecomp misses pointer targets.

SituationLessonRule now
Scanner says a function is never calledIt means no direct call was found, not that nothing calls itLog what a real run called before deleting it
A run calls new codeEach run adds facts the scan could notFeed them back and scan again
A path no run tookThe headless run presses start and cross; it never visits every screenTreat that code as unproven, not dead

Guardrails

See it

The project is snuri00/ps2-web-recomp on GitHub (MIT, by snuri00). Discussion: the Hacker News thread.

Sources: the ps2-web-recomp README (16 KiB units, two games brought up, three and a half minutes on an 8-core laptop, the headless exploring runs).