没有*。当 F# 为程序发出 IL 时,对 condition 的所有访问都是通过属性访问器完成的。由于这个额外的间接层,JIT 引擎无法优化掉reliesOnCondition 的整个主体。
让我展示一下我是如何发现这一点的。 (也在old blog 帖子中列出。)
创建新的 F# 项目“SOQ”
构建我们的 F# 应用程序。我只是将条件硬编码为false。
module Program
let condition = false
let inline reliesOnCondition (x:int) =
if condition then
printfn "%i" x
[<EntryPoint>]
let main args =
printfn "(attach a debugger and press any key)"
System.Console.ReadKey(true) |> ignore
reliesOnCondition System.DateTime.Now.Second
0
反汇编它并用 PDB 中的 IL 操作码重新组装它
接下来使用ildasm 使用/SOURCE 参数反汇编IL 二进制文件。这不仅会为您提供源代码的 IL 转储,还包括作为 cmets 保留的原始源代码。
ildasm SOQ.exe /OUT=SOQ-annotated.exe.il /SOURCE
从 IL 重新组装我们的二进制文件
接下来使用ilasm 重新组装IL 二进制文件,但传入/DEBUG 标志以获得PDB。生成的应用程序将具有 两个 级别的代码。首先,原始的F#将作为cmets保留,实际代码将是IL指令。
ilasm SOQ-annotated.exe.il /DEBUG
运行进程并附加 Visual Studio 调试器
运行新注释的程序。这将导致应用程序像往常一样进行 JIT-ted。接下来,将 Visual Studio 调试器附加到活动进程。
单步调试代码
在 VS 调试器中查看 IL 转储是不够的。右键单击“堆栈跟踪”窗口并检查 Go To Disassembly。这将为您显示实际的 x86 指令。
这里是 x86 操作码转储。请注意顶部的原始 F# 源代码行 (ildasm /SOURCE)、其下方的 IL 指令 (ilasm /DEBUG) 以及下方的 x86 指令(由 Visual Studio 提供)。
//000014: reliesOnCondition System.DateTime.Now.Second
IL_0026: call valuetype [mscorlib]System.DateTime [mscorlib]System.DateTime::get_Now()
000000db lea ecx,[ebp-58h]
000000de call 595E8C00
IL_002b: stloc.3
000000e3 lea edi,[ebp-30h]
000000e6 lea esi,[ebp-58h]
000000e9 movq xmm0,mmword ptr [esi]
000000ed movq mmword ptr [edi],xmm0
IL_002c: ldloca.s V_3
000000f1 lea eax,[ebp-30h]
000000f4 mov dword ptr [ebp-74h],eax
IL_002e: call instance int32 [mscorlib]System.DateTime::get_Second()
000000f7 mov ecx,dword ptr [ebp-74h]
000000fa call 5960A670
000000ff mov dword ptr [ebp-5Ch],eax
IL_0033: stloc.2
00000102 mov eax,dword ptr [ebp-5Ch]
00000105 mov dword ptr [ebp-28h],eax
IL_0034: call bool Program::get_condition()
00000108 call dword ptr ds:[004232D8h]
0000010e mov dword ptr [ebp-60h],eax
IL_0039: brfalse.s IL_003d
00000111 cmp dword ptr [ebp-60h],0
00000115 je 0000011A
... snip ...
如您所见,IL 指令 34 调用 Program::get_condition(),因此 JIT 没有足够的信息来正确消除无操作函数调用。 (请注意,只有函数可以标记为内联,所以你不能再进一步了。)
*在我的机器上 (x64 Win7)。 x86 和 x64 JIT 引擎以及您是否使用 NGEN 生成可执行文件之间存在差异。您的里程可能会有所不同。