Share via


Having debugger-friendly codegen

One of the things I like about C# anonymous delegates is that the codegen is clever enough that they're reasonably debuggable without any additional debugger support. This type of debugger-friendly codegen is a key part in making your 3rd-party language debuggable by existing debuggers.

Consider the following C# code:

using System;

class Foo
{
delegate int SomeDelegate(int x, int y);
static void Main(string[] args)
{
SomeDelegate del = delegate(int x, int y)
{
return x+y;
};
Console.WriteLine(del(4,5));
}
}

We can set a breakpoint and stop in the anonymous delegate without any additional debugger support.  And we still get a reasonable callstack and locals. In this case, we can see that the name of the anonymous delegate is 'Foo.<Main>b__0'.  Here are the results in Mdbg, which doesn't know anything about anonymous delegates:

run t.exe
STOP: Breakpoint Hit
7: {
[p#:0, t#:0] mdbg> b 10
Breakpoint #1 bound (line 10 in t.cs)
[p#:0, t#:0] mdbg> g
STOP: Breakpoint 1 Hit
10: return x+y;
[p#:0, t#:0] mdbg> w
Thread [#:0]
*0. Foo.<Main>b__0 (t.cs:10)
1. Foo.Main (t.cs:12)
[p#:0, t#:0] mdbg> sh 5
5 delegate int SomeDelegate(int x, int y);
6 static void Main(string[] args)
7 {
8 SomeDelegate del = delegate(int x, int y)
9 {
10:* return x+y;
11 };
12 Console.WriteLine(del(4,5));
13 }
[p#:0, t#:0] mdbg> p
CS$1$0000=0
x=4
y=5

[p#:0, t#:0] mdbg>

It looks like VS has some extra sugar to convert the name into "AnonymousMethod".

Note that the sequence points that map from IL to source are very flexible and allow any IL offset to be mapped to any file and line number. So it's no problem that the source range for function Foo.Main actually overlaps the source range for the anonymous method. In other words, the PDB can express the fact that the lexical scope for Main() is a superset of the lexical scope for the anonymous method.