2

A method could get inlined; there is an attribute to prevent that ("there's an att for that"). However, apparently a method may also not get its own stack frame on x64 due to tail-call optimization by the JITter (http://www.hanselman.com/blog/ReleaseISNOTDebug64bitOptimizationsAndCMethodInliningInReleaseBuildCallStacks.aspx). Would this affect the behavior of MethodBase.GetCurrentMethod?

The discussions that I can find are mostly about inlining (When is a method eligible to be inlined by the CLR?). While those discussions are interesting in their own right, my problem is really about under what circumstances -- if any -- that MethodBase.GetCurrentMethod can be relied upon to identify the same method where the programmer placed the call (e.g., for late binding to a method for which the current method is really a surrogate). Inlining is a way that MethodBase.GetCurrentMethod could be fooled, but I wonder if it is the only way?

Community
  • 1
  • 1
  • That's not what tail-call optimization does, it simply rewrites a recursive call to a for loop. A method *always* has a stack frame, required for code security and exceptions. When a method gets inlined then you'll simply get the name of the caller method. Beware that GetCurrentMethod is very expensive and can't hold a candle to simply writing the method name in your code. Which in itself also solves the inlining problem. – Hans Passant Jan 17 '12 at 22:51
  • @Hans, here's what I found about tail-call optimization on x64: [link](http://www.hanselman.com/blog/ReleaseISNOTDebug64bitOptimizationsAndCMethodInliningInReleaseBuildCallStacks.aspx). Your comment may stand, but in that example we are not looking at recursion. In my late binding scenario, the surrogate constructs and caches a dynamic delegate so that subsequent calls to the surrogate do not need to reflect again. Thus performance is not a primary consideration; rather reliability is (embedding the method name in the code is vulnerable to reliability problems if the method is renamed). – Will Montgomery Jan 17 '12 at 23:06
  • It just occurred to me: I don't need `GetCurrentMethod` (unreliable), nor to embed the method name in the code as a string (which wouldn't automatically deal with typos or renames). Instead, I can embed an expression that invokes the method. For some time now I have been doing this for property references; I don't know why it took me so long to think of applying the same technique to methods. – Will Montgomery Jan 19 '12 at 15:55

1 Answers1

2

No - a method is either inlined at run time or it isn't.

It can be fooled, I believe, if somebody were to implement their own runtime - as MethodBase.GetCurrentMethod ultimately boils down to this, declared in RuntimeMethodHandle:

[SecurityCritical]
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern IRuntimeMethodInfo 
  _GetCurrentMethod(ref StackCrawlMark stackMark);

In a custom runtime, that could do anything - and in the future it could also do anything too. At the moment, I believe the only way that the Microsoft runtime(s) will not return the correct method is if the code is inlined; can't speak for Mono, for example. Relying on that always to be the case, however, is like relying on a reflected private field of an internal type always to be present to enable a piece of code to work, I think.

In nearly every case where I have tried (I no longer worry about it now) or someone tries to justify needing to be able to reliably identify the calling method, outside of profiling, the issue of inlined methods always comes up.

The reality is, though, how important is it to worry about those methods?

If reliability is absolutely crucial, you will get more luck Using an IL-rewriter post compilation to inject the logging calls; this can be necessarily method-aware and therefore can subvert the inlining, even if it takes place (which it might not if the rewritten IL becomes bulky enough, thus hurting performance). Or if you don't fancy rolling your own, an AOP library might be in order - such as PostSharp.

Andras Zoltan
  • 41,961
  • 13
  • 104
  • 160
  • My question isn't really about inlining. Inlining is just one way that I know of that `MethodBase.GetCurrentMethod` can be fooled. My question is: are there other ways that `MethodBase.GetCurrentMethod` can be fooled (i.e., identify a method different from the one where the programmer put the call). – Will Montgomery Jan 17 '12 at 23:39
  • Okay well it's possible for JIT inlining not to be the only way - as my updated answer shows, at the moment it's *probable* that the MS runtime could only fool it by inlining, but as for the future, and other runtimes, who knows. Best not to rely on any specific behaviour. And actually - given your definition - then any IL rewriter could achieve this behaviour - if you're talking about a different between where the developer put the call and where it actually ends up. – Andras Zoltan Jan 17 '12 at 23:50