Remove invalid Unsafe.As from array helpers - #99778

Merged
jkotas merged 15 commits into
dotnet:mainfrom
MichalPetryka:patch-32
Mar 21, 2024
Merged

Remove invalid Unsafe.As from array helpers#99778
jkotas merged 15 commits into
dotnet:mainfrom
MichalPetryka:patch-32

Conversation

@MichalPetryka

Copy link
Copy Markdown
Contributor

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

Causes almost no diffs outside of calling a managed throw helper now.

@ghostghost added the area-VM-coreclr label Mar 14, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Mar 14, 2024
@jkotas

Copy link
Copy Markdown
Member

publicstaticunsafevoidStelemRef(Arrayarray,nintindex,objectobj)
has clone of this code with the same potential issue.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

has clone of this code

What's the INPLACE_RUNTIME stuff there? Is it related to some old multimodule mode? (I'll change that file tomorrow)

@jkotas

Copy link
Copy Markdown
Member

What's the INPLACE_RUNTIME stuff there? Is it related to some old multimodule mode? (I'll change that file tomorrow)

I think we build INPLACE_RUNTIME defined everywhere currently. !INPLACE_RUNTIME was a build configuration in ProjectN where the GC and the lowest level of the runtime (including these helpers) were build as a separate library that can be used by multiple higher-level runtimes all running in the same process.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

I think we build INPLACE_RUNTIME defined everywhere currently. !INPLACE_RUNTIME was a build configuration in ProjectN where the GC and the lowest level of the runtime (including these helpers) were build as a separate library that can be used by multiple higher-level runtimes all running in the same process.

Do we want to cleanup the code then and remove those paths later (and keep it as is for now)? Or should I also change the !INPLACE_RUNTIME path?

@jkotas

Copy link
Copy Markdown
Member

Do we want to cleanup the code then and remove those paths later (and keep it as is for now)? Or should I also change the !INPLACE_RUNTIME path?

Any of these options is fine with me.

@jkotas

Copy link
Copy Markdown
Member

Is the code for helper same or better with this change?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Is the code for helper same or better with this change?

The codegen for normal path is almost the same (the operands for cmp are swapped but that doesn't matter).
The cold throw path is a bit bigger cause it calls the managed throw helper instead of the native one:

 G_M56901_IG04:
- call CORINFO_HELP_RNGCHKFAIL- ;; size=5 bbWeight=0 PerfScore 0.00-G_M56901_IG05:
mov rax, 0xD1FFAB1E ; code for System.Runtime.CompilerServices.CastHelpers:ThrowArrayMismatchException():byref
call [rax]System.Runtime.CompilerServices.CastHelpers:ThrowArrayMismatchException():byref
+ ;; size=12 bbWeight=0 PerfScore 0.00+G_M56901_IG05:+ mov rax, 0xD1FFAB1E ; code for System.Runtime.CompilerServices.CastHelpers:ThrowIndexOutOfRangeException()+ call [rax]System.Runtime.CompilerServices.CastHelpers:ThrowIndexOutOfRangeException()
int3 ;; size=13 bbWeight=0 PerfScore 0.00

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas Do you know what's going on with the CI refusing to run pipelines on PRs as of recently?

@jkotas

Copy link
Copy Markdown
Member

Do you know what's going on with the CI refusing to run pipelines on PRs as of recently?

Yes, it is broken. The people responsible for our eng system are not on-call during the weekend, so it may take till Monday to resolve.

It actually runs them, just the github status is not updating. For example, here is the pipeline link for this PR
https://dev.azure.com/dnceng-public/public/_build/results?buildId=605885&view=results

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot


#if INPLACE_RUNTIME
if ((nuint)index >= (uint)array.Length)
ThrowIndexOutOfRangeException(array);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can just use ThrowHelper.ThrowIndexOutOfRangeException given that is for INPLACE_RUNTIME. It is unnecessary to go through GetClasslibException indirection for INPLACE_RUNTIME. The main point of INPLACE_RUNTIME is to avoid these indirections.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to remove the !INPLACE_RUNTIME code in the next PR and to keep this like earlier for now.
Also I think that ThrowHelper is not in the Test.CoreLib (not sure what that is for tbh but right now there's a build failure here due to MemoryMarshal not being there too).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test.CoreLib is very minimal implementation of CoreLib for testing, debugging and various experiments. It is fine to add minimal implementations of MemoryMarshal or ThrowHelper to it to keep it working.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

Comment threadsrc/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

Comment threadsrc/coreclr/vm/metasig.h Outdated
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas This caused StelemRef_Helper to not be inlined into StelemRef anymore but now StelemRef_Helper_NoCacheLookup started being inlined into it, should I bring the previous behaviour back with AggressiveInlining and NoInlining?

@jkotas

Copy link
Copy Markdown
Member

Does it affect performance of any of the fast paths?

This caused StelemRef_Helper to not be inlined into StelemRef anymore

StelemRef_Helper is marked with [MethodImpl(MethodImplOptions.NoInlining)] both before and after this change. I do not see how StelemRef_Helper could have been ever inlined.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

StelemRef_Helper is marked with [MethodImpl(MethodImplOptions.NoInlining)] both before and after this change. I do not see how StelemRef_Helper could have been ever inlined.

Ah wait nevermind, I've accidentally diffed StelemRef_Helper with StelemRef.

The non cached one being inlined is the only difference now then: MihuBot/runtime-utils#332 (comment)

@huoyaoyuan

Copy link
Copy Markdown
Member

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

I wonder what the problem would be. Is there any context?

@jkotas

Copy link
Copy Markdown
Member

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

I wonder what the problem would be. Is there any context?

Unsafe.As used by the helper code today is undefined behavior. In theory, it can interact poorly with other JIT optimizations and produce bad code. See discussion in #87374 for more details.

@jkotas

Copy link
Copy Markdown
Member

Does it affect performance of any of the fast paths?

@MichalPetryka Did you have a chance to check the perf impact of these changes?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Did you have a chance to check the perf impact of these changes?

I'll do so today.

@MichalPetryka

MichalPetryka commented Mar 19, 2024

Copy link
Copy Markdown
ContributorAuthor

BenchmarkDotNet v0.13.12, Windows 10 (10.0.19045.4170/22H2/2022Update)
AMD Ryzen 9 7900X, 1 CPU, 24 logical and 12 physical cores
.NET SDK 8.0.200
[Host] : .NET 8.0.2 (8.0.224.6711), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-JUCZRX : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-NEFMBN : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
.NET 8.0 : .NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Runtime=.NET 8.0 
MethodJobToolchainsMeanErrorStdDevRatioRatioSDCode SizeAllocatedAlloc Ratio
WriteNullJob-JUCZRXmain?29.33 ns0.076 ns0.067 ns1.000.00480 B-NA
WriteNullJob-NEFMBNpr?34.87 ns0.070 ns0.062 ns1.190.00356 B-NA
WriteNull.NET 8.0Default?34.56 ns0.135 ns0.127 ns1.180.0053 B-NA
WriteToObjectJob-JUCZRXmain63.41 ns0.330 ns0.292 ns1.000.00331 B-NA
WriteToObjectJob-NEFMBNpr57.73 ns0.282 ns0.264 ns0.910.01356 B-NA
WriteToObject.NET 8.0Default63.91 ns0.558 ns0.494 ns1.010.0153 B-NA
WriteToInterfaceJob-JUCZRXmain117.00 ns0.711 ns0.630 ns1.000.00422 B-NA
WriteToInterfaceJob-NEFMBNpr88.45 ns1.282 ns1.425 ns0.750.01369 B-NA
WriteToInterface.NET 8.0Default93.90 ns0.541 ns0.480 ns0.800.0153 B-NA
WriteToTypeJob-JUCZRXmain41.50 ns0.684 ns0.640 ns1.000.0060 B-NA
WriteToTypeJob-NEFMBNpr40.00 ns0.070 ns0.058 ns0.960.0260 B-NA
WriteToType.NET 8.0Default39.99 ns0.062 ns0.048 ns0.960.0258 B-NA

@jkotas I've benchmarked with string, the paths for value seem to be better but the test with null seems to confuse PGO and have it place the null path in the slow code behind the throw helper now. Not sure if this can be fixed without JIT changes, the JIT should probably assume that throw helpers are always colder than cold paths.

Full codegen:

Details

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8jne short M01_L00xorecx,ecxmov[rax],rcxaddrsp,28retM01_L00:cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CB4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:call CORINFO_HELP_RNGCHKFAILint3; Total bytes of code 93
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8movrcx,290F9800B80movrcx,[rcx]movrax,[rsi]addrcx,10rorxrdx,rax,20xorrdx,rbxmovr8,9E3779B97F4A7C15imulrdx,r8movr8d,[rcx]shrxrdx,rdx,r8xorr8d,r8dM02_L00:lear10d,[rdx+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rcx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incr8daddedx,r8dandedx,[rcx+4]cmpr8d,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,7FFB69DC54C8call CORINFO_HELP_COUNTPROFILE32movrcx,rdimovrdx,rsicall System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,7FFB69DC54CCcall CORINFO_HELP_COUNTPROFILE32movrcx,rdimovrdx,rbxmovr8,rsicall qword ptr [7FFB68CB44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 221
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrsi,rcxmovrdi,rdxmovrbx,r8testrbx,rbxjne short M03_L00movrdx,2D18E150008movrcx,rdxcall qword ptr [7FFB68D1D3B0]M03_L00:movrcx,rdimovrdx,rbxcall System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)movrbx,raxtestrbx,rbxje short M03_L01movrcx,rsimovrdx,rbxaddrsp,20poprbxpoprsipoprdijmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M03_L01:movrcx,offset MT_System.ArrayTypeMismatchExceptioncall CORINFO_HELP_NEWSFASTmovrbx,raxmovrcx,rbxcall qword ptr [7FFB69827C78]movrcx,rbxcall CORINFO_HELP_THROWint3; Total bytes of code 113

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L01learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8jne short M01_L02xorecx,ecxmov[rax],rcxaddrsp,28retM01_L00:movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L03movrcx,raxaddrsp,28jmp qword ptr [7FFB6BDB44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L01:call qword ptr [7FFB6BDB4450]int3M01_L02:cmprdx,[r8]jne short M01_L00M01_L03:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object); Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC8B31840]movrdx,[rax+0B50]movrax,[rsi]addrdx,10movr8,raxrolr8,20xorr8,rbxmovr10,9E3779B97F4A7C15imulr8,r10movecx,[rdx]shrr8,clxorecx,ecxM02_L00:lear10d,[r8+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddr8d,ecxandr8d,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC8B4A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rbxmovrdx,rsicall qword ptr [7FFBC8B4A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M02_L04movrcx,rdimovrdx,raxcall qword ptr [7FFBC8B4A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L04:call qword ptr [7FFBC8B4A2E0]int3; Total bytes of code 209

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8je short M01_L01cmprdx,[r8]je short M01_L00movr10,offset MT_System.Object[]cmp[rcx],r10jne short M01_L03M01_L00:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L01:xorecx,ecxmov[rax],rcxaddrsp,28retM01_L02:call CORINFO_HELP_RNGCHKFAILM01_L03:movrcx,raxaddrsp,28jmp qword ptr [7FFB68CD4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object); Total bytes of code 92
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC7912090]movrdx,[rax+0B48]movr8,[rsi]addrdx,10movrax,r8rolrax,20xorrax,rbxmovr10,9E3779B97F4A7C15imulrax,r10movecx,[rdx]shrrax,clxorecx,ecxM02_L00:lear10d,[rax+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,r8jne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddeax,ecxandeax,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC792CD88]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rdimovrdx,rbxmovr8,rsicall qword ptr [7FFBC792CDC8]; Precode of System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 186

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8je short M01_L01cmprdx,[r8]je short M01_L00movr10,offset MT_System.Object[]cmp[rcx],r10jne short M01_L03M01_L00:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L01:xorecx,ecxmov[rax],rcxaddrsp,28retM01_L02:call qword ptr [7FFB68CA4450]int3M01_L03:movrcx,raxaddrsp,28jmp qword ptr [7FFB68CA44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object); Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC8661840]movrdx,[rax+0B50]movrax,[rsi]addrdx,10movr8,raxrolr8,20xorr8,rbxmovr10,9E3779B97F4A7C15imulr8,r10movecx,[rdx]shrr8,clxorecx,ecxM02_L00:lear10d,[r8+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddr8d,ecxandr8d,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC867A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rbxmovrdx,rsicall qword ptr [7FFBC867A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M02_L04movrcx,rdimovrdx,raxcall qword ptr [7FFBC867A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L04:call qword ptr [7FFBC867A2E0]int3; Total bytes of code 209

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L00learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8je short M01_L02cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CD4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L00:call CORINFO_HELP_RNGCHKFAILM01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:xorecx,ecxmov[rax],rcxaddrsp,28ret; Total bytes of code 92
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrax,25A67800B80movrax,[rax]movr10,[r8]addrax,10rorxr9,r10,20xorr9,rdxmovr11,9E3779B97F4A7C15imulr9,r11movr11d,[rax]shrxr9,r9,r11xorr11d,r11dM02_L00:leaebx,[r9+1]movsxdrbx,ebxlearbx,[rbx+rbx*2]learbx,[rax+rbx*8]movesi,[rbx]movrdi,[rbx+8]andesi,0FFFFFFFEcmprdi,r10jne short M02_L01movrdi,rdxxorrdi,[rbx+10]cmprdi,1jbe short M02_L02M02_L01:testesi,esije short M02_L03incr11daddr9d,r11dandr9d,[rax+4]cmpr11d,8jl short M02_L00jmp short M02_L03M02_L02:cmpesi,[rbx]jne short M02_L03cmpedi,1jne short M02_L03movrdx,r8call System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:call qword ptr [7FFB68CD44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 166
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrsi,rcxmovrdi,rdxmovrbx,r8testrbx,rbxjne short M03_L00movrcx,[7FFBC79636C8]movrdx,[rcx]movrcx,rdxcall qword ptr [7FFBC79300B8]M03_L00:movrcx,rdimovrdx,rbxcall qword ptr [7FFBC792CD68]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)movrbx,raxtestrbx,rbxje short M03_L01movrdx,rbxmovrcx,rsilearax,[7FFBC792CD90]addrsp,20poprbxpoprsipoprdijmp qword ptr [rax]M03_L01:call qword ptr [7FFBC791B5E8]movrbx,raxmovrcx,rbxcall qword ptr [7FFBC7924598]movrcx,rbxcall qword ptr [7FFBC7911760]; CORINFO_HELP_THROWint3; Total bytes of code 111

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L00learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8je short M01_L02cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CC44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L00:call qword ptr [7FFB68CC4450]int3M01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:xorecx,ecxmov[rax],rcxaddrsp,28ret; Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrax,21C53C00B88movrax,[rax]movr10,[r8]addrax,10rorxr9,r10,20xorr9,rdxmovr11,9E3779B97F4A7C15imulr9,r11movr11d,[rax]shrxr9,r9,r11xorr11d,r11dM02_L00:leaebx,[r9+1]movsxdrbx,ebxlearbx,[rbx+rbx*2]learbx,[rax+rbx*8]movesi,[rbx]movrdi,[rbx+8]andesi,0FFFFFFFEcmprdi,r10jne short M02_L01movrdi,rdxxorrdi,[rbx+10]cmprdi,1jbe short M02_L02M02_L01:testesi,esije short M02_L03incr11daddr9d,r11dandr9d,[rax+4]cmpr11d,8jl short M02_L00jmp short M02_L03M02_L02:cmpesi,[rbx]jne short M02_L03cmpedi,1jne short M02_L03movrdx,r8call System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:call qword ptr [7FFB68CC44C8]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 166
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrbxsubrsp,20movrbx,rcxmovrax,r8movrcx,rdxmovrdx,raxcall qword ptr [7FFBC867A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M03_L00movrdx,raxmovrcx,rbxlearax,[7FFBC867A2B0]addrsp,20poprbxjmp qword ptr [rax]M03_L00:call qword ptr [7FFBC867A2E0]int3; Total bytes of code 56

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax+rax]M00_L00:learcx,[rsi+rdi*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 60

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax+rax]M00_L00:learcx,[rsi+rdi*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 60

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxmovrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax]nop dword ptr [rax+rax]M00_L00:movecx,edilearcx,[rsi+rcx*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:poprbxpoprbppoprsipoprdiret; Total bytes of code 58

@jkotas

jkotas commented Mar 20, 2024

Copy link
Copy Markdown
Member

I agree that the cold blocks ordering with PGO can be better in some case. I do not see any material code difference caused by this change. The exact code for these helpers can differ from workload to workload and from run to run depending on how PGO rolls the dice.

I have pushed a commit with a minor cleanup as I was looking at the code.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-VM-coreclrcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@MichalPetryka@jkotas@huoyaoyuan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Remove invalid Unsafe.As from array helpers - #99778

Merged
jkotas merged 15 commits into
dotnet:mainfrom
MichalPetryka:patch-32
Mar 21, 2024
Merged

Remove invalid Unsafe.As from array helpers#99778
jkotas merged 15 commits into
dotnet:mainfrom
MichalPetryka:patch-32

Conversation

@MichalPetryka

Copy link
Copy Markdown
Contributor

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

Causes almost no diffs outside of calling a managed throw helper now.

@ghostghost added the area-VM-coreclr label Mar 14, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Mar 14, 2024
@jkotas

Copy link
Copy Markdown
Member

publicstaticunsafevoidStelemRef(Arrayarray,nintindex,objectobj)
has clone of this code with the same potential issue.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

has clone of this code

What's the INPLACE_RUNTIME stuff there? Is it related to some old multimodule mode? (I'll change that file tomorrow)

@jkotas

Copy link
Copy Markdown
Member

What's the INPLACE_RUNTIME stuff there? Is it related to some old multimodule mode? (I'll change that file tomorrow)

I think we build INPLACE_RUNTIME defined everywhere currently. !INPLACE_RUNTIME was a build configuration in ProjectN where the GC and the lowest level of the runtime (including these helpers) were build as a separate library that can be used by multiple higher-level runtimes all running in the same process.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

I think we build INPLACE_RUNTIME defined everywhere currently. !INPLACE_RUNTIME was a build configuration in ProjectN where the GC and the lowest level of the runtime (including these helpers) were build as a separate library that can be used by multiple higher-level runtimes all running in the same process.

Do we want to cleanup the code then and remove those paths later (and keep it as is for now)? Or should I also change the !INPLACE_RUNTIME path?

@jkotas

Copy link
Copy Markdown
Member

Do we want to cleanup the code then and remove those paths later (and keep it as is for now)? Or should I also change the !INPLACE_RUNTIME path?

Any of these options is fine with me.

@jkotas

Copy link
Copy Markdown
Member

Is the code for helper same or better with this change?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Is the code for helper same or better with this change?

The codegen for normal path is almost the same (the operands for cmp are swapped but that doesn't matter).
The cold throw path is a bit bigger cause it calls the managed throw helper instead of the native one:

 G_M56901_IG04:
- call CORINFO_HELP_RNGCHKFAIL- ;; size=5 bbWeight=0 PerfScore 0.00-G_M56901_IG05:
mov rax, 0xD1FFAB1E ; code for System.Runtime.CompilerServices.CastHelpers:ThrowArrayMismatchException():byref
call [rax]System.Runtime.CompilerServices.CastHelpers:ThrowArrayMismatchException():byref
+ ;; size=12 bbWeight=0 PerfScore 0.00+G_M56901_IG05:+ mov rax, 0xD1FFAB1E ; code for System.Runtime.CompilerServices.CastHelpers:ThrowIndexOutOfRangeException()+ call [rax]System.Runtime.CompilerServices.CastHelpers:ThrowIndexOutOfRangeException()
int3 ;; size=13 bbWeight=0 PerfScore 0.00

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas Do you know what's going on with the CI refusing to run pipelines on PRs as of recently?

@jkotas

Copy link
Copy Markdown
Member

Do you know what's going on with the CI refusing to run pipelines on PRs as of recently?

Yes, it is broken. The people responsible for our eng system are not on-call during the weekend, so it may take till Monday to resolve.

It actually runs them, just the github status is not updating. For example, here is the pipeline link for this PR
https://dev.azure.com/dnceng-public/public/_build/results?buildId=605885&view=results

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot


#if INPLACE_RUNTIME
if ((nuint)index >= (uint)array.Length)
ThrowIndexOutOfRangeException(array);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can just use ThrowHelper.ThrowIndexOutOfRangeException given that is for INPLACE_RUNTIME. It is unnecessary to go through GetClasslibException indirection for INPLACE_RUNTIME. The main point of INPLACE_RUNTIME is to avoid these indirections.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to remove the !INPLACE_RUNTIME code in the next PR and to keep this like earlier for now.
Also I think that ThrowHelper is not in the Test.CoreLib (not sure what that is for tbh but right now there's a build failure here due to MemoryMarshal not being there too).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test.CoreLib is very minimal implementation of CoreLib for testing, debugging and various experiments. It is fine to add minimal implementations of MemoryMarshal or ThrowHelper to it to keep it working.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

Comment threadsrc/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

Comment threadsrc/coreclr/vm/metasig.h Outdated
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas This caused StelemRef_Helper to not be inlined into StelemRef anymore but now StelemRef_Helper_NoCacheLookup started being inlined into it, should I bring the previous behaviour back with AggressiveInlining and NoInlining?

@jkotas

Copy link
Copy Markdown
Member

Does it affect performance of any of the fast paths?

This caused StelemRef_Helper to not be inlined into StelemRef anymore

StelemRef_Helper is marked with [MethodImpl(MethodImplOptions.NoInlining)] both before and after this change. I do not see how StelemRef_Helper could have been ever inlined.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

StelemRef_Helper is marked with [MethodImpl(MethodImplOptions.NoInlining)] both before and after this change. I do not see how StelemRef_Helper could have been ever inlined.

Ah wait nevermind, I've accidentally diffed StelemRef_Helper with StelemRef.

The non cached one being inlined is the only difference now then: MihuBot/runtime-utils#332 (comment)

@huoyaoyuan

Copy link
Copy Markdown
Member

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

I wonder what the problem would be. Is there any context?

@jkotas

Copy link
Copy Markdown
Member

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

I wonder what the problem would be. Is there any context?

Unsafe.As used by the helper code today is undefined behavior. In theory, it can interact poorly with other JIT optimizations and produce bad code. See discussion in #87374 for more details.

@jkotas

Copy link
Copy Markdown
Member

Does it affect performance of any of the fast paths?

@MichalPetryka Did you have a chance to check the perf impact of these changes?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Did you have a chance to check the perf impact of these changes?

I'll do so today.

@MichalPetryka

MichalPetryka commented Mar 19, 2024

Copy link
Copy Markdown
ContributorAuthor

BenchmarkDotNet v0.13.12, Windows 10 (10.0.19045.4170/22H2/2022Update)
AMD Ryzen 9 7900X, 1 CPU, 24 logical and 12 physical cores
.NET SDK 8.0.200
[Host] : .NET 8.0.2 (8.0.224.6711), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-JUCZRX : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-NEFMBN : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
.NET 8.0 : .NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Runtime=.NET 8.0 
MethodJobToolchainsMeanErrorStdDevRatioRatioSDCode SizeAllocatedAlloc Ratio
WriteNullJob-JUCZRXmain?29.33 ns0.076 ns0.067 ns1.000.00480 B-NA
WriteNullJob-NEFMBNpr?34.87 ns0.070 ns0.062 ns1.190.00356 B-NA
WriteNull.NET 8.0Default?34.56 ns0.135 ns0.127 ns1.180.0053 B-NA
WriteToObjectJob-JUCZRXmain63.41 ns0.330 ns0.292 ns1.000.00331 B-NA
WriteToObjectJob-NEFMBNpr57.73 ns0.282 ns0.264 ns0.910.01356 B-NA
WriteToObject.NET 8.0Default63.91 ns0.558 ns0.494 ns1.010.0153 B-NA
WriteToInterfaceJob-JUCZRXmain117.00 ns0.711 ns0.630 ns1.000.00422 B-NA
WriteToInterfaceJob-NEFMBNpr88.45 ns1.282 ns1.425 ns0.750.01369 B-NA
WriteToInterface.NET 8.0Default93.90 ns0.541 ns0.480 ns0.800.0153 B-NA
WriteToTypeJob-JUCZRXmain41.50 ns0.684 ns0.640 ns1.000.0060 B-NA
WriteToTypeJob-NEFMBNpr40.00 ns0.070 ns0.058 ns0.960.0260 B-NA
WriteToType.NET 8.0Default39.99 ns0.062 ns0.048 ns0.960.0258 B-NA

@jkotas I've benchmarked with string, the paths for value seem to be better but the test with null seems to confuse PGO and have it place the null path in the slow code behind the throw helper now. Not sure if this can be fixed without JIT changes, the JIT should probably assume that throw helpers are always colder than cold paths.

Full codegen:

Details

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8jne short M01_L00xorecx,ecxmov[rax],rcxaddrsp,28retM01_L00:cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CB4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:call CORINFO_HELP_RNGCHKFAILint3; Total bytes of code 93
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8movrcx,290F9800B80movrcx,[rcx]movrax,[rsi]addrcx,10rorxrdx,rax,20xorrdx,rbxmovr8,9E3779B97F4A7C15imulrdx,r8movr8d,[rcx]shrxrdx,rdx,r8xorr8d,r8dM02_L00:lear10d,[rdx+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rcx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incr8daddedx,r8dandedx,[rcx+4]cmpr8d,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,7FFB69DC54C8call CORINFO_HELP_COUNTPROFILE32movrcx,rdimovrdx,rsicall System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,7FFB69DC54CCcall CORINFO_HELP_COUNTPROFILE32movrcx,rdimovrdx,rbxmovr8,rsicall qword ptr [7FFB68CB44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 221
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrsi,rcxmovrdi,rdxmovrbx,r8testrbx,rbxjne short M03_L00movrdx,2D18E150008movrcx,rdxcall qword ptr [7FFB68D1D3B0]M03_L00:movrcx,rdimovrdx,rbxcall System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)movrbx,raxtestrbx,rbxje short M03_L01movrcx,rsimovrdx,rbxaddrsp,20poprbxpoprsipoprdijmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M03_L01:movrcx,offset MT_System.ArrayTypeMismatchExceptioncall CORINFO_HELP_NEWSFASTmovrbx,raxmovrcx,rbxcall qword ptr [7FFB69827C78]movrcx,rbxcall CORINFO_HELP_THROWint3; Total bytes of code 113

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L01learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8jne short M01_L02xorecx,ecxmov[rax],rcxaddrsp,28retM01_L00:movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L03movrcx,raxaddrsp,28jmp qword ptr [7FFB6BDB44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L01:call qword ptr [7FFB6BDB4450]int3M01_L02:cmprdx,[r8]jne short M01_L00M01_L03:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object); Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC8B31840]movrdx,[rax+0B50]movrax,[rsi]addrdx,10movr8,raxrolr8,20xorr8,rbxmovr10,9E3779B97F4A7C15imulr8,r10movecx,[rdx]shrr8,clxorecx,ecxM02_L00:lear10d,[r8+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddr8d,ecxandr8d,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC8B4A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rbxmovrdx,rsicall qword ptr [7FFBC8B4A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M02_L04movrcx,rdimovrdx,raxcall qword ptr [7FFBC8B4A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L04:call qword ptr [7FFBC8B4A2E0]int3; Total bytes of code 209

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8je short M01_L01cmprdx,[r8]je short M01_L00movr10,offset MT_System.Object[]cmp[rcx],r10jne short M01_L03M01_L00:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L01:xorecx,ecxmov[rax],rcxaddrsp,28retM01_L02:call CORINFO_HELP_RNGCHKFAILM01_L03:movrcx,raxaddrsp,28jmp qword ptr [7FFB68CD4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object); Total bytes of code 92
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC7912090]movrdx,[rax+0B48]movr8,[rsi]addrdx,10movrax,r8rolrax,20xorrax,rbxmovr10,9E3779B97F4A7C15imulrax,r10movecx,[rdx]shrrax,clxorecx,ecxM02_L00:lear10d,[rax+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,r8jne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddeax,ecxandeax,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC792CD88]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rdimovrdx,rbxmovr8,rsicall qword ptr [7FFBC792CDC8]; Precode of System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 186

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8je short M01_L01cmprdx,[r8]je short M01_L00movr10,offset MT_System.Object[]cmp[rcx],r10jne short M01_L03M01_L00:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L01:xorecx,ecxmov[rax],rcxaddrsp,28retM01_L02:call qword ptr [7FFB68CA4450]int3M01_L03:movrcx,raxaddrsp,28jmp qword ptr [7FFB68CA44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object); Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC8661840]movrdx,[rax+0B50]movrax,[rsi]addrdx,10movr8,raxrolr8,20xorr8,rbxmovr10,9E3779B97F4A7C15imulr8,r10movecx,[rdx]shrr8,clxorecx,ecxM02_L00:lear10d,[r8+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddr8d,ecxandr8d,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC867A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rbxmovrdx,rsicall qword ptr [7FFBC867A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M02_L04movrcx,rdimovrdx,raxcall qword ptr [7FFBC867A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L04:call qword ptr [7FFBC867A2E0]int3; Total bytes of code 209

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L00learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8je short M01_L02cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CD4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L00:call CORINFO_HELP_RNGCHKFAILM01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:xorecx,ecxmov[rax],rcxaddrsp,28ret; Total bytes of code 92
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrax,25A67800B80movrax,[rax]movr10,[r8]addrax,10rorxr9,r10,20xorr9,rdxmovr11,9E3779B97F4A7C15imulr9,r11movr11d,[rax]shrxr9,r9,r11xorr11d,r11dM02_L00:leaebx,[r9+1]movsxdrbx,ebxlearbx,[rbx+rbx*2]learbx,[rax+rbx*8]movesi,[rbx]movrdi,[rbx+8]andesi,0FFFFFFFEcmprdi,r10jne short M02_L01movrdi,rdxxorrdi,[rbx+10]cmprdi,1jbe short M02_L02M02_L01:testesi,esije short M02_L03incr11daddr9d,r11dandr9d,[rax+4]cmpr11d,8jl short M02_L00jmp short M02_L03M02_L02:cmpesi,[rbx]jne short M02_L03cmpedi,1jne short M02_L03movrdx,r8call System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:call qword ptr [7FFB68CD44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 166
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrsi,rcxmovrdi,rdxmovrbx,r8testrbx,rbxjne short M03_L00movrcx,[7FFBC79636C8]movrdx,[rcx]movrcx,rdxcall qword ptr [7FFBC79300B8]M03_L00:movrcx,rdimovrdx,rbxcall qword ptr [7FFBC792CD68]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)movrbx,raxtestrbx,rbxje short M03_L01movrdx,rbxmovrcx,rsilearax,[7FFBC792CD90]addrsp,20poprbxpoprsipoprdijmp qword ptr [rax]M03_L01:call qword ptr [7FFBC791B5E8]movrbx,raxmovrcx,rbxcall qword ptr [7FFBC7924598]movrcx,rbxcall qword ptr [7FFBC7911760]; CORINFO_HELP_THROWint3; Total bytes of code 111

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L00learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8je short M01_L02cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CC44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L00:call qword ptr [7FFB68CC4450]int3M01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:xorecx,ecxmov[rax],rcxaddrsp,28ret; Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrax,21C53C00B88movrax,[rax]movr10,[r8]addrax,10rorxr9,r10,20xorr9,rdxmovr11,9E3779B97F4A7C15imulr9,r11movr11d,[rax]shrxr9,r9,r11xorr11d,r11dM02_L00:leaebx,[r9+1]movsxdrbx,ebxlearbx,[rbx+rbx*2]learbx,[rax+rbx*8]movesi,[rbx]movrdi,[rbx+8]andesi,0FFFFFFFEcmprdi,r10jne short M02_L01movrdi,rdxxorrdi,[rbx+10]cmprdi,1jbe short M02_L02M02_L01:testesi,esije short M02_L03incr11daddr9d,r11dandr9d,[rax+4]cmpr11d,8jl short M02_L00jmp short M02_L03M02_L02:cmpesi,[rbx]jne short M02_L03cmpedi,1jne short M02_L03movrdx,r8call System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:call qword ptr [7FFB68CC44C8]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 166
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrbxsubrsp,20movrbx,rcxmovrax,r8movrcx,rdxmovrdx,raxcall qword ptr [7FFBC867A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M03_L00movrdx,raxmovrcx,rbxlearax,[7FFBC867A2B0]addrsp,20poprbxjmp qword ptr [rax]M03_L00:call qword ptr [7FFBC867A2E0]int3; Total bytes of code 56

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax+rax]M00_L00:learcx,[rsi+rdi*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 60

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax+rax]M00_L00:learcx,[rsi+rdi*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 60

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxmovrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax]nop dword ptr [rax+rax]M00_L00:movecx,edilearcx,[rsi+rcx*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:poprbxpoprbppoprsipoprdiret; Total bytes of code 58

@jkotas

jkotas commented Mar 20, 2024

Copy link
Copy Markdown
Member

I agree that the cold blocks ordering with PGO can be better in some case. I do not see any material code difference caused by this change. The exact code for these helpers can differ from workload to workload and from run to run depending on how PGO rolls the dice.

I have pushed a commit with a minor cleanup as I was looking at the code.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-VM-coreclrcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@MichalPetryka@jkotas@huoyaoyuan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Remove invalid Unsafe.As from array helpers - #99778

Merged
jkotas merged 15 commits into
dotnet:mainfrom
MichalPetryka:patch-32
Mar 21, 2024
Merged

Remove invalid Unsafe.As from array helpers#99778
jkotas merged 15 commits into
dotnet:mainfrom
MichalPetryka:patch-32

Conversation

@MichalPetryka

Copy link
Copy Markdown
Contributor

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

Causes almost no diffs outside of calling a managed throw helper now.

@ghostghost added the area-VM-coreclr label Mar 14, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Mar 14, 2024
@jkotas

Copy link
Copy Markdown
Member

publicstaticunsafevoidStelemRef(Arrayarray,nintindex,objectobj)
has clone of this code with the same potential issue.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

has clone of this code

What's the INPLACE_RUNTIME stuff there? Is it related to some old multimodule mode? (I'll change that file tomorrow)

@jkotas

Copy link
Copy Markdown
Member

What's the INPLACE_RUNTIME stuff there? Is it related to some old multimodule mode? (I'll change that file tomorrow)

I think we build INPLACE_RUNTIME defined everywhere currently. !INPLACE_RUNTIME was a build configuration in ProjectN where the GC and the lowest level of the runtime (including these helpers) were build as a separate library that can be used by multiple higher-level runtimes all running in the same process.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

I think we build INPLACE_RUNTIME defined everywhere currently. !INPLACE_RUNTIME was a build configuration in ProjectN where the GC and the lowest level of the runtime (including these helpers) were build as a separate library that can be used by multiple higher-level runtimes all running in the same process.

Do we want to cleanup the code then and remove those paths later (and keep it as is for now)? Or should I also change the !INPLACE_RUNTIME path?

@jkotas

Copy link
Copy Markdown
Member

Do we want to cleanup the code then and remove those paths later (and keep it as is for now)? Or should I also change the !INPLACE_RUNTIME path?

Any of these options is fine with me.

@jkotas

Copy link
Copy Markdown
Member

Is the code for helper same or better with this change?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Is the code for helper same or better with this change?

The codegen for normal path is almost the same (the operands for cmp are swapped but that doesn't matter).
The cold throw path is a bit bigger cause it calls the managed throw helper instead of the native one:

 G_M56901_IG04:
- call CORINFO_HELP_RNGCHKFAIL- ;; size=5 bbWeight=0 PerfScore 0.00-G_M56901_IG05:
mov rax, 0xD1FFAB1E ; code for System.Runtime.CompilerServices.CastHelpers:ThrowArrayMismatchException():byref
call [rax]System.Runtime.CompilerServices.CastHelpers:ThrowArrayMismatchException():byref
+ ;; size=12 bbWeight=0 PerfScore 0.00+G_M56901_IG05:+ mov rax, 0xD1FFAB1E ; code for System.Runtime.CompilerServices.CastHelpers:ThrowIndexOutOfRangeException()+ call [rax]System.Runtime.CompilerServices.CastHelpers:ThrowIndexOutOfRangeException()
int3 ;; size=13 bbWeight=0 PerfScore 0.00

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas Do you know what's going on with the CI refusing to run pipelines on PRs as of recently?

@jkotas

Copy link
Copy Markdown
Member

Do you know what's going on with the CI refusing to run pipelines on PRs as of recently?

Yes, it is broken. The people responsible for our eng system are not on-call during the weekend, so it may take till Monday to resolve.

It actually runs them, just the github status is not updating. For example, here is the pipeline link for this PR
https://dev.azure.com/dnceng-public/public/_build/results?buildId=605885&view=results

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot


#if INPLACE_RUNTIME
if ((nuint)index >= (uint)array.Length)
ThrowIndexOutOfRangeException(array);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can just use ThrowHelper.ThrowIndexOutOfRangeException given that is for INPLACE_RUNTIME. It is unnecessary to go through GetClasslibException indirection for INPLACE_RUNTIME. The main point of INPLACE_RUNTIME is to avoid these indirections.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to remove the !INPLACE_RUNTIME code in the next PR and to keep this like earlier for now.
Also I think that ThrowHelper is not in the Test.CoreLib (not sure what that is for tbh but right now there's a build failure here due to MemoryMarshal not being there too).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test.CoreLib is very minimal implementation of CoreLib for testing, debugging and various experiments. It is fine to add minimal implementations of MemoryMarshal or ThrowHelper to it to keep it working.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

Comment threadsrc/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

Comment threadsrc/coreclr/vm/metasig.h Outdated
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas This caused StelemRef_Helper to not be inlined into StelemRef anymore but now StelemRef_Helper_NoCacheLookup started being inlined into it, should I bring the previous behaviour back with AggressiveInlining and NoInlining?

@jkotas

Copy link
Copy Markdown
Member

Does it affect performance of any of the fast paths?

This caused StelemRef_Helper to not be inlined into StelemRef anymore

StelemRef_Helper is marked with [MethodImpl(MethodImplOptions.NoInlining)] both before and after this change. I do not see how StelemRef_Helper could have been ever inlined.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

StelemRef_Helper is marked with [MethodImpl(MethodImplOptions.NoInlining)] both before and after this change. I do not see how StelemRef_Helper could have been ever inlined.

Ah wait nevermind, I've accidentally diffed StelemRef_Helper with StelemRef.

The non cached one being inlined is the only difference now then: MihuBot/runtime-utils#332 (comment)

@huoyaoyuan

Copy link
Copy Markdown
Member

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

I wonder what the problem would be. Is there any context?

@jkotas

Copy link
Copy Markdown
Member

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

I wonder what the problem would be. Is there any context?

Unsafe.As used by the helper code today is undefined behavior. In theory, it can interact poorly with other JIT optimizations and produce bad code. See discussion in #87374 for more details.

@jkotas

Copy link
Copy Markdown
Member

Does it affect performance of any of the fast paths?

@MichalPetryka Did you have a chance to check the perf impact of these changes?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Did you have a chance to check the perf impact of these changes?

I'll do so today.

@MichalPetryka

MichalPetryka commented Mar 19, 2024

Copy link
Copy Markdown
ContributorAuthor

BenchmarkDotNet v0.13.12, Windows 10 (10.0.19045.4170/22H2/2022Update)
AMD Ryzen 9 7900X, 1 CPU, 24 logical and 12 physical cores
.NET SDK 8.0.200
[Host] : .NET 8.0.2 (8.0.224.6711), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-JUCZRX : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-NEFMBN : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
.NET 8.0 : .NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Runtime=.NET 8.0 
MethodJobToolchainsMeanErrorStdDevRatioRatioSDCode SizeAllocatedAlloc Ratio
WriteNullJob-JUCZRXmain?29.33 ns0.076 ns0.067 ns1.000.00480 B-NA
WriteNullJob-NEFMBNpr?34.87 ns0.070 ns0.062 ns1.190.00356 B-NA
WriteNull.NET 8.0Default?34.56 ns0.135 ns0.127 ns1.180.0053 B-NA
WriteToObjectJob-JUCZRXmain63.41 ns0.330 ns0.292 ns1.000.00331 B-NA
WriteToObjectJob-NEFMBNpr57.73 ns0.282 ns0.264 ns0.910.01356 B-NA
WriteToObject.NET 8.0Default63.91 ns0.558 ns0.494 ns1.010.0153 B-NA
WriteToInterfaceJob-JUCZRXmain117.00 ns0.711 ns0.630 ns1.000.00422 B-NA
WriteToInterfaceJob-NEFMBNpr88.45 ns1.282 ns1.425 ns0.750.01369 B-NA
WriteToInterface.NET 8.0Default93.90 ns0.541 ns0.480 ns0.800.0153 B-NA
WriteToTypeJob-JUCZRXmain41.50 ns0.684 ns0.640 ns1.000.0060 B-NA
WriteToTypeJob-NEFMBNpr40.00 ns0.070 ns0.058 ns0.960.0260 B-NA
WriteToType.NET 8.0Default39.99 ns0.062 ns0.048 ns0.960.0258 B-NA

@jkotas I've benchmarked with string, the paths for value seem to be better but the test with null seems to confuse PGO and have it place the null path in the slow code behind the throw helper now. Not sure if this can be fixed without JIT changes, the JIT should probably assume that throw helpers are always colder than cold paths.

Full codegen:

Details

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8jne short M01_L00xorecx,ecxmov[rax],rcxaddrsp,28retM01_L00:cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CB4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:call CORINFO_HELP_RNGCHKFAILint3; Total bytes of code 93
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8movrcx,290F9800B80movrcx,[rcx]movrax,[rsi]addrcx,10rorxrdx,rax,20xorrdx,rbxmovr8,9E3779B97F4A7C15imulrdx,r8movr8d,[rcx]shrxrdx,rdx,r8xorr8d,r8dM02_L00:lear10d,[rdx+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rcx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incr8daddedx,r8dandedx,[rcx+4]cmpr8d,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,7FFB69DC54C8call CORINFO_HELP_COUNTPROFILE32movrcx,rdimovrdx,rsicall System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,7FFB69DC54CCcall CORINFO_HELP_COUNTPROFILE32movrcx,rdimovrdx,rbxmovr8,rsicall qword ptr [7FFB68CB44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 221
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrsi,rcxmovrdi,rdxmovrbx,r8testrbx,rbxjne short M03_L00movrdx,2D18E150008movrcx,rdxcall qword ptr [7FFB68D1D3B0]M03_L00:movrcx,rdimovrdx,rbxcall System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)movrbx,raxtestrbx,rbxje short M03_L01movrcx,rsimovrdx,rbxaddrsp,20poprbxpoprsipoprdijmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M03_L01:movrcx,offset MT_System.ArrayTypeMismatchExceptioncall CORINFO_HELP_NEWSFASTmovrbx,raxmovrcx,rbxcall qword ptr [7FFB69827C78]movrcx,rbxcall CORINFO_HELP_THROWint3; Total bytes of code 113

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L01learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8jne short M01_L02xorecx,ecxmov[rax],rcxaddrsp,28retM01_L00:movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L03movrcx,raxaddrsp,28jmp qword ptr [7FFB6BDB44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L01:call qword ptr [7FFB6BDB4450]int3M01_L02:cmprdx,[r8]jne short M01_L00M01_L03:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object); Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC8B31840]movrdx,[rax+0B50]movrax,[rsi]addrdx,10movr8,raxrolr8,20xorr8,rbxmovr10,9E3779B97F4A7C15imulr8,r10movecx,[rdx]shrr8,clxorecx,ecxM02_L00:lear10d,[r8+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddr8d,ecxandr8d,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC8B4A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rbxmovrdx,rsicall qword ptr [7FFBC8B4A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M02_L04movrcx,rdimovrdx,raxcall qword ptr [7FFBC8B4A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L04:call qword ptr [7FFBC8B4A2E0]int3; Total bytes of code 209

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8je short M01_L01cmprdx,[r8]je short M01_L00movr10,offset MT_System.Object[]cmp[rcx],r10jne short M01_L03M01_L00:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L01:xorecx,ecxmov[rax],rcxaddrsp,28retM01_L02:call CORINFO_HELP_RNGCHKFAILM01_L03:movrcx,raxaddrsp,28jmp qword ptr [7FFB68CD4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object); Total bytes of code 92
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC7912090]movrdx,[rax+0B48]movr8,[rsi]addrdx,10movrax,r8rolrax,20xorrax,rbxmovr10,9E3779B97F4A7C15imulrax,r10movecx,[rdx]shrrax,clxorecx,ecxM02_L00:lear10d,[rax+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,r8jne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddeax,ecxandeax,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC792CD88]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rdimovrdx,rbxmovr8,rsicall qword ptr [7FFBC792CDC8]; Precode of System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 186

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8je short M01_L01cmprdx,[r8]je short M01_L00movr10,offset MT_System.Object[]cmp[rcx],r10jne short M01_L03M01_L00:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L01:xorecx,ecxmov[rax],rcxaddrsp,28retM01_L02:call qword ptr [7FFB68CA4450]int3M01_L03:movrcx,raxaddrsp,28jmp qword ptr [7FFB68CA44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object); Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC8661840]movrdx,[rax+0B50]movrax,[rsi]addrdx,10movr8,raxrolr8,20xorr8,rbxmovr10,9E3779B97F4A7C15imulr8,r10movecx,[rdx]shrr8,clxorecx,ecxM02_L00:lear10d,[r8+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddr8d,ecxandr8d,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC867A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rbxmovrdx,rsicall qword ptr [7FFBC867A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M02_L04movrcx,rdimovrdx,raxcall qword ptr [7FFBC867A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L04:call qword ptr [7FFBC867A2E0]int3; Total bytes of code 209

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L00learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8je short M01_L02cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CD4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L00:call CORINFO_HELP_RNGCHKFAILM01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:xorecx,ecxmov[rax],rcxaddrsp,28ret; Total bytes of code 92
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrax,25A67800B80movrax,[rax]movr10,[r8]addrax,10rorxr9,r10,20xorr9,rdxmovr11,9E3779B97F4A7C15imulr9,r11movr11d,[rax]shrxr9,r9,r11xorr11d,r11dM02_L00:leaebx,[r9+1]movsxdrbx,ebxlearbx,[rbx+rbx*2]learbx,[rax+rbx*8]movesi,[rbx]movrdi,[rbx+8]andesi,0FFFFFFFEcmprdi,r10jne short M02_L01movrdi,rdxxorrdi,[rbx+10]cmprdi,1jbe short M02_L02M02_L01:testesi,esije short M02_L03incr11daddr9d,r11dandr9d,[rax+4]cmpr11d,8jl short M02_L00jmp short M02_L03M02_L02:cmpesi,[rbx]jne short M02_L03cmpedi,1jne short M02_L03movrdx,r8call System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:call qword ptr [7FFB68CD44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 166
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrsi,rcxmovrdi,rdxmovrbx,r8testrbx,rbxjne short M03_L00movrcx,[7FFBC79636C8]movrdx,[rcx]movrcx,rdxcall qword ptr [7FFBC79300B8]M03_L00:movrcx,rdimovrdx,rbxcall qword ptr [7FFBC792CD68]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)movrbx,raxtestrbx,rbxje short M03_L01movrdx,rbxmovrcx,rsilearax,[7FFBC792CD90]addrsp,20poprbxpoprsipoprdijmp qword ptr [rax]M03_L01:call qword ptr [7FFBC791B5E8]movrbx,raxmovrcx,rbxcall qword ptr [7FFBC7924598]movrcx,rbxcall qword ptr [7FFBC7911760]; CORINFO_HELP_THROWint3; Total bytes of code 111

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L00learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8je short M01_L02cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CC44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L00:call qword ptr [7FFB68CC4450]int3M01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:xorecx,ecxmov[rax],rcxaddrsp,28ret; Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrax,21C53C00B88movrax,[rax]movr10,[r8]addrax,10rorxr9,r10,20xorr9,rdxmovr11,9E3779B97F4A7C15imulr9,r11movr11d,[rax]shrxr9,r9,r11xorr11d,r11dM02_L00:leaebx,[r9+1]movsxdrbx,ebxlearbx,[rbx+rbx*2]learbx,[rax+rbx*8]movesi,[rbx]movrdi,[rbx+8]andesi,0FFFFFFFEcmprdi,r10jne short M02_L01movrdi,rdxxorrdi,[rbx+10]cmprdi,1jbe short M02_L02M02_L01:testesi,esije short M02_L03incr11daddr9d,r11dandr9d,[rax+4]cmpr11d,8jl short M02_L00jmp short M02_L03M02_L02:cmpesi,[rbx]jne short M02_L03cmpedi,1jne short M02_L03movrdx,r8call System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:call qword ptr [7FFB68CC44C8]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 166
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrbxsubrsp,20movrbx,rcxmovrax,r8movrcx,rdxmovrdx,raxcall qword ptr [7FFBC867A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M03_L00movrdx,raxmovrcx,rbxlearax,[7FFBC867A2B0]addrsp,20poprbxjmp qword ptr [rax]M03_L00:call qword ptr [7FFBC867A2E0]int3; Total bytes of code 56

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax+rax]M00_L00:learcx,[rsi+rdi*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 60

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax+rax]M00_L00:learcx,[rsi+rdi*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 60

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxmovrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax]nop dword ptr [rax+rax]M00_L00:movecx,edilearcx,[rsi+rcx*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:poprbxpoprbppoprsipoprdiret; Total bytes of code 58

@jkotas

jkotas commented Mar 20, 2024

Copy link
Copy Markdown
Member

I agree that the cold blocks ordering with PGO can be better in some case. I do not see any material code difference caused by this change. The exact code for these helpers can differ from workload to workload and from run to run depending on how PGO rolls the dice.

I have pushed a commit with a minor cleanup as I was looking at the code.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-VM-coreclrcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@MichalPetryka@jkotas@huoyaoyuan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Remove invalid Unsafe.As from array helpers - #99778

Merged
jkotas merged 15 commits into
dotnet:mainfrom
MichalPetryka:patch-32
Mar 21, 2024
Merged

Remove invalid Unsafe.As from array helpers#99778
jkotas merged 15 commits into
dotnet:mainfrom
MichalPetryka:patch-32

Conversation

@MichalPetryka

Copy link
Copy Markdown
Contributor

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

Causes almost no diffs outside of calling a managed throw helper now.

@ghostghost added the area-VM-coreclr label Mar 14, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Mar 14, 2024
@jkotas

Copy link
Copy Markdown
Member

publicstaticunsafevoidStelemRef(Arrayarray,nintindex,objectobj)
has clone of this code with the same potential issue.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

has clone of this code

What's the INPLACE_RUNTIME stuff there? Is it related to some old multimodule mode? (I'll change that file tomorrow)

@jkotas

Copy link
Copy Markdown
Member

What's the INPLACE_RUNTIME stuff there? Is it related to some old multimodule mode? (I'll change that file tomorrow)

I think we build INPLACE_RUNTIME defined everywhere currently. !INPLACE_RUNTIME was a build configuration in ProjectN where the GC and the lowest level of the runtime (including these helpers) were build as a separate library that can be used by multiple higher-level runtimes all running in the same process.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

I think we build INPLACE_RUNTIME defined everywhere currently. !INPLACE_RUNTIME was a build configuration in ProjectN where the GC and the lowest level of the runtime (including these helpers) were build as a separate library that can be used by multiple higher-level runtimes all running in the same process.

Do we want to cleanup the code then and remove those paths later (and keep it as is for now)? Or should I also change the !INPLACE_RUNTIME path?

@jkotas

Copy link
Copy Markdown
Member

Do we want to cleanup the code then and remove those paths later (and keep it as is for now)? Or should I also change the !INPLACE_RUNTIME path?

Any of these options is fine with me.

@jkotas

Copy link
Copy Markdown
Member

Is the code for helper same or better with this change?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Is the code for helper same or better with this change?

The codegen for normal path is almost the same (the operands for cmp are swapped but that doesn't matter).
The cold throw path is a bit bigger cause it calls the managed throw helper instead of the native one:

 G_M56901_IG04:
- call CORINFO_HELP_RNGCHKFAIL- ;; size=5 bbWeight=0 PerfScore 0.00-G_M56901_IG05:
mov rax, 0xD1FFAB1E ; code for System.Runtime.CompilerServices.CastHelpers:ThrowArrayMismatchException():byref
call [rax]System.Runtime.CompilerServices.CastHelpers:ThrowArrayMismatchException():byref
+ ;; size=12 bbWeight=0 PerfScore 0.00+G_M56901_IG05:+ mov rax, 0xD1FFAB1E ; code for System.Runtime.CompilerServices.CastHelpers:ThrowIndexOutOfRangeException()+ call [rax]System.Runtime.CompilerServices.CastHelpers:ThrowIndexOutOfRangeException()
int3 ;; size=13 bbWeight=0 PerfScore 0.00

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas Do you know what's going on with the CI refusing to run pipelines on PRs as of recently?

@jkotas

Copy link
Copy Markdown
Member

Do you know what's going on with the CI refusing to run pipelines on PRs as of recently?

Yes, it is broken. The people responsible for our eng system are not on-call during the weekend, so it may take till Monday to resolve.

It actually runs them, just the github status is not updating. For example, here is the pipeline link for this PR
https://dev.azure.com/dnceng-public/public/_build/results?buildId=605885&view=results

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot


#if INPLACE_RUNTIME
if ((nuint)index >= (uint)array.Length)
ThrowIndexOutOfRangeException(array);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can just use ThrowHelper.ThrowIndexOutOfRangeException given that is for INPLACE_RUNTIME. It is unnecessary to go through GetClasslibException indirection for INPLACE_RUNTIME. The main point of INPLACE_RUNTIME is to avoid these indirections.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to remove the !INPLACE_RUNTIME code in the next PR and to keep this like earlier for now.
Also I think that ThrowHelper is not in the Test.CoreLib (not sure what that is for tbh but right now there's a build failure here due to MemoryMarshal not being there too).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test.CoreLib is very minimal implementation of CoreLib for testing, debugging and various experiments. It is fine to add minimal implementations of MemoryMarshal or ThrowHelper to it to keep it working.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

Comment threadsrc/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

Comment threadsrc/coreclr/vm/metasig.h Outdated
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas This caused StelemRef_Helper to not be inlined into StelemRef anymore but now StelemRef_Helper_NoCacheLookup started being inlined into it, should I bring the previous behaviour back with AggressiveInlining and NoInlining?

@jkotas

Copy link
Copy Markdown
Member

Does it affect performance of any of the fast paths?

This caused StelemRef_Helper to not be inlined into StelemRef anymore

StelemRef_Helper is marked with [MethodImpl(MethodImplOptions.NoInlining)] both before and after this change. I do not see how StelemRef_Helper could have been ever inlined.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

StelemRef_Helper is marked with [MethodImpl(MethodImplOptions.NoInlining)] both before and after this change. I do not see how StelemRef_Helper could have been ever inlined.

Ah wait nevermind, I've accidentally diffed StelemRef_Helper with StelemRef.

The non cached one being inlined is the only difference now then: MihuBot/runtime-utils#332 (comment)

@huoyaoyuan

Copy link
Copy Markdown
Member

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

I wonder what the problem would be. Is there any context?

@jkotas

Copy link
Copy Markdown
Member

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

I wonder what the problem would be. Is there any context?

Unsafe.As used by the helper code today is undefined behavior. In theory, it can interact poorly with other JIT optimizations and produce bad code. See discussion in #87374 for more details.

@jkotas

Copy link
Copy Markdown
Member

Does it affect performance of any of the fast paths?

@MichalPetryka Did you have a chance to check the perf impact of these changes?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Did you have a chance to check the perf impact of these changes?

I'll do so today.

@MichalPetryka

MichalPetryka commented Mar 19, 2024

Copy link
Copy Markdown
ContributorAuthor

BenchmarkDotNet v0.13.12, Windows 10 (10.0.19045.4170/22H2/2022Update)
AMD Ryzen 9 7900X, 1 CPU, 24 logical and 12 physical cores
.NET SDK 8.0.200
[Host] : .NET 8.0.2 (8.0.224.6711), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-JUCZRX : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-NEFMBN : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
.NET 8.0 : .NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Runtime=.NET 8.0 
MethodJobToolchainsMeanErrorStdDevRatioRatioSDCode SizeAllocatedAlloc Ratio
WriteNullJob-JUCZRXmain?29.33 ns0.076 ns0.067 ns1.000.00480 B-NA
WriteNullJob-NEFMBNpr?34.87 ns0.070 ns0.062 ns1.190.00356 B-NA
WriteNull.NET 8.0Default?34.56 ns0.135 ns0.127 ns1.180.0053 B-NA
WriteToObjectJob-JUCZRXmain63.41 ns0.330 ns0.292 ns1.000.00331 B-NA
WriteToObjectJob-NEFMBNpr57.73 ns0.282 ns0.264 ns0.910.01356 B-NA
WriteToObject.NET 8.0Default63.91 ns0.558 ns0.494 ns1.010.0153 B-NA
WriteToInterfaceJob-JUCZRXmain117.00 ns0.711 ns0.630 ns1.000.00422 B-NA
WriteToInterfaceJob-NEFMBNpr88.45 ns1.282 ns1.425 ns0.750.01369 B-NA
WriteToInterface.NET 8.0Default93.90 ns0.541 ns0.480 ns0.800.0153 B-NA
WriteToTypeJob-JUCZRXmain41.50 ns0.684 ns0.640 ns1.000.0060 B-NA
WriteToTypeJob-NEFMBNpr40.00 ns0.070 ns0.058 ns0.960.0260 B-NA
WriteToType.NET 8.0Default39.99 ns0.062 ns0.048 ns0.960.0258 B-NA

@jkotas I've benchmarked with string, the paths for value seem to be better but the test with null seems to confuse PGO and have it place the null path in the slow code behind the throw helper now. Not sure if this can be fixed without JIT changes, the JIT should probably assume that throw helpers are always colder than cold paths.

Full codegen:

Details

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8jne short M01_L00xorecx,ecxmov[rax],rcxaddrsp,28retM01_L00:cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CB4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:call CORINFO_HELP_RNGCHKFAILint3; Total bytes of code 93
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8movrcx,290F9800B80movrcx,[rcx]movrax,[rsi]addrcx,10rorxrdx,rax,20xorrdx,rbxmovr8,9E3779B97F4A7C15imulrdx,r8movr8d,[rcx]shrxrdx,rdx,r8xorr8d,r8dM02_L00:lear10d,[rdx+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rcx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incr8daddedx,r8dandedx,[rcx+4]cmpr8d,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,7FFB69DC54C8call CORINFO_HELP_COUNTPROFILE32movrcx,rdimovrdx,rsicall System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,7FFB69DC54CCcall CORINFO_HELP_COUNTPROFILE32movrcx,rdimovrdx,rbxmovr8,rsicall qword ptr [7FFB68CB44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 221
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrsi,rcxmovrdi,rdxmovrbx,r8testrbx,rbxjne short M03_L00movrdx,2D18E150008movrcx,rdxcall qword ptr [7FFB68D1D3B0]M03_L00:movrcx,rdimovrdx,rbxcall System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)movrbx,raxtestrbx,rbxje short M03_L01movrcx,rsimovrdx,rbxaddrsp,20poprbxpoprsipoprdijmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M03_L01:movrcx,offset MT_System.ArrayTypeMismatchExceptioncall CORINFO_HELP_NEWSFASTmovrbx,raxmovrcx,rbxcall qword ptr [7FFB69827C78]movrcx,rbxcall CORINFO_HELP_THROWint3; Total bytes of code 113

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L01learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8jne short M01_L02xorecx,ecxmov[rax],rcxaddrsp,28retM01_L00:movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L03movrcx,raxaddrsp,28jmp qword ptr [7FFB6BDB44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L01:call qword ptr [7FFB6BDB4450]int3M01_L02:cmprdx,[r8]jne short M01_L00M01_L03:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object); Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC8B31840]movrdx,[rax+0B50]movrax,[rsi]addrdx,10movr8,raxrolr8,20xorr8,rbxmovr10,9E3779B97F4A7C15imulr8,r10movecx,[rdx]shrr8,clxorecx,ecxM02_L00:lear10d,[r8+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddr8d,ecxandr8d,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC8B4A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rbxmovrdx,rsicall qword ptr [7FFBC8B4A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M02_L04movrcx,rdimovrdx,raxcall qword ptr [7FFBC8B4A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L04:call qword ptr [7FFBC8B4A2E0]int3; Total bytes of code 209

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8je short M01_L01cmprdx,[r8]je short M01_L00movr10,offset MT_System.Object[]cmp[rcx],r10jne short M01_L03M01_L00:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L01:xorecx,ecxmov[rax],rcxaddrsp,28retM01_L02:call CORINFO_HELP_RNGCHKFAILM01_L03:movrcx,raxaddrsp,28jmp qword ptr [7FFB68CD4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object); Total bytes of code 92
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC7912090]movrdx,[rax+0B48]movr8,[rsi]addrdx,10movrax,r8rolrax,20xorrax,rbxmovr10,9E3779B97F4A7C15imulrax,r10movecx,[rdx]shrrax,clxorecx,ecxM02_L00:lear10d,[rax+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,r8jne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddeax,ecxandeax,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC792CD88]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rdimovrdx,rbxmovr8,rsicall qword ptr [7FFBC792CDC8]; Precode of System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 186

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8je short M01_L01cmprdx,[r8]je short M01_L00movr10,offset MT_System.Object[]cmp[rcx],r10jne short M01_L03M01_L00:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L01:xorecx,ecxmov[rax],rcxaddrsp,28retM01_L02:call qword ptr [7FFB68CA4450]int3M01_L03:movrcx,raxaddrsp,28jmp qword ptr [7FFB68CA44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object); Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC8661840]movrdx,[rax+0B50]movrax,[rsi]addrdx,10movr8,raxrolr8,20xorr8,rbxmovr10,9E3779B97F4A7C15imulr8,r10movecx,[rdx]shrr8,clxorecx,ecxM02_L00:lear10d,[r8+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddr8d,ecxandr8d,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC867A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rbxmovrdx,rsicall qword ptr [7FFBC867A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M02_L04movrcx,rdimovrdx,raxcall qword ptr [7FFBC867A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L04:call qword ptr [7FFBC867A2E0]int3; Total bytes of code 209

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L00learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8je short M01_L02cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CD4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L00:call CORINFO_HELP_RNGCHKFAILM01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:xorecx,ecxmov[rax],rcxaddrsp,28ret; Total bytes of code 92
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrax,25A67800B80movrax,[rax]movr10,[r8]addrax,10rorxr9,r10,20xorr9,rdxmovr11,9E3779B97F4A7C15imulr9,r11movr11d,[rax]shrxr9,r9,r11xorr11d,r11dM02_L00:leaebx,[r9+1]movsxdrbx,ebxlearbx,[rbx+rbx*2]learbx,[rax+rbx*8]movesi,[rbx]movrdi,[rbx+8]andesi,0FFFFFFFEcmprdi,r10jne short M02_L01movrdi,rdxxorrdi,[rbx+10]cmprdi,1jbe short M02_L02M02_L01:testesi,esije short M02_L03incr11daddr9d,r11dandr9d,[rax+4]cmpr11d,8jl short M02_L00jmp short M02_L03M02_L02:cmpesi,[rbx]jne short M02_L03cmpedi,1jne short M02_L03movrdx,r8call System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:call qword ptr [7FFB68CD44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 166
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrsi,rcxmovrdi,rdxmovrbx,r8testrbx,rbxjne short M03_L00movrcx,[7FFBC79636C8]movrdx,[rcx]movrcx,rdxcall qword ptr [7FFBC79300B8]M03_L00:movrcx,rdimovrdx,rbxcall qword ptr [7FFBC792CD68]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)movrbx,raxtestrbx,rbxje short M03_L01movrdx,rbxmovrcx,rsilearax,[7FFBC792CD90]addrsp,20poprbxpoprsipoprdijmp qword ptr [rax]M03_L01:call qword ptr [7FFBC791B5E8]movrbx,raxmovrcx,rbxcall qword ptr [7FFBC7924598]movrcx,rbxcall qword ptr [7FFBC7911760]; CORINFO_HELP_THROWint3; Total bytes of code 111

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L00learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8je short M01_L02cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CC44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L00:call qword ptr [7FFB68CC4450]int3M01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:xorecx,ecxmov[rax],rcxaddrsp,28ret; Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrax,21C53C00B88movrax,[rax]movr10,[r8]addrax,10rorxr9,r10,20xorr9,rdxmovr11,9E3779B97F4A7C15imulr9,r11movr11d,[rax]shrxr9,r9,r11xorr11d,r11dM02_L00:leaebx,[r9+1]movsxdrbx,ebxlearbx,[rbx+rbx*2]learbx,[rax+rbx*8]movesi,[rbx]movrdi,[rbx+8]andesi,0FFFFFFFEcmprdi,r10jne short M02_L01movrdi,rdxxorrdi,[rbx+10]cmprdi,1jbe short M02_L02M02_L01:testesi,esije short M02_L03incr11daddr9d,r11dandr9d,[rax+4]cmpr11d,8jl short M02_L00jmp short M02_L03M02_L02:cmpesi,[rbx]jne short M02_L03cmpedi,1jne short M02_L03movrdx,r8call System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:call qword ptr [7FFB68CC44C8]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 166
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrbxsubrsp,20movrbx,rcxmovrax,r8movrcx,rdxmovrdx,raxcall qword ptr [7FFBC867A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M03_L00movrdx,raxmovrcx,rbxlearax,[7FFBC867A2B0]addrsp,20poprbxjmp qword ptr [rax]M03_L00:call qword ptr [7FFBC867A2E0]int3; Total bytes of code 56

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax+rax]M00_L00:learcx,[rsi+rdi*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 60

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax+rax]M00_L00:learcx,[rsi+rdi*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 60

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxmovrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax]nop dword ptr [rax+rax]M00_L00:movecx,edilearcx,[rsi+rcx*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:poprbxpoprbppoprsipoprdiret; Total bytes of code 58

@jkotas

jkotas commented Mar 20, 2024

Copy link
Copy Markdown
Member

I agree that the cold blocks ordering with PGO can be better in some case. I do not see any material code difference caused by this change. The exact code for these helpers can differ from workload to workload and from run to run depending on how PGO rolls the dice.

I have pushed a commit with a minor cleanup as I was looking at the code.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-VM-coreclrcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@MichalPetryka@jkotas@huoyaoyuan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Remove invalid Unsafe.As from array helpers - #99778

Merged
jkotas merged 15 commits into
dotnet:mainfrom
MichalPetryka:patch-32
Mar 21, 2024
Merged

Remove invalid Unsafe.As from array helpers#99778
jkotas merged 15 commits into
dotnet:mainfrom
MichalPetryka:patch-32

Conversation

@MichalPetryka

Copy link
Copy Markdown
Contributor

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

Causes almost no diffs outside of calling a managed throw helper now.

@ghostghost added the area-VM-coreclr label Mar 14, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Mar 14, 2024
@jkotas

Copy link
Copy Markdown
Member

publicstaticunsafevoidStelemRef(Arrayarray,nintindex,objectobj)
has clone of this code with the same potential issue.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

has clone of this code

What's the INPLACE_RUNTIME stuff there? Is it related to some old multimodule mode? (I'll change that file tomorrow)

@jkotas

Copy link
Copy Markdown
Member

What's the INPLACE_RUNTIME stuff there? Is it related to some old multimodule mode? (I'll change that file tomorrow)

I think we build INPLACE_RUNTIME defined everywhere currently. !INPLACE_RUNTIME was a build configuration in ProjectN where the GC and the lowest level of the runtime (including these helpers) were build as a separate library that can be used by multiple higher-level runtimes all running in the same process.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

I think we build INPLACE_RUNTIME defined everywhere currently. !INPLACE_RUNTIME was a build configuration in ProjectN where the GC and the lowest level of the runtime (including these helpers) were build as a separate library that can be used by multiple higher-level runtimes all running in the same process.

Do we want to cleanup the code then and remove those paths later (and keep it as is for now)? Or should I also change the !INPLACE_RUNTIME path?

@jkotas

Copy link
Copy Markdown
Member

Do we want to cleanup the code then and remove those paths later (and keep it as is for now)? Or should I also change the !INPLACE_RUNTIME path?

Any of these options is fine with me.

@jkotas

Copy link
Copy Markdown
Member

Is the code for helper same or better with this change?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Is the code for helper same or better with this change?

The codegen for normal path is almost the same (the operands for cmp are swapped but that doesn't matter).
The cold throw path is a bit bigger cause it calls the managed throw helper instead of the native one:

 G_M56901_IG04:
- call CORINFO_HELP_RNGCHKFAIL- ;; size=5 bbWeight=0 PerfScore 0.00-G_M56901_IG05:
mov rax, 0xD1FFAB1E ; code for System.Runtime.CompilerServices.CastHelpers:ThrowArrayMismatchException():byref
call [rax]System.Runtime.CompilerServices.CastHelpers:ThrowArrayMismatchException():byref
+ ;; size=12 bbWeight=0 PerfScore 0.00+G_M56901_IG05:+ mov rax, 0xD1FFAB1E ; code for System.Runtime.CompilerServices.CastHelpers:ThrowIndexOutOfRangeException()+ call [rax]System.Runtime.CompilerServices.CastHelpers:ThrowIndexOutOfRangeException()
int3 ;; size=13 bbWeight=0 PerfScore 0.00

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas Do you know what's going on with the CI refusing to run pipelines on PRs as of recently?

@jkotas

Copy link
Copy Markdown
Member

Do you know what's going on with the CI refusing to run pipelines on PRs as of recently?

Yes, it is broken. The people responsible for our eng system are not on-call during the weekend, so it may take till Monday to resolve.

It actually runs them, just the github status is not updating. For example, here is the pipeline link for this PR
https://dev.azure.com/dnceng-public/public/_build/results?buildId=605885&view=results

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot


#if INPLACE_RUNTIME
if ((nuint)index >= (uint)array.Length)
ThrowIndexOutOfRangeException(array);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can just use ThrowHelper.ThrowIndexOutOfRangeException given that is for INPLACE_RUNTIME. It is unnecessary to go through GetClasslibException indirection for INPLACE_RUNTIME. The main point of INPLACE_RUNTIME is to avoid these indirections.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to remove the !INPLACE_RUNTIME code in the next PR and to keep this like earlier for now.
Also I think that ThrowHelper is not in the Test.CoreLib (not sure what that is for tbh but right now there's a build failure here due to MemoryMarshal not being there too).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test.CoreLib is very minimal implementation of CoreLib for testing, debugging and various experiments. It is fine to add minimal implementations of MemoryMarshal or ThrowHelper to it to keep it working.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

Comment threadsrc/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

Comment threadsrc/coreclr/vm/metasig.h Outdated
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas This caused StelemRef_Helper to not be inlined into StelemRef anymore but now StelemRef_Helper_NoCacheLookup started being inlined into it, should I bring the previous behaviour back with AggressiveInlining and NoInlining?

@jkotas

Copy link
Copy Markdown
Member

Does it affect performance of any of the fast paths?

This caused StelemRef_Helper to not be inlined into StelemRef anymore

StelemRef_Helper is marked with [MethodImpl(MethodImplOptions.NoInlining)] both before and after this change. I do not see how StelemRef_Helper could have been ever inlined.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

StelemRef_Helper is marked with [MethodImpl(MethodImplOptions.NoInlining)] both before and after this change. I do not see how StelemRef_Helper could have been ever inlined.

Ah wait nevermind, I've accidentally diffed StelemRef_Helper with StelemRef.

The non cached one being inlined is the only difference now then: MihuBot/runtime-utils#332 (comment)

@huoyaoyuan

Copy link
Copy Markdown
Member

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

I wonder what the problem would be. Is there any context?

@jkotas

Copy link
Copy Markdown
Member

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

I wonder what the problem would be. Is there any context?

Unsafe.As used by the helper code today is undefined behavior. In theory, it can interact poorly with other JIT optimizations and produce bad code. See discussion in #87374 for more details.

@jkotas

Copy link
Copy Markdown
Member

Does it affect performance of any of the fast paths?

@MichalPetryka Did you have a chance to check the perf impact of these changes?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Did you have a chance to check the perf impact of these changes?

I'll do so today.

@MichalPetryka

MichalPetryka commented Mar 19, 2024

Copy link
Copy Markdown
ContributorAuthor

BenchmarkDotNet v0.13.12, Windows 10 (10.0.19045.4170/22H2/2022Update)
AMD Ryzen 9 7900X, 1 CPU, 24 logical and 12 physical cores
.NET SDK 8.0.200
[Host] : .NET 8.0.2 (8.0.224.6711), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-JUCZRX : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-NEFMBN : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
.NET 8.0 : .NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Runtime=.NET 8.0 
MethodJobToolchainsMeanErrorStdDevRatioRatioSDCode SizeAllocatedAlloc Ratio
WriteNullJob-JUCZRXmain?29.33 ns0.076 ns0.067 ns1.000.00480 B-NA
WriteNullJob-NEFMBNpr?34.87 ns0.070 ns0.062 ns1.190.00356 B-NA
WriteNull.NET 8.0Default?34.56 ns0.135 ns0.127 ns1.180.0053 B-NA
WriteToObjectJob-JUCZRXmain63.41 ns0.330 ns0.292 ns1.000.00331 B-NA
WriteToObjectJob-NEFMBNpr57.73 ns0.282 ns0.264 ns0.910.01356 B-NA
WriteToObject.NET 8.0Default63.91 ns0.558 ns0.494 ns1.010.0153 B-NA
WriteToInterfaceJob-JUCZRXmain117.00 ns0.711 ns0.630 ns1.000.00422 B-NA
WriteToInterfaceJob-NEFMBNpr88.45 ns1.282 ns1.425 ns0.750.01369 B-NA
WriteToInterface.NET 8.0Default93.90 ns0.541 ns0.480 ns0.800.0153 B-NA
WriteToTypeJob-JUCZRXmain41.50 ns0.684 ns0.640 ns1.000.0060 B-NA
WriteToTypeJob-NEFMBNpr40.00 ns0.070 ns0.058 ns0.960.0260 B-NA
WriteToType.NET 8.0Default39.99 ns0.062 ns0.048 ns0.960.0258 B-NA

@jkotas I've benchmarked with string, the paths for value seem to be better but the test with null seems to confuse PGO and have it place the null path in the slow code behind the throw helper now. Not sure if this can be fixed without JIT changes, the JIT should probably assume that throw helpers are always colder than cold paths.

Full codegen:

Details

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8jne short M01_L00xorecx,ecxmov[rax],rcxaddrsp,28retM01_L00:cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CB4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:call CORINFO_HELP_RNGCHKFAILint3; Total bytes of code 93
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8movrcx,290F9800B80movrcx,[rcx]movrax,[rsi]addrcx,10rorxrdx,rax,20xorrdx,rbxmovr8,9E3779B97F4A7C15imulrdx,r8movr8d,[rcx]shrxrdx,rdx,r8xorr8d,r8dM02_L00:lear10d,[rdx+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rcx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incr8daddedx,r8dandedx,[rcx+4]cmpr8d,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,7FFB69DC54C8call CORINFO_HELP_COUNTPROFILE32movrcx,rdimovrdx,rsicall System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,7FFB69DC54CCcall CORINFO_HELP_COUNTPROFILE32movrcx,rdimovrdx,rbxmovr8,rsicall qword ptr [7FFB68CB44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 221
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrsi,rcxmovrdi,rdxmovrbx,r8testrbx,rbxjne short M03_L00movrdx,2D18E150008movrcx,rdxcall qword ptr [7FFB68D1D3B0]M03_L00:movrcx,rdimovrdx,rbxcall System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)movrbx,raxtestrbx,rbxje short M03_L01movrcx,rsimovrdx,rbxaddrsp,20poprbxpoprsipoprdijmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M03_L01:movrcx,offset MT_System.ArrayTypeMismatchExceptioncall CORINFO_HELP_NEWSFASTmovrbx,raxmovrcx,rbxcall qword ptr [7FFB69827C78]movrcx,rbxcall CORINFO_HELP_THROWint3; Total bytes of code 113

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L01learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8jne short M01_L02xorecx,ecxmov[rax],rcxaddrsp,28retM01_L00:movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L03movrcx,raxaddrsp,28jmp qword ptr [7FFB6BDB44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L01:call qword ptr [7FFB6BDB4450]int3M01_L02:cmprdx,[r8]jne short M01_L00M01_L03:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object); Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC8B31840]movrdx,[rax+0B50]movrax,[rsi]addrdx,10movr8,raxrolr8,20xorr8,rbxmovr10,9E3779B97F4A7C15imulr8,r10movecx,[rdx]shrr8,clxorecx,ecxM02_L00:lear10d,[r8+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddr8d,ecxandr8d,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC8B4A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rbxmovrdx,rsicall qword ptr [7FFBC8B4A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M02_L04movrcx,rdimovrdx,raxcall qword ptr [7FFBC8B4A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L04:call qword ptr [7FFBC8B4A2E0]int3; Total bytes of code 209

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8je short M01_L01cmprdx,[r8]je short M01_L00movr10,offset MT_System.Object[]cmp[rcx],r10jne short M01_L03M01_L00:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L01:xorecx,ecxmov[rax],rcxaddrsp,28retM01_L02:call CORINFO_HELP_RNGCHKFAILM01_L03:movrcx,raxaddrsp,28jmp qword ptr [7FFB68CD4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object); Total bytes of code 92
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC7912090]movrdx,[rax+0B48]movr8,[rsi]addrdx,10movrax,r8rolrax,20xorrax,rbxmovr10,9E3779B97F4A7C15imulrax,r10movecx,[rdx]shrrax,clxorecx,ecxM02_L00:lear10d,[rax+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,r8jne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddeax,ecxandeax,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC792CD88]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rdimovrdx,rbxmovr8,rsicall qword ptr [7FFBC792CDC8]; Precode of System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 186

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8je short M01_L01cmprdx,[r8]je short M01_L00movr10,offset MT_System.Object[]cmp[rcx],r10jne short M01_L03M01_L00:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L01:xorecx,ecxmov[rax],rcxaddrsp,28retM01_L02:call qword ptr [7FFB68CA4450]int3M01_L03:movrcx,raxaddrsp,28jmp qword ptr [7FFB68CA44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object); Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC8661840]movrdx,[rax+0B50]movrax,[rsi]addrdx,10movr8,raxrolr8,20xorr8,rbxmovr10,9E3779B97F4A7C15imulr8,r10movecx,[rdx]shrr8,clxorecx,ecxM02_L00:lear10d,[r8+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddr8d,ecxandr8d,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC867A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rbxmovrdx,rsicall qword ptr [7FFBC867A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M02_L04movrcx,rdimovrdx,raxcall qword ptr [7FFBC867A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L04:call qword ptr [7FFBC867A2E0]int3; Total bytes of code 209

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L00learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8je short M01_L02cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CD4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L00:call CORINFO_HELP_RNGCHKFAILM01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:xorecx,ecxmov[rax],rcxaddrsp,28ret; Total bytes of code 92
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrax,25A67800B80movrax,[rax]movr10,[r8]addrax,10rorxr9,r10,20xorr9,rdxmovr11,9E3779B97F4A7C15imulr9,r11movr11d,[rax]shrxr9,r9,r11xorr11d,r11dM02_L00:leaebx,[r9+1]movsxdrbx,ebxlearbx,[rbx+rbx*2]learbx,[rax+rbx*8]movesi,[rbx]movrdi,[rbx+8]andesi,0FFFFFFFEcmprdi,r10jne short M02_L01movrdi,rdxxorrdi,[rbx+10]cmprdi,1jbe short M02_L02M02_L01:testesi,esije short M02_L03incr11daddr9d,r11dandr9d,[rax+4]cmpr11d,8jl short M02_L00jmp short M02_L03M02_L02:cmpesi,[rbx]jne short M02_L03cmpedi,1jne short M02_L03movrdx,r8call System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:call qword ptr [7FFB68CD44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 166
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrsi,rcxmovrdi,rdxmovrbx,r8testrbx,rbxjne short M03_L00movrcx,[7FFBC79636C8]movrdx,[rcx]movrcx,rdxcall qword ptr [7FFBC79300B8]M03_L00:movrcx,rdimovrdx,rbxcall qword ptr [7FFBC792CD68]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)movrbx,raxtestrbx,rbxje short M03_L01movrdx,rbxmovrcx,rsilearax,[7FFBC792CD90]addrsp,20poprbxpoprsipoprdijmp qword ptr [rax]M03_L01:call qword ptr [7FFBC791B5E8]movrbx,raxmovrcx,rbxcall qword ptr [7FFBC7924598]movrcx,rbxcall qword ptr [7FFBC7911760]; CORINFO_HELP_THROWint3; Total bytes of code 111

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L00learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8je short M01_L02cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CC44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L00:call qword ptr [7FFB68CC4450]int3M01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:xorecx,ecxmov[rax],rcxaddrsp,28ret; Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrax,21C53C00B88movrax,[rax]movr10,[r8]addrax,10rorxr9,r10,20xorr9,rdxmovr11,9E3779B97F4A7C15imulr9,r11movr11d,[rax]shrxr9,r9,r11xorr11d,r11dM02_L00:leaebx,[r9+1]movsxdrbx,ebxlearbx,[rbx+rbx*2]learbx,[rax+rbx*8]movesi,[rbx]movrdi,[rbx+8]andesi,0FFFFFFFEcmprdi,r10jne short M02_L01movrdi,rdxxorrdi,[rbx+10]cmprdi,1jbe short M02_L02M02_L01:testesi,esije short M02_L03incr11daddr9d,r11dandr9d,[rax+4]cmpr11d,8jl short M02_L00jmp short M02_L03M02_L02:cmpesi,[rbx]jne short M02_L03cmpedi,1jne short M02_L03movrdx,r8call System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:call qword ptr [7FFB68CC44C8]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 166
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrbxsubrsp,20movrbx,rcxmovrax,r8movrcx,rdxmovrdx,raxcall qword ptr [7FFBC867A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M03_L00movrdx,raxmovrcx,rbxlearax,[7FFBC867A2B0]addrsp,20poprbxjmp qword ptr [rax]M03_L00:call qword ptr [7FFBC867A2E0]int3; Total bytes of code 56

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax+rax]M00_L00:learcx,[rsi+rdi*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 60

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax+rax]M00_L00:learcx,[rsi+rdi*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 60

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxmovrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax]nop dword ptr [rax+rax]M00_L00:movecx,edilearcx,[rsi+rcx*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:poprbxpoprbppoprsipoprdiret; Total bytes of code 58

@jkotas

jkotas commented Mar 20, 2024

Copy link
Copy Markdown
Member

I agree that the cold blocks ordering with PGO can be better in some case. I do not see any material code difference caused by this change. The exact code for these helpers can differ from workload to workload and from run to run depending on how PGO rolls the dice.

I have pushed a commit with a minor cleanup as I was looking at the code.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-VM-coreclrcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@MichalPetryka@jkotas@huoyaoyuan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Remove invalid Unsafe.As from array helpers - #99778

Merged
jkotas merged 15 commits into
dotnet:mainfrom
MichalPetryka:patch-32
Mar 21, 2024
Merged

Remove invalid Unsafe.As from array helpers#99778
jkotas merged 15 commits into
dotnet:mainfrom
MichalPetryka:patch-32

Conversation

@MichalPetryka

Copy link
Copy Markdown
Contributor

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

Causes almost no diffs outside of calling a managed throw helper now.

@ghostghost added the area-VM-coreclr label Mar 14, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Mar 14, 2024
@jkotas

Copy link
Copy Markdown
Member

publicstaticunsafevoidStelemRef(Arrayarray,nintindex,objectobj)
has clone of this code with the same potential issue.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

has clone of this code

What's the INPLACE_RUNTIME stuff there? Is it related to some old multimodule mode? (I'll change that file tomorrow)

@jkotas

Copy link
Copy Markdown
Member

What's the INPLACE_RUNTIME stuff there? Is it related to some old multimodule mode? (I'll change that file tomorrow)

I think we build INPLACE_RUNTIME defined everywhere currently. !INPLACE_RUNTIME was a build configuration in ProjectN where the GC and the lowest level of the runtime (including these helpers) were build as a separate library that can be used by multiple higher-level runtimes all running in the same process.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

I think we build INPLACE_RUNTIME defined everywhere currently. !INPLACE_RUNTIME was a build configuration in ProjectN where the GC and the lowest level of the runtime (including these helpers) were build as a separate library that can be used by multiple higher-level runtimes all running in the same process.

Do we want to cleanup the code then and remove those paths later (and keep it as is for now)? Or should I also change the !INPLACE_RUNTIME path?

@jkotas

Copy link
Copy Markdown
Member

Do we want to cleanup the code then and remove those paths later (and keep it as is for now)? Or should I also change the !INPLACE_RUNTIME path?

Any of these options is fine with me.

@jkotas

Copy link
Copy Markdown
Member

Is the code for helper same or better with this change?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Is the code for helper same or better with this change?

The codegen for normal path is almost the same (the operands for cmp are swapped but that doesn't matter).
The cold throw path is a bit bigger cause it calls the managed throw helper instead of the native one:

 G_M56901_IG04:
- call CORINFO_HELP_RNGCHKFAIL- ;; size=5 bbWeight=0 PerfScore 0.00-G_M56901_IG05:
mov rax, 0xD1FFAB1E ; code for System.Runtime.CompilerServices.CastHelpers:ThrowArrayMismatchException():byref
call [rax]System.Runtime.CompilerServices.CastHelpers:ThrowArrayMismatchException():byref
+ ;; size=12 bbWeight=0 PerfScore 0.00+G_M56901_IG05:+ mov rax, 0xD1FFAB1E ; code for System.Runtime.CompilerServices.CastHelpers:ThrowIndexOutOfRangeException()+ call [rax]System.Runtime.CompilerServices.CastHelpers:ThrowIndexOutOfRangeException()
int3 ;; size=13 bbWeight=0 PerfScore 0.00

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas Do you know what's going on with the CI refusing to run pipelines on PRs as of recently?

@jkotas

Copy link
Copy Markdown
Member

Do you know what's going on with the CI refusing to run pipelines on PRs as of recently?

Yes, it is broken. The people responsible for our eng system are not on-call during the weekend, so it may take till Monday to resolve.

It actually runs them, just the github status is not updating. For example, here is the pipeline link for this PR
https://dev.azure.com/dnceng-public/public/_build/results?buildId=605885&view=results

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot


#if INPLACE_RUNTIME
if ((nuint)index >= (uint)array.Length)
ThrowIndexOutOfRangeException(array);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can just use ThrowHelper.ThrowIndexOutOfRangeException given that is for INPLACE_RUNTIME. It is unnecessary to go through GetClasslibException indirection for INPLACE_RUNTIME. The main point of INPLACE_RUNTIME is to avoid these indirections.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to remove the !INPLACE_RUNTIME code in the next PR and to keep this like earlier for now.
Also I think that ThrowHelper is not in the Test.CoreLib (not sure what that is for tbh but right now there's a build failure here due to MemoryMarshal not being there too).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test.CoreLib is very minimal implementation of CoreLib for testing, debugging and various experiments. It is fine to add minimal implementations of MemoryMarshal or ThrowHelper to it to keep it working.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

Comment threadsrc/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

Comment threadsrc/coreclr/vm/metasig.h Outdated
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas This caused StelemRef_Helper to not be inlined into StelemRef anymore but now StelemRef_Helper_NoCacheLookup started being inlined into it, should I bring the previous behaviour back with AggressiveInlining and NoInlining?

@jkotas

Copy link
Copy Markdown
Member

Does it affect performance of any of the fast paths?

This caused StelemRef_Helper to not be inlined into StelemRef anymore

StelemRef_Helper is marked with [MethodImpl(MethodImplOptions.NoInlining)] both before and after this change. I do not see how StelemRef_Helper could have been ever inlined.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

StelemRef_Helper is marked with [MethodImpl(MethodImplOptions.NoInlining)] both before and after this change. I do not see how StelemRef_Helper could have been ever inlined.

Ah wait nevermind, I've accidentally diffed StelemRef_Helper with StelemRef.

The non cached one being inlined is the only difference now then: MihuBot/runtime-utils#332 (comment)

@huoyaoyuan

Copy link
Copy Markdown
Member

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

I wonder what the problem would be. Is there any context?

@jkotas

Copy link
Copy Markdown
Member

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

I wonder what the problem would be. Is there any context?

Unsafe.As used by the helper code today is undefined behavior. In theory, it can interact poorly with other JIT optimizations and produce bad code. See discussion in #87374 for more details.

@jkotas

Copy link
Copy Markdown
Member

Does it affect performance of any of the fast paths?

@MichalPetryka Did you have a chance to check the perf impact of these changes?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Did you have a chance to check the perf impact of these changes?

I'll do so today.

@MichalPetryka

MichalPetryka commented Mar 19, 2024

Copy link
Copy Markdown
ContributorAuthor

BenchmarkDotNet v0.13.12, Windows 10 (10.0.19045.4170/22H2/2022Update)
AMD Ryzen 9 7900X, 1 CPU, 24 logical and 12 physical cores
.NET SDK 8.0.200
[Host] : .NET 8.0.2 (8.0.224.6711), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-JUCZRX : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-NEFMBN : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
.NET 8.0 : .NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Runtime=.NET 8.0 
MethodJobToolchainsMeanErrorStdDevRatioRatioSDCode SizeAllocatedAlloc Ratio
WriteNullJob-JUCZRXmain?29.33 ns0.076 ns0.067 ns1.000.00480 B-NA
WriteNullJob-NEFMBNpr?34.87 ns0.070 ns0.062 ns1.190.00356 B-NA
WriteNull.NET 8.0Default?34.56 ns0.135 ns0.127 ns1.180.0053 B-NA
WriteToObjectJob-JUCZRXmain63.41 ns0.330 ns0.292 ns1.000.00331 B-NA
WriteToObjectJob-NEFMBNpr57.73 ns0.282 ns0.264 ns0.910.01356 B-NA
WriteToObject.NET 8.0Default63.91 ns0.558 ns0.494 ns1.010.0153 B-NA
WriteToInterfaceJob-JUCZRXmain117.00 ns0.711 ns0.630 ns1.000.00422 B-NA
WriteToInterfaceJob-NEFMBNpr88.45 ns1.282 ns1.425 ns0.750.01369 B-NA
WriteToInterface.NET 8.0Default93.90 ns0.541 ns0.480 ns0.800.0153 B-NA
WriteToTypeJob-JUCZRXmain41.50 ns0.684 ns0.640 ns1.000.0060 B-NA
WriteToTypeJob-NEFMBNpr40.00 ns0.070 ns0.058 ns0.960.0260 B-NA
WriteToType.NET 8.0Default39.99 ns0.062 ns0.048 ns0.960.0258 B-NA

@jkotas I've benchmarked with string, the paths for value seem to be better but the test with null seems to confuse PGO and have it place the null path in the slow code behind the throw helper now. Not sure if this can be fixed without JIT changes, the JIT should probably assume that throw helpers are always colder than cold paths.

Full codegen:

Details

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8jne short M01_L00xorecx,ecxmov[rax],rcxaddrsp,28retM01_L00:cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CB4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:call CORINFO_HELP_RNGCHKFAILint3; Total bytes of code 93
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8movrcx,290F9800B80movrcx,[rcx]movrax,[rsi]addrcx,10rorxrdx,rax,20xorrdx,rbxmovr8,9E3779B97F4A7C15imulrdx,r8movr8d,[rcx]shrxrdx,rdx,r8xorr8d,r8dM02_L00:lear10d,[rdx+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rcx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incr8daddedx,r8dandedx,[rcx+4]cmpr8d,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,7FFB69DC54C8call CORINFO_HELP_COUNTPROFILE32movrcx,rdimovrdx,rsicall System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,7FFB69DC54CCcall CORINFO_HELP_COUNTPROFILE32movrcx,rdimovrdx,rbxmovr8,rsicall qword ptr [7FFB68CB44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 221
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrsi,rcxmovrdi,rdxmovrbx,r8testrbx,rbxjne short M03_L00movrdx,2D18E150008movrcx,rdxcall qword ptr [7FFB68D1D3B0]M03_L00:movrcx,rdimovrdx,rbxcall System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)movrbx,raxtestrbx,rbxje short M03_L01movrcx,rsimovrdx,rbxaddrsp,20poprbxpoprsipoprdijmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M03_L01:movrcx,offset MT_System.ArrayTypeMismatchExceptioncall CORINFO_HELP_NEWSFASTmovrbx,raxmovrcx,rbxcall qword ptr [7FFB69827C78]movrcx,rbxcall CORINFO_HELP_THROWint3; Total bytes of code 113

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L01learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8jne short M01_L02xorecx,ecxmov[rax],rcxaddrsp,28retM01_L00:movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L03movrcx,raxaddrsp,28jmp qword ptr [7FFB6BDB44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L01:call qword ptr [7FFB6BDB4450]int3M01_L02:cmprdx,[r8]jne short M01_L00M01_L03:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object); Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC8B31840]movrdx,[rax+0B50]movrax,[rsi]addrdx,10movr8,raxrolr8,20xorr8,rbxmovr10,9E3779B97F4A7C15imulr8,r10movecx,[rdx]shrr8,clxorecx,ecxM02_L00:lear10d,[r8+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddr8d,ecxandr8d,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC8B4A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rbxmovrdx,rsicall qword ptr [7FFBC8B4A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M02_L04movrcx,rdimovrdx,raxcall qword ptr [7FFBC8B4A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L04:call qword ptr [7FFBC8B4A2E0]int3; Total bytes of code 209

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8je short M01_L01cmprdx,[r8]je short M01_L00movr10,offset MT_System.Object[]cmp[rcx],r10jne short M01_L03M01_L00:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L01:xorecx,ecxmov[rax],rcxaddrsp,28retM01_L02:call CORINFO_HELP_RNGCHKFAILM01_L03:movrcx,raxaddrsp,28jmp qword ptr [7FFB68CD4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object); Total bytes of code 92
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC7912090]movrdx,[rax+0B48]movr8,[rsi]addrdx,10movrax,r8rolrax,20xorrax,rbxmovr10,9E3779B97F4A7C15imulrax,r10movecx,[rdx]shrrax,clxorecx,ecxM02_L00:lear10d,[rax+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,r8jne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddeax,ecxandeax,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC792CD88]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rdimovrdx,rbxmovr8,rsicall qword ptr [7FFBC792CDC8]; Precode of System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 186

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8je short M01_L01cmprdx,[r8]je short M01_L00movr10,offset MT_System.Object[]cmp[rcx],r10jne short M01_L03M01_L00:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L01:xorecx,ecxmov[rax],rcxaddrsp,28retM01_L02:call qword ptr [7FFB68CA4450]int3M01_L03:movrcx,raxaddrsp,28jmp qword ptr [7FFB68CA44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object); Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC8661840]movrdx,[rax+0B50]movrax,[rsi]addrdx,10movr8,raxrolr8,20xorr8,rbxmovr10,9E3779B97F4A7C15imulr8,r10movecx,[rdx]shrr8,clxorecx,ecxM02_L00:lear10d,[r8+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddr8d,ecxandr8d,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC867A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rbxmovrdx,rsicall qword ptr [7FFBC867A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M02_L04movrcx,rdimovrdx,raxcall qword ptr [7FFBC867A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L04:call qword ptr [7FFBC867A2E0]int3; Total bytes of code 209

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L00learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8je short M01_L02cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CD4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L00:call CORINFO_HELP_RNGCHKFAILM01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:xorecx,ecxmov[rax],rcxaddrsp,28ret; Total bytes of code 92
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrax,25A67800B80movrax,[rax]movr10,[r8]addrax,10rorxr9,r10,20xorr9,rdxmovr11,9E3779B97F4A7C15imulr9,r11movr11d,[rax]shrxr9,r9,r11xorr11d,r11dM02_L00:leaebx,[r9+1]movsxdrbx,ebxlearbx,[rbx+rbx*2]learbx,[rax+rbx*8]movesi,[rbx]movrdi,[rbx+8]andesi,0FFFFFFFEcmprdi,r10jne short M02_L01movrdi,rdxxorrdi,[rbx+10]cmprdi,1jbe short M02_L02M02_L01:testesi,esije short M02_L03incr11daddr9d,r11dandr9d,[rax+4]cmpr11d,8jl short M02_L00jmp short M02_L03M02_L02:cmpesi,[rbx]jne short M02_L03cmpedi,1jne short M02_L03movrdx,r8call System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:call qword ptr [7FFB68CD44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 166
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrsi,rcxmovrdi,rdxmovrbx,r8testrbx,rbxjne short M03_L00movrcx,[7FFBC79636C8]movrdx,[rcx]movrcx,rdxcall qword ptr [7FFBC79300B8]M03_L00:movrcx,rdimovrdx,rbxcall qword ptr [7FFBC792CD68]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)movrbx,raxtestrbx,rbxje short M03_L01movrdx,rbxmovrcx,rsilearax,[7FFBC792CD90]addrsp,20poprbxpoprsipoprdijmp qword ptr [rax]M03_L01:call qword ptr [7FFBC791B5E8]movrbx,raxmovrcx,rbxcall qword ptr [7FFBC7924598]movrcx,rbxcall qword ptr [7FFBC7911760]; CORINFO_HELP_THROWint3; Total bytes of code 111

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L00learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8je short M01_L02cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CC44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L00:call qword ptr [7FFB68CC4450]int3M01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:xorecx,ecxmov[rax],rcxaddrsp,28ret; Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrax,21C53C00B88movrax,[rax]movr10,[r8]addrax,10rorxr9,r10,20xorr9,rdxmovr11,9E3779B97F4A7C15imulr9,r11movr11d,[rax]shrxr9,r9,r11xorr11d,r11dM02_L00:leaebx,[r9+1]movsxdrbx,ebxlearbx,[rbx+rbx*2]learbx,[rax+rbx*8]movesi,[rbx]movrdi,[rbx+8]andesi,0FFFFFFFEcmprdi,r10jne short M02_L01movrdi,rdxxorrdi,[rbx+10]cmprdi,1jbe short M02_L02M02_L01:testesi,esije short M02_L03incr11daddr9d,r11dandr9d,[rax+4]cmpr11d,8jl short M02_L00jmp short M02_L03M02_L02:cmpesi,[rbx]jne short M02_L03cmpedi,1jne short M02_L03movrdx,r8call System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:call qword ptr [7FFB68CC44C8]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 166
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrbxsubrsp,20movrbx,rcxmovrax,r8movrcx,rdxmovrdx,raxcall qword ptr [7FFBC867A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M03_L00movrdx,raxmovrcx,rbxlearax,[7FFBC867A2B0]addrsp,20poprbxjmp qword ptr [rax]M03_L00:call qword ptr [7FFBC867A2E0]int3; Total bytes of code 56

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax+rax]M00_L00:learcx,[rsi+rdi*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 60

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax+rax]M00_L00:learcx,[rsi+rdi*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 60

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxmovrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax]nop dword ptr [rax+rax]M00_L00:movecx,edilearcx,[rsi+rcx*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:poprbxpoprbppoprsipoprdiret; Total bytes of code 58

@jkotas

jkotas commented Mar 20, 2024

Copy link
Copy Markdown
Member

I agree that the cold blocks ordering with PGO can be better in some case. I do not see any material code difference caused by this change. The exact code for these helpers can differ from workload to workload and from run to run depending on how PGO rolls the dice.

I have pushed a commit with a minor cleanup as I was looking at the code.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-VM-coreclrcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@MichalPetryka@jkotas@huoyaoyuan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Remove invalid Unsafe.As from array helpers - #99778

Merged
jkotas merged 15 commits into
dotnet:mainfrom
MichalPetryka:patch-32
Mar 21, 2024
Merged

Remove invalid Unsafe.As from array helpers#99778
jkotas merged 15 commits into
dotnet:mainfrom
MichalPetryka:patch-32

Conversation

@MichalPetryka

Copy link
Copy Markdown
Contributor

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

Causes almost no diffs outside of calling a managed throw helper now.

@ghostghost added the area-VM-coreclr label Mar 14, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Mar 14, 2024
@jkotas

Copy link
Copy Markdown
Member

publicstaticunsafevoidStelemRef(Arrayarray,nintindex,objectobj)
has clone of this code with the same potential issue.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

has clone of this code

What's the INPLACE_RUNTIME stuff there? Is it related to some old multimodule mode? (I'll change that file tomorrow)

@jkotas

Copy link
Copy Markdown
Member

What's the INPLACE_RUNTIME stuff there? Is it related to some old multimodule mode? (I'll change that file tomorrow)

I think we build INPLACE_RUNTIME defined everywhere currently. !INPLACE_RUNTIME was a build configuration in ProjectN where the GC and the lowest level of the runtime (including these helpers) were build as a separate library that can be used by multiple higher-level runtimes all running in the same process.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

I think we build INPLACE_RUNTIME defined everywhere currently. !INPLACE_RUNTIME was a build configuration in ProjectN where the GC and the lowest level of the runtime (including these helpers) were build as a separate library that can be used by multiple higher-level runtimes all running in the same process.

Do we want to cleanup the code then and remove those paths later (and keep it as is for now)? Or should I also change the !INPLACE_RUNTIME path?

@jkotas

Copy link
Copy Markdown
Member

Do we want to cleanup the code then and remove those paths later (and keep it as is for now)? Or should I also change the !INPLACE_RUNTIME path?

Any of these options is fine with me.

@jkotas

Copy link
Copy Markdown
Member

Is the code for helper same or better with this change?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Is the code for helper same or better with this change?

The codegen for normal path is almost the same (the operands for cmp are swapped but that doesn't matter).
The cold throw path is a bit bigger cause it calls the managed throw helper instead of the native one:

 G_M56901_IG04:
- call CORINFO_HELP_RNGCHKFAIL- ;; size=5 bbWeight=0 PerfScore 0.00-G_M56901_IG05:
mov rax, 0xD1FFAB1E ; code for System.Runtime.CompilerServices.CastHelpers:ThrowArrayMismatchException():byref
call [rax]System.Runtime.CompilerServices.CastHelpers:ThrowArrayMismatchException():byref
+ ;; size=12 bbWeight=0 PerfScore 0.00+G_M56901_IG05:+ mov rax, 0xD1FFAB1E ; code for System.Runtime.CompilerServices.CastHelpers:ThrowIndexOutOfRangeException()+ call [rax]System.Runtime.CompilerServices.CastHelpers:ThrowIndexOutOfRangeException()
int3 ;; size=13 bbWeight=0 PerfScore 0.00

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas Do you know what's going on with the CI refusing to run pipelines on PRs as of recently?

@jkotas

Copy link
Copy Markdown
Member

Do you know what's going on with the CI refusing to run pipelines on PRs as of recently?

Yes, it is broken. The people responsible for our eng system are not on-call during the weekend, so it may take till Monday to resolve.

It actually runs them, just the github status is not updating. For example, here is the pipeline link for this PR
https://dev.azure.com/dnceng-public/public/_build/results?buildId=605885&view=results

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot


#if INPLACE_RUNTIME
if ((nuint)index >= (uint)array.Length)
ThrowIndexOutOfRangeException(array);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can just use ThrowHelper.ThrowIndexOutOfRangeException given that is for INPLACE_RUNTIME. It is unnecessary to go through GetClasslibException indirection for INPLACE_RUNTIME. The main point of INPLACE_RUNTIME is to avoid these indirections.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to remove the !INPLACE_RUNTIME code in the next PR and to keep this like earlier for now.
Also I think that ThrowHelper is not in the Test.CoreLib (not sure what that is for tbh but right now there's a build failure here due to MemoryMarshal not being there too).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test.CoreLib is very minimal implementation of CoreLib for testing, debugging and various experiments. It is fine to add minimal implementations of MemoryMarshal or ThrowHelper to it to keep it working.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

Comment threadsrc/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

Comment threadsrc/coreclr/vm/metasig.h Outdated
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas This caused StelemRef_Helper to not be inlined into StelemRef anymore but now StelemRef_Helper_NoCacheLookup started being inlined into it, should I bring the previous behaviour back with AggressiveInlining and NoInlining?

@jkotas

Copy link
Copy Markdown
Member

Does it affect performance of any of the fast paths?

This caused StelemRef_Helper to not be inlined into StelemRef anymore

StelemRef_Helper is marked with [MethodImpl(MethodImplOptions.NoInlining)] both before and after this change. I do not see how StelemRef_Helper could have been ever inlined.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

StelemRef_Helper is marked with [MethodImpl(MethodImplOptions.NoInlining)] both before and after this change. I do not see how StelemRef_Helper could have been ever inlined.

Ah wait nevermind, I've accidentally diffed StelemRef_Helper with StelemRef.

The non cached one being inlined is the only difference now then: MihuBot/runtime-utils#332 (comment)

@huoyaoyuan

Copy link
Copy Markdown
Member

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

I wonder what the problem would be. Is there any context?

@jkotas

Copy link
Copy Markdown
Member

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

I wonder what the problem would be. Is there any context?

Unsafe.As used by the helper code today is undefined behavior. In theory, it can interact poorly with other JIT optimizations and produce bad code. See discussion in #87374 for more details.

@jkotas

Copy link
Copy Markdown
Member

Does it affect performance of any of the fast paths?

@MichalPetryka Did you have a chance to check the perf impact of these changes?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Did you have a chance to check the perf impact of these changes?

I'll do so today.

@MichalPetryka

MichalPetryka commented Mar 19, 2024

Copy link
Copy Markdown
ContributorAuthor

BenchmarkDotNet v0.13.12, Windows 10 (10.0.19045.4170/22H2/2022Update)
AMD Ryzen 9 7900X, 1 CPU, 24 logical and 12 physical cores
.NET SDK 8.0.200
[Host] : .NET 8.0.2 (8.0.224.6711), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-JUCZRX : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-NEFMBN : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
.NET 8.0 : .NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Runtime=.NET 8.0 
MethodJobToolchainsMeanErrorStdDevRatioRatioSDCode SizeAllocatedAlloc Ratio
WriteNullJob-JUCZRXmain?29.33 ns0.076 ns0.067 ns1.000.00480 B-NA
WriteNullJob-NEFMBNpr?34.87 ns0.070 ns0.062 ns1.190.00356 B-NA
WriteNull.NET 8.0Default?34.56 ns0.135 ns0.127 ns1.180.0053 B-NA
WriteToObjectJob-JUCZRXmain63.41 ns0.330 ns0.292 ns1.000.00331 B-NA
WriteToObjectJob-NEFMBNpr57.73 ns0.282 ns0.264 ns0.910.01356 B-NA
WriteToObject.NET 8.0Default63.91 ns0.558 ns0.494 ns1.010.0153 B-NA
WriteToInterfaceJob-JUCZRXmain117.00 ns0.711 ns0.630 ns1.000.00422 B-NA
WriteToInterfaceJob-NEFMBNpr88.45 ns1.282 ns1.425 ns0.750.01369 B-NA
WriteToInterface.NET 8.0Default93.90 ns0.541 ns0.480 ns0.800.0153 B-NA
WriteToTypeJob-JUCZRXmain41.50 ns0.684 ns0.640 ns1.000.0060 B-NA
WriteToTypeJob-NEFMBNpr40.00 ns0.070 ns0.058 ns0.960.0260 B-NA
WriteToType.NET 8.0Default39.99 ns0.062 ns0.048 ns0.960.0258 B-NA

@jkotas I've benchmarked with string, the paths for value seem to be better but the test with null seems to confuse PGO and have it place the null path in the slow code behind the throw helper now. Not sure if this can be fixed without JIT changes, the JIT should probably assume that throw helpers are always colder than cold paths.

Full codegen:

Details

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8jne short M01_L00xorecx,ecxmov[rax],rcxaddrsp,28retM01_L00:cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CB4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:call CORINFO_HELP_RNGCHKFAILint3; Total bytes of code 93
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8movrcx,290F9800B80movrcx,[rcx]movrax,[rsi]addrcx,10rorxrdx,rax,20xorrdx,rbxmovr8,9E3779B97F4A7C15imulrdx,r8movr8d,[rcx]shrxrdx,rdx,r8xorr8d,r8dM02_L00:lear10d,[rdx+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rcx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incr8daddedx,r8dandedx,[rcx+4]cmpr8d,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,7FFB69DC54C8call CORINFO_HELP_COUNTPROFILE32movrcx,rdimovrdx,rsicall System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,7FFB69DC54CCcall CORINFO_HELP_COUNTPROFILE32movrcx,rdimovrdx,rbxmovr8,rsicall qword ptr [7FFB68CB44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 221
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrsi,rcxmovrdi,rdxmovrbx,r8testrbx,rbxjne short M03_L00movrdx,2D18E150008movrcx,rdxcall qword ptr [7FFB68D1D3B0]M03_L00:movrcx,rdimovrdx,rbxcall System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)movrbx,raxtestrbx,rbxje short M03_L01movrcx,rsimovrdx,rbxaddrsp,20poprbxpoprsipoprdijmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M03_L01:movrcx,offset MT_System.ArrayTypeMismatchExceptioncall CORINFO_HELP_NEWSFASTmovrbx,raxmovrcx,rbxcall qword ptr [7FFB69827C78]movrcx,rbxcall CORINFO_HELP_THROWint3; Total bytes of code 113

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L01learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8jne short M01_L02xorecx,ecxmov[rax],rcxaddrsp,28retM01_L00:movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L03movrcx,raxaddrsp,28jmp qword ptr [7FFB6BDB44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L01:call qword ptr [7FFB6BDB4450]int3M01_L02:cmprdx,[r8]jne short M01_L00M01_L03:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object); Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC8B31840]movrdx,[rax+0B50]movrax,[rsi]addrdx,10movr8,raxrolr8,20xorr8,rbxmovr10,9E3779B97F4A7C15imulr8,r10movecx,[rdx]shrr8,clxorecx,ecxM02_L00:lear10d,[r8+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddr8d,ecxandr8d,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC8B4A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rbxmovrdx,rsicall qword ptr [7FFBC8B4A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M02_L04movrcx,rdimovrdx,raxcall qword ptr [7FFBC8B4A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L04:call qword ptr [7FFBC8B4A2E0]int3; Total bytes of code 209

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8je short M01_L01cmprdx,[r8]je short M01_L00movr10,offset MT_System.Object[]cmp[rcx],r10jne short M01_L03M01_L00:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L01:xorecx,ecxmov[rax],rcxaddrsp,28retM01_L02:call CORINFO_HELP_RNGCHKFAILM01_L03:movrcx,raxaddrsp,28jmp qword ptr [7FFB68CD4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object); Total bytes of code 92
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC7912090]movrdx,[rax+0B48]movr8,[rsi]addrdx,10movrax,r8rolrax,20xorrax,rbxmovr10,9E3779B97F4A7C15imulrax,r10movecx,[rdx]shrrax,clxorecx,ecxM02_L00:lear10d,[rax+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,r8jne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddeax,ecxandeax,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC792CD88]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rdimovrdx,rbxmovr8,rsicall qword ptr [7FFBC792CDC8]; Precode of System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 186

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8je short M01_L01cmprdx,[r8]je short M01_L00movr10,offset MT_System.Object[]cmp[rcx],r10jne short M01_L03M01_L00:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L01:xorecx,ecxmov[rax],rcxaddrsp,28retM01_L02:call qword ptr [7FFB68CA4450]int3M01_L03:movrcx,raxaddrsp,28jmp qword ptr [7FFB68CA44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object); Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC8661840]movrdx,[rax+0B50]movrax,[rsi]addrdx,10movr8,raxrolr8,20xorr8,rbxmovr10,9E3779B97F4A7C15imulr8,r10movecx,[rdx]shrr8,clxorecx,ecxM02_L00:lear10d,[r8+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddr8d,ecxandr8d,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC867A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rbxmovrdx,rsicall qword ptr [7FFBC867A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M02_L04movrcx,rdimovrdx,raxcall qword ptr [7FFBC867A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L04:call qword ptr [7FFBC867A2E0]int3; Total bytes of code 209

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L00learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8je short M01_L02cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CD4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L00:call CORINFO_HELP_RNGCHKFAILM01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:xorecx,ecxmov[rax],rcxaddrsp,28ret; Total bytes of code 92
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrax,25A67800B80movrax,[rax]movr10,[r8]addrax,10rorxr9,r10,20xorr9,rdxmovr11,9E3779B97F4A7C15imulr9,r11movr11d,[rax]shrxr9,r9,r11xorr11d,r11dM02_L00:leaebx,[r9+1]movsxdrbx,ebxlearbx,[rbx+rbx*2]learbx,[rax+rbx*8]movesi,[rbx]movrdi,[rbx+8]andesi,0FFFFFFFEcmprdi,r10jne short M02_L01movrdi,rdxxorrdi,[rbx+10]cmprdi,1jbe short M02_L02M02_L01:testesi,esije short M02_L03incr11daddr9d,r11dandr9d,[rax+4]cmpr11d,8jl short M02_L00jmp short M02_L03M02_L02:cmpesi,[rbx]jne short M02_L03cmpedi,1jne short M02_L03movrdx,r8call System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:call qword ptr [7FFB68CD44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 166
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrsi,rcxmovrdi,rdxmovrbx,r8testrbx,rbxjne short M03_L00movrcx,[7FFBC79636C8]movrdx,[rcx]movrcx,rdxcall qword ptr [7FFBC79300B8]M03_L00:movrcx,rdimovrdx,rbxcall qword ptr [7FFBC792CD68]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)movrbx,raxtestrbx,rbxje short M03_L01movrdx,rbxmovrcx,rsilearax,[7FFBC792CD90]addrsp,20poprbxpoprsipoprdijmp qword ptr [rax]M03_L01:call qword ptr [7FFBC791B5E8]movrbx,raxmovrcx,rbxcall qword ptr [7FFBC7924598]movrcx,rbxcall qword ptr [7FFBC7911760]; CORINFO_HELP_THROWint3; Total bytes of code 111

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L00learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8je short M01_L02cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CC44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L00:call qword ptr [7FFB68CC4450]int3M01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:xorecx,ecxmov[rax],rcxaddrsp,28ret; Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrax,21C53C00B88movrax,[rax]movr10,[r8]addrax,10rorxr9,r10,20xorr9,rdxmovr11,9E3779B97F4A7C15imulr9,r11movr11d,[rax]shrxr9,r9,r11xorr11d,r11dM02_L00:leaebx,[r9+1]movsxdrbx,ebxlearbx,[rbx+rbx*2]learbx,[rax+rbx*8]movesi,[rbx]movrdi,[rbx+8]andesi,0FFFFFFFEcmprdi,r10jne short M02_L01movrdi,rdxxorrdi,[rbx+10]cmprdi,1jbe short M02_L02M02_L01:testesi,esije short M02_L03incr11daddr9d,r11dandr9d,[rax+4]cmpr11d,8jl short M02_L00jmp short M02_L03M02_L02:cmpesi,[rbx]jne short M02_L03cmpedi,1jne short M02_L03movrdx,r8call System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:call qword ptr [7FFB68CC44C8]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 166
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrbxsubrsp,20movrbx,rcxmovrax,r8movrcx,rdxmovrdx,raxcall qword ptr [7FFBC867A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M03_L00movrdx,raxmovrcx,rbxlearax,[7FFBC867A2B0]addrsp,20poprbxjmp qword ptr [rax]M03_L00:call qword ptr [7FFBC867A2E0]int3; Total bytes of code 56

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax+rax]M00_L00:learcx,[rsi+rdi*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 60

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax+rax]M00_L00:learcx,[rsi+rdi*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 60

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxmovrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax]nop dword ptr [rax+rax]M00_L00:movecx,edilearcx,[rsi+rcx*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:poprbxpoprbppoprsipoprdiret; Total bytes of code 58

@jkotas

jkotas commented Mar 20, 2024

Copy link
Copy Markdown
Member

I agree that the cold blocks ordering with PGO can be better in some case. I do not see any material code difference caused by this change. The exact code for these helpers can differ from workload to workload and from run to run depending on how PGO rolls the dice.

I have pushed a commit with a minor cleanup as I was looking at the code.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-VM-coreclrcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@MichalPetryka@jkotas@huoyaoyuan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Remove invalid Unsafe.As from array helpers - #99778

Merged
jkotas merged 15 commits into
dotnet:mainfrom
MichalPetryka:patch-32
Mar 21, 2024
Merged

Remove invalid Unsafe.As from array helpers#99778
jkotas merged 15 commits into
dotnet:mainfrom
MichalPetryka:patch-32

Conversation

@MichalPetryka

Copy link
Copy Markdown
Contributor

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

Causes almost no diffs outside of calling a managed throw helper now.

@ghostghost added the area-VM-coreclr label Mar 14, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Mar 14, 2024
@jkotas

Copy link
Copy Markdown
Member

publicstaticunsafevoidStelemRef(Arrayarray,nintindex,objectobj)
has clone of this code with the same potential issue.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

has clone of this code

What's the INPLACE_RUNTIME stuff there? Is it related to some old multimodule mode? (I'll change that file tomorrow)

@jkotas

Copy link
Copy Markdown
Member

What's the INPLACE_RUNTIME stuff there? Is it related to some old multimodule mode? (I'll change that file tomorrow)

I think we build INPLACE_RUNTIME defined everywhere currently. !INPLACE_RUNTIME was a build configuration in ProjectN where the GC and the lowest level of the runtime (including these helpers) were build as a separate library that can be used by multiple higher-level runtimes all running in the same process.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

I think we build INPLACE_RUNTIME defined everywhere currently. !INPLACE_RUNTIME was a build configuration in ProjectN where the GC and the lowest level of the runtime (including these helpers) were build as a separate library that can be used by multiple higher-level runtimes all running in the same process.

Do we want to cleanup the code then and remove those paths later (and keep it as is for now)? Or should I also change the !INPLACE_RUNTIME path?

@jkotas

Copy link
Copy Markdown
Member

Do we want to cleanup the code then and remove those paths later (and keep it as is for now)? Or should I also change the !INPLACE_RUNTIME path?

Any of these options is fine with me.

@jkotas

Copy link
Copy Markdown
Member

Is the code for helper same or better with this change?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Is the code for helper same or better with this change?

The codegen for normal path is almost the same (the operands for cmp are swapped but that doesn't matter).
The cold throw path is a bit bigger cause it calls the managed throw helper instead of the native one:

 G_M56901_IG04:
- call CORINFO_HELP_RNGCHKFAIL- ;; size=5 bbWeight=0 PerfScore 0.00-G_M56901_IG05:
mov rax, 0xD1FFAB1E ; code for System.Runtime.CompilerServices.CastHelpers:ThrowArrayMismatchException():byref
call [rax]System.Runtime.CompilerServices.CastHelpers:ThrowArrayMismatchException():byref
+ ;; size=12 bbWeight=0 PerfScore 0.00+G_M56901_IG05:+ mov rax, 0xD1FFAB1E ; code for System.Runtime.CompilerServices.CastHelpers:ThrowIndexOutOfRangeException()+ call [rax]System.Runtime.CompilerServices.CastHelpers:ThrowIndexOutOfRangeException()
int3 ;; size=13 bbWeight=0 PerfScore 0.00

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas Do you know what's going on with the CI refusing to run pipelines on PRs as of recently?

@jkotas

Copy link
Copy Markdown
Member

Do you know what's going on with the CI refusing to run pipelines on PRs as of recently?

Yes, it is broken. The people responsible for our eng system are not on-call during the weekend, so it may take till Monday to resolve.

It actually runs them, just the github status is not updating. For example, here is the pipeline link for this PR
https://dev.azure.com/dnceng-public/public/_build/results?buildId=605885&view=results

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot


#if INPLACE_RUNTIME
if ((nuint)index >= (uint)array.Length)
ThrowIndexOutOfRangeException(array);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can just use ThrowHelper.ThrowIndexOutOfRangeException given that is for INPLACE_RUNTIME. It is unnecessary to go through GetClasslibException indirection for INPLACE_RUNTIME. The main point of INPLACE_RUNTIME is to avoid these indirections.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to remove the !INPLACE_RUNTIME code in the next PR and to keep this like earlier for now.
Also I think that ThrowHelper is not in the Test.CoreLib (not sure what that is for tbh but right now there's a build failure here due to MemoryMarshal not being there too).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test.CoreLib is very minimal implementation of CoreLib for testing, debugging and various experiments. It is fine to add minimal implementations of MemoryMarshal or ThrowHelper to it to keep it working.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

Comment threadsrc/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@MihuBot

Comment threadsrc/coreclr/vm/metasig.h Outdated
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas This caused StelemRef_Helper to not be inlined into StelemRef anymore but now StelemRef_Helper_NoCacheLookup started being inlined into it, should I bring the previous behaviour back with AggressiveInlining and NoInlining?

@jkotas

Copy link
Copy Markdown
Member

Does it affect performance of any of the fast paths?

This caused StelemRef_Helper to not be inlined into StelemRef anymore

StelemRef_Helper is marked with [MethodImpl(MethodImplOptions.NoInlining)] both before and after this change. I do not see how StelemRef_Helper could have been ever inlined.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

StelemRef_Helper is marked with [MethodImpl(MethodImplOptions.NoInlining)] both before and after this change. I do not see how StelemRef_Helper could have been ever inlined.

Ah wait nevermind, I've accidentally diffed StelemRef_Helper with StelemRef.

The non cached one being inlined is the only difference now then: MihuBot/runtime-utils#332 (comment)

@huoyaoyuan

Copy link
Copy Markdown
Member

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

I wonder what the problem would be. Is there any context?

@jkotas

Copy link
Copy Markdown
Member

This probably doesn't cause issues today but it might start to do so when we start inlining helpers.

I wonder what the problem would be. Is there any context?

Unsafe.As used by the helper code today is undefined behavior. In theory, it can interact poorly with other JIT optimizations and produce bad code. See discussion in #87374 for more details.

@jkotas

Copy link
Copy Markdown
Member

Does it affect performance of any of the fast paths?

@MichalPetryka Did you have a chance to check the perf impact of these changes?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Did you have a chance to check the perf impact of these changes?

I'll do so today.

@MichalPetryka

MichalPetryka commented Mar 19, 2024

Copy link
Copy Markdown
ContributorAuthor

BenchmarkDotNet v0.13.12, Windows 10 (10.0.19045.4170/22H2/2022Update)
AMD Ryzen 9 7900X, 1 CPU, 24 logical and 12 physical cores
.NET SDK 8.0.200
[Host] : .NET 8.0.2 (8.0.224.6711), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-JUCZRX : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-NEFMBN : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
.NET 8.0 : .NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Runtime=.NET 8.0 
MethodJobToolchainsMeanErrorStdDevRatioRatioSDCode SizeAllocatedAlloc Ratio
WriteNullJob-JUCZRXmain?29.33 ns0.076 ns0.067 ns1.000.00480 B-NA
WriteNullJob-NEFMBNpr?34.87 ns0.070 ns0.062 ns1.190.00356 B-NA
WriteNull.NET 8.0Default?34.56 ns0.135 ns0.127 ns1.180.0053 B-NA
WriteToObjectJob-JUCZRXmain63.41 ns0.330 ns0.292 ns1.000.00331 B-NA
WriteToObjectJob-NEFMBNpr57.73 ns0.282 ns0.264 ns0.910.01356 B-NA
WriteToObject.NET 8.0Default63.91 ns0.558 ns0.494 ns1.010.0153 B-NA
WriteToInterfaceJob-JUCZRXmain117.00 ns0.711 ns0.630 ns1.000.00422 B-NA
WriteToInterfaceJob-NEFMBNpr88.45 ns1.282 ns1.425 ns0.750.01369 B-NA
WriteToInterface.NET 8.0Default93.90 ns0.541 ns0.480 ns0.800.0153 B-NA
WriteToTypeJob-JUCZRXmain41.50 ns0.684 ns0.640 ns1.000.0060 B-NA
WriteToTypeJob-NEFMBNpr40.00 ns0.070 ns0.058 ns0.960.0260 B-NA
WriteToType.NET 8.0Default39.99 ns0.062 ns0.048 ns0.960.0258 B-NA

@jkotas I've benchmarked with string, the paths for value seem to be better but the test with null seems to confuse PGO and have it place the null path in the slow code behind the throw helper now. Not sure if this can be fixed without JIT changes, the JIT should probably assume that throw helpers are always colder than cold paths.

Full codegen:

Details

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8jne short M01_L00xorecx,ecxmov[rax],rcxaddrsp,28retM01_L00:cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CB4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:call CORINFO_HELP_RNGCHKFAILint3; Total bytes of code 93
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8movrcx,290F9800B80movrcx,[rcx]movrax,[rsi]addrcx,10rorxrdx,rax,20xorrdx,rbxmovr8,9E3779B97F4A7C15imulrdx,r8movr8d,[rcx]shrxrdx,rdx,r8xorr8d,r8dM02_L00:lear10d,[rdx+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rcx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incr8daddedx,r8dandedx,[rcx+4]cmpr8d,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,7FFB69DC54C8call CORINFO_HELP_COUNTPROFILE32movrcx,rdimovrdx,rsicall System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,7FFB69DC54CCcall CORINFO_HELP_COUNTPROFILE32movrcx,rdimovrdx,rbxmovr8,rsicall qword ptr [7FFB68CB44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 221
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrsi,rcxmovrdi,rdxmovrbx,r8testrbx,rbxjne short M03_L00movrdx,2D18E150008movrcx,rdxcall qword ptr [7FFB68D1D3B0]M03_L00:movrcx,rdimovrdx,rbxcall System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)movrbx,raxtestrbx,rbxje short M03_L01movrcx,rsimovrdx,rbxaddrsp,20poprbxpoprsipoprdijmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M03_L01:movrcx,offset MT_System.ArrayTypeMismatchExceptioncall CORINFO_HELP_NEWSFASTmovrbx,raxmovrcx,rbxcall qword ptr [7FFB69827C78]movrcx,rbxcall CORINFO_HELP_THROWint3; Total bytes of code 113

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L01learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8jne short M01_L02xorecx,ecxmov[rax],rcxaddrsp,28retM01_L00:movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L03movrcx,raxaddrsp,28jmp qword ptr [7FFB6BDB44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L01:call qword ptr [7FFB6BDB4450]int3M01_L02:cmprdx,[r8]jne short M01_L00M01_L03:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object); Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC8B31840]movrdx,[rax+0B50]movrax,[rsi]addrdx,10movr8,raxrolr8,20xorr8,rbxmovr10,9E3779B97F4A7C15imulr8,r10movecx,[rdx]shrr8,clxorecx,ecxM02_L00:lear10d,[r8+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddr8d,ecxandr8d,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC8B4A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rbxmovrdx,rsicall qword ptr [7FFBC8B4A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M02_L04movrcx,rdimovrdx,raxcall qword ptr [7FFBC8B4A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L04:call qword ptr [7FFBC8B4A2E0]int3; Total bytes of code 209

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteNull(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8je short M01_L01cmprdx,[r8]je short M01_L00movr10,offset MT_System.Object[]cmp[rcx],r10jne short M01_L03M01_L00:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L01:xorecx,ecxmov[rax],rcxaddrsp,28retM01_L02:call CORINFO_HELP_RNGCHKFAILM01_L03:movrcx,raxaddrsp,28jmp qword ptr [7FFB68CD4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object); Total bytes of code 92
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC7912090]movrdx,[rax+0B48]movr8,[rsi]addrdx,10movrax,r8rolrax,20xorrax,rbxmovr10,9E3779B97F4A7C15imulrax,r10movecx,[rdx]shrrax,clxorecx,ecxM02_L00:lear10d,[rax+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,r8jne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddeax,ecxandeax,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC792CD88]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rdimovrdx,rbxmovr8,rsicall qword ptr [7FFBC792CDC8]; Precode of System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 186

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L02learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8je short M01_L01cmprdx,[r8]je short M01_L00movr10,offset MT_System.Object[]cmp[rcx],r10jne short M01_L03M01_L00:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L01:xorecx,ecxmov[rax],rcxaddrsp,28retM01_L02:call qword ptr [7FFB68CA4450]int3M01_L03:movrcx,raxaddrsp,28jmp qword ptr [7FFB68CA44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object); Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrdi,rcxmovrbx,rdxmovrsi,r8call qword ptr [7FFBC8661840]movrdx,[rax+0B50]movrax,[rsi]addrdx,10movr8,raxrolr8,20xorr8,rbxmovr10,9E3779B97F4A7C15imulr8,r10movecx,[rdx]shrr8,clxorecx,ecxM02_L00:lear10d,[r8+1]movsxdr10,r10dlear10,[r10+r10*2]lear10,[rdx+r10*8]movr9d,[r10]movr11,[r10+8]andr9d,0FFFFFFFEcmpr11,raxjne short M02_L01movr11,rbxxorr11,[r10+10]cmpr11,1jbe short M02_L02M02_L01:testr9d,r9dje short M02_L03incecxaddr8d,ecxandr8d,[rdx+4]cmpecx,8jl short M02_L00jmp short M02_L03M02_L02:cmpr9d,[r10]jne short M02_L03cmpr11d,1jne short M02_L03movrcx,rdimovrdx,rsicall qword ptr [7FFBC867A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:movrcx,rbxmovrdx,rsicall qword ptr [7FFBC867A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M02_L04movrcx,rdimovrdx,raxcall qword ptr [7FFBC867A2A8]; System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L04:call qword ptr [7FFBC867A2E0]int3; Total bytes of code 209

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToObject(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+8]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Array, IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprdx,raxjae short M01_L00learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+38]testr8,r8je short M01_L02cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CD4498]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L00:call CORINFO_HELP_RNGCHKFAILM01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:xorecx,ecxmov[rax],rcxaddrsp,28ret; Total bytes of code 92
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrax,25A67800B80movrax,[rax]movr10,[r8]addrax,10rorxr9,r10,20xorr9,rdxmovr11,9E3779B97F4A7C15imulr9,r11movr11d,[rax]shrxr9,r9,r11xorr11d,r11dM02_L00:leaebx,[r9+1]movsxdrbx,ebxlearbx,[rbx+rbx*2]learbx,[rax+rbx*8]movesi,[rbx]movrdi,[rbx+8]andesi,0FFFFFFFEcmprdi,r10jne short M02_L01movrdi,rdxxorrdi,[rbx+10]cmprdi,1jbe short M02_L02M02_L01:testesi,esije short M02_L03incr11daddr9d,r11dandr9d,[rax+4]cmpr11d,8jl short M02_L00jmp short M02_L03M02_L02:cmpesi,[rbx]jne short M02_L03cmpedi,1jne short M02_L03movrdx,r8call System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:call qword ptr [7FFB68CD44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 166
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrsi,rcxmovrdi,rdxmovrbx,r8testrbx,rbxjne short M03_L00movrcx,[7FFBC79636C8]movrdx,[rcx]movrcx,rdxcall qword ptr [7FFBC79300B8]M03_L00:movrcx,rdimovrdx,rbxcall qword ptr [7FFBC792CD68]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)movrbx,raxtestrbx,rbxje short M03_L01movrdx,rbxmovrcx,rsilearax,[7FFBC792CD90]addrsp,20poprbxpoprsipoprdijmp qword ptr [rax]M03_L01:call qword ptr [7FFBC791B5E8]movrbx,raxmovrcx,rbxcall qword ptr [7FFBC7924598]movrcx,rbxcall qword ptr [7FFBC7911760]; CORINFO_HELP_THROWint3; Total bytes of code 111

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)incedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53
; System.Runtime.CompilerServices.CastHelpers.StelemRef(System.Object[], IntPtr, System.Object)subrsp,28moveax,[rcx+8]cmprax,rdxjbe short M01_L00learax,[rcx+rdx*8+10]movrdx,[rcx]movrdx,[rdx+30]testr8,r8je short M01_L02cmprdx,[r8]je short M01_L01movr10,offset MT_System.Object[]cmp[rcx],r10je short M01_L01movrcx,raxaddrsp,28jmp qword ptr [7FFB68CC44B0]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)M01_L00:call qword ptr [7FFB68CC4450]int3M01_L01:movrcx,raxmovrdx,r8addrsp,28jmp near ptr System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)M01_L02:xorecx,ecxmov[rax],rcxaddrsp,28ret; Total bytes of code 94
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper(System.Object ByRef, Void*, System.Object)pushrdipushrsipushrbxsubrsp,20movrax,21C53C00B88movrax,[rax]movr10,[r8]addrax,10rorxr9,r10,20xorr9,rdxmovr11,9E3779B97F4A7C15imulr9,r11movr11d,[rax]shrxr9,r9,r11xorr11d,r11dM02_L00:leaebx,[r9+1]movsxdrbx,ebxlearbx,[rbx+rbx*2]learbx,[rax+rbx*8]movesi,[rbx]movrdi,[rbx+8]andesi,0FFFFFFFEcmprdi,r10jne short M02_L01movrdi,rdxxorrdi,[rbx+10]cmprdi,1jbe short M02_L02M02_L01:testesi,esije short M02_L03incr11daddr9d,r11dandr9d,[rax+4]cmpr11d,8jl short M02_L00jmp short M02_L03M02_L02:cmpesi,[rbx]jne short M02_L03cmpedi,1jne short M02_L03movrdx,r8call System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)nopaddrsp,20poprbxpoprsipoprdiretM02_L03:call qword ptr [7FFB68CC44C8]; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)nopaddrsp,20poprbxpoprsipoprdiret; Total bytes of code 166
; System.Runtime.CompilerServices.CastHelpers.StelemRef_Helper_NoCacheLookup(System.Object ByRef, Void*, System.Object)pushrbxsubrsp,20movrbx,rcxmovrax,r8movrcx,rdxmovrdx,raxcall qword ptr [7FFBC867A288]; System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)testrax,raxje short M03_L00movrdx,raxmovrcx,rbxlearax,[7FFBC867A2B0]addrsp,20poprbxjmp qword ptr [rax]M03_L00:call qword ptr [7FFBC867A2E0]int3; Total bytes of code 56

Extern method
System.Runtime.CompilerServices.CastHelpers.WriteBarrier(System.Object ByRef, System.Object)
System.Runtime.CompilerServices.CastHelpers.IsInstanceOfAny_NoCacheLookup(Void*, System.Object)

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToInterface(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+10]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01M00_L00:movsxdrdx,edimovrcx,rsimovr8,rbxcall CORINFO_HELP_ARRADDR_STincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 53

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax+rax]M00_L00:learcx,[rsi+rdi*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 60

.NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxsubrsp,28movrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax+rax]M00_L00:learcx,[rsi+rdi*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:addrsp,28poprbxpoprbppoprsipoprdiret; Total bytes of code 60

.NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

; ConsoleApp7.Benchmark.WriteToType(System.String)pushrdipushrsipushrbppushrbxmovrbx,rdxmovrsi,[rcx+18]xoredi,edimovebp,[rsi+8]testebp,ebpjle short M00_L01nop dword ptr [rax]nop dword ptr [rax+rax]M00_L00:movecx,edilearcx,[rsi+rcx*8+10]movrdx,rbxcall CORINFO_HELP_ASSIGN_REFincedicmpebp,edijg short M00_L00M00_L01:poprbxpoprbppoprsipoprdiret; Total bytes of code 58

@jkotas

jkotas commented Mar 20, 2024

Copy link
Copy Markdown
Member

I agree that the cold blocks ordering with PGO can be better in some case. I do not see any material code difference caused by this change. The exact code for these helpers can differ from workload to workload and from run to run depending on how PGO rolls the dice.

I have pushed a commit with a minor cleanup as I was looking at the code.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-VM-coreclrcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@MichalPetryka@jkotas@huoyaoyuan