none
Pre-Jit in method table RRS feed

  • Question

  • Hi,

    I am curious about ngen assemblies.  I was playing around with sos and noticed there are no entries in method table for pre-jit methods (not including object methods).  Why is this?  I know ngen methods don't use prejit stub but the address of code should still be somewhere.  I looked at methoddesc for prejit method and I can't figure any of the data besides 2nd word is method metatable index.  So how do we get the code address? Sos prints it out so it must be possible.

    !DumpMT -MD 73049b08
    EEClass: 72e71264
    Module: 72de1000
    Name: System.Diagnostics.Debugger
    mdToken: 0200029d  (C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
    BaseSize: 0xc
    ComponentSize: 0x0
    Number of IFaces in IFaceMap: 0
    Slots in VTable: 14
    --------------------------------------
    MethodDesc Table
       Entry MethodDesc      JIT Name
    72fa6a70   72e24934   PreJIT System.Object.ToString()
    72fa6a90   72e2493c   PreJIT System.Object.Equals(System.Object)
    72fa6b00   72e2496c   PreJIT System.Object.GetHashCode()
    730172f0   72e24990   PreJIT System.Object.Finalize()
    7350ce60   72ec1e64   PreJIT System.Diagnostics.Debugger..ctor()
    7350cdf4   72ec1e04   PreJIT System.Diagnostics.Debugger.Break()
    7350cda0   72ec1e10   PreJIT System.Diagnostics.Debugger.BreakCanThrow()
    72f74b90   72ec1e1c     NONE System.Diagnostics.Debugger.BreakInternal()
    7350cd1c   72ec1e2c   PreJIT System.Diagnostics.Debugger.Launch()
    72f74b88   72ec1e38     NONE System.Diagnostics.Debugger.LaunchInternal()
    72fced50   72ec1e48   PreJIT System.Diagnostics.Debugger.get_IsAttached()
    72f61a88   72e1f804     NONE System.Diagnostics.Debugger.IsDebuggerAttached()
    72f74b98   72ec1e54     NONE System.Diagnostics.Debugger.Log(Int32, System.String, System.String)
    72f61a90   72e1f814     NONE System.Diagnostics.Debugger.IsLogging()




    0x73049B08  00000000 0000000c 00050015 00000004 73050508 72de1000 72e0a014 72e71264 
    0x73049B28  00000000 00000000 72fa6a70 72fa6a90 72fa6b00 730172f0 004c3320 ffffffe4 
    0x73049B48  00000014 ffffffe8 00000004 00000002 00080000 00000020 000f0015 0002000f 
    0x73049B68  73050e0c 72de1000 72de39c8 72de39d0 00000000 00000000 72fa6a70 72fa16b0 
    0x73049B88  72fd71d0 730172f0 72ff64c0 72fa8080 72ffc8b0 73015a50 72fa8230 7347da20 
    0x73049BA8  7347d6a8 72ff6890 72f62cdc 72f74ba4 72f74bb0 73049bc0 7304a398 00000002 
    0x73049BC8  73027c54 00000002 00000000 0000000c 000b0015 0000000a 73050508 72de1000 
    Tuesday, June 30, 2009 1:56 PM

Answers

  • You are right. I forgot that 2.0 SP2 implemented NGEN cold startup improvements.
    MethodTable stored in NGEN is a little bit more complicated in 2.0 SP2: Virtual slots are stored as code pointers, non-virtual VTable slots are stored as relative code pointers and non-VTable methods are stored as relative pointers behind the MethodDesc.

    Note that 4.0 format in NGEN is even more complicated and the virtual slots won't be stored as a simple list of code pointers.

    Here's an example using 2.0 SP2:

    !Name2EE mscorlib.dll System.Diagnostics.Debugger
        Module: 70661000 (mscorlib.dll)
        Token: 0x0200029d
        MethodTable: 708c9b08
        EEClass: 706f1264
        Name: System.Diagnostics.Debugger

    !DumpMT -MD 708c9b08
        EEClass: 706f1264
        Module: 70661000
        Name: System.Diagnostics.Debugger
        mdToken: 0200029d  (C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
        BaseSize: 0xc
        ComponentSize: 0x0
        Number of IFaces in IFaceMap: 0
        Slots in VTable: 14
        --------------------------------------
        MethodDesc Table
           Entry MethodDesc      JIT Name
        70826a70   706a4934   PreJIT System.Object.ToString()
        70826a90   706a493c   PreJIT System.Object.Equals(System.Object)
        70826b00   706a496c   PreJIT System.Object.GetHashCode()
        708972f0   706a4990   PreJIT System.Object.Finalize()
        70d8ce60   70741e64   PreJIT System.Diagnostics.Debugger..ctor()
        70d8cdf4   70741e04   PreJIT System.Diagnostics.Debugger.Break()
        70d8cda0   70741e10   PreJIT System.Diagnostics.Debugger.BreakCanThrow()
        707f4b90   70741e1c     NONE System.Diagnostics.Debugger.BreakInternal()
        70d8cd1c   70741e2c   PreJIT System.Diagnostics.Debugger.Launch()
        707f4b88   70741e38     NONE System.Diagnostics.Debugger.LaunchInternal()
        7084ed50   70741e48   PreJIT System.Diagnostics.Debugger.get_IsAttached()
        707e1a88   7069f804     NONE System.Diagnostics.Debugger.IsDebuggerAttached()
        707f4b98   70741e54     NONE System.Diagnostics.Debugger.Log(Int32, System.String, System.String)
        707e1a90   7069f814     NONE System.Diagnostics.Debugger.IsLogging()

    !DumpClass 706f1264
        Class Name: System.Diagnostics.Debugger
        mdToken: 0200029d (C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
        Parent Class: 70663ef0
        Module: 70661000
        Method Table: 708c9b08
        Vtable Slots: 4
        Total Method Slots: 5
        Class Attributes: 100101 
        NumInstanceFields: 0
        NumStaticFields: 1
              MT    Field   Offset                 Type VT     Attr    Value Name
        708d08ec  40009f5      1e8        System.String  0   shared   static DefaultCategory
            >> Domain:Value  00342870:NotInit  <<

    dd 708c9b08
        MethodTable (size 0x28):
            708c9b08  00000000 0000000c 00050015 00000004
            708c9b18  708d0508 70661000 7068a014 706f1264
            708c9b28  00000000 00000000
        behind MethodTable: virtual slots (4 = EEClass.'Vtable Slots')
                            70826a70 ... System.Object.ToString()
                            70826a90 ... System.Object.Equals(System.Object)
            708c9b38  70826b00 ... System.Object.GetHashCode()
                            708972f0 ... System.Object.Finalize()
        behind virtual slots: non-virtual slots (1 = EEClass.'Total Method Slots' - EEClass.'Vtable Slots')
                            004c3320 ... relative pointer: 708c9b40 + 004c3320 = 70d8ce60 ... System.Diagnostics.Debugger..ctor()

    !DumpMD 70741e64
        Method Name: System.Diagnostics.Debugger..ctor()
        Class: 706f1264
        MethodTable: 708c9b08
        mdToken: 06001ab5
        Module: 70661000
        IsJitted: yes
        CodeAddr: 70d8ce60
    dd 70741e04
        MethodDesc (size 0xc ... because next MD starts at 70741e10)
            70741e04  71001aac 2020d805 
                            0064afe8 ... relative pointer: 70741e0c + 0064afe8 = 70d8cdf4 ... System.Diagnostics.Debugger.Break()

    Wednesday, July 1, 2009 4:45 PM
    Moderator
  • Well first, they are in order - first virtual VTable slots, then non-virtual method slots, then methods without slots. The number of virutal VTable slots ("Vtable Slots") and the number of all method slots ("Total Method Slots") are in EEClass:

    !DumpClass 706f1264
        Class Name: System.Diagnostics.Debugger
        mdToken: 0200029d (C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
        Parent Class: 70663ef0
        Module: 70661000
        Method Table: 708c9b08
        Vtable Slots: 4
        Total Method Slots: 5

    Getting to the number of all methods (incl. those without slots) is quite non-trivial. The number is stored in the MethodTable, but it is at variable position and depends on the MethodTable.
    Does it answer your question?

    Thanks,
    -Karel
    • Marked as answer by AbdElRaheim Thursday, July 2, 2009 6:39 PM
    Thursday, July 2, 2009 3:42 PM
    Moderator

All replies

  • There shouldn't be any hidden magic. MethodTable contains just plain list of code pointers to all virtual methods (first) and then non-virtual and static methods. !DumpMT just displays those code pointers (with additional info like JIT status, MethodDesc pointer and method name)

    Also it works for me perfectly fine (using 2.0.50727.1434 = CLR 2.0 SP1 "Orcas RTM"). Can you try it again? Which CLR version do you use? (lm vm mscorwks)

    !Name2EE mscorlib.dll System.Diagnostics.Debugger
        Module: 790c2000 (mscorlib.dll)
        Token: 0x02000299
        MethodTable: 79182040
        EEClass: 79216aec
        Name: System.Diagnostics.Debugger

    !DumpMT -MD 79182040
        EEClass: 79216aec
        Module: 790c2000
        Name: System.Diagnostics.Debugger
        mdToken: 02000299  (C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
        BaseSize: 0xc
        ComponentSize: 0x0
        Number of IFaces in IFaceMap: 0
        Slots in VTable: 14
        --------------------------------------
        MethodDesc Table
           Entry MethodDesc      JIT Name
        79371278   7914b928   PreJIT System.Object.ToString()
        7936b3b0   7914b930   PreJIT System.Object.Equals(System.Object)
        7936b3d0   7914b948   PreJIT System.Object.GetHashCode()
        793624d0   7914b950   PreJIT System.Object.Finalize()
        79420410   79282350   PreJIT System.Diagnostics.Debugger.Break()
        79420484   79282358   PreJIT System.Diagnostics.Debugger.BreakCanThrow()
        7a113cbc   79282318    FCALL System.Diagnostics.Debugger.BreakInternal()
        794204ec   79282360   PreJIT System.Diagnostics.Debugger.Launch()
        7a113de2   79282320    FCALL System.Diagnostics.Debugger.LaunchInternal()
        7936b4d8   79282368   PreJIT System.Diagnostics.Debugger.get_IsAttached()
        79eaedd4   79282328    FCALL System.Diagnostics.Debugger.IsDebuggerAttached()
        7a113f01   79282330    FCALL System.Diagnostics.Debugger.Log(Int32, System.String, System.String)
        7a113c5d   79282338    FCALL System.Diagnostics.Debugger.IsLogging()
        79420570   79282370   PreJIT System.Diagnostics.Debugger..ctor()

    dd 79182040
        79182040  02040000 0000000c 000e0422 00000004
        79182050  790fd0f0 790c2000 790c8eac 79216aec
        79182060  00000000 00000000 79371278 7936b3b0
        79182070  7936b3d0 793624d0 79420410 79420484
        79182080  7a113cbc 794204ec 7a113de2 7936b4d8
        79182090  79eaedd4 7a113f01 7a113c5d 79420570

    -Karel

    Tuesday, June 30, 2009 4:30 PM
    Moderator
  • I recently installed .net 3.5 sp1 and had to install 2.0 sp2.  I think there were some changes in sp2 on how this stuff works.  I notice in 2.0 sp1 the methoddesc is 8 bytes and in 2.0sp2 the method desc is now 12bytes.  Only prejit method don't show up are not showing up in methodtable.   I wonder where they are
    Tuesday, June 30, 2009 8:02 PM
  • Looks like a lot of changes in the "methodtable" in 2.0 sp2.  I dont see the stub addresses in the table address space anymore except object methods and static ctors.  The methoddesc are now 12-bytes and the last DWORD is the stub address except for prejit methods.  For prejits this is not an absolute address and I don't know what the numbers means.  anyone have any idea?

    Wednesday, July 1, 2009 3:09 PM
  • You are right. I forgot that 2.0 SP2 implemented NGEN cold startup improvements.
    MethodTable stored in NGEN is a little bit more complicated in 2.0 SP2: Virtual slots are stored as code pointers, non-virtual VTable slots are stored as relative code pointers and non-VTable methods are stored as relative pointers behind the MethodDesc.

    Note that 4.0 format in NGEN is even more complicated and the virtual slots won't be stored as a simple list of code pointers.

    Here's an example using 2.0 SP2:

    !Name2EE mscorlib.dll System.Diagnostics.Debugger
        Module: 70661000 (mscorlib.dll)
        Token: 0x0200029d
        MethodTable: 708c9b08
        EEClass: 706f1264
        Name: System.Diagnostics.Debugger

    !DumpMT -MD 708c9b08
        EEClass: 706f1264
        Module: 70661000
        Name: System.Diagnostics.Debugger
        mdToken: 0200029d  (C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
        BaseSize: 0xc
        ComponentSize: 0x0
        Number of IFaces in IFaceMap: 0
        Slots in VTable: 14
        --------------------------------------
        MethodDesc Table
           Entry MethodDesc      JIT Name
        70826a70   706a4934   PreJIT System.Object.ToString()
        70826a90   706a493c   PreJIT System.Object.Equals(System.Object)
        70826b00   706a496c   PreJIT System.Object.GetHashCode()
        708972f0   706a4990   PreJIT System.Object.Finalize()
        70d8ce60   70741e64   PreJIT System.Diagnostics.Debugger..ctor()
        70d8cdf4   70741e04   PreJIT System.Diagnostics.Debugger.Break()
        70d8cda0   70741e10   PreJIT System.Diagnostics.Debugger.BreakCanThrow()
        707f4b90   70741e1c     NONE System.Diagnostics.Debugger.BreakInternal()
        70d8cd1c   70741e2c   PreJIT System.Diagnostics.Debugger.Launch()
        707f4b88   70741e38     NONE System.Diagnostics.Debugger.LaunchInternal()
        7084ed50   70741e48   PreJIT System.Diagnostics.Debugger.get_IsAttached()
        707e1a88   7069f804     NONE System.Diagnostics.Debugger.IsDebuggerAttached()
        707f4b98   70741e54     NONE System.Diagnostics.Debugger.Log(Int32, System.String, System.String)
        707e1a90   7069f814     NONE System.Diagnostics.Debugger.IsLogging()

    !DumpClass 706f1264
        Class Name: System.Diagnostics.Debugger
        mdToken: 0200029d (C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
        Parent Class: 70663ef0
        Module: 70661000
        Method Table: 708c9b08
        Vtable Slots: 4
        Total Method Slots: 5
        Class Attributes: 100101 
        NumInstanceFields: 0
        NumStaticFields: 1
              MT    Field   Offset                 Type VT     Attr    Value Name
        708d08ec  40009f5      1e8        System.String  0   shared   static DefaultCategory
            >> Domain:Value  00342870:NotInit  <<

    dd 708c9b08
        MethodTable (size 0x28):
            708c9b08  00000000 0000000c 00050015 00000004
            708c9b18  708d0508 70661000 7068a014 706f1264
            708c9b28  00000000 00000000
        behind MethodTable: virtual slots (4 = EEClass.'Vtable Slots')
                            70826a70 ... System.Object.ToString()
                            70826a90 ... System.Object.Equals(System.Object)
            708c9b38  70826b00 ... System.Object.GetHashCode()
                            708972f0 ... System.Object.Finalize()
        behind virtual slots: non-virtual slots (1 = EEClass.'Total Method Slots' - EEClass.'Vtable Slots')
                            004c3320 ... relative pointer: 708c9b40 + 004c3320 = 70d8ce60 ... System.Diagnostics.Debugger..ctor()

    !DumpMD 70741e64
        Method Name: System.Diagnostics.Debugger..ctor()
        Class: 706f1264
        MethodTable: 708c9b08
        mdToken: 06001ab5
        Module: 70661000
        IsJitted: yes
        CodeAddr: 70d8ce60
    dd 70741e04
        MethodDesc (size 0xc ... because next MD starts at 70741e10)
            70741e04  71001aac 2020d805 
                            0064afe8 ... relative pointer: 70741e0c + 0064afe8 = 70d8cdf4 ... System.Diagnostics.Debugger.Break()

    Wednesday, July 1, 2009 4:45 PM
    Moderator
  • Sweet.  Thank you so much for helping me with this. 
    Wednesday, July 1, 2009 5:11 PM
  • Hi Karel,

    Thanks for your help earlier.  I have one more quick question.  How do I know which is which?  Is there a flag in the methoddesc or something?

    Thursday, July 2, 2009 3:33 AM
  • Well first, they are in order - first virtual VTable slots, then non-virtual method slots, then methods without slots. The number of virutal VTable slots ("Vtable Slots") and the number of all method slots ("Total Method Slots") are in EEClass:

    !DumpClass 706f1264
        Class Name: System.Diagnostics.Debugger
        mdToken: 0200029d (C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
        Parent Class: 70663ef0
        Module: 70661000
        Method Table: 708c9b08
        Vtable Slots: 4
        Total Method Slots: 5

    Getting to the number of all methods (incl. those without slots) is quite non-trivial. The number is stored in the MethodTable, but it is at variable position and depends on the MethodTable.
    Does it answer your question?

    Thanks,
    -Karel
    • Marked as answer by AbdElRaheim Thursday, July 2, 2009 6:39 PM
    Thursday, July 2, 2009 3:42 PM
    Moderator