Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

"System.Reflection.Emit" is not compatible with NativeAOT.

Using C/C++/Rust to do the same task is probably more productive than emitting MSIL opcodes, so that solution wasn't really that practical.

But with these new features being more ergonomic and practical, it becomes cost effective to just do it in C# instead of introducing another language.



Yeah, but nothing of that is the point being discussed, with Native AOT still not available in GUI workloads.

Also P/Invoke and CCW/RCW do have costs cross the runtime layer, even if minor when compared with other languages.


I believe you can avoid most of not all of the P/invoke overhead these days by using unmanaged function pointers and not using the automatic marshalling.


Whenever you use [DllImport], the analyzer will nudge you to auto-fix it to [LibraryImport] which source-generates a marshalling stub (if any is needed) that then calls an inner [DllImport] that does not require runtime marshalling. This is very cheap since function address gets cached into a readonly static which then gets baked into the machine code once the JIT produces Tier-1 compilation for your method.

On NativeAOT, you can instead use "DirectPInvoke" which links against specified binary and relies on system loader just like C/C++ code would. Then, you can also statically link and embed the dependency into your binary (if .lib/.a is available) instead which will turn pinvokes into direct calls (marshalling if applicable and GC frame transition remain, on that read below).

Lastly, it is beneficial to annotate short-lived PInvoke calls with [SuppressGCTransition] which avoids some deoptimizations and GC frame transition calls around interop and makes the calls as cheap as direct calls in C + GC poll (a single usually not-taken branch). With this the cost of interop effectively evaporates which is one of the features that makes .NET as a relatively high-level runtime so good at systems programming.

Unmanaged function pointers have similar overhead, and identical if you apply [SuppressGCTransition] to them in the same way.

* LibraryImport is not needed if pinvoke signature only has primitives, structs that satisfy 'unmanaged' constraint or raw pointers since no marshalling is required for these.


Saving this as I don't remember seeing such succinct explanation of these attributes before :)


I'm not sure I follow. Where are GUI workloads being discussed in the article?

If anything, article doesn't talk about MSIL or CLR, but C# language features. CLR is not the only target C# supports.

NativeAOT is supported in Avalonia (cross-platform UI framework), Razor Slices (dynamically render HTML from Minimal APIs) and I think there is also some support for AOT in MonoGame & FNA (game dev frameworks).

However, it's still early and a lot of the ecosystem doesn't support NativeAOT.


No, neither was Native AOT.

Native AOT depends on CLR infrastructure.




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: