The VES provides the ability to both debug (observe and modify the behavior) and profile (measure resource utilization) of running programs. It does this by providing three underlying services, described in detail in the Debugging Specifications and the Profiling Specification:
If the source language compiler produces IL as its output, both of these maps must be recomputed based on the conversion of IL to native code. As with traditional compilation, the optimizations performed by a JIT compiler make it impossible to guarantee that the maps are maintained with 100% accuracy. For example, the JIT compiler may merge IL code sequences together so that a single native address corresponds to more than one source reference. It may also merge local variables with independent life times into a single stack frame slot (or, worse, split a variable so that it resides simultaneously in a register and on the stack).
The interface between the EE and the JIT compiler includes a mechanism for updating these maps. This can be used either to produce new maps that are persisted (for example, when a new PE file is created) or simply reported back to the VES-supplied debugging and profiling system (when JITting to memory for immediate execution).
Without modifying the code, the API provides tools information about:
By requesting modification of the executing code, the profiling tool can also obtain information about the dynamic context (chain of stack frames, executing thread, etc.) at entry or exit from a method or function.
Delegates
The VES provides the implementation for a set of types known as delegates. Delegates are the object-oriented equivalent of function pointers. Unlike function pointers, delegates are object-oriented, type-safe, and secure. Delegates are created by defining a class that derives from the base type System.Delegate. Each particular type of delegate provides a method named Invoke with appropriate parameters, and each instance of a delegate forwards calls to its Invoke method to a compatible static or instance method on a particular object. The object and method to which it delegates are chosen when the delegate instance is created.
In addition to an instance constructor and an Invoke method, delegates may optionally have two additional methods: BeginInvoke and EndInvoke. These are used for asynchronous calls and are described in a separate specification.
While, for the most part, delegates appear to be simply another kind of user defined class, they are tightly controlled. The implementations of the methods are provided by the VES, not user code. Also, the user can specify no additional members; the definition of a delegate is really no more than the signature of the method to which it forwards its calls.