Skip to content

JIT does not elide empty try/catch blocks #107191

Description

@colejohnson66

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIin-prThere is an active PR which will close this issue when it is mergedtenet-performancePerformance related issue

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions