runtime: Enable inlining P/Invokes in exception clauses

To fully complete #69758, we need to enable P/Invoke inlining in more places to ensure we generate zero IL stubs on startup for many target scenarios. Today, we don’t inline P/Invokes for a few cases:

  • P/Invoke in a try block
  • P/Invoke in a catch clause
  • P/Invoke in a filter clause
  • P/Invoke in a finally clause
  • P/Invoke in a cold (rarely executed) block

To get to zero managed->native IL stubs with a Hello World program where we use dotnet trace collect to track P/Invoke stub generation, we need to enable inlining P/Invokes in try blocks and finally clauses. We’ll likely want to also enable inlining P/Invoke stubs into catch and filter clauses for more complex scenarios. We don’t want to enable inlining P/Invokes in cold blocks as that has caused major perf regressions in the past.

This work will require both exception handling work to enable correctly handling exception interop on Windows (particularly handling unwinding exactly to the method that has the InlinedCallFrame), as well as some simple JIT work to remove blocking the inlining of these IL stubs.

cc: @dotnet/interop-contrib

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Reactions: 2
  • Comments: 18 (18 by maintainers)

Most upvoted comments

Sounds good.

The parity with built-in interop is interesting for throughput perf. If the source-generated interop has try/finally, it will get an extra frame at runtime that is not free. We may not be seeing it in our micro-benchmarks, but somebody will notice sooner or later.

I do not think we want to force the blittable stubs to be always inlineable by fixing all limitations you have listed. It is not profitable for cold code (catch blocks, filter blocks, cold based on profile data). That leaves try clauses associated with finally that should just work, and finally clauses where the PInvoke inlining is complicated.