Inspection / interception of IL generated by LambdaCompiler #18447
Labels
area-System.Linq.Expressions
help wanted
[up-for-grabs] Good issue for external contributors
test-enhancement
Improvements of test source code
Milestone
IL generated by
LambdaCompiler
andILGen
turns out to be quite tricky to inspect. On desktop CLR, I used to emit IL to an assembly usingCompileToMethod
for offline inspection, or use SOS to!dumpil
. While the latter still works, it's not an option at runtime, e.g. for testing purposes. In particular, when testing code emit optimizations, we don't have a good option to assert the output.One option is to perform private reflection on
DynamicMethod
to obtain thebyte[] m_iLStream
and use one of the decoders to print it as textual IL. Some code is around to do that on the MSDN blogs, so it's one option worth looking into. In fact, I've been using this over at https://github.com/bartdesmet/ExpressionFutures and it works ok-ish. There are some issues with visualizing some metadata tokens but it may be possible to work around that. It may suffice for testing purposes.An alternative which I've put in place in my https://github.com/bartdesmet/corefx/tree/CheaperClosures branch is an indirection of
ILGenerator
calls through an interface, currently only when a conditional compilation symbol is set. Unfortunately, one can't derive fromILGenerator
because it only hasinternal
constructors (and one of itsEmit
overloads is notvirtual
either), so an additional interface has to be put in place. My implementation logs all the calls made, so aToString
can be obtained.Note that the last option offers some benefits because one could implement e.g. an optimizing back-end by capturing the emitted instructions and run a post-process step on it (assuming we add one additional method call to "bake" the emitted IL, which could flush to the underlying emitter target after running post-process steps):
An interceptor for logging would implement
IILGenerator
and get passed anIILGenerator
that's the target to emit to. ItsBake
method can simply forward to the underlying generator; every other method forwards and logs to populate data structures that allow for pretty printing.An optimizer would implement
IILGenerator
but won't forward theEmit
methods directly; it'd build up internal data structures that are used upon a call toBake
to run optimizations prior to makingEmit
calls to the underlying generator, followed by aBake
call.Of course, this would add a level of indirection with virtual calls, unless
ILGenerator
would implement such an interface (and make theEmit(OpCode, sbyte)
overloadvirtual
) so there's no additional cost if no wrapper is installed around theILGenerator
obtained fromDynamicMethod
. See https://github.com/dotnet/corefx/issues/11454 for a case where such a back-end could provide value.I got the last thing implemented (including an inspector and a basic optimizer) in an offline copy here in Bing, which is based on a fork of the expression API a few years back. I'll to port it to CoreFX as a proof of concept so the merits can be debated with some concrete piece of code to back it up.
The text was updated successfully, but these errors were encountered: