Cohost feels like a great place to ramble.
A bit of an unnecessary exercise but maybe an interesting one, I think... especially with a system as well understood as the Gameboy. There've been some JIT projects that I think avoid a lot of the static recompilation struggle.
As a thought experiment, the first thing I'd do is naively go from the entry point and adjust the program counter while marking addresses as code. Hitting conditional branches would flag additional regions to scan through, so we'd put the "true" and "false" result PC value in a queue and tag those as 'code' later (or thread it!).
This might, given enough time, provide all the code paths from the entry point, but there's still interrupts, OAM, and possible dynamic code to parse through... the first one is straightforward, but OAM and dynamic code would require us to start doing a bit more analysis (jp [hl] anyone?).
This of course doesn't even consider flagging data... and at some point, if you consider doing static analysis to figure out all the dynamic aspects, you might as well just write a JIT to run through every possible state.
...and if your system doesn't support WX memory and the game needs dynamic code execution (even for just OAM), you might be SOL unless you start doing funky stuff like recording every possible dynamic code bit.
Possible, I think, but at some point it's definitely a little nonsensical. Though maybe feasible if there's a better way to handle dynamic code?