-
Notifications
You must be signed in to change notification settings - Fork 4.7k
/
methodtable.h
4010 lines (3283 loc) · 146 KB
/
methodtable.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
//
// File: methodtable.h
//
#ifndef _METHODTABLE_H_
#define _METHODTABLE_H_
/*
* Include Files
*/
#include "vars.hpp"
#include "cor.h"
#include "hash.h"
#include "crst.h"
#include "cgensys.h"
#ifdef FEATURE_COMINTEROP
#include "stdinterfaces.h"
#endif
#include "slist.h"
#include "spinlock.h"
#include "typehandle.h"
#include "eehash.h"
#include "contractimpl.h"
#include "generics.h"
#include "fixuppointer.h"
#include "gcinfotypes.h"
/*
* Forward Declarations
*/
class AppDomain;
class ArrayClass;
class ArrayMethodDesc;
struct ClassCtorInfoEntry;
class ClassLoader;
class FCallMethodDesc;
class EEClass;
class EnCFieldDesc;
class FieldDesc;
class JIT_TrialAlloc;
struct LayoutRawFieldInfo;
class MetaSig;
class MethodDesc;
class MethodDescChunk;
class MethodTable;
class Module;
class Object;
class Stub;
class Substitution;
class TypeHandle;
class Dictionary;
class AllocMemTracker;
class SimpleRWLock;
class MethodDataCache;
class EEClassLayoutInfo;
class EEClassNativeLayoutInfo;
#ifdef FEATURE_COMINTEROP
class ComCallWrapperTemplate;
#endif
#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
class ClassFactoryBase;
#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
class ArgDestination;
enum class WellKnownAttribute : DWORD;
//============================================================================
// This is the in-memory structure of a class and it will evolve.
//============================================================================
// <TODO>
// Add a sync block
// Also this class currently has everything public - this may changes
// Might also need to hold onto the meta data loader fot this class</TODO>
//
// A MethodTable contains an array of these structures, which describes each interface implemented
// by this class (directly declared or indirectly declared).
//
// Generic type instantiations (in C# syntax: C<ty_1,...,ty_n>) are represented by
// MethodTables, i.e. a new MethodTable gets allocated for each such instantiation.
// The entries in these tables (i.e. the code) are, however, often shared.
//
// In particular, a MethodTable's vtable contents (and hence method descriptors) may be
// shared between compatible instantiations (e.g. List<string> and List<object> have
// the same vtable *contents*). Likewise the EEClass will be shared between
// compatible instantiations whenever the vtable contents are.
//
// !!! Thus that it is _not_ generally the case that GetClass.GetMethodTable() == t. !!!
//
// Instantiated interfaces have their own method tables unique to the instantiation e.g. I<string> is
// distinct from I<int> and I<object>
//
// For generic types the interface map lists generic interfaces
// For instantiated types the interface map lists instantiated interfaces
// e.g. for C<T> : I<T>, J<string>
// the interface map for C would list I and J
// the interface map for C<int> would list I<int> and J<string>
//
struct InterfaceInfo_t
{
#ifdef DACCESS_COMPILE
friend class NativeImageDumper;
#endif
// Method table of the interface
#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
RelativeFixupPointer<PTR_MethodTable> m_pMethodTable;
#else
FixupPointer<PTR_MethodTable> m_pMethodTable;
#endif
public:
FORCEINLINE PTR_MethodTable GetMethodTable()
{
LIMITED_METHOD_CONTRACT;
return ReadPointerMaybeNull(this, &InterfaceInfo_t::m_pMethodTable);
}
#ifndef DACCESS_COMPILE
void SetMethodTable(MethodTable * pMT)
{
LIMITED_METHOD_CONTRACT;
m_pMethodTable.SetValueMaybeNull(pMT);
}
// Get approximate method table. This is used by the type loader before the type is fully loaded.
PTR_MethodTable GetApproxMethodTable(Module * pContainingModule);
#endif // !DACCESS_COMPILE
#ifndef DACCESS_COMPILE
InterfaceInfo_t(InterfaceInfo_t &right)
{
m_pMethodTable.SetValueMaybeNull(right.m_pMethodTable.GetValueMaybeNull());
}
#else // !DACCESS_COMPILE
private:
InterfaceInfo_t(InterfaceInfo_t &right);
#endif // !DACCESS_COMPILE
}; // struct InterfaceInfo_t
typedef DPTR(InterfaceInfo_t) PTR_InterfaceInfo;
namespace ClassCompat
{
struct InterfaceInfo_t;
};
// Data needed when simulating old VTable layout for COM Interop
// This is necessary as the data is saved in MethodDescs and we need
// to simulate different values without copying or changing the existing
// MethodDescs
//
// This will be created in a parallel array to ppMethodDescList and
// ppUnboxMethodDescList in the bmtMethAndFieldDescs structure below
struct InteropMethodTableSlotData
{
enum
{
e_DUPLICATE = 0x0001 // The entry is duplicate
};
MethodDesc *pMD; // The MethodDesc for this slot
WORD wSlot; // The simulated slot value for the MethodDesc
WORD wFlags; // The simulated duplicate value
MethodDesc *pDeclMD; // To keep track of MethodImpl's
void SetDuplicate()
{
wFlags |= e_DUPLICATE;
}
BOOL IsDuplicate() {
return ((BOOL)(wFlags & e_DUPLICATE));
}
WORD GetSlot() {
return wSlot;
}
void SetSlot(WORD wSlot) {
this->wSlot = wSlot;
}
}; // struct InteropMethodTableSlotData
#ifdef FEATURE_COMINTEROP
struct InteropMethodTableData
{
WORD cVTable; // Count of vtable slots
InteropMethodTableSlotData *pVTable; // Data for each slot
WORD cNonVTable; // Count of non-vtable slots
InteropMethodTableSlotData *pNonVTable; // Data for each slot
WORD cInterfaceMap; // Count of interfaces
ClassCompat::InterfaceInfo_t *
pInterfaceMap; // The interface map
// Utility methods
static WORD GetRealMethodDesc(MethodTable *pMT, MethodDesc *pMD);
static WORD GetSlotForMethodDesc(MethodTable *pMT, MethodDesc *pMD);
ClassCompat::InterfaceInfo_t* FindInterface(MethodTable *pInterface);
WORD GetStartSlotForInterface(MethodTable* pInterface);
};
class InteropMethodTableSlotDataMap
{
protected:
InteropMethodTableSlotData *m_pSlotData;
DWORD m_cSlotData;
DWORD m_iCurSlot;
public:
InteropMethodTableSlotDataMap(InteropMethodTableSlotData *pSlotData, DWORD cSlotData);
InteropMethodTableSlotData *GetData(MethodDesc *pMD);
BOOL Exists(MethodDesc *pMD);
protected:
InteropMethodTableSlotData *Exists_Helper(MethodDesc *pMD);
InteropMethodTableSlotData *GetNewEntry();
}; // class InteropMethodTableSlotDataMap
#endif // FEATURE_COMINTEROP
//
// This struct contains cached information on the GUID associated with a type.
//
struct GuidInfo
{
GUID m_Guid; // The actual guid of the type.
BOOL m_bGeneratedFromName; // A boolean indicating if it was generated from the
// name of the type.
};
typedef DPTR(GuidInfo) PTR_GuidInfo;
// GenericsDictInfo is stored at negative offset of the dictionary
struct GenericsDictInfo
{
#ifdef HOST_64BIT
DWORD m_dwPadding; // Just to keep the size a multiple of 8
#endif
// Total number of instantiation dictionaries including inherited ones
// i.e. how many instantiated classes (including this one) are there in the hierarchy?
// See comments about PerInstInfo
WORD m_wNumDicts;
// Number of type parameters (NOT including those of superclasses).
WORD m_wNumTyPars;
}; // struct GenericsDictInfo
typedef DPTR(GenericsDictInfo) PTR_GenericsDictInfo;
struct GenericsStaticsInfo
{
// Pointer to field descs for statics
RelativePointer<PTR_FieldDesc> m_pFieldDescs;
// Method table ID for statics
SIZE_T m_DynamicTypeID;
}; // struct GenericsStaticsInfo
typedef DPTR(GenericsStaticsInfo) PTR_GenericsStaticsInfo;
// CrossModuleGenericsStaticsInfo is used in NGen images for statics of cross-module
// generic instantiations. CrossModuleGenericsStaticsInfo is optional member of
// MethodTableWriteableData.
struct CrossModuleGenericsStaticsInfo
{
// Module this method table statics are attached to.
//
// The statics has to be attached to module referenced from the generic instantiation
// in domain-neutral code. We need to guarantee that the module for the statics
// has a valid local represenation in an appdomain.
//
PTR_Module m_pModuleForStatics;
// Method table ID for statics
SIZE_T m_DynamicTypeID;
}; // struct CrossModuleGenericsStaticsInfo
typedef DPTR(CrossModuleGenericsStaticsInfo) PTR_CrossModuleGenericsStaticsInfo;
//
// This struct consolidates the writeable parts of the MethodTable
// so that we can layout a read-only MethodTable with a pointer
// to the writeable parts of the MethodTable in an ngen image
//
struct MethodTableWriteableData
{
friend class MethodTable;
#if defined(DACCESS_COMPILE)
friend class NativeImageDumper;
#endif
enum
{
// AS YOU ADD NEW FLAGS PLEASE CONSIDER WHETHER Generics::NewInstantiation NEEDS
// TO BE UPDATED IN ORDER TO ENSURE THAT METHODTABLES DUPLICATED FOR GENERIC INSTANTIATIONS
// CARRY THE CORRECT INITIAL FLAGS.
enum_flag_Unrestored = 0x00000004,
enum_flag_HasApproxParent = 0x00000010,
enum_flag_UnrestoredTypeKey = 0x00000020,
enum_flag_IsNotFullyLoaded = 0x00000040,
enum_flag_DependenciesLoaded = 0x00000080, // class and all depedencies loaded up to CLASS_LOADED_BUT_NOT_VERIFIED
// enum_unused = 0x00000100,
enum_flag_CanCompareBitsOrUseFastGetHashCode = 0x00000200, // Is any field type or sub field type overrode Equals or GetHashCode
enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode = 0x00000400, // Whether we have checked the overridden Equals or GetHashCode
#ifdef FEATURE_PREJIT
// These flags are used only at ngen time. We store them here since
// we are running out of available flags in MethodTable. They may eventually
// go into ngen speficic state.
enum_flag_NGEN_IsFixedUp = 0x00010000, // This MT has been fixed up during NGEN
enum_flag_NGEN_IsNeedsRestoreCached = 0x00020000, // Set if we have cached the results of needs restore computation
enum_flag_NGEN_CachedNeedsRestore = 0x00040000, // The result of the needs restore computation
// enum_unused = 0x00080000,
#ifdef FEATURE_READYTORUN_COMPILER
enum_flag_NGEN_IsLayoutFixedComputed = 0x0010000, // Set if we have cached the result of IsLayoutFixed computation
enum_flag_NGEN_IsLayoutFixed = 0x0020000, // The result of the IsLayoutFixed computation
enum_flag_NGEN_IsLayoutInCurrentVersionBubbleComputed = 0x0040000, // Set if we have cached the result of IsLayoutInCurrentVersionBubble computation
enum_flag_NGEN_IsLayoutInCurrentVersionBubble = 0x0080000, // The result of the IsLayoutInCurrentVersionBubble computation
#endif
#endif // FEATURE_PREJIT
#ifdef _DEBUG
enum_flag_ParentMethodTablePointerValid = 0x40000000,
enum_flag_HasInjectedInterfaceDuplicates = 0x80000000,
#endif
};
DWORD m_dwFlags; // Lot of empty bits here.
/*
* m_hExposedClassObject is LoaderAllocator slot index to
* a RuntimeType instance for this class.
*/
LOADERHANDLE m_hExposedClassObject;
#ifdef _DEBUG
// to avoid verify same method table too many times when it's not changing, we cache the GC count
// on which the method table is verified. When fast GC STRESS is turned on, we only verify the MT if
// current GC count is bigger than the number. Note most thing which will invalidate a MT will require a
// GC (like AD unload)
Volatile<DWORD> m_dwLastVerifedGCCnt;
#ifdef HOST_64BIT
DWORD m_dwPadding; // Just to keep the size a multiple of 8
#endif
#endif
// Optional CrossModuleGenericsStaticsInfo may be here.
public:
#ifdef _DEBUG
inline BOOL IsParentMethodTablePointerValid() const
{
LIMITED_METHOD_DAC_CONTRACT;
return (m_dwFlags & enum_flag_ParentMethodTablePointerValid);
}
inline void SetParentMethodTablePointerValid()
{
LIMITED_METHOD_CONTRACT;
m_dwFlags |= enum_flag_ParentMethodTablePointerValid;
}
#endif
#ifdef FEATURE_PREJIT
void Save(DataImage *image, MethodTable *pMT, DWORD profilingFlags) const;
void Fixup(DataImage *image, MethodTable *pMT, BOOL needsRestore);
inline BOOL IsFixedUp() const
{
LIMITED_METHOD_CONTRACT;
return (m_dwFlags & enum_flag_NGEN_IsFixedUp);
}
inline void SetFixedUp()
{
LIMITED_METHOD_CONTRACT;
m_dwFlags |= enum_flag_NGEN_IsFixedUp;
}
inline BOOL IsNeedsRestoreCached() const
{
LIMITED_METHOD_CONTRACT;
return (m_dwFlags & enum_flag_NGEN_IsNeedsRestoreCached);
}
inline BOOL GetCachedNeedsRestore() const
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(IsNeedsRestoreCached());
return (m_dwFlags & enum_flag_NGEN_CachedNeedsRestore);
}
inline void SetCachedNeedsRestore(BOOL fNeedsRestore)
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(!IsNeedsRestoreCached());
m_dwFlags |= enum_flag_NGEN_IsNeedsRestoreCached;
if (fNeedsRestore) m_dwFlags |= enum_flag_NGEN_CachedNeedsRestore;
}
#endif // FEATURE_PREJIT
inline LOADERHANDLE GetExposedClassObjectHandle() const
{
LIMITED_METHOD_CONTRACT;
return m_hExposedClassObject;
}
void SetIsNotFullyLoadedForBuildMethodTable()
{
LIMITED_METHOD_CONTRACT;
// Used only during method table initialization - no need for logging or Interlocked Exchange.
m_dwFlags |= (MethodTableWriteableData::enum_flag_UnrestoredTypeKey |
MethodTableWriteableData::enum_flag_Unrestored |
MethodTableWriteableData::enum_flag_IsNotFullyLoaded |
MethodTableWriteableData::enum_flag_HasApproxParent);
}
void SetIsRestoredForBuildMethodTable()
{
LIMITED_METHOD_CONTRACT;
// Used only during method table initialization - no need for logging or Interlocked Exchange.
m_dwFlags &= ~(MethodTableWriteableData::enum_flag_UnrestoredTypeKey |
MethodTableWriteableData::enum_flag_Unrestored);
}
void SetIsRestoredForBuildArrayMethodTable()
{
LIMITED_METHOD_CONTRACT;
// Used only during method table initialization - no need for logging or Interlocked Exchange.
SetIsRestoredForBuildMethodTable();
// Array's parent is always precise
m_dwFlags &= ~(MethodTableWriteableData::enum_flag_HasApproxParent);
}
inline CrossModuleGenericsStaticsInfo * GetCrossModuleGenericsStaticsInfo()
{
LIMITED_METHOD_DAC_CONTRACT;
SIZE_T size = sizeof(MethodTableWriteableData);
return PTR_CrossModuleGenericsStaticsInfo(dac_cast<TADDR>(this) + size);
}
}; // struct MethodTableWriteableData
typedef DPTR(MethodTableWriteableData) PTR_MethodTableWriteableData;
typedef DPTR(MethodTableWriteableData const) PTR_Const_MethodTableWriteableData;
#ifdef UNIX_AMD64_ABI_ITF
inline
SystemVClassificationType CorInfoType2UnixAmd64Classification(CorElementType eeType)
{
static const SystemVClassificationType toSystemVAmd64ClassificationTypeMap[] = {
SystemVClassificationTypeUnknown, // ELEMENT_TYPE_END
SystemVClassificationTypeUnknown, // ELEMENT_TYPE_VOID
SystemVClassificationTypeInteger, // ELEMENT_TYPE_BOOLEAN
SystemVClassificationTypeInteger, // ELEMENT_TYPE_CHAR
SystemVClassificationTypeInteger, // ELEMENT_TYPE_I1
SystemVClassificationTypeInteger, // ELEMENT_TYPE_U1
SystemVClassificationTypeInteger, // ELEMENT_TYPE_I2
SystemVClassificationTypeInteger, // ELEMENT_TYPE_U2
SystemVClassificationTypeInteger, // ELEMENT_TYPE_I4
SystemVClassificationTypeInteger, // ELEMENT_TYPE_U4
SystemVClassificationTypeInteger, // ELEMENT_TYPE_I8
SystemVClassificationTypeInteger, // ELEMENT_TYPE_U8
SystemVClassificationTypeSSE, // ELEMENT_TYPE_R4
SystemVClassificationTypeSSE, // ELEMENT_TYPE_R8
SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_STRING
SystemVClassificationTypeInteger, // ELEMENT_TYPE_PTR
SystemVClassificationTypeIntegerByRef, // ELEMENT_TYPE_BYREF
SystemVClassificationTypeStruct, // ELEMENT_TYPE_VALUETYPE
SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_CLASS
SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_VAR (type variable)
SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_ARRAY
SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_GENERICINST
SystemVClassificationTypeStruct, // ELEMENT_TYPE_TYPEDBYREF
SystemVClassificationTypeUnknown, // ELEMENT_TYPE_VALUEARRAY_UNSUPPORTED
SystemVClassificationTypeInteger, // ELEMENT_TYPE_I
SystemVClassificationTypeInteger, // ELEMENT_TYPE_U
SystemVClassificationTypeUnknown, // ELEMENT_TYPE_R_UNSUPPORTED
// put the correct type when we know our implementation
SystemVClassificationTypeInteger, // ELEMENT_TYPE_FNPTR
SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_OBJECT
SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_SZARRAY
SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_MVAR
SystemVClassificationTypeUnknown, // ELEMENT_TYPE_CMOD_REQD
SystemVClassificationTypeUnknown, // ELEMENT_TYPE_CMOD_OPT
SystemVClassificationTypeUnknown, // ELEMENT_TYPE_INTERNAL
};
_ASSERTE(sizeof(toSystemVAmd64ClassificationTypeMap) == ELEMENT_TYPE_MAX);
_ASSERTE(eeType < (CorElementType) sizeof(toSystemVAmd64ClassificationTypeMap));
// spot check of the map
_ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_I4] == SystemVClassificationTypeInteger);
_ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_PTR] == SystemVClassificationTypeInteger);
_ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_VALUETYPE] == SystemVClassificationTypeStruct);
_ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_TYPEDBYREF] == SystemVClassificationTypeStruct);
_ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_BYREF] == SystemVClassificationTypeIntegerByRef);
return (((unsigned)eeType) < ELEMENT_TYPE_MAX) ? (toSystemVAmd64ClassificationTypeMap[(unsigned)eeType]) : SystemVClassificationTypeUnknown;
};
#define SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES 8 // Size of an eightbyte in bytes.
#define SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT 16 // Maximum number of fields in struct passed in registers
struct SystemVStructRegisterPassingHelper
{
SystemVStructRegisterPassingHelper(unsigned int totalStructSize) :
structSize(totalStructSize),
eightByteCount(0),
inEmbeddedStruct(false),
currentUniqueOffsetField(0),
largestFieldOffset(-1)
{
for (int i = 0; i < CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS; i++)
{
eightByteClassifications[i] = SystemVClassificationTypeNoClass;
eightByteSizes[i] = 0;
eightByteOffsets[i] = 0;
}
// Initialize the work arrays
for (int i = 0; i < SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT; i++)
{
fieldClassifications[i] = SystemVClassificationTypeNoClass;
fieldSizes[i] = 0;
fieldOffsets[i] = 0;
}
}
// Input state.
unsigned int structSize;
// These fields are the output; these are what is computed by the classification algorithm.
unsigned int eightByteCount;
SystemVClassificationType eightByteClassifications[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS];
unsigned int eightByteSizes[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS];
unsigned int eightByteOffsets[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS];
// Helper members to track state.
bool inEmbeddedStruct;
unsigned int currentUniqueOffsetField; // A virtual field that could encompass many overlapping fields.
int largestFieldOffset;
SystemVClassificationType fieldClassifications[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT];
unsigned int fieldSizes[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT];
unsigned int fieldOffsets[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT];
};
typedef DPTR(SystemVStructRegisterPassingHelper) SystemVStructRegisterPassingHelperPtr;
#endif // UNIX_AMD64_ABI_ITF
//===============================================================================================
//
// GC data appears before the beginning of the MethodTable
//
//@GENERICS:
// Each generic type has a corresponding "generic" method table that serves the following
// purposes:
// * The method table pointer is used as a representative for the generic type e.g. in reflection
// * MethodDescs for methods in the vtable are used for reflection; they should never be invoked.
// Some other information (e.g. BaseSize) makes no sense "generically" but unfortunately gets put in anyway.
//
// Each distinct instantiation of a generic type has its own MethodTable structure.
// However, the EEClass structure can be shared between compatible instantiations e.g. List<string> and List<object>.
// In that case, MethodDescs are also shared between compatible instantiations (but see below about generic methods).
// Hence the vtable entries for MethodTables belonging to such an EEClass are the same.
//
// The non-vtable section of such MethodTables are only present for one of the instantiations (the first one
// requested) as non-vtable entries are never accessed through the vtable pointer of an object so it's always possible
// to ensure that they are accessed through the representative MethodTable that contains them.
// A MethodTable is the fundamental representation of type in the runtime. It is this structure that
// objects point at (see code:Object). It holds the size and GC layout of the type, as well as the dispatch table
// for virtual dispach (but not interface dispatch). There is a distinct method table for every instance of
// a generic type. From here you can get to
//
// * code:EEClass
//
// Important fields
// * code:MethodTable.m_pEEClass - pointer to the cold part of the type.
// * code:MethodTable.m_pParentMethodTable - the method table of the parent type.
//
class MethodTableBuilder;
class MethodTable
{
/************************************
* FRIEND FUNCTIONS
************************************/
// DO NOT ADD FRIENDS UNLESS ABSOLUTELY NECESSARY
// USE ACCESSORS TO READ/WRITE private field members
// Special access for setting up String object method table correctly
friend class ClassLoader;
friend class JIT_TrialAlloc;
friend class Module;
friend class EEClass;
friend class MethodTableBuilder;
friend class CheckAsmOffsets;
#if defined(DACCESS_COMPILE)
friend class NativeImageDumper;
#endif
public:
// Do some sanity checking to make sure it's a method table
// and not pointing to some random memory. In particular
// check that (apart from the special case of instantiated generic types) we have
// GetCanonicalMethodTable() == this;
BOOL SanityCheck();
static void CallFinalizer(Object *obj);
public:
PTR_Module GetModule();
PTR_Module GetModule_NoLogging();
Assembly *GetAssembly();
PTR_Module GetModuleIfLoaded();
// GetDomain on an instantiated type, e.g. C<ty1,ty2> returns the SharedDomain if all the
// constituent parts of the type are SharedDomain (i.e. domain-neutral),
// and returns an AppDomain if any of the parts are from an AppDomain,
// i.e. are domain-bound. Note that if any of the parts are domain-bound
// then they will all belong to the same domain.
PTR_BaseDomain GetDomain();
// Does this immediate item live in an NGEN module?
BOOL IsZapped();
// For types that are part of an ngen-ed assembly this gets the
// Module* that contains this methodtable.
PTR_Module GetZapModule();
// For regular, non-constructed types, GetLoaderModule() == GetModule()
// For constructed types (e.g. int[], Dict<int[], C>) the hash table through which a type
// is accessed lives in a "loader module". The rule for determining the loader module must ensure
// that a type never outlives its loader module with respect to app-domain unloading
//
// GetModuleForStatics() is the third kind of module. GetModuleForStatics() is module that
// statics are attached to.
PTR_Module GetLoaderModule();
PTR_LoaderAllocator GetLoaderAllocator();
void SetLoaderModule(Module* pModule);
void SetLoaderAllocator(LoaderAllocator* pAllocator);
// Get the domain local module - useful for static init checks
PTR_DomainLocalModule GetDomainLocalModule();
MethodTable *LoadEnclosingMethodTable(ClassLoadLevel targetLevel = CLASS_DEPENDENCIES_LOADED);
LPCWSTR GetPathForErrorMessages();
//-------------------------------------------------------------------
// COM INTEROP
//
#ifdef FEATURE_COMINTEROP
TypeHandle GetCoClassForInterface();
private:
TypeHandle SetupCoClassForInterface();
public:
DWORD IsComClassInterface();
// Retrieves the COM interface type.
CorIfaceAttr GetComInterfaceType();
void SetComInterfaceType(CorIfaceAttr ItfType);
OBJECTHANDLE GetOHDelegate();
void SetOHDelegate (OBJECTHANDLE _ohDelegate);
CorClassIfaceAttr GetComClassInterfaceType();
TypeHandle GetDefItfForComClassItf();
void GetEventInterfaceInfo(MethodTable **ppSrcItfType, MethodTable **ppEvProvType);
BOOL IsExtensibleRCW();
// Helper to get parent class skipping over COM class in
// the hierarchy
MethodTable* GetComPlusParentMethodTable();
DWORD IsComImport();
// class is a special COM event interface
int IsComEventItfType();
//-------------------------------------------------------------------
// Sparse VTables. These require a SparseVTableMap in the EEClass in
// order to record how the CLR's vtable slots map across to COM
// Interop slots.
//
int IsSparseForCOMInterop();
// COM interop helpers
// accessors for m_pComData
ComCallWrapperTemplate *GetComCallWrapperTemplate();
BOOL SetComCallWrapperTemplate(ComCallWrapperTemplate *pTemplate);
#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
ClassFactoryBase *GetComClassFactory();
BOOL SetComClassFactory(ClassFactoryBase *pFactory);
#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
OBJECTREF GetObjCreateDelegate();
void SetObjCreateDelegate(OBJECTREF orDelegate);
private:
// This is for COM Interop backwards compatibility
BOOL InsertComInteropData(InteropMethodTableData *pData);
InteropMethodTableData *CreateComInteropData(AllocMemTracker *pamTracker);
public:
InteropMethodTableData *LookupComInteropData();
// This is the preferable entrypoint, as it will make sure that all
// parent MT's have their interop data created, and will create and
// add this MT's data if not available. The caller should make sure that
// an appropriate lock is taken to prevent duplicates.
// NOTE: The current caller of this is ComInterop, and it makes calls
// under its own lock to ensure not duplicates.
InteropMethodTableData *GetComInteropData();
#endif // !FEATURE_COMINTEROP
// class is a com object class
BOOL IsComObjectType()
{
LIMITED_METHOD_DAC_CONTRACT;
return GetFlag(enum_flag_ComObject);
}
// mark the class type as COM object class
void SetComObjectType();
#ifdef FEATURE_ICASTABLE
void SetICastable();
#endif
BOOL IsICastable(); // This type implements ICastable interface
void SetIDynamicInterfaceCastable();
BOOL IsIDynamicInterfaceCastable();
#ifdef FEATURE_TYPEEQUIVALENCE
// mark the type as opted into type equivalence
void SetHasTypeEquivalence()
{
LIMITED_METHOD_CONTRACT;
SetFlag(enum_flag_HasTypeEquivalence);
}
#endif // FEATURE_TYPEEQUIVALENCE
// type has opted into type equivalence or is instantiated by/derived from a type that is
BOOL HasTypeEquivalence()
{
LIMITED_METHOD_CONTRACT;
#ifdef FEATURE_TYPEEQUIVALENCE
return GetFlag(enum_flag_HasTypeEquivalence);
#else
return FALSE;
#endif // FEATURE_TYPEEQUIVALENCE
}
//-------------------------------------------------------------------
// DYNAMIC ADDITION OF INTERFACES FOR COM INTEROP
//
// Support for dynamically added interfaces on extensible RCW's.
#ifdef FEATURE_COMINTEROP
PTR_InterfaceInfo GetDynamicallyAddedInterfaceMap();
unsigned GetNumDynamicallyAddedInterfaces();
BOOL FindDynamicallyAddedInterface(MethodTable *pInterface);
void AddDynamicInterface(MethodTable *pItfMT);
BOOL HasDynamicInterfaceMap()
{
LIMITED_METHOD_DAC_CONTRACT;
// currently all ComObjects except
// for __ComObject have dynamic Interface maps
return GetNumInterfaces() > 0 && IsComObjectType() && !ParentEquals(g_pObjectClass);
}
#endif // FEATURE_COMINTEROP
#ifndef DACCESS_COMPILE
VOID EnsureActive();
VOID EnsureInstanceActive();
#endif
CHECK CheckActivated();
CHECK CheckInstanceActivated();
//-------------------------------------------------------------------
// THE DEFAULT CONSTRUCTOR
//
public:
BOOL HasDefaultConstructor();
void SetHasDefaultConstructor();
WORD GetDefaultConstructorSlot();
MethodDesc *GetDefaultConstructor(BOOL forceBoxedEntryPoint = FALSE);
BOOL HasExplicitOrImplicitPublicDefaultConstructor();
//-------------------------------------------------------------------
// THE CLASS INITIALIZATION CONDITION
// (and related DomainLocalModule storage)
//
// - populate the DomainLocalModule if needed
// - run the cctor
//
public:
// checks whether the class initialiser should be run on this class, and runs it if necessary
void CheckRunClassInitThrowing();
// checks whether or not the non-beforefieldinit class initializers have been run for all types in this type's
// inheritance hierarchy, and runs them if necessary. This simulates the behavior of running class constructors
// during object construction.
void CheckRunClassInitAsIfConstructingThrowing();
#if defined(UNIX_AMD64_ABI_ITF)
// Builds the internal data structures and classifies struct eightbytes for Amd System V calling convention.
bool ClassifyEightBytes(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct, bool isNativeStruct);
bool ClassifyEightBytesWithNativeLayout(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct, EEClassNativeLayoutInfo const* nativeLayoutInfo);
#endif // defined(UNIX_AMD64_ABI_ITF)
// Copy m_dwFlags from another method table
void CopyFlags(MethodTable * pOldMT)
{
LIMITED_METHOD_CONTRACT;
m_dwFlags = pOldMT->m_dwFlags;
m_wFlags2 = pOldMT->m_wFlags2;
}
// Init the m_dwFlags field for an array
void SetIsArray(CorElementType arrayType);
BOOL IsClassPreInited();
// mark the class as having its cctor run.
#ifndef DACCESS_COMPILE
void SetClassInited();
BOOL IsClassInited();
BOOL IsInitError();
void SetClassInitError();
#endif
inline BOOL IsGlobalClass()
{
WRAPPER_NO_CONTRACT;
return (GetTypeDefRid() == RidFromToken(COR_GLOBAL_PARENT_TOKEN));
}
// uniquely identifes this type in the Domain table
DWORD GetClassIndex();
private:
#if defined(UNIX_AMD64_ABI_ITF)
void AssignClassifiedEightByteTypes(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel) const;
// Builds the internal data structures and classifies struct eightbytes for Amd System V calling convention.
bool ClassifyEightBytesWithManagedLayout(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct, bool isNativeStruct);
#endif // defined(UNIX_AMD64_ABI_ITF)
DWORD GetClassIndexFromToken(mdTypeDef typeToken)
{
LIMITED_METHOD_CONTRACT;
return RidFromToken(typeToken) - 1;
}
// called from CheckRunClassInitThrowing(). The type wasn't marked as
// inited while we were there, so let's attempt to do the work.
void DoRunClassInitThrowing();
BOOL RunClassInitEx(OBJECTREF *pThrowable);
public:
//-------------------------------------------------------------------
// THE CLASS CONSTRUCTOR
//
MethodDesc * GetClassConstructor();
BOOL HasClassConstructor();
void SetHasClassConstructor();
WORD GetClassConstructorSlot();
void SetClassConstructorSlot (WORD wCCtorSlot);
ClassCtorInfoEntry* GetClassCtorInfoIfExists();
void GetSavedExtent(TADDR *ppStart, TADDR *ppEnd);
//-------------------------------------------------------------------
// Save/Fixup/Restore/NeedsRestore
//
// Restore this method table if it's not already restored
// This is done by forcing a class load which in turn calls the Restore method
// The pending list is required for restoring types that reference themselves through
// instantiations of the superclass or interfaces e.g. System.Int32 : IComparable<System.Int32>
#ifdef FEATURE_PREJIT
void Save(DataImage *image, DWORD profilingFlags);
void Fixup(DataImage *image);
// This is different from !IsRestored() in that it checks if restoring
// will ever be needed for this ngened data-structure.
// This is to be used at ngen time of a dependent module to determine
// if it can be accessed directly, or if the restoring mechanism needs
// to be hooked in.
BOOL ComputeNeedsRestore(DataImage *image, TypeHandleList *pVisited);
BOOL NeedsRestore(DataImage *image)
{
WRAPPER_NO_CONTRACT;
return ComputeNeedsRestore(image, NULL);
}
private:
BOOL ComputeNeedsRestoreWorker(DataImage *image, TypeHandleList *pVisited);
public:
// This returns true at NGen time if we can eager bind to all dictionaries along the inheritance chain
BOOL CanEagerBindToParentDictionaries(DataImage *image, TypeHandleList *pVisited);
// This returns true at NGen time if we may need to attach statics to
// other module than current loader module at runtime
BOOL NeedsCrossModuleGenericsStaticsInfo();
// Returns true at NGen time if we may need to write into the MethodTable at runtime
BOOL IsWriteable();
#endif // FEATURE_PREJIT
void AllocateRegularStaticBoxes();
static OBJECTREF AllocateStaticBox(MethodTable* pFieldMT, BOOL fPinned, OBJECTHANDLE* pHandle = 0);
void CheckRestore();
// Perform restore actions on type key components of method table (EEClass pointer + Module, generic args)
void DoRestoreTypeKey();
inline BOOL HasUnrestoredTypeKey() const
{
LIMITED_METHOD_DAC_CONTRACT;
return !IsPreRestored() &&
(GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_UnrestoredTypeKey) != 0;
}
// Actually do the restore actions on the method table
void Restore();
void SetIsRestored();
inline BOOL IsRestored_NoLogging()
{
LIMITED_METHOD_DAC_CONTRACT;
// If we are prerestored then we are considered a restored methodtable.
// Note that IsPreRestored is always false for jitted code.
if (IsPreRestored())
return TRUE;
return !(GetWriteableData_NoLogging()->m_dwFlags & MethodTableWriteableData::enum_flag_Unrestored);
}
inline BOOL IsRestored()
{
LIMITED_METHOD_DAC_CONTRACT;