This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/
class.h
2430 lines (2085 loc) · 78.2 KB
/
class.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.
// See the LICENSE file in the project root for more information.
// ==--==
//
// File: CLASS.H
//
//
// NOTE: Even though EEClass is considered to contain cold data (relative to MethodTable), these data
// structures *are* touched (especially during startup as part of soft-binding). As a result, and given the
// number of EEClasses allocated for large assemblies, the size of this structure can have a direct impact on
// performance, especially startup performance.
//
// Given that the data itself is touched infrequently, we can trade off space reduction against cpu-usage to
// good effect here. A fair amount of work has gone into reducing the size of each EEClass instance (see
// EEClassOptionalFields and EEClassPackedFields) at the expense of somewhat more convoluted runtime access.
//
// Please consider this (and measure the impact of your changes against startup scenarios) before adding
// fields to EEClass or otherwise increasing its size.
//
// ============================================================================
#ifndef CLASS_H
#define CLASS_H
/*
* Include Files
*/
#include "eecontract.h"
#include "argslot.h"
#include "vars.hpp"
#include "cor.h"
#include "clrex.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 "methodtable.h"
#include "eeconfig.h"
#include "typectxt.h"
#include "iterator_util.h"
#ifdef FEATURE_COMINTEROP
#include "..\md\winmd\inc\adapter.h"
#endif
#include "packedfields.inl"
#include "array.h"
#define IBCLOG(x) g_IBCLogger.##x
VOID DECLSPEC_NORETURN RealCOMPlusThrowHR(HRESULT hr);
/*
* Macro definitions
*/
#define MAX_LOG2_PRIMITIVE_FIELD_SIZE 3
#define MAX_PRIMITIVE_FIELD_SIZE (1 << MAX_LOG2_PRIMITIVE_FIELD_SIZE)
/*
* Forward declarations
*/
class AppDomain;
class ArrayClass;
class ArrayMethodDesc;
class Assembly;
class ClassLoader;
class DictionaryLayout;
class DomainLocalBlock;
class FCallMethodDesc;
class EEClass;
class EnCFieldDesc;
class FieldDesc;
class FieldMarshaler;
struct LayoutRawFieldInfo;
class MetaSig;
class MethodDesc;
class MethodDescChunk;
class MethodTable;
class Module;
struct ModuleCtorInfo;
class Object;
class Stub;
class Substitution;
class SystemDomain;
class TypeHandle;
class StackingAllocator;
class AllocMemTracker;
class InteropMethodTableSlotDataMap;
class LoadingEntry_LockHolder;
class DispatchMapBuilder;
class LoaderAllocator;
class ComCallWrapperTemplate;
typedef DPTR(DictionaryLayout) PTR_DictionaryLayout;
typedef DPTR(FieldMarshaler) PTR_FieldMarshaler;
//---------------------------------------------------------------------------------
// Fields in an explicit-layout class present varying degrees of risk depending
// on how they overlap.
//
// Each level is a superset of the lower (in numerical value) level - i.e.
// all kVerifiable fields are also kLegal, but not vice-versa.
//---------------------------------------------------------------------------------
class ExplicitFieldTrust
{
public:
enum TrustLevel
{
// Note: order is important here - each guarantee also implicitly guarantees all promises
// made by values lower in number.
// What's guaranteed. What the loader does.
//----- ----------------------- -------------------------------
kNone = 0, // no guarantees at all - Type refuses to load at all.
kLegal = 1, // guarantees no objref <-> scalar overlap and no unaligned objref - Type loads but field access won't verify
kVerifiable = 2, // guarantees no objref <-> objref overlap and all guarantees above - Type loads and field access will verify
kNonOverLayed = 3, // guarantees no overlap at all and all guarantees above - Type loads, field access verifies and Equals() may be optimized if structure is tightly packed
kMaxTrust = kNonOverLayed,
};
};
//----------------------------------------------------------------------------------------------
// This class is a helper for HandleExplicitLayout. To make it harder to introduce security holes
// into this function, we will manage all updates to the class's trust level through the ExplicitClassTrust
// class. This abstraction enforces the rule that the overall class is only as trustworthy as
// the least trustworthy field.
//----------------------------------------------------------------------------------------------
class ExplicitClassTrust : private ExplicitFieldTrust
{
public:
ExplicitClassTrust()
{
LIMITED_METHOD_CONTRACT;
m_trust = kMaxTrust; // Yes, we start out with maximal trust. This reflects that explicit layout structures with no fields do represent no risk.
}
VOID AddField(TrustLevel fieldTrust)
{
LIMITED_METHOD_CONTRACT;
m_trust = min(m_trust, fieldTrust);
}
BOOL IsLegal()
{
LIMITED_METHOD_CONTRACT;
return m_trust >= kLegal;
}
BOOL IsVerifiable()
{
LIMITED_METHOD_CONTRACT;
return m_trust >= kVerifiable;
}
BOOL IsNonOverLayed()
{
LIMITED_METHOD_CONTRACT;
return m_trust >= kNonOverLayed;
}
TrustLevel GetTrustLevel()
{
LIMITED_METHOD_CONTRACT;
return m_trust;
}
private:
TrustLevel m_trust;
};
//----------------------------------------------------------------------------------------------
// This class is a helper for HandleExplicitLayout. To make it harder to introduce security holes
// into this function, this class will collect trust information about individual fields to be later
// aggregated into the overall class level.
//
// This abstraction enforces the rule that all fields are presumed guilty until explicitly declared
// safe by calling SetTrust(). If you fail to call SetTrust before leaving the block, the destructor
// will automatically cause the entire class to be declared illegal (and you will get an assert
// telling you to fix this bug.)
//----------------------------------------------------------------------------------------------
class ExplicitFieldTrustHolder : private ExplicitFieldTrust
{
public:
ExplicitFieldTrustHolder(ExplicitClassTrust *pExplicitClassTrust)
{
LIMITED_METHOD_CONTRACT;
m_pExplicitClassTrust = pExplicitClassTrust;
#ifdef _DEBUG
m_trustDeclared = FALSE;
#endif
m_fieldTrust = kNone;
}
VOID SetTrust(TrustLevel fieldTrust)
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(fieldTrust >= kNone && fieldTrust <= kMaxTrust);
_ASSERTE(!m_trustDeclared && "You should not set the trust value more than once.");
#ifdef _DEBUG
m_trustDeclared = TRUE;
#endif
m_fieldTrust = fieldTrust;
}
~ExplicitFieldTrustHolder()
{
LIMITED_METHOD_CONTRACT;
// If no SetTrust() was ever called, we will default to kNone (i.e. declare the entire type
// illegal.) It'd be nice to assert here but since this case can be legitimately reached
// on exception unwind, we cannot.
m_pExplicitClassTrust->AddField(m_fieldTrust);
}
private:
ExplicitClassTrust* m_pExplicitClassTrust;
TrustLevel m_fieldTrust;
#ifdef _DEBUG
BOOL m_trustDeclared; // Debug flag to detect multiple Sets. (Which we treat as a bug as this shouldn't be necessary.)
#endif
};
//*******************************************************************************
// Enumerator to traverse the interface declarations of a type, automatically building
// a substitution chain on the stack.
class InterfaceImplEnum
{
Module* m_pModule;
HENUMInternalHolder hEnumInterfaceImpl;
const Substitution *m_pSubstChain;
Substitution m_CurrSubst;
mdTypeDef m_CurrTok;
public:
InterfaceImplEnum(Module *pModule, mdTypeDef cl, const Substitution *pSubstChain)
: hEnumInterfaceImpl(pModule->GetMDImport())
{
WRAPPER_NO_CONTRACT;
m_pModule = pModule;
hEnumInterfaceImpl.EnumInit(mdtInterfaceImpl, cl);
m_pSubstChain = pSubstChain;
}
// Returns:
// S_OK ... if has next (TRUE)
// S_FALSE ... if does not have next (FALSE)
// error code.
HRESULT Next()
{
WRAPPER_NO_CONTRACT;
HRESULT hr;
mdInterfaceImpl ii;
if (!m_pModule->GetMDImport()->EnumNext(&hEnumInterfaceImpl, &ii))
{
return S_FALSE;
}
IfFailRet(m_pModule->GetMDImport()->GetTypeOfInterfaceImpl(ii, &m_CurrTok));
m_CurrSubst = Substitution(m_CurrTok, m_pModule, m_pSubstChain);
return S_OK;
}
const Substitution *CurrentSubst() const { LIMITED_METHOD_CONTRACT; return &m_CurrSubst; }
mdTypeDef CurrentToken() const { LIMITED_METHOD_CONTRACT; return m_CurrTok; }
};
#ifdef FEATURE_COMINTEROP
//
// Class used to map MethodTable slot numbers to COM vtable slots numbers
// (either for calling a classic COM component or for constructing a classic COM
// vtable via which COM components can call managed classes). This structure is
// embedded in the EEClass but the mapping list itself is only allocated if the
// COM vtable is sparse.
//
class SparseVTableMap
{
public:
#ifdef DACCESS_COMPILE
friend class NativeImageDumper;
#endif
SparseVTableMap();
~SparseVTableMap();
// First run through MT slots calling RecordGap wherever a gap in VT slots
// occurs.
void RecordGap(WORD StartMTSlot, WORD NumSkipSlots);
// Then call FinalizeMapping to create the actual mapping list.
void FinalizeMapping(WORD TotalMTSlots);
// Map MT to VT slot.
WORD LookupVTSlot(WORD MTSlot);
// Retrieve the number of slots in the vtable (both empty and full).
WORD GetNumVTableSlots();
const void* GetMapList()
{
LIMITED_METHOD_CONTRACT;
return (void*)m_MapList;
}
#ifdef FEATURE_PREJIT
// Methods to persist structure
void Save(DataImage *image);
void Fixup(DataImage *image);
#endif // FEATURE_PREJIT
private:
enum { MapGrow = 4 };
struct Entry
{
WORD m_Start; // Starting MT slot number
WORD m_Span; // # of consecutive slots that map linearly
WORD m_MapTo; // Starting VT slot number
};
Entry *m_MapList; // Pointer to array of Entry structures
WORD m_MapEntries; // Number of entries in above
WORD m_Allocated; // Number of entries allocated
WORD m_LastUsed; // Index of last entry used in successful lookup
WORD m_VTSlot; // Current VT slot number, used during list build
WORD m_MTSlot; // Current MT slot number, used during list build
void AllocOrExpand(); // Allocate or expand the mapping list for a new entry
};
#endif // FEATURE_COMINTEROP
//=======================================================================
// Adjunct to the EEClass structure for classes w/ layout
//=======================================================================
class EEClassLayoutInfo
{
static VOID CollectLayoutFieldMetadataThrowing(
mdTypeDef cl, // cl of the NStruct being loaded
BYTE packingSize, // packing size (from @dll.struct)
BYTE nlType, // nltype (from @dll.struct)
#ifdef FEATURE_COMINTEROP
BOOL isWinRT, // Is the type a WinRT type
#endif // FEATURE_COMINTEROP
BOOL fExplicitOffsets, // explicit offsets?
MethodTable *pParentMT, // the loaded superclass
ULONG cTotalFields, // total number of fields (instance and static)
HENUMInternal *phEnumField, // enumerator for field
Module* pModule, // Module that defines the scope, loader and heap (for allocate FieldMarshalers)
const SigTypeContext *pTypeContext, // Type parameters for NStruct being loaded
EEClassLayoutInfo *pEEClassLayoutInfoOut, // caller-allocated structure to fill in.
LayoutRawFieldInfo *pInfoArrayOut, // caller-allocated array to fill in. Needs room for cMember+1 elements
LoaderAllocator * pAllocator,
AllocMemTracker *pamTracker
);
friend class ClassLoader;
friend class EEClass;
friend class MethodTableBuilder;
#ifdef DACCESS_COMPILE
friend class NativeImageDumper;
#endif
private:
// size (in bytes) of fixed portion of NStruct.
UINT32 m_cbNativeSize;
UINT32 m_cbManagedSize;
public:
// 1,2,4 or 8: this is equal to the largest of the alignment requirements
// of each of the EEClass's members. If the NStruct extends another NStruct,
// the base NStruct is treated as the first member for the purpose of
// this calculation.
BYTE m_LargestAlignmentRequirementOfAllMembers;
// Post V1.0 addition: This is the equivalent of m_LargestAlignmentRequirementOfAllMember
// for the managed layout.
BYTE m_ManagedLargestAlignmentRequirementOfAllMembers;
private:
enum {
// TRUE if the GC layout of the class is bit-for-bit identical
// to its unmanaged counterpart (i.e. no internal reference fields,
// no ansi-unicode char conversions required, etc.) Used to
// optimize marshaling.
e_BLITTABLE = 0x01,
// Post V1.0 addition: Is this type also sequential in managed memory?
e_MANAGED_SEQUENTIAL = 0x02,
// When a sequential/explicit type has no fields, it is conceptually
// zero-sized, but actually is 1 byte in length. This holds onto this
// fact and allows us to revert the 1 byte of padding when another
// explicit type inherits from this type.
e_ZERO_SIZED = 0x04,
// The size of the struct is explicitly specified in the meta-data.
e_HAS_EXPLICIT_SIZE = 0x08,
#ifdef UNIX_AMD64_ABI
#ifdef FEATURE_HFA
#error "Can't have FEATURE_HFA and UNIX_AMD64_ABI defined at the same time."
#endif // FEATURE_HFA
e_NATIVE_PASS_IN_REGISTERS = 0x10, // Flag wheter a native struct is passed in registers.
#endif // UNIX_AMD64_ABI
#ifdef FEATURE_HFA
// HFA type of the unmanaged layout
// Note that these are not flags, they are discrete values.
e_R4_HFA = 0x10,
e_R8_HFA = 0x20,
e_16_HFA = 0x30,
e_HFATypeFlags = 0x30,
#endif
};
BYTE m_bFlags;
// Packing size in bytes (1, 2, 4, 8 etc.)
BYTE m_cbPackingSize;
// # of fields that are of the calltime-marshal variety.
UINT m_numCTMFields;
// An array of FieldMarshaler data blocks, used to drive call-time
// marshaling of NStruct reference parameters. The number of elements
// equals m_numCTMFields.
RelativePointer<PTR_FieldMarshaler> m_pFieldMarshalers;
public:
BOOL GetNativeSize() const
{
LIMITED_METHOD_CONTRACT;
return m_cbNativeSize;
}
UINT32 GetManagedSize() const
{
LIMITED_METHOD_CONTRACT;
return m_cbManagedSize;
}
BYTE GetLargestAlignmentRequirementOfAllMembers() const
{
LIMITED_METHOD_CONTRACT;
return m_LargestAlignmentRequirementOfAllMembers;
}
UINT GetNumCTMFields() const
{
LIMITED_METHOD_CONTRACT;
return m_numCTMFields;
}
PTR_FieldMarshaler GetFieldMarshalers() const
{
LIMITED_METHOD_CONTRACT;
return ReadPointerMaybeNull(this, &EEClassLayoutInfo::m_pFieldMarshalers);
}
#ifndef DACCESS_COMPILE
void SetFieldMarshalers(FieldMarshaler *pFieldMarshallers)
{
LIMITED_METHOD_CONTRACT;
m_pFieldMarshalers.SetValueMaybeNull(pFieldMarshallers);
}
#endif // DACCESS_COMPILE
BOOL IsBlittable() const
{
LIMITED_METHOD_CONTRACT;
return (m_bFlags & e_BLITTABLE) == e_BLITTABLE;
}
BOOL IsManagedSequential() const
{
LIMITED_METHOD_CONTRACT;
return (m_bFlags & e_MANAGED_SEQUENTIAL) == e_MANAGED_SEQUENTIAL;
}
// If true, this says that the type was originally zero-sized
// and the native size was bumped up to one for similar behaviour
// to C++ structs. However, it is necessary to keep track of this
// so that we can ignore the one byte padding if other types derive
// from this type, that we can
BOOL IsZeroSized() const
{
LIMITED_METHOD_CONTRACT;
return (m_bFlags & e_ZERO_SIZED) == e_ZERO_SIZED;
}
BOOL HasExplicitSize() const
{
LIMITED_METHOD_CONTRACT;
return (m_bFlags & e_HAS_EXPLICIT_SIZE) == e_HAS_EXPLICIT_SIZE;
}
DWORD GetPackingSize() const
{
LIMITED_METHOD_CONTRACT;
return m_cbPackingSize;
}
#ifdef UNIX_AMD64_ABI
bool IsNativeStructPassedInRegisters()
{
LIMITED_METHOD_CONTRACT;
return (m_bFlags & e_NATIVE_PASS_IN_REGISTERS) != 0;
}
#else
bool IsNativeStructPassedInRegisters()
{
return false;
}
#endif // UNIX_AMD64_ABI
CorElementType GetNativeHFATypeRaw();
#ifdef FEATURE_HFA
bool IsNativeHFA()
{
LIMITED_METHOD_CONTRACT;
return (m_bFlags & e_HFATypeFlags) != 0;
}
CorElementType GetNativeHFAType()
{
LIMITED_METHOD_CONTRACT;
switch (m_bFlags & e_HFATypeFlags)
{
case e_R4_HFA: return ELEMENT_TYPE_R4;
case e_R8_HFA: return ELEMENT_TYPE_R8;
case e_16_HFA: return ELEMENT_TYPE_VALUETYPE;
default: return ELEMENT_TYPE_END;
}
}
#else // !FEATURE_HFA
bool IsNativeHFA()
{
return GetNativeHFATypeRaw() != ELEMENT_TYPE_END;
}
CorElementType GetNativeHFAType()
{
return GetNativeHFATypeRaw();
}
#endif // !FEATURE_HFA
private:
void SetIsBlittable(BOOL isBlittable)
{
LIMITED_METHOD_CONTRACT;
m_bFlags = isBlittable ? (m_bFlags | e_BLITTABLE)
: (m_bFlags & ~e_BLITTABLE);
}
void SetIsManagedSequential(BOOL isManagedSequential)
{
LIMITED_METHOD_CONTRACT;
m_bFlags = isManagedSequential ? (m_bFlags | e_MANAGED_SEQUENTIAL)
: (m_bFlags & ~e_MANAGED_SEQUENTIAL);
}
void SetIsZeroSized(BOOL isZeroSized)
{
LIMITED_METHOD_CONTRACT;
m_bFlags = isZeroSized ? (m_bFlags | e_ZERO_SIZED)
: (m_bFlags & ~e_ZERO_SIZED);
}
void SetHasExplicitSize(BOOL hasExplicitSize)
{
LIMITED_METHOD_CONTRACT;
m_bFlags = hasExplicitSize ? (m_bFlags | e_HAS_EXPLICIT_SIZE)
: (m_bFlags & ~e_HAS_EXPLICIT_SIZE);
}
#ifdef FEATURE_HFA
void SetNativeHFAType(CorElementType hfaType)
{
LIMITED_METHOD_CONTRACT;
// We should call this at most once.
_ASSERTE((m_bFlags & e_HFATypeFlags) == 0);
switch (hfaType)
{
case ELEMENT_TYPE_R4: m_bFlags |= e_R4_HFA; break;
case ELEMENT_TYPE_R8: m_bFlags |= e_R8_HFA; break;
case ELEMENT_TYPE_VALUETYPE: m_bFlags |= e_16_HFA; break;
default: _ASSERTE(!"Invalid HFA Type");
}
}
#endif
#ifdef UNIX_AMD64_ABI
void SetNativeStructPassedInRegisters()
{
LIMITED_METHOD_CONTRACT;
m_bFlags |= e_NATIVE_PASS_IN_REGISTERS;
}
#endif // UNIX_AMD64_ABI
};
//
// This structure is used only when the classloader is building the interface map. Before the class
// is resolved, the EEClass contains an array of these, which are all interfaces *directly* declared
// for this class/interface by the metadata - inherited interfaces will not be present if they are
// not specifically declared.
//
// This structure is destroyed after resolving has completed.
//
typedef struct
{
// The interface method table; for instantiated interfaces, this is the generic interface
MethodTable *m_pMethodTable;
} BuildingInterfaceInfo_t;
//
// We should not need to touch anything in here once the classes are all loaded, unless we
// are doing reflection. Try to avoid paging this data structure in.
//
// Size of hash bitmap for method names
#define METHOD_HASH_BYTES 8
// Hash table size - prime number
#define METHOD_HASH_BITS 61
// These are some macros for forming fully qualified class names for a class.
// These are abstracted so that we can decide later if a max length for a
// class name is acceptable.
// It doesn't make any sense not to have a small but usually quite capable
// stack buffer to build class names into. Most class names that I can think
// of would fit in 128 characters, and that's a pretty small amount of stack
// to use in exchange for not having to new and delete the memory.
#define DEFAULT_NONSTACK_CLASSNAME_SIZE (MAX_CLASSNAME_LENGTH/4)
#define DefineFullyQualifiedNameForClass() \
ScratchBuffer<DEFAULT_NONSTACK_CLASSNAME_SIZE> _scratchbuffer_; \
InlineSString<DEFAULT_NONSTACK_CLASSNAME_SIZE> _ssclsname_;
#define DefineFullyQualifiedNameForClassOnStack() \
ScratchBuffer<MAX_CLASSNAME_LENGTH> _scratchbuffer_; \
InlineSString<MAX_CLASSNAME_LENGTH> _ssclsname_;
#define DefineFullyQualifiedNameForClassW() \
InlineSString<DEFAULT_NONSTACK_CLASSNAME_SIZE> _ssclsname_w_;
#define DefineFullyQualifiedNameForClassWOnStack() \
InlineSString<MAX_CLASSNAME_LENGTH> _ssclsname_w_;
#define GetFullyQualifiedNameForClassNestedAware(pClass) \
pClass->_GetFullyQualifiedNameForClassNestedAware(_ssclsname_).GetUTF8(_scratchbuffer_)
#define GetFullyQualifiedNameForClassNestedAwareW(pClass) \
pClass->_GetFullyQualifiedNameForClassNestedAware(_ssclsname_w_).GetUnicode()
#define GetFullyQualifiedNameForClass(pClass) \
pClass->_GetFullyQualifiedNameForClass(_ssclsname_).GetUTF8(_scratchbuffer_)
#define GetFullyQualifiedNameForClassW(pClass) \
pClass->_GetFullyQualifiedNameForClass(_ssclsname_w_).GetUnicode()
#define GetFullyQualifiedNameForClassW_WinRT(pClass) \
pClass->_GetFullyQualifiedNameForClass(_ssclsname_w_).GetUnicode()
#define GetFullyQualifiedNameForClass_WinRT(pClass) \
pClass->_GetFullyQualifiedNameForClass(_ssclsname_).GetUTF8(_scratchbuffer_)
// Structure containing EEClass fields used by a minority of EEClass instances. This separation allows us to
// save memory and improve the density of accessed fields in the EEClasses themselves. This class is reached
// via the m_rpOptionalFields field EEClass (use the GetOptionalFields() accessor rather than the field
// itself).
class EEClassOptionalFields
{
// All fields here are intentionally private. Use the corresponding accessor on EEClass instead (this
// makes it easier to add and remove fields from the optional section in the future). We make exceptions
// for MethodTableBuilder and NativeImageDumper, which need raw field-level access.
friend class EEClass;
friend class MethodTableBuilder;
#ifdef DACCESS_COMPILE
friend class NativeImageDumper;
#endif
//
// GENERICS RELATED FIELDS.
//
// If IsSharedByGenericInstantiations(), layout of handle dictionary for generic type
// (the last dictionary pointed to from PerInstInfo). Otherwise NULL.
PTR_DictionaryLayout m_pDictLayout;
// Variance info for each type parameter (gpNonVariant, gpCovariant, or gpContravariant)
// If NULL, this type has no type parameters that are co/contravariant
RelativePointer<PTR_BYTE> m_pVarianceInfo;
//
// COM RELATED FIELDS.
//
#ifdef FEATURE_COMINTEROP
SparseVTableMap *m_pSparseVTableMap;
TypeHandle m_pCoClassForIntf; // @TODO: Coclass for an interface
#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
// Points to activation information if the type is an activatable COM/WinRT class.
ClassFactoryBase *m_pClassFactory;
#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
WinMDAdapter::RedirectedTypeIndex m_WinRTRedirectedTypeIndex;
#endif // FEATURE_COMINTEROP
//
// MISC FIELDS
//
#define MODULE_NON_DYNAMIC_STATICS ((DWORD)-1)
DWORD m_cbModuleDynamicID;
#if defined(UNIX_AMD64_ABI)
// Number of eightBytes in the following arrays
int m_numberEightBytes;
// Classification of the eightBytes
SystemVClassificationType m_eightByteClassifications[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS];
// Size of data the eightBytes
unsigned int m_eightByteSizes[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS];
#endif // UNIX_AMD64_ABI
// Set default values for optional fields.
inline void Init();
PTR_BYTE GetVarianceInfo()
{
LIMITED_METHOD_DAC_CONTRACT;
return ReadPointerMaybeNull(this, &EEClassOptionalFields::m_pVarianceInfo);
}
};
typedef DPTR(EEClassOptionalFields) PTR_EEClassOptionalFields;
//
// Another mechanism used to reduce the size of the average EEClass instance is the notion of packed fields.
// This is based on the observation that EEClass has a large number of integer fields that typically contain
// small values and that are fixed once class layout has completed. We can compact these fields by discarding
// the leading zero bits (and for small values there'll be a lot of these) and packing the significant data
// into compact bitfields. This is a dynamic operation (the exact packing used depends on the exact data
// stored in the fields).
//
// The PackedDWORDFields<> class (defined in PackedFields.inl) encapsulates this. It takes one template
// parameter, the number of fields to pack, and provides operations to get and set those fields until we're
// happy with the values, at which point it will compact them for us.
//
// The packed fields themselves are stored at the end of the EEClass instance (or the LayoutEEClass or the
// DelegateEEClass etc.) so we can take advantage of the variable sized nature of the fields. We gain nothing for
// runtime allocated EEClasses (we have to allocate a maximally sized structure for the packed fields because
// we can't tell at the beginning of EEClass layout what the field values will be). But in the ngen scenario
// we can compact the fields just prior to saving and only store the portion of the EEClass that is relvant,
// helping us with our goal of packing all the EEClass instances together as tightly as possible.
//
// Since each packed field is now accessed via an array-like index, we give each of those indices a name with
// the enum below to make the code more readable.
//
enum EEClassFieldId
{
EEClass_Field_NumInstanceFields = 0,
EEClass_Field_NumMethods,
EEClass_Field_NumStaticFields,
EEClass_Field_NumHandleStatics,
EEClass_Field_NumBoxedStatics,
EEClass_Field_NonGCStaticFieldBytes,
EEClass_Field_NumThreadStaticFields,
EEClass_Field_NumHandleThreadStatics,
EEClass_Field_NumBoxedThreadStatics,
EEClass_Field_NonGCThreadStaticFieldBytes,
EEClass_Field_NumNonVirtualSlots,
EEClass_Field_COUNT
};
typedef PackedDWORDFields<EEClass_Field_COUNT> EEClassPackedFields;
typedef DPTR(EEClassPackedFields) PTR_EEClassPackedFields;
//@GENERICS:
// For most types there is a one-to-one mapping between MethodTable* and EEClass*
// However this is not the case for instantiated types where code and representation
// are shared between compatible instantiations (e.g. List<string> and List<object>)
// Then a single EEClass structure is shared between multiple MethodTable structures
// Uninstantiated generic types (e.g. List) have their own EEClass and MethodTable,
// used (a) as a representative for the generic type itself, (b) for static fields and
// methods, which aren't present in the instantiations, and (c) to hold some information
// (e.g. formal instantiations of superclass and implemented interfaces) that is common
// to all instantiations and isn't stored in the EEClass structures for instantiated types
//
//
// ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE
//
// A word about EEClass vs. MethodTable
// ------------------------------------
//
// At compile-time, we are happy to touch both MethodTable and EEClass. However,
// at runtime we want to restrict ourselves to the MethodTable. This is critical
// for common code paths, where we want to keep the EEClass out of our working
// set. For uncommon code paths, like throwing exceptions or strange Contexts
// issues, it's okay to access the EEClass.
//
// To this end, the TypeHandle (CLASS_HANDLE) abstraction is now based on the
// MethodTable pointer instead of the EEClass pointer. If you are writing a
// runtime helper that calls GetClass() to access the associated EEClass, please
// stop to wonder if you are making a mistake.
//
// ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE
// An code:EEClass is a representation of the part of a managed type that is not used very frequently (it is
// cold), and thus is segregated from the hot portion (which lives in code:MethodTable). As noted above an
// it is also the case that EEClass is SHARED among all instantiations of a generic type, so anything that
// is specific to a paritcular type can not live off the EEClass.
//
// From here you can get to
// code:MethodTable - The representation of the hot portion of a type.
// code:MethodDesc - The representation of a method
// code:FieldDesc - The representation of a field.
//
// EEClasses hold the following important fields
// * code:EEClass.m_pMethodTable - Points a MethodTable associated with
// * code:EEClass.m_pChunks - a list of code:MethodDescChunk which is simply a list of code:MethodDesc
// which represent the methods.
// * code:EEClass.m_pFieldDescList - a list of fields in the type.
//
class EEClass // DO NOT CREATE A NEW EEClass USING NEW!
{
/************************************
* FRIEND FUNCTIONS
************************************/
// DO NOT ADD FRIENDS UNLESS ABSOLUTELY NECESSARY
// USE ACCESSORS TO READ/WRITE private field members
// To access bmt stuff
friend class MethodTable;
friend class MethodTableBuilder;
friend class FieldDesc;
friend class CheckAsmOffsets;
friend class ClrDataAccess;
#ifdef DACCESS_COMPILE
friend class NativeImageDumper;
#endif
/************************************
* PUBLIC INSTANCE METHODS
************************************/
public:
DWORD IsSealed()
{
LIMITED_METHOD_CONTRACT;
return IsTdSealed(m_dwAttrClass);
}
inline DWORD IsInterface()
{
WRAPPER_NO_CONTRACT;
return IsTdInterface(m_dwAttrClass);
}
inline DWORD IsAbstract()
{
WRAPPER_NO_CONTRACT;
return IsTdAbstract(m_dwAttrClass);
}
BOOL HasExplicitFieldOffsetLayout()
{
WRAPPER_NO_CONTRACT;
return IsTdExplicitLayout(GetAttrClass()) && HasLayout();
}
BOOL HasSequentialLayout()
{
WRAPPER_NO_CONTRACT;
return IsTdSequentialLayout(GetAttrClass());
}
BOOL IsBeforeFieldInit()
{
WRAPPER_NO_CONTRACT;
return IsTdBeforeFieldInit(GetAttrClass());
}
DWORD GetProtection()
{
WRAPPER_NO_CONTRACT;
return (m_dwAttrClass & tdVisibilityMask);
}
// class is blittable
BOOL IsBlittable();
#ifndef DACCESS_COMPILE
void *operator new(size_t size, LoaderHeap* pHeap, AllocMemTracker *pamTracker);
void Destruct(MethodTable * pMT);
static EEClass * CreateMinimalClass(LoaderHeap *pHeap, AllocMemTracker *pamTracker);
#endif // !DACCESS_COMPILE
#ifdef EnC_SUPPORTED
// Add a new method to an already loaded type for EnC
static HRESULT AddMethod(MethodTable * pMT, mdMethodDef methodDef, RVA newRVA, MethodDesc **ppMethod);
// Add a new field to an already loaded type for EnC
static HRESULT AddField(MethodTable * pMT, mdFieldDef fieldDesc, EnCFieldDesc **pAddedField);
static VOID FixupFieldDescForEnC(MethodTable * pMT, EnCFieldDesc *pFD, mdFieldDef fieldDef);
#endif // EnC_SUPPORTED
inline DWORD IsComImport()
{
WRAPPER_NO_CONTRACT;
return IsTdImport(m_dwAttrClass);
}
#ifdef FEATURE_PREJIT
DWORD GetSize();
void Save(DataImage *image, MethodTable *pMT);
void Fixup(DataImage *image, MethodTable *pMT);
#endif // FEATURE_PREJIT
EEClassLayoutInfo *GetLayoutInfo();
#ifdef DACCESS_COMPILE
void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, MethodTable *pMT);
#endif
static CorElementType ComputeInternalCorElementTypeForValueType(MethodTable * pMT);
/************************************
* INSTANCE MEMBER VARIABLES
************************************/
#ifdef _DEBUG
public:
inline LPCUTF8 GetDebugClassName ()
{
LIMITED_METHOD_CONTRACT;
return m_szDebugClassName;
}
inline void SetDebugClassName (LPCUTF8 szDebugClassName)
{
LIMITED_METHOD_CONTRACT;
m_szDebugClassName = szDebugClassName;
}
/*
* Controls debugging breaks and output if a method class
* is mentioned in the registry ("BreakOnClassBuild")
* Method layout within this class can cause a debug
* break by setting "BreakOnMethodName". Not accessible
* outside the class.
*/
#endif // _DEBUG
#ifdef FEATURE_COMINTEROP
/*
* Used to map MethodTable slots to VTable slots
*/
inline SparseVTableMap* GetSparseCOMInteropVTableMap ()
{
LIMITED_METHOD_CONTRACT;
return HasOptionalFields() ? GetOptionalFields()->m_pSparseVTableMap : NULL;
}
inline void SetSparseCOMInteropVTableMap (SparseVTableMap *map)
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(HasOptionalFields());
GetOptionalFields()->m_pSparseVTableMap = map;
}
#endif // FEATURE_COMINTEROP
public:
/*
* Maintain back pointer to statcally hot portion of EEClass.
* For an EEClass representing multiple instantiations of a generic type, this is the method table
* for the first instantiation requested and is the only one containing entries for non-virtual instance methods
* (i.e. non-vtable entries).
*/
// Note that EEClass structures may be shared between generic instantiations
// (see IsSharedByGenericInstantiations). In these cases EEClass::GetMethodTable