Skip to content

better user experience working with decompilation of huge functions (not just a "faster decompiler" request) #5730

@slippycheeze

Description

@slippycheeze

Is your feature request related to a problem? Please describe.
The LoadFromDatabase function for the class I'm working on right now is, I grant you, a truely horrible function. Huge amounts of what should probably be table driven logic to extract data into fields in the 220kb class that calls it.

The decompiler takes around 2:30 to 3:00 to get through it, though, on my 4.9GHz peak, i9-11900K @ 3.50GHz, with 64GB of memory total to play around with. No shortage of resources, and no competition for the CPU at the time. (though the basics of why this is so slow /are/ obvious to me; I'm not here for raw decompiler performance.)

The main reason this function is valuable to me is that it gives human names and semantics to a whole lot of fields in the class. I can tell the field at offset 0xFC8 is a std::string based on how it is handled by the code, but I can tell it means "the name of the sound to play when a formula is learned" based on assigning it from the database value "learnFormulaSoundName".

Right now, saving a change to that field (name, or DataType) means waiting 150 seconds for the decompiler to catch up, as does changing the name or parameter types of a function it calls.

Even batching multiple changes by working in the structure editor rather than using l or C-l to prompt to rename / retype is imperfect: it is annoyingly easy to "off by one" a field name, and not discover that until I commit the changes,

Describe the solution you'd like
The main reason this is so painful is that every change triggers the decompiler to start work on the function again, even when it is "clearly" only cosmetic. While that happens, all other decompiler actions are blocked, so the decomp window is effectively non-interactable, even for changes that are safe to do in parallel (like assign field names and types) because they automatically restart the decomp process.

I'd love it if:

  1. the decompiler "knew" that setting a field name on a type didn't change the decomp output meaningfully, or
  2. there was a way to set the decompiler to "manual refresh only, ignore everything I do until then", or
  3. decompiler actions were still possible in the previous decomp output which it worked on a refresh, and additional changes simply restarted the background recalculation process.

all those boil down to owning that decompilation of 29k of x64 instructions is never going to be fast, and aiming to make it possible to work while the long, slow background process carries on.1

Describe alternatives you've considered
I've found some ways to continue working, either by doing things in a way that batches changes (name and type fields in the structure editor, and do not hit save), or whatever, but at the end of the day there isn't much that can be done.

The one "alternative approach" I can imagine is something that somehow magically made assignments to structure fields "better" visible in the disassembly Listing window. If I could more readily identify that R14 + 0x11d8 mapped to this->offset_0x11d8 in the listing, it'd make working there much easier.

The main challenge I have with that approach, right now, is that the "dynamic content" of a register like R14 is not very visible to a human in anything but the simplest code. :)

The other "alternative approach" I just thought of was the ability to right-click something (eg: FUN_1803dba0) which is called from the LoadFromDatabaase function, and effectively "decompile in a new tab" so that I could let LoadFromDatabase re-de-compile in the background while I worked on something in parallel.

Additional context
decompiler debug XML from the function; I think it provides everything required to reproduce the performance, if y'all feel the need to do that for yourselves. it isn't a very exciting function, though. I attach it more out of a sort of sense of obligation than anything else. :)

decompiler-performance-LoadFromDatabase.zip

Footnotes

  1. I'm certain decompilation can be faster, the task subdivided, or a "smart enough" decompiler could avoid redoing large parts of the work, but honestly? no matter how fast it is, some developer is going to build a worse function than this one to produce the same pain.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions