Description
If we want to format some runtime values for a Debug.WriteLine invocation, it's possible for the formatting method to throw. So, I figured I'd wrap a try/catch around the Debug.WriteLine call. However, the JIT does not elide the block in release mode.
https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEBDAzgWwB8ABABgAJiBGAOgBEBLbAcwDsJcMGxcBuAWABQZSrQBKAV1Zd8MGgGEI+AA4MANjCgBlTQDduMPkJHUaAFRgIMAwcYDMlAEzl5avLiEBvIeV/kA2gCyMBgAFhAAJgCSKmoAFMFhkTHKagDyylwQrLg0AILMzLC4uAy6MBkyDABe2FmsAJQAuj5+xA7EKOSJ4RFxwACeGDD+TeQRddgNrb7egn4L5BhQAzOLc4ub5HQwwBLMNADqUAzDADIMrDBxAKKskBGXBwCqZgBiABw0AOIhWstPOITDBTBo2LbkAC+awWYDqYFCML8Gwhfh2ewOx1OMAuVziACJgNgImoBuQAGbQfB1YYRcaTfFgpG+aHzPysyFAA===
C# / IL / JIT ASM
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Text;
public class Class
{
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public void Method(byte[] data)
{
try
{
Debug.WriteLine(Encoding.UTF8.GetString(data));
}
catch
{
Debug.WriteLine("badly formatted data");
}
}
}
.method public hidebysig
instance void Method (
uint8[] data
) cil managed flag(0200)
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = (
01 00 01 00 00
)
// Method begins at RVA 0x2050
// Code size 6 (0x6)
.maxstack 1
.try
{
IL_0000: leave.s IL_0005
} // end .try
catch [System.Runtime]System.Object
{
IL_0002: pop
IL_0003: leave.s IL_0005
} // end handler
IL_0005: ret
} // end of method Class::Method
; Core CLR 8.0.724.31311 on x64
Class..ctor()
L0000: ret
Class.Method(Byte[])
L0000: push rbp
L0001: sub rsp, 0x10
L0005: lea rbp, [rsp+0x10]
L000a: mov [rbp-0x10], rsp
L000e: add rsp, 0x10
L0012: pop rbp
L0013: ret
L0014: push rbp
L0015: sub rsp, 0x10
L0019: mov rbp, [rcx]
L001c: mov [rsp], rbp
L0020: lea rbp, [rbp+0x10]
L0024: lea rax, [L000e]
L002b: add rsp, 0x10
L002f: pop rbp
L0030: ret
Configuration
8.0.724.31311 on x64
Analysis
The assembly appears to set up a stack frame, immediately tear it down, then return. Curiously, there are unreachable instructions after the ret on L0013.
Alternatively, the JIT will elide an empty try/finally block, reducing Class.Method to a simple ret.
https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEBDAzgWwB8ABABgAJiBGAOgBEBLbAcwDsJcMGxcBuAWABQZSrQAqMBBgGChxAMyUATOQDCAGzy4hAbyHkDlRcRTkAsjAwALCABMAFMACeGGAG0AuuVvYM2AJT6hnqChmHkGFBOQeHkIbGxdDDAAK7MNADqUAyuADIMrDD2AKKskLYF6QCqYgBiABw0AOKWAMqRlfY+fv7+MgnkAL4x4QBmBdjq6tGhCfEDhkmp6Vk5MPmF9gBEW30jYcOzBoeDQA
C# / IL / JIT ASM
using System.Diagnostics;
using System.Text;
public class Class
{
public void Method(byte[] data)
{
try
{
Debug.WriteLine(Encoding.UTF8.GetString(data));
}
finally
{
Debug.WriteLine("");
}
}
}
.method public hidebysig
instance void Method (
uint8[] data
) cil managed
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = (
01 00 01 00 00
)
// Method begins at RVA 0x2050
// Code size 4 (0x4)
.maxstack 0
.try
{
IL_0000: leave.s IL_0003
} // end .try
finally
{
IL_0002: endfinally
} // end handler
IL_0003: ret
} // end of method Class::Method
; Core CLR 8.0.724.31311 on x64
Class..ctor()
L0000: ret
Class.Method(Byte[])
L0000: ret
Description
If we want to format some runtime values for a
Debug.WriteLineinvocation, it's possible for the formatting method to throw. So, I figured I'd wrap a try/catch around theDebug.WriteLinecall. However, the JIT does not elide the block in release mode.https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEBDAzgWwB8ABABgAJiBGAOgBEBLbAcwDsJcMGxcBuAWABQZSrQBKAV1Zd8MGgGEI+AA4MANjCgBlTQDduMPkJHUaAFRgIMAwcYDMlAEzl5avLiEBvIeV/kA2gCyMBgAFhAAJgCSKmoAFMFhkTHKagDyylwQrLg0AILMzLC4uAy6MBkyDABe2FmsAJQAuj5+xA7EKOSJ4RFxwACeGDD+TeQRddgNrb7egn4L5BhQAzOLc4ub5HQwwBLMNADqUAzDADIMrDBxAKKskBGXBwCqZgBiABw0AOIhWstPOITDBTBo2LbkAC+awWYDqYFCML8Gwhfh2ewOx1OMAuVziACJgNgImoBuQAGbQfB1YYRcaTfFgpG+aHzPysyFAA===
C# / IL / JIT ASM
Configuration
8.0.724.31311 on x64
Analysis
The assembly appears to set up a stack frame, immediately tear it down, then return. Curiously, there are unreachable instructions after the
retonL0013.Alternatively, the JIT will elide an empty try/finally block, reducing
Class.Methodto a simpleret.https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEBDAzgWwB8ABABgAJiBGAOgBEBLbAcwDsJcMGxcBuAWABQZSrQAqMBBgGChxAMyUATOQDCAGzy4hAbyHkDlRcRTkAsjAwALCABMAFMACeGGAG0AuuVvYM2AJT6hnqChmHkGFBOQeHkIbGxdDDAAK7MNADqUAyuADIMrDD2AKKskLYF6QCqYgBiABw0AOKWAMqRlfY+fv7+MgnkAL4x4QBmBdjq6tGhCfEDhkmp6Vk5MPmF9gBEW30jYcOzBoeDQA
C# / IL / JIT ASM