MichalStrehovsky / iltrim

MIT License
9 stars 1 forks source link

Optimization to remove unused method bodies #54

Closed MichalStrehovsky closed 2 years ago

MichalStrehovsky commented 2 years ago

Recommended to look at #42 to understand how conditional dependencies work.

If we have:

class Foo
{
    public void DoSomethingExpensive() => new ExpensiveClass().OtherStuff();
}

and then:

Foo f = null;

// ...

if (f != null)
    f.DoSomethingExpensive();

We'll pull ExpensiveClass into the dependency graph even though it can practically be never reached (Foo was never allocated and the instance method is not actually reachable). It would be nice to do something about it.

We cannot remove the call to the method easily, but we're able to remove the method body.

We already know when a type was allocated thanks to #42 and the ConstructedTypeNode.

MethodDefinition currently unconditionally depends on the method body. For instance methods on reference types (the type system can be used to answer those two questions), we should make the dependency conditional on a ConstructedTypeNode being present in the graph.

When we're in the the writing phase of the MethodDefinition, grab the method body node, and find out if it's Marked property is false. If the body wasn't marked, instead of int rva = bodyNode.Write(writeContext);, we should ask the writing context what the RVA of a throwing method is - writing context should generate a method body whose only instructions are ldnull/throw, remember the RVA, and return that - this will be a new API on writing context.