EgorBo / Disasmo

VS2022 Add-in. Click on any method or class to see what .NET Core's JIT generates for them (ASM).
MIT License
638 stars 39 forks source link

Add support for generic types and methods #41

Open RedworkDE opened 1 year ago

RedworkDE commented 1 year ago

Adds a setting to provide types to use for generic arguments.

Example:

static T[] NewArray<T>()
{
    return new T[5];
}

produces the output

; Assembly listing for method Program2:NewArray[System.__Canon]():<unnamed>
; Emitting BLENDED_CODE for X64 CPU with AVX - Windows
; optimized code
; rsp based frame
; partially interruptible
; No PGO data
; Final local variable assignments
;
;  V00 TypeCtx      [V00,T00] (  5,  4.25)    long  ->  rcx         single-def
;  V01 OutArgs      [V01    ] (  1,  1   )  lclBlk (32) [rsp+00H]   "OutgoingArgSpace"
;  V02 tmp1         [V02,T01] (  3,  3   )    long  ->  rdx         "spilling Runtime Lookup tree"
;  V03 cse0         [V03,T02] (  3,  2.25)    long  ->  rdx         "CSE - aggressive"
;
; Lcl frame size = 40

G_M13538_IG01:              ;; offset=0000H
       4883EC28             sub      rsp, 40
       48894C2420           mov      qword ptr [rsp+20H], rcx
                        ;; size=9 bbWeight=1    PerfScore 1.25
G_M13538_IG02:              ;; offset=0009H
       488B5138             mov      rdx, qword ptr [rcx+38H]
       488B5210             mov      rdx, qword ptr [rdx+10H]
       4885D2               test     rdx, rdx
       7402                 je       SHORT G_M13538_IG04
                        ;; size=13 bbWeight=1    PerfScore 5.25
G_M13538_IG03:              ;; offset=0016H
       EB12                 jmp      SHORT G_M13538_IG05
                        ;; size=2 bbWeight=0.25 PerfScore 0.50
G_M13538_IG04:              ;; offset=0018H
       48BA905DC4D6F77F0000 mov      rdx, 0x7FF7D6C45D90      ; global ptr
       E899F9505F           call     CORINFO_HELP_RUNTIMEHANDLE_METHOD
       488BD0               mov      rdx, rax
                        ;; size=18 bbWeight=0.25 PerfScore 0.38
G_M13538_IG05:              ;; offset=002AH
       488BCA               mov      rcx, rdx
       BA05000000           mov      edx, 5
       E809F7875F           call     CORINFO_HELP_NEWARR_1_OBJ
       90                   nop      
                        ;; size=14 bbWeight=1    PerfScore 1.75
G_M13538_IG06:              ;; offset=0038H
       4883C428             add      rsp, 40
       C3                   ret      
                        ;; size=5 bbWeight=1    PerfScore 1.25

; Total bytes of code 61, prolog size 9, PerfScore 16.48, instruction count 16, allocated bytes for code 61 (MethodHash=f226cb1d) for method Program2:NewArray[System.__Canon]():<unnamed>
; ============================================================

; Assembly listing for method Program2:NewArray[int]():<unnamed>
; Emitting BLENDED_CODE for X64 CPU with AVX - Windows
; optimized code
; rsp based frame
; partially interruptible
; No PGO data
; Final local variable assignments
;
;  V00 OutArgs      [V00    ] (  1,  1   )  lclBlk (32) [rsp+00H]   "OutgoingArgSpace"
;
; Lcl frame size = 40

G_M25943_IG01:              ;; offset=0000H
       4883EC28             sub      rsp, 40
                        ;; size=4 bbWeight=1    PerfScore 0.25
G_M25943_IG02:              ;; offset=0004H
       48B978D05FD6F77F0000 mov      rcx, 0x7FF7D65FD078      ; <unnamed>
       BA05000000           mov      edx, 5
       E868F6875F           call     CORINFO_HELP_NEWARR_1_VC
       90                   nop      
                        ;; size=21 bbWeight=1    PerfScore 1.75
G_M25943_IG03:              ;; offset=0019H
       4883C428             add      rsp, 40
       C3                   ret      
                        ;; size=5 bbWeight=1    PerfScore 1.25

; Total bytes of code 30, prolog size 4, PerfScore 6.25, instruction count 7, allocated bytes for code 30 (MethodHash=e37a9aa8) for method Program2:NewArray[int]():<unnamed>
; ============================================================

The default setting is to try int and Tuple<object, int> for all arguments, because common value type and some reference type. Exact reference type doesn't matter anyways and this way it demonstrates the syntax for specifying generic arguments. For completeness, I added a way to specify pointer and array types, but I don't think there is a way for them to matter, so they are not documented in the UI.

EgorBo commented 1 year ago

@RedworkDE oops, just noticed your PR, thank you so much for the contribution!

It slightly not aligned to the way I see generics support - I want to avoid complex UI for them and give user ability to quickly declare generics via comments directly in code, e.g.:

// Disasmo-Generic: int, System.String
// Disasmo-Generic: byte, float
static void Foo<T1, T2>()
{

}

this is expected to produce two compilations: Foo<int, System._Canon> and Foo<byte, float>

If user attempts to disasm a function without these annotations - a quick tutorial is printed in the output.

RedworkDE commented 1 year ago

I'll have to think about how to best get data from such a format into the loader; I imagine there will be some complications with correctly matching things in all cases, tho I think it would be easiest to reuse the loader that i currently have and to just live with a few extra instantiations if you reuse the generic parameter name in type and method / disassemble the whole type.

I'll see what works without becoming a giant mess and taking too much time.