Skip to content

JIT uses too wide reads for small returned structs #58874

@jakobbotsch

Description

@jakobbotsch

For

using System.Runtime.CompilerServices;

class Program
{
    static void Main(string[] args)
    {
        Test t = default;
        Foo(ref t);
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    static Test Foo(ref Test t)
        => t;
}

struct Test
{
    public byte A, B;
}

we generate:

; Assembly listing for method Program:Foo(byref):Test
; Emitting BLENDED_CODE for X64 CPU with AVX - Windows
; optimized code
; rsp based frame
; partially interruptible
; No PGO data
; Final local variable assignments
;
;  V00 arg0         [V00,T00] (  3,  3   )   byref  ->  rcx         single-def
;# V01 OutArgs      [V01    ] (  1,  1   )  lclBlk ( 0) [rsp+00H]   "OutgoingArgSpace"
;
; Lcl frame size = 0

G_M39029_IG01:              ;; offset=0000H
                                                ;; bbWeight=1    PerfScore 0.00
G_M39029_IG02:              ;; offset=0000H
       8B01                 mov      eax, dword ptr [rcx]
                                                ;; bbWeight=1    PerfScore 2.00
G_M39029_IG03:              ;; offset=0002H
       C3                   ret
                                                ;; bbWeight=1    PerfScore 1.00

; Total bytes of code 3, prolog size 0, PerfScore 3.30, instruction count 2, allocated bytes for code 3 (MethodHash=7e33678a) for method Program:Foo(byref):Test
; ============================================================

It means for instance that the following program (usually) throws AccessViolationException:

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

unsafe class Program
{
    static void Main(string[] args)
    {
        IntPtr page = VirtualAlloc(IntPtr.Zero, 0x1000, 0x1000 | 0x2000, 0x04);
        ref Test validRef = ref *(Test*)(page + 0x1000 - sizeof(Test));
        validRef = default;
        Foo(ref validRef);
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    static Test Foo(ref Test t)
        => t;

    [DllImport("kernel32")]
    public static extern IntPtr VirtualAlloc(IntPtr lpAddress, nuint dwSize, uint flAllocationType, uint flProtect);
}

struct Test
{
    public byte A, B;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions