Last active
March 18, 2018 18:19
-
-
Save gfoidl/4bfa371af9ae21ea8b867e9206ace5cc to your computer and use it in GitHub Desktop.
ThrowHelper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Numerics; | |
using System.Runtime.CompilerServices; | |
using System.Runtime.InteropServices; | |
using BenchmarkDotNet.Attributes; | |
using BenchmarkDotNet.Running; | |
namespace ConsoleApplication | |
{ | |
public unsafe class Program | |
{ | |
public static void Main(string[] args) | |
{ | |
Sample sample = new Sample(); | |
Console.WriteLine(A(sample)); | |
Console.WriteLine(B(sample)); | |
Console.WriteLine(C(sample)); | |
Console.WriteLine(D(sample)); | |
Console.WriteLine(E(sample)); | |
} | |
[MethodImpl(MethodImplOptions.NoInlining)] | |
private static int A(Sample sample) | |
{ | |
if (sample == null) ThrowHelper.ThrowArgumentNull(); | |
return sample.A; | |
} | |
[MethodImpl(MethodImplOptions.NoInlining)] | |
private static int B(Sample sample) | |
{ | |
if (sample == null) ThrowHelper.ThrowArgumentNull1(); | |
return sample.A; | |
} | |
[MethodImpl(MethodImplOptions.NoInlining)] | |
private static int C(Sample sample) | |
{ | |
if (sample == null) ThrowArgumentNull(); | |
return sample.A; | |
} | |
[MethodImpl(MethodImplOptions.NoInlining)] | |
private static int D(Sample sample) | |
{ | |
ThrowHelper.ThrowIfArgumentNull(sample); | |
return sample.A; | |
} | |
[MethodImpl(MethodImplOptions.NoInlining)] | |
private static int E(Sample sample) | |
{ | |
ThrowHelper.ThrowIfArgumentNull1(sample); | |
return sample.A; | |
} | |
private static void ThrowArgumentNull() => throw new ArgumentNullException("argument"); | |
} | |
public class Sample | |
{ | |
public int A { get; set; } = 42; | |
} | |
internal static class ThrowHelper | |
{ | |
public static void ThrowArgumentNull() => throw CreateArgumentNull(); | |
[MethodImpl(MethodImplOptions.NoInlining)] | |
private static Exception CreateArgumentNull() => new ArgumentNullException("argument"); | |
public static void ThrowArgumentNull1() => throw new ArgumentNullException("argument"); | |
public static void ThrowIfArgumentNull<T>(T arg) where T : class | |
{ | |
if (arg == null) | |
throw new ArgumentNullException("argument"); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static void ThrowIfArgumentNull1<T>(T arg) where T : class | |
{ | |
if (arg == null) | |
throw new ArgumentNullException("argument"); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 | |
42 | |
42 | |
42 | |
; Assembly listing for method ConsoleApplication.Program:A(ref):int | |
; Emitting BLENDED_CODE for X64 CPU with AVX | |
; optimized code | |
; rsp based frame | |
; partially interruptible | |
; Final local variable assignments | |
; | |
; V00 arg0 [V00,T00] ( 5, 5 ) ref -> rdi class-hnd | |
;# V01 OutArgs [V01 ] ( 1, 1 ) lclBlk ( 0) [rsp+0x00] | |
; | |
; Lcl frame size = 8 | |
G_M64832_IG01: | |
50 push rax | |
G_M64832_IG02: | |
4885FF test rdi, rdi | |
7408 je SHORT G_M64832_IG05 | |
G_M64832_IG03: | |
8B4708 mov eax, dword ptr [rdi+8] | |
G_M64832_IG04: | |
4883C408 add rsp, 8 | |
C3 ret | |
G_M64832_IG05: | |
E8E5FBFFFF call ConsoleApplication.ThrowHelper:ThrowArgumentNull() | |
CC int3 | |
; Total bytes of code 20, prolog size 1 for method ConsoleApplication.Program:A(ref):int | |
; ============================================================ | |
; Assembly listing for method ConsoleApplication.Program:B(ref):int | |
; Emitting BLENDED_CODE for X64 CPU with AVX | |
; optimized code | |
; rsp based frame | |
; partially interruptible | |
; Final local variable assignments | |
; | |
; V00 arg0 [V00,T00] ( 5, 5 ) ref -> rdi class-hnd | |
;# V01 OutArgs [V01 ] ( 1, 1 ) lclBlk ( 0) [rsp+0x00] | |
; | |
; Lcl frame size = 8 | |
G_M64831_IG01: | |
50 push rax | |
G_M64831_IG02: | |
4885FF test rdi, rdi | |
7408 je SHORT G_M64831_IG05 | |
G_M64831_IG03: | |
8B4708 mov eax, dword ptr [rdi+8] | |
G_M64831_IG04: | |
4883C408 add rsp, 8 | |
C3 ret | |
G_M64831_IG05: | |
E885E7FFFF call ConsoleApplication.ThrowHelper:ThrowArgumentNull1() | |
CC int3 | |
; Total bytes of code 20, prolog size 1 for method ConsoleApplication.Program:B(ref):int | |
; ============================================================ | |
; Assembly listing for method ConsoleApplication.Program:C(ref):int | |
; Emitting BLENDED_CODE for X64 CPU with AVX | |
; optimized code | |
; rsp based frame | |
; partially interruptible | |
; Final local variable assignments | |
; | |
; V00 arg0 [V00,T00] ( 5, 5 ) ref -> rdi class-hnd | |
;# V01 OutArgs [V01 ] ( 1, 1 ) lclBlk ( 0) [rsp+0x00] | |
; | |
; Lcl frame size = 8 | |
G_M64830_IG01: | |
50 push rax | |
G_M64830_IG02: | |
4885FF test rdi, rdi | |
7408 je SHORT G_M64830_IG05 | |
G_M64830_IG03: | |
8B4708 mov eax, dword ptr [rdi+8] | |
G_M64830_IG04: | |
4883C408 add rsp, 8 | |
C3 ret | |
G_M64830_IG05: | |
E8D5E2FFFF call ConsoleApplication.Program:ThrowArgumentNull() | |
CC int3 | |
; Total bytes of code 20, prolog size 1 for method ConsoleApplication.Program:C(ref):int | |
; ============================================================ | |
; Assembly listing for method ConsoleApplication.Program:D(ref):int | |
; Emitting BLENDED_CODE for X64 CPU with AVX | |
; optimized code | |
; rsp based frame | |
; partially interruptible | |
; Final local variable assignments | |
; | |
; V00 arg0 [V00,T00] ( 4, 4 ) ref -> rbx class-hnd | |
;# V01 OutArgs [V01 ] ( 1, 1 ) lclBlk ( 0) [rsp+0x00] | |
; | |
; Lcl frame size = 0 | |
G_M64828_IG01: | |
53 push rbx | |
488BDF mov rbx, rdi | |
G_M64828_IG02: | |
488BF3 mov rsi, rbx | |
48BF6080ADC6377F0000 mov rdi, 0x7F37C6AD8060 | |
E872F9FFFF call ConsoleApplication.ThrowHelper:ThrowIfArgumentNull(ref) | |
8B4308 mov eax, dword ptr [rbx+8] | |
G_M64828_IG03: | |
5B pop rbx | |
C3 ret | |
; Total bytes of code 27, prolog size 1 for method ConsoleApplication.Program:D(ref):int | |
; ============================================================ | |
; Assembly listin42 | |
g for method ConsoleApplication.Program:E(ref):int | |
; Emitting BLENDED_CODE for X64 CPU with AVX | |
; optimized code | |
; rsp based frame | |
; partially interruptible | |
; Final local variable assignments | |
; | |
; V00 arg0 [V00,T00] ( 5, 5 ) ref -> rdi class-hnd | |
; V01 tmp0 [V01,T01] ( 3, 0 ) ref -> rbx class-hnd exact | |
; V02 tmp1 [V02,T02] ( 2, 0 ) ref -> rsi | |
;# V03 OutArgs [V03 ] ( 1, 1 ) lclBlk ( 0) [rsp+0x00] | |
; | |
; Lcl frame size = 0 | |
G_M64828_IG01: | |
53 push rbx | |
G_M64828_IG02: | |
4885FF test rdi, rdi | |
7405 je SHORT G_M64828_IG05 | |
G_M64828_IG03: | |
8B4708 mov eax, dword ptr [rdi+8] | |
G_M64828_IG04: | |
5B pop rbx | |
C3 ret | |
G_M64828_IG05: | |
48BF301658C6377F0000 mov rdi, 0x7F37C6581630 | |
E8A62E9678 call CORINFO_HELP_NEWSFAST | |
488BD8 mov rbx, rax | |
BF01000000 mov edi, 1 | |
48BE603D26C5377F0000 mov rsi, 0x7F37C5263D60 | |
E8AF439678 call CORINFO_HELP_STRCNS | |
488BF0 mov rsi, rax | |
488BFB mov rdi, rbx | |
E8042760FF call System.ArgumentNullException:.ctor(ref):this | |
488BFB mov rdi, rbx | |
E89C249778 call CORINFO_HELP_THROW | |
CC int3 | |
; Total bytes of code 69, prolog size 1 for method ConsoleApplication.Program:E(ref):int | |
; ============================================================ |
There is even a further improvement when (string-) arguments must be passed to the ThrowHelper.
See Reference source -- ThrowHelper.
String argument in callee
G_M57615_IG01:
55 push rbp
488BEC mov rbp, rsp
G_M57615_IG02:
85F6 test esi, esi
7C07 jl SHORT G_M57615_IG05
G_M57615_IG03:
8BC6 mov eax, esi
C1E005 shl eax, 5
G_M57615_IG04:
5D pop rbp
C3 ret
G_M57615_IG05:
E8D4FBFFFF call ConsoleApp3.Strings:get_Unknown():ref
488BF8 mov rdi, rax
E8DCFBFFFF call ConsoleApp3.ThrowHelper:ThrowException(ref)
CC int3
; Total bytes of code 29, prolog size 4
Without string argument in callee
G_M57615_IG01:
50 push rax
G_M57615_IG02:
85F6 test esi, esi
7C0A jl SHORT G_M57615_IG05
G_M57615_IG03:
8BC6 mov eax, esi
C1E005 shl eax, 5
G_M57615_IG04:
4883C408 add rsp, 8
C3 ret
G_M57615_IG05:
BF01000000 mov edi, 1
E8AFFBFFFF call ConsoleApp3.ThrowHelper:ThrowException(int)
CC int3
; Total bytes of code 26, prolog size 1
This is produced by:
public class Foo
{
public int Do(int a)
{
if (a < 0) ThrowHelper.ThrowException(ThrowHelper.Reason.Unknown);
return a * 32;
}
}
internal static class ThrowHelper
{
public static void ThrowException(Reason reason) => throw new Exception(GetMessage(reason));
private static string GetMessage(Reason reason)
{
switch (reason)
{
case Reason.ArgumentOutOfRange:
return Strings.ArgumentOutOfRange;
case Reason.Unknown:
return Strings.Unknown;
default:
return string.Empty;
}
}
public enum Reason
{
ArgumentOutOfRange,
Unknown
}
}
Also see dotnet/extensions#324 (comment)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Discussion
As of dotnet/coreclr#6103
A
,B
, andC
produce the same code.