FatalExecutionEngineError. Other times the code executed without a problem. It was difficult to establish any pattern in these failures. windbg+SoS revealed nothing beyond the fact that the IL was being generated correctly, and excavations of RedBits/Rotor code did not help much either. I went over the whole mess in my mind while listening to a jazz performance, and realized that the flaw was in my delegate-creation IL code, which went like this:
push target object
newobj Procedure..ctor(object, native int)
store new delegate
This code creates a working delegate, but the delegate's internal
_methodBasefield is initially null. The bald function pointer does not work as a GC reference, and if there are no other references to the dynamic method, it is liable to be garbage-collected, and the delegate containing the stale function pointer naturally but silently becomes a nest of nasal demons.
Delegate.CreateDelegateoverloads don't fill
DynamicMethod.CreateDelegatedoes fill it explicitly, but it is impossible to get the
DynamicMethodobject from its token without calling mscorlib's internal methods. I understand the security reasons behind this decision, but it's damned uncomfortable.
The only solution to the problem I have found so far is to call the new delegate's
get_Method()function to fill
_methodBaseand establish a GC-visible reference to the dynamic method. Whew!
Update: reported this issue to Microsoft; they decided to close it as a 'known limitation'. Well, it is known — now :3