DebuggerVisualizer for DynamicMethod (Show me the IL)
Like emitting IL to MethodBuilder, we first get ILGenerator from a DynamicMethod, and make a series of ILGenerator.Emit calls to emit the IL instructions. If the emit sequence/logic is complicated, we are likely to wanna check the on-the-fly IL content when debugging. (In fact, class DynamicILInfo provides an alternative way to set the IL code for dynamic method.)
It is not straightforward to find out this information and show it. Those instructions are stored in a byte array, so we need an ILReader to parse it; if the ILDasm-style output is preferred, we need to resolve type/field/method back from tokens (DynamicMethod has its own token management mechanism). By the way, Yiru wrote an excellent post "Debugging LCG", where windbg + SOS were used, and !dumpil was called with the DynamicMethod's MethodDesc (which is not available until jit'ting)
What if we want to live with the nice-looking Visual Studio 2005 environment, and still be able to see what has been emitted by far while we are debugging the dynamic method? Peli (our CLR team member and also an active Emit/LCG user) proposed that DebuggerVisualizer is a good solution. If you are interested in DebuggerVisualizer in general, some references can be found at Scott's blog (or msdn: how to write a visualizer)
Introducing my DynamicMethod DebuggerVisualizer... here are some visualizer-in-action pictures:
We can launch the visualizer dialog by clicking the magnifying glass visualizer button, from the local/watch windows or any DynamicMethod variable's data tip.
This is my DynamicMethod DebuggerVisualizer dialog window. The main area shows the IL we emitted so far. "Show bytes" checkbox allows us to specify whether we want to see the raw byte data. The window size/position and other settings are saved in the registry (unfortunately).
It contains two dlls:
- DynamicMethodVisualizer: Just some routine debugger visualizer code here. Since DynamicMethod is not serializable, I have to prepare all necessary info in the debuggee side first, and save them into my MethodBodyInfo class. All IL instructions turn into the string format. No doubt, there are some side-effects on the the debuggee side.
- ILReader: I mentioned a Reflection-based ILReader implementation in my previous post. In addition we need know some DynamicMethod implementation details (you can sleuth it using Reflector or Rotor 2.0 source code in the future): the internal m_ILStream field in class DynamicILGenerateor is used to store IL instructions; another class DynamicScope is to keep track of those used tokens. In order to retrieve the byte array and to resolve those tokens to some meaningful members, reflection APIs (such as FieldInfo.GetValue, PropertyInfo.GetValue etc) are used to explore those internal fields;
LEGAL NOTE: All source code is provided as is, with no warranties intended or implied. Use at your own risk.
Also, the implementation depends on internal DynamicMethod implementation, and does not ensure continuing working in the future. Such approach is not recommended for any production code either.
You may download the source code and binaries here at gotdotnet.com (which also includes a visualizer test program). To let this visualizer help your DynamicMethod debugging, (build &) copy DynamicMethodVisualizer.dll and ILReader.dll to your "My Documents\Visual Studio 2005\Visualizers" folder (or follow this search result).
Any comments are welcome.
Update (December 30, 2005): As Toby and others pointed out below, there was some issue around branch instructions. I fixed it and updated the source code at gotdotnet site. Also this version avoids using registry to keep the application settings.
Update (December 1, 2006): New version can be found here.