防止方法上的 JIT 内联
我的情况比较特殊。我一直在开发一个用于发送电子邮件的开源库。在这个库中,我需要一种可靠的方法来获取调用方法。我通过分析 StackTrace 内部的 StackFrame 对象来完成此操作。这在关闭优化的调试模式项目中没有问题。
当我切换到打开优化的发布模式时,就会出现问题。堆栈跟踪如下所示:
> FindActionName at offset 66 in file:line:column <filename unknown>:0:0
> Email at offset 296 in file:line:column <filename unknown>:0:0
> CallingEmailFromRealControllerShouldFindMailersActionName at offset 184
in file:line:column <filename unknown>:0:0
> _InvokeMethodFast at offset 0 in file:line:column <filename unknown>:0:0
> InvokeMethodFast at offset 152 in file:line:column <filename unknown>:0:0
...
这是从失败的单元测试中获取的。在此跟踪的第 3 行中,我应该看到一个名为 TestEmail
的方法,该方法是在其他地方定义的,但我相信 JITter 正在内联它。我读过,您可以通过将方法设为虚拟来防止内联,但这不起作用。有谁知道防止方法内联的可靠方法,以便您的方法将显示在堆栈跟踪中?
I've got sort of a unique situation. I've been working on an open source library for sending email. In this library, I need a reliable way to get the calling method. I've done this with a StackTrace
by analyzing the StackFrame
objects inside it. This works without issue in a debug-mode project where optimizations are turned off.
The problem occurs when I switch to release mode where optimizations are turned on. The stack trace looks like this:
> FindActionName at offset 66 in file:line:column <filename unknown>:0:0
> Email at offset 296 in file:line:column <filename unknown>:0:0
> CallingEmailFromRealControllerShouldFindMailersActionName at offset 184
in file:line:column <filename unknown>:0:0
> _InvokeMethodFast at offset 0 in file:line:column <filename unknown>:0:0
> InvokeMethodFast at offset 152 in file:line:column <filename unknown>:0:0
...
This is taken from a failing unit test. In line 3 of this trace, I should see a method called TestEmail
which is defined elsewhere, but I believe the JITter is inlining it. I've read that you can prevent inlining by making a method virtual, but this doesn't work. Does anyone know of a reliable method for preventing method inlining so your method will show up in a stack trace?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可以使用
MethodImplAttribute
并指定MethodImplOptions.NoInlined
。请注意,这仍然不能保证您可以获得源代码中所示的实际调用方法。您的方法不会被内联,但您的方法的调用者可以内联到它自己的调用者中,等等。
You could use
MethodImplAttribute
and specifyMethodImplOptions.NoInlining
.Note that this still doesn't guarantee that you can get at the actual calling method as seen in the source code. Your method won't be inlined, but your method's caller could be inlined into its own caller, etc etc.
您可以使用标有
System.Runtime 的其他参数.CompilerServices.CallerMemberNameAttribute
及其同级CallerFilePath
和CallerLineNumber
。如果我理解正确的话,这应该会给你正确的方法名称,无论什么是内联的,什么不是。然而,您只会获得方法名称,我看不到任何获得类名称/程序集等的内容。这应该不言而喻,但只是为了确定......这样的事情不应该不在日志记录/诊断之外使用。
执行此操作的正确方法可能是:
Thread.ExecutionContext
在调用该函数时,我意识到这可能对 Scott 没有任何帮助,但也许对其他人有帮助可以从中受益。
You could use additional parameters marked with
System.Runtime.CompilerServices.CallerMemberNameAttribute
and it's siblingsCallerFilePath
andCallerLineNumber
. If I understand it correctly this should get you the correct method name, no matter what's inlined an what's not. You will only get the method name however, I don't see anything to get the class name/assembly etc.It should go without saying, but just to be sure... something like this should not be used outside of logging/diagnostics.
Proper ways to do this would probably be:
Thread.ExecutionContext
while calling the functionI realize that this probably won't be of any help to Scott after all this time, but maybe someone else can benefit from it.