1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//
5// File: clsload.hpp
6//
7
8
9
10//
11
12//
13// ============================================================================
14
15#ifndef _H_CLSLOAD
16#define _H_CLSLOAD
17
18#include "crst.h"
19#include "eehash.h"
20#include "vars.hpp"
21#include "stubmgr.h"
22#include "typehandle.h"
23#include "object.h" // only needed for def. of PTRARRAYREF
24#include "classloadlevel.h"
25#include "specstrings.h"
26#include "simplerwlock.hpp"
27#include "classhash.h"
28
29// SystemDomain is a friend of ClassLoader.
30class SystemDomain;
31class Assembly;
32class ClassLoader;
33class TypeKey;
34class PendingTypeLoadEntry;
35class PendingTypeLoadTable;
36class EEClass;
37class Thread;
38class EETypeHashTable;
39class DynamicResolver;
40class SigPointer;
41
42// Hash table parameter for unresolved class hash
43#define UNRESOLVED_CLASS_HASH_BUCKETS 8
44
45// This is information required to look up a type in the loader. Besides the
46// basic name there is the meta data information for the type, whether the
47// the name is case sensitive, and tokens not to load. This last item allows
48// the loader to prevent a type from being recursively loaded.
49typedef enum NameHandleTable
50{
51 nhCaseSensitive = 0,
52 nhCaseInsensitive = 1
53} NameHandleTable;
54
55class HashedTypeEntry
56{
57public:
58 typedef enum
59 {
60 IsNullEntry, // Uninitialized HashedTypeEntry
61 IsHashedTokenEntry, // Entry is a token value in a R2R hashtable in from the R2R module
62 IsHashedClassEntry // Entry is a EEClassHashEntry_t from the hashtable constructed at
63 // module load time (or from the hashtable loaded from the native image)
64 } EntryType;
65
66 typedef struct
67 {
68 mdToken m_TypeToken;
69 Module * m_pModule;
70 } TokenTypeEntry;
71
72private:
73 EntryType m_EntryType;
74 PTR_EEClassHashEntry m_pClassHashEntry;
75 TokenTypeEntry m_TokenAndModulePair;
76
77public:
78 HashedTypeEntry()
79 {
80 m_EntryType = EntryType::IsNullEntry;
81 m_pClassHashEntry = PTR_NULL;
82 }
83
84 EntryType GetEntryType() { return m_EntryType; }
85 bool IsNull() { return m_EntryType == EntryType::IsNullEntry; }
86
87 const HashedTypeEntry& SetClassHashBasedEntryValue(EEClassHashEntry_t * pClassHashEntry)
88 {
89 LIMITED_METHOD_CONTRACT;
90
91 m_EntryType = EntryType::IsHashedClassEntry;
92 m_pClassHashEntry = dac_cast<PTR_EEClassHashEntry>(pClassHashEntry);
93 return *this;
94 }
95 EEClassHashEntry_t * GetClassHashBasedEntryValue()
96 {
97 LIMITED_METHOD_CONTRACT;
98
99 _ASSERT(m_EntryType == EntryType::IsHashedClassEntry);
100 return m_pClassHashEntry;
101 }
102
103 const HashedTypeEntry& SetTokenBasedEntryValue(mdTypeDef typeToken, Module * pModule)
104 {
105 LIMITED_METHOD_CONTRACT;
106
107 m_EntryType = EntryType::IsHashedTokenEntry;
108 m_TokenAndModulePair.m_TypeToken = typeToken;
109 m_TokenAndModulePair.m_pModule = pModule;
110 return *this;
111 }
112 const TokenTypeEntry& GetTokenBasedEntryValue()
113 {
114 LIMITED_METHOD_CONTRACT;
115
116 _ASSERT(m_EntryType == EntryType::IsHashedTokenEntry);
117 return m_TokenAndModulePair;
118 }
119};
120
121class NameHandle
122{
123 friend class ClassLoader;
124
125 LPCUTF8 m_nameSpace;
126 LPCUTF8 m_name;
127
128 PTR_Module m_pTypeScope;
129 mdToken m_mdType;
130 mdToken m_mdTokenNotToLoad;
131 NameHandleTable m_WhichTable;
132 HashedTypeEntry m_Bucket;
133
134public:
135
136 NameHandle()
137 {
138 LIMITED_METHOD_CONTRACT;
139 memset((void*) this, NULL, sizeof(*this));
140 }
141
142 NameHandle(LPCUTF8 name) :
143 m_nameSpace(NULL),
144 m_name(name),
145 m_pTypeScope(PTR_NULL),
146 m_mdType(mdTokenNil),
147 m_mdTokenNotToLoad(tdNoTypes),
148 m_WhichTable(nhCaseSensitive),
149 m_Bucket()
150 {
151 LIMITED_METHOD_CONTRACT;
152 }
153
154 NameHandle(LPCUTF8 nameSpace, LPCUTF8 name) :
155 m_nameSpace(nameSpace),
156 m_name(name),
157 m_pTypeScope(PTR_NULL),
158 m_mdType(mdTokenNil),
159 m_mdTokenNotToLoad(tdNoTypes),
160 m_WhichTable(nhCaseSensitive),
161 m_Bucket()
162 {
163 LIMITED_METHOD_CONTRACT;
164 SUPPORTS_DAC;
165 }
166
167 NameHandle(Module* pModule, mdToken token) :
168 m_nameSpace(NULL),
169 m_name(NULL),
170 m_pTypeScope(pModule),
171 m_mdType(token),
172 m_mdTokenNotToLoad(tdNoTypes),
173 m_WhichTable(nhCaseSensitive),
174 m_Bucket()
175 {
176 LIMITED_METHOD_CONTRACT;
177 SUPPORTS_DAC;
178 }
179
180 NameHandle(const NameHandle & p)
181 {
182 LIMITED_METHOD_CONTRACT;
183 SUPPORTS_DAC;
184 m_nameSpace = p.m_nameSpace;
185 m_name = p.m_name;
186 m_pTypeScope = p.m_pTypeScope;
187 m_mdType = p.m_mdType;
188 m_mdTokenNotToLoad = p.m_mdTokenNotToLoad;
189 m_WhichTable = p.m_WhichTable;
190 m_Bucket = p.m_Bucket;
191 }
192
193 void SetName(LPCUTF8 pName)
194 {
195 LIMITED_METHOD_CONTRACT;
196 m_name = pName;
197 }
198
199 void SetName(LPCUTF8 pNameSpace, LPCUTF8 pName)
200 {
201 LIMITED_METHOD_CONTRACT;
202 SUPPORTS_DAC_HOST_ONLY;
203
204 m_nameSpace = pNameSpace;
205 m_name = pName;
206 }
207
208 LPCUTF8 GetName() const
209 {
210 LIMITED_METHOD_CONTRACT;
211 SUPPORTS_DAC;
212 return m_name;
213 }
214
215 LPCUTF8 GetNameSpace() const
216 {
217 LIMITED_METHOD_CONTRACT;
218 SUPPORTS_DAC;
219 return m_nameSpace;
220 }
221
222 void SetTypeToken(Module* pModule, mdToken mdToken)
223 {
224 LIMITED_METHOD_CONTRACT;
225 m_pTypeScope = dac_cast<PTR_Module>(pModule);
226 m_mdType = mdToken;
227 }
228
229 PTR_Module GetTypeModule() const
230 {
231 LIMITED_METHOD_CONTRACT;
232 SUPPORTS_DAC;
233 return m_pTypeScope;
234 }
235
236 mdToken GetTypeToken() const
237 {
238 LIMITED_METHOD_CONTRACT;
239 SUPPORTS_DAC;
240 return m_mdType;
241 }
242
243 void SetTokenNotToLoad(mdToken mdtok)
244 {
245 LIMITED_METHOD_CONTRACT;
246 SUPPORTS_DAC; // "this" must be a host address
247 m_mdTokenNotToLoad = mdtok;
248 }
249
250 mdToken GetTokenNotToLoad() const
251 {
252 LIMITED_METHOD_CONTRACT;
253 SUPPORTS_DAC;
254 return m_mdTokenNotToLoad;
255 }
256
257 void SetCaseInsensitive()
258 {
259 LIMITED_METHOD_CONTRACT;
260 m_WhichTable = nhCaseInsensitive;
261 }
262
263 NameHandleTable GetTable() const
264 {
265 LIMITED_METHOD_CONTRACT;
266 SUPPORTS_DAC;
267 return m_WhichTable;
268 }
269
270 void SetBucket(const HashedTypeEntry& bucket)
271 {
272 LIMITED_METHOD_CONTRACT;
273 SUPPORTS_DAC; // "this" must be a host address
274 m_Bucket = bucket;
275 }
276
277
278 HashedTypeEntry& GetBucket()
279 {
280 LIMITED_METHOD_CONTRACT;
281 SUPPORTS_DAC;
282 return m_Bucket;
283 }
284
285 static BOOL OKToLoad(mdToken token, mdToken tokenNotToLoad)
286 {
287 LIMITED_METHOD_CONTRACT;
288 SUPPORTS_DAC;
289
290 return (token == 0 || token != tokenNotToLoad) && tokenNotToLoad != tdAllTypes;
291 }
292
293 BOOL OKToLoad()
294 {
295 WRAPPER_NO_CONTRACT;
296 SUPPORTS_DAC;
297 return OKToLoad(m_mdType, m_mdTokenNotToLoad);
298 }
299
300};
301
302//-------------------------------------------------------------------------------------------
303//
304// Introducing AccessCheckContext so that we can defer caller resolution as much as possible.
305// Stack walk is expensive and we should avoid it if we can determine accessibility without
306// knowing the caller. For example, public transparent APIs without link demand should always
307// be accessible.
308// We will have two types of AccessCheckContext.
309// 1. StaticAccessCheckContext is used by JIT and other places where the caller is statically known.
310// 2. RefSecContext is used by reflection and resolves the caller by performing a stack walk.
311//
312//-------------------------------------------------------------------------------------------
313class AccessCheckContext
314{
315public:
316 virtual MethodDesc* GetCallerMethod() = 0; // The method that wants access.
317 virtual MethodTable* GetCallerMT() = 0; // The class that wants access; NULL if interop caller.
318 virtual Assembly* GetCallerAssembly() = 0; // Assembly containing that class.
319 virtual bool IsCalledFromInterop() = 0;
320};
321
322class StaticAccessCheckContext : public AccessCheckContext
323{
324public:
325
326 StaticAccessCheckContext(MethodDesc* pCallerMethod, MethodTable* pCallerType, Assembly* pCallerAssembly)
327 : m_pCallerMethod(pCallerMethod),
328 m_pCallerMT(pCallerType),
329 m_pCallerAssembly(pCallerAssembly)
330 {
331 CONTRACTL
332 {
333 LIMITED_METHOD_CONTRACT;
334 PRECONDITION(CheckPointer(pCallerMethod, NULL_OK));
335 PRECONDITION(CheckPointer(pCallerType, NULL_OK));
336 PRECONDITION(CheckPointer(pCallerAssembly));
337 }
338 CONTRACTL_END;
339 }
340
341 StaticAccessCheckContext(MethodDesc* pCallerMethod);
342
343 StaticAccessCheckContext(MethodDesc* pCallerMethod, MethodTable* pCallerType);
344
345 virtual MethodDesc* GetCallerMethod()
346 {
347 LIMITED_METHOD_CONTRACT;
348 return m_pCallerMethod;
349 }
350
351 virtual MethodTable* GetCallerMT()
352 {
353 LIMITED_METHOD_CONTRACT;
354 return m_pCallerMT;
355 }
356
357 virtual Assembly* GetCallerAssembly()
358 {
359 WRAPPER_NO_CONTRACT;
360 return m_pCallerAssembly;
361 }
362
363 virtual bool IsCalledFromInterop()
364 {
365 WRAPPER_NO_CONTRACT;
366 return false;
367 }
368
369private:
370 MethodDesc* m_pCallerMethod;
371 MethodTable* m_pCallerMT;
372 Assembly* m_pCallerAssembly;
373};
374
375//******************************************************************************
376// This type specifies the kind of accessibility checks to perform.
377// On failure, it can be configured to either return FALSE or to throw an exception.
378class AccessCheckOptions
379{
380public:
381 enum AccessCheckType
382 {
383 // Used by statically compiled code.
384 // Desktop: Just do normal accessibility checks. No security demands.
385 // CoreCLR: Just do normal accessibility checks.
386 kNormalAccessibilityChecks,
387
388 // Used only for resource loading and reflection inovcation when the target is remoted.
389 // Desktop: If normal accessiblity checks fail, return TRUE if a demand for MemberAccess succeeds
390 // CoreCLR: If normal accessiblity checks fail, return TRUE if a the caller is Security(Safe)Critical
391 kMemberAccess,
392
393 // Used by Reflection invocation and DynamicMethod with RestrictedSkipVisibility.
394 // Desktop: If normal accessiblity checks fail, return TRUE if a demand for RestrictedMemberAccess
395 // and grant set of the target assembly succeeds.
396 // CoreCLR: If normal accessiblity checks fail, return TRUE if the callee is App transparent code (in a user assembly)
397 kRestrictedMemberAccess,
398
399 // Used by normal DynamicMethods in full trust CoreCLR
400 // CoreCLR: Do normal visibility checks but bypass transparency checks.
401 kNormalAccessNoTransparency,
402
403 // Used by DynamicMethods with restrictedSkipVisibility in full trust CoreCLR
404 // CoreCLR: Do RestrictedMemberAcess visibility checks but bypass transparency checks.
405 kRestrictedMemberAccessNoTransparency,
406
407 };
408
409 AccessCheckOptions(
410 AccessCheckType accessCheckType,
411 DynamicResolver * pAccessContext,
412 BOOL throwIfTargetIsInaccessible,
413 MethodTable * pTargetMT);
414
415 AccessCheckOptions(
416 AccessCheckType accessCheckType,
417 DynamicResolver * pAccessContext,
418 BOOL throwIfTargetIsInaccessible,
419 MethodDesc * pTargetMD);
420
421 AccessCheckOptions(
422 AccessCheckType accessCheckType,
423 DynamicResolver * pAccessContext,
424 BOOL throwIfTargetIsInaccessible,
425 FieldDesc * pTargetFD);
426
427 AccessCheckOptions(
428 const AccessCheckOptions & templateAccessCheckOptions,
429 BOOL throwIfTargetIsInaccessible);
430
431 // Follow standard rules for doing accessability
432 BOOL DoNormalAccessibilityChecks() const
433 {
434 LIMITED_METHOD_CONTRACT;
435 return m_accessCheckType == kNormalAccessibilityChecks;
436 }
437
438 // Do visibility checks including security demands for reflection access to members
439 BOOL DoReflectionAccessibilityChecks() const
440 {
441 WRAPPER_NO_CONTRACT;
442 return !DoNormalAccessibilityChecks();
443 }
444
445 BOOL Throws() const
446 {
447 LIMITED_METHOD_CONTRACT;
448 return m_fThrowIfTargetIsInaccessible;
449 }
450
451 BOOL DemandMemberAccessOrFail(AccessCheckContext *pContext, MethodTable * pTargetMT, BOOL visibilityCheck) const;
452 BOOL FailOrThrow(AccessCheckContext *pContext) const;
453
454 BOOL TransparencyCheckNeeded() const
455 {
456 LIMITED_METHOD_CONTRACT;
457 return (m_accessCheckType != kNormalAccessNoTransparency && m_accessCheckType != kRestrictedMemberAccessNoTransparency);
458 }
459
460 static AccessCheckOptions* s_pNormalAccessChecks;
461
462 static void Startup();
463
464private:
465 void Initialize(
466 AccessCheckType accessCheckType,
467 BOOL throwIfTargetIsInaccessible,
468 MethodTable * pTargetMT,
469 MethodDesc * pTargetMD,
470 FieldDesc * pTargetFD);
471
472 BOOL DemandMemberAccess(AccessCheckContext *pContext, MethodTable * pTargetMT, BOOL visibilityCheck) const;
473
474 void ThrowAccessException(
475 AccessCheckContext* pContext,
476 MethodTable* pFailureMT = NULL,
477 Exception* pInnerException = NULL) const;
478
479 MethodTable * m_pTargetMT;
480 MethodDesc * m_pTargetMethod;
481 FieldDesc * m_pTargetField;
482
483 AccessCheckType m_accessCheckType;
484 // The context used to determine if access is allowed. It is the resolver that carries the compressed-stack used to do the Demand.
485 // If this is NULL, the access is checked against the current call-stack.
486 // This is non-NULL only for m_accessCheckType==kRestrictedMemberAccess
487 DynamicResolver * m_pAccessContext;
488 // If the target is not accessible, should the API return FALSE, or should it throw an exception?
489 BOOL m_fThrowIfTargetIsInaccessible;
490};
491
492void DECLSPEC_NORETURN ThrowFieldAccessException(MethodDesc *pCallerMD,
493 FieldDesc *pFD,
494 UINT messageID = 0,
495 Exception *pInnerException = NULL);
496
497void DECLSPEC_NORETURN ThrowMethodAccessException(MethodDesc *pCallerMD,
498 MethodDesc *pCalleeMD,
499 UINT messageID = 0,
500 Exception *pInnerException = NULL);
501
502void DECLSPEC_NORETURN ThrowTypeAccessException(MethodDesc *pCallerMD,
503 MethodTable *pMT,
504 UINT messageID = 0,
505 Exception *pInnerException = NULL);
506
507void DECLSPEC_NORETURN ThrowFieldAccessException(AccessCheckContext* pContext,
508 FieldDesc *pFD,
509 UINT messageID = 0,
510 Exception *pInnerException = NULL);
511
512void DECLSPEC_NORETURN ThrowMethodAccessException(AccessCheckContext* pContext,
513 MethodDesc *pCalleeMD,
514 UINT messageID = 0,
515 Exception *pInnerException = NULL);
516
517void DECLSPEC_NORETURN ThrowTypeAccessException(AccessCheckContext* pContext,
518 MethodTable *pMT,
519 UINT messageID = 0,
520 Exception *pInnerException = NULL);
521
522
523//---------------------------------------------------------------------------------------
524//
525class ClassLoader
526{
527 friend class PendingTypeLoadEntry;
528 friend class MethodTableBuilder;
529 friend class AppDomain;
530 friend class Assembly;
531 friend class Module;
532 friend class CLRPrivTypeCacheWinRT;
533 friend class CLRPrivTypeCacheReflectionOnlyWinRT;
534
535 // the following two classes are friends because they will call LoadTypeHandleForTypeKey by token directly
536 friend class COMDynamicWrite;
537 friend class COMModule;
538
539private:
540 // Classes for which load is in progress
541 PendingTypeLoadTable * m_pUnresolvedClassHash;
542 CrstExplicitInit m_UnresolvedClassLock;
543
544 // Protects addition of elements to module's m_pAvailableClasses.
545 // (indeed thus protects addition of elements to any m_pAvailableClasses in any
546 // of the modules managed by this loader)
547 CrstExplicitInit m_AvailableClassLock;
548
549 CrstExplicitInit m_AvailableTypesLock;
550
551 // Do we have any modules which need to have their classes added to
552 // the available list?
553 Volatile<LONG> m_cUnhashedModules;
554
555 // Back reference to the assembly
556 PTR_Assembly m_pAssembly;
557
558public:
559
560#ifdef _DEBUG
561 DWORD m_dwDebugMethods;
562 DWORD m_dwDebugFieldDescs; // Doesn't include anything we don't allocate a FieldDesc for
563 DWORD m_dwDebugClasses;
564 DWORD m_dwDebugDuplicateInterfaceSlots;
565 DWORD m_dwGCSize;
566 DWORD m_dwInterfaceMapSize;
567 DWORD m_dwMethodTableSize;
568 DWORD m_dwVtableData;
569 DWORD m_dwStaticFieldData;
570 DWORD m_dwFieldDescData;
571 DWORD m_dwMethodDescData;
572 size_t m_dwEEClassData;
573#endif
574
575public:
576 ClassLoader(Assembly *pAssembly);
577 ~ClassLoader();
578
579private:
580
581 VOID PopulateAvailableClassHashTable(Module *pModule,
582 AllocMemTracker *pamTracker);
583
584 void LazyPopulateCaseSensitiveHashTables();
585 void LazyPopulateCaseInsensitiveHashTables();
586
587 // Lookup the hash table entry from the hash table
588 void GetClassValue(NameHandleTable nhTable,
589 NameHandle *pName,
590 HashDatum *pData,
591 EEClassHashTable **ppTable,
592 Module* pLookInThisModuleOnly,
593 HashedTypeEntry* pFoundEntry,
594 Loader::LoadFlag loadFlag,
595 BOOL& needsToBuildHashtable);
596
597
598public:
599 //#LoaderModule
600 // LoaderModule determines in which module an item gets placed.
601 // For everything except paramaterized types and methods the choice is easy.
602 //
603 // If NGEN'ing we may choose to place the item into the current module (which is different from runtime behavior).
604 //
605 // The rule for determining the loader module must ensure that a type or method never outlives its loader module
606 // with respect to app-domain unloading
607 static Module * ComputeLoaderModule(MethodTable * pMT,
608 mdToken token, // the token of the method
609 Instantiation methodInst); // the type arguments to the method (if any)
610 static Module * ComputeLoaderModule(TypeKey * typeKey);
611 inline static PTR_Module ComputeLoaderModuleForFunctionPointer(TypeHandle * pRetAndArgTypes, DWORD NumArgsPlusRetType);
612 inline static PTR_Module ComputeLoaderModuleForParamType(TypeHandle paramType);
613
614private:
615 static PTR_Module ComputeLoaderModuleWorker(Module *pDefinitionModule, // the module that declares the generic type or method
616 mdToken token,
617 Instantiation classInst, // the type arguments to the type (if any)
618 Instantiation methodInst); // the type arguments to the method (if any)
619
620 BOOL FindClassModuleThrowing(
621 const NameHandle * pName,
622 TypeHandle * pType,
623 mdToken * pmdClassToken,
624 Module ** ppModule,
625 mdToken * pmdFoundExportedType,
626 HashedTypeEntry * pEntry,
627 Module * pLookInThisModuleOnly,
628 Loader::LoadFlag loadFlag);
629
630 static PTR_Module ComputeLoaderModuleForCompilation(Module *pDefinitionModule, // the module that declares the generic type or method
631 mdToken token,
632 Instantiation classInst, // the type arguments to the type (if any)
633 Instantiation methodInst); // the type arguments to the method (if any)
634
635public:
636 void Init(AllocMemTracker *pamTracker);
637
638 PTR_Assembly GetAssembly();
639 DomainAssembly* GetDomainAssembly(AppDomain *pDomain = NULL);
640
641 void FreeModules();
642
643#ifdef DACCESS_COMPILE
644 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
645#endif
646
647 //==================================================================================
648 // Main entry points to class loader
649 // Organized as follows:
650 // by token:
651 // TypeDef
652 // TypeDefOrRef
653 // TypeDefOrRefOrSpec
654 // by constructed type:
655 // ArrayType
656 // PointerOrByrefType
657 // FnPtrType
658 // GenericInstantiation
659 // by name:
660 // ByName
661 // Each takes a parameter comes, with the following semantics:
662 // fLoadTypes=DontLoadTypes: if type isn't already in the loader's table, return NULL
663 // fLoadTypes=LoadTypes: if type isn't already in the loader's table, then create it
664 // Each comes in two variants, LoadXThrowing and LoadXNoThrow, the latter being just
665 // an exception-handling wrapper around the former.
666 //
667 // Each also allows types to be loaded only up to a particular level (see classloadlevel.h).
668 // The class loader itself makes use of these levels to "break" recursion across
669 // generic instantiations. External clients should leave the parameter at its default
670 // value (CLASS_LOADED).
671 //==================================================================================
672
673public:
674
675 // We use enums for these flags so that we can easily search the codebase to
676 // determine where the flags are set to their non-default values.
677 //
678 // This enum tells us what to do if the load fails. If ThrowIfNotFound is used
679 // with a HRESULT-returning NOTHROW function then it actually indicates that
680 // an error-HRESULT will be returned.
681 // The ThrowButNullV11McppWorkaround value means ThrowIfNotFound, except when the case
682 // of a Nil ResolutionScope for a value type (erroneously generated by Everett MCPP
683 // compiler.)
684 typedef enum { ThrowIfNotFound, ReturnNullIfNotFound, ThrowButNullV11McppWorkaround } NotFoundAction;
685
686 // This flag indicates whether we should accept an uninstantiatednaked TypeDef or TypeRef
687 // for a generic type definition, where "uninstantiated" means "not used as part of
688 // a TypeSpec"
689 typedef enum { FailIfUninstDefOrRef, PermitUninstDefOrRef } PermitUninstantiatedFlag;
690
691 // This flag indicates whether we want to "load" the type if it isn't already in the
692 // loader's tables and has reached the load level desired.
693 typedef enum { LoadTypes, DontLoadTypes } LoadTypesFlag;
694
695
696 // Load types by token (Def, Ref and Spec)
697 static TypeHandle LoadTypeDefThrowing(Module *pModule,
698 mdToken typeDef,
699 NotFoundAction fNotFound = ThrowIfNotFound,
700 PermitUninstantiatedFlag fUninstantiated = FailIfUninstDefOrRef,
701 mdToken tokenNotToLoad = tdNoTypes,
702 ClassLoadLevel level = CLASS_LOADED,
703 Instantiation * pTargetInstantiation = NULL /* used to verify arity of the loaded type */);
704
705 static TypeHandle LoadTypeDefOrRefThrowing(Module *pModule,
706 mdToken typeRefOrDef,
707 NotFoundAction fNotFound = ThrowIfNotFound,
708 PermitUninstantiatedFlag fUninstantiated = FailIfUninstDefOrRef,
709 mdToken tokenNotToLoad = tdNoTypes,
710 ClassLoadLevel level = CLASS_LOADED);
711
712 static TypeHandle LoadTypeDefOrRefOrSpecThrowing(Module *pModule,
713 mdToken typeRefOrDefOrSpec,
714 const SigTypeContext *pTypeContext,
715 NotFoundAction fNotFound = ThrowIfNotFound,
716 PermitUninstantiatedFlag fUninstantiated = FailIfUninstDefOrRef,
717 LoadTypesFlag fLoadTypes = LoadTypes,
718 ClassLoadLevel level = CLASS_LOADED,
719 BOOL dropGenericArgumentLevel = FALSE,
720 const Substitution *pSubst = NULL /* substitution to apply if the token is a type spec with generic variables */ );
721
722 // Load constructed types by providing their constituents
723 static TypeHandle LoadPointerOrByrefTypeThrowing(CorElementType typ,
724 TypeHandle baseType,
725 LoadTypesFlag fLoadTypes = LoadTypes,
726 ClassLoadLevel level = CLASS_LOADED);
727
728 // The resulting type behaves like the unmanaged view of a given value type.
729 static TypeHandle LoadNativeValueTypeThrowing(TypeHandle baseType,
730 LoadTypesFlag fLoadTypes = LoadTypes,
731 ClassLoadLevel level = CLASS_LOADED);
732
733 static TypeHandle LoadArrayTypeThrowing(TypeHandle baseType,
734 CorElementType typ = ELEMENT_TYPE_SZARRAY,
735 unsigned rank = 0,
736 LoadTypesFlag fLoadTypes = LoadTypes,
737 ClassLoadLevel level = CLASS_LOADED);
738
739 static TypeHandle LoadFnptrTypeThrowing(BYTE callConv,
740 DWORD numArgs,
741 TypeHandle* retAndArgTypes,
742 LoadTypesFlag fLoadTypes = LoadTypes,
743 ClassLoadLevel level = CLASS_LOADED);
744
745 // Load types by name
746 static TypeHandle LoadTypeByNameThrowing(Assembly *pAssembly,
747 LPCUTF8 nameSpace,
748 LPCUTF8 name,
749 NotFoundAction fNotFound = ThrowIfNotFound,
750 LoadTypesFlag fLoadTypes = LoadTypes,
751 ClassLoadLevel level = CLASS_LOADED);
752
753 // Resolve a TypeRef to a TypeDef
754 // (Just a no-op on TypeDefs)
755 // Return FALSE if operation failed (e.g. type does not exist)
756 // *pfUsesTypeForwarder is set to TRUE if a type forwarder is found. It is never set to FALSE.
757 static BOOL ResolveTokenToTypeDefThrowing(Module * pTypeRefModule,
758 mdTypeRef typeRefToken,
759 Module ** ppTypeDefModule,
760 mdTypeDef * pTypeDefToken,
761 Loader::LoadFlag loadFlag = Loader::Load,
762 BOOL * pfUsesTypeForwarder = NULL);
763
764 // Resolve a name to a TypeDef
765 // Return FALSE if operation failed (e.g. type does not exist)
766 // *pfUsesTypeForwarder is set to TRUE if a type forwarder is found. It is never set to FALSE.
767 static BOOL ResolveNameToTypeDefThrowing(Module * pTypeRefModule,
768 NameHandle * pName,
769 Module ** ppTypeDefModule,
770 mdTypeDef * pTypeDefToken,
771 Loader::LoadFlag loadFlag = Loader::Load,
772 BOOL * pfUsesTypeForwarder = NULL);
773
774 static void EnsureLoaded(TypeHandle typeHnd, ClassLoadLevel level = CLASS_LOADED);
775 static void TryEnsureLoaded(TypeHandle typeHnd, ClassLoadLevel level = CLASS_LOADED);
776
777public:
778 // Look up a class by name
779 //
780 // Guaranteed to only return NULL if pName->OKToLoad() returns FALSE.
781 // Thus when type loads are enabled this will return non-null.
782 TypeHandle LoadTypeHandleThrowIfFailed(NameHandle* pName, ClassLoadLevel level = CLASS_LOADED,
783 Module* pLookInThisModuleOnly=NULL);
784
785public:
786 // Looks up class in the local module table, if it is there it succeeds,
787 // Otherwise it fails, This is meant only for optimizations etc
788 static TypeHandle LookupTypeDefOrRefInModule(Module *pModule, mdToken cl, ClassLoadLevel *pLoadLevel = NULL);
789
790private:
791
792 VOID AddAvailableClassDontHaveLock(Module *pModule,
793 mdTypeDef classdef,
794 AllocMemTracker *pamTracker);
795
796 VOID AddAvailableClassHaveLock(Module * pModule,
797 mdTypeDef classdef,
798 AllocMemTracker * pamTracker,
799 LPCSTR szWinRtNamespacePrefix,
800 DWORD cchWinRtNamespacePrefix);
801
802 VOID AddExportedTypeDontHaveLock(Module *pManifestModule,
803 mdExportedType cl,
804 AllocMemTracker *pamTracker);
805
806 VOID AddExportedTypeHaveLock(Module *pManifestModule,
807 mdExportedType cl,
808 AllocMemTracker *pamTracker);
809
810public:
811
812 // For an generic type instance return the representative within the class of
813 // all type handles that share code. For example,
814 // <int> --> <int>,
815 // <object> --> <__Canon>,
816 // <string> --> <__Canon>,
817 // <List<string>> --> <__Canon>,
818 // <Struct<string>> --> <Struct<__Canon>>
819 //
820 // If the code for the type handle is not shared then return
821 // the type handle itself.
822 static TypeHandle CanonicalizeGenericArg(TypeHandle genericArg);
823
824 // Determine if the specified type representation induces a sharable
825 // set of compatible instantiations when used as a type parameter to
826 // a generic type or method.
827 //
828 // For example, when sharing at reference types "object" and "Struct<object>"
829 // both induce sets of compatible instantiations, e.g. when used to build types
830 // "List<object>" and "List<Struct<object>>" respectively.
831 static BOOL IsSharableInstantiation(Instantiation inst);
832
833 // Determine if it is normalized canonical generic instantiation.
834 // Dictionary<__Canon, __Canon> -> TRUE
835 // Dictionary<__Canon, int> -> TRUE
836 // Dictionary<__Canon, String> -> FALSE
837 static BOOL IsCanonicalGenericInstantiation(Instantiation inst);
838
839 // Determine if it is the entirely-canonical generic instantiation
840 // Dictionary<__Canon, __Canon> -> TRUE
841 // Dictionary<anything else> -> FALSE
842 static BOOL IsTypicalSharedInstantiation(Instantiation inst);
843
844 // Return TRUE if inst is the typical instantiation for the type or method specified by pModule/token
845 static BOOL IsTypicalInstantiation(Module *pModule, mdToken token, Instantiation inst);
846
847 // Load canonical shared instantiation for type key (each instantiation argument is
848 // substituted by CanonicalizeGenericArg)
849 static TypeHandle LoadCanonicalGenericInstantiation(TypeKey *pTypeKey,
850 LoadTypesFlag fLoadTypes/*=LoadTypes*/,
851 ClassLoadLevel level/*=CLASS_LOADED*/);
852
853 // Create a generic instantiation.
854 // If typeDef is not a generic type then throw an exception
855 // If its arity does not match nGenericClassArgCount then throw an exception
856 // The pointer to the instantiation is not persisted e.g. the type parameters can be stack-allocated.
857 // If inst=NULL then <__Canon,...,__Canon> is assumed
858 // If fLoadTypes=DontLoadTypes then the type handle is not created if it is not
859 // already present in the tables.
860 static TypeHandle LoadGenericInstantiationThrowing(Module *pModule,
861 mdTypeDef typeDef,
862 Instantiation inst,
863 LoadTypesFlag fLoadTypes = LoadTypes,
864 ClassLoadLevel level = CLASS_LOADED,
865 const InstantiationContext *pInstContext = NULL,
866 BOOL fFromNativeImage = FALSE);
867
868// Public access Check APIs
869public:
870
871 static BOOL CanAccessClass(
872 AccessCheckContext* pContext,
873 MethodTable* pTargetClass,
874 Assembly* pTargetAssembly,
875 const AccessCheckOptions & accessCheckOptions = *AccessCheckOptions::s_pNormalAccessChecks);
876
877 static BOOL CanAccess(
878 AccessCheckContext* pContext,
879 MethodTable* pTargetClass,
880 Assembly* pTargetAssembly,
881 DWORD dwMemberAttrs,
882 MethodDesc* pOptionalTargetMethod,
883 FieldDesc* pOptionalTargetField,
884 const AccessCheckOptions & accessCheckOptions = *AccessCheckOptions::s_pNormalAccessChecks);
885
886 static BOOL CanAccessFamilyVerification(
887 TypeHandle thCurrentClass,
888 TypeHandle thInstanceClass);
889
890private:
891 // Access check helpers
892 static BOOL CanAccessMethodInstantiation(
893 AccessCheckContext* pContext,
894 MethodDesc* pOptionalTargetMethod,
895 const AccessCheckOptions & accessCheckOptions);
896
897 static BOOL CanAccessFamily(
898 MethodTable* pCurrentClass,
899 MethodTable* pTargetClass);
900
901 static BOOL CheckAccessMember(
902 AccessCheckContext* pContext,
903 MethodTable* pTargetClass,
904 Assembly* pTargetAssembly,
905 DWORD dwMemberAttrs,
906 MethodDesc* pOptionalTargetMethod,
907 FieldDesc* pOptionalTargetField,
908 const AccessCheckOptions & accessCheckOptions = *AccessCheckOptions::s_pNormalAccessChecks);
909
910
911public:
912 //Creates a key with both the namespace and name converted to lowercase and
913 //made into a proper namespace-path.
914 VOID CreateCanonicallyCasedKey(LPCUTF8 pszNameSpace, LPCUTF8 pszName,
915 __out LPUTF8 *ppszOutNameSpace, __out LPUTF8 *ppszOutName);
916
917 static HRESULT FindTypeDefByExportedType(IMDInternalImport *pCTImport,
918 mdExportedType mdCurrent,
919 IMDInternalImport *pTDImport,
920 mdTypeDef *mtd);
921
922 class AvailableClasses_LockHolder : public CrstHolder
923 {
924 public:
925 AvailableClasses_LockHolder(ClassLoader *classLoader)
926 : CrstHolder(&classLoader->m_AvailableClassLock)
927 {
928 WRAPPER_NO_CONTRACT;
929 }
930 };
931
932 friend class AvailableClasses_LockHolder;
933
934private:
935 static TypeHandle LoadConstructedTypeThrowing(TypeKey *pKey,
936 LoadTypesFlag fLoadTypes = LoadTypes,
937 ClassLoadLevel level = CLASS_LOADED,
938 const InstantiationContext *pInstContext = NULL);
939
940 static TypeHandle LookupTypeKeyUnderLock(TypeKey *pKey,
941 EETypeHashTable *pTable,
942 CrstBase *pLock);
943
944 static TypeHandle LookupTypeKey(TypeKey *pKey,
945 EETypeHashTable *pTable,
946 CrstBase *pLock,
947 BOOL fCheckUnderLock);
948
949 static TypeHandle LookupInLoaderModule(TypeKey* pKey, BOOL fCheckUnderLock);
950#ifdef FEATURE_PREJIT
951 static TypeHandle LookupInPreferredZapModule(TypeKey* pKey, BOOL fCheckUnderLock);
952#endif // FEATURE_PREJIT
953
954 // Lookup a handle in the appropriate table
955 // (declaring module for TypeDef or loader-module for constructed types)
956 static TypeHandle LookupTypeHandleForTypeKey(TypeKey *pTypeKey);
957 static TypeHandle LookupTypeHandleForTypeKeyInner(TypeKey *pTypeKey, BOOL fCheckUnderLock);
958
959 static void DECLSPEC_NORETURN ThrowTypeLoadException(TypeKey *pKey, UINT resIDWhy);
960
961
962 BOOL IsNested(NameHandle* pName, mdToken *mdEncloser);
963 static BOOL IsNested(Module *pModude, mdToken typeDefOrRef, mdToken *mdEncloser);
964
965public:
966 // Helpers for FindClassModule()
967 BOOL CompareNestedEntryWithTypeDef(IMDInternalImport *pImport,
968 mdTypeDef mdCurrent,
969 EEClassHashTable *pClassHash,
970 PTR_EEClassHashEntry pEntry);
971 BOOL CompareNestedEntryWithTypeRef(IMDInternalImport *pImport,
972 mdTypeRef mdCurrent,
973 EEClassHashTable *pClassHash,
974 PTR_EEClassHashEntry pEntry);
975 BOOL CompareNestedEntryWithExportedType(IMDInternalImport *pImport,
976 mdExportedType mdCurrent,
977 EEClassHashTable *pClassHash,
978 PTR_EEClassHashEntry pEntry);
979
980 //Attempts to find/load/create a type handle but does not throw
981 // if used in "find" mode.
982 TypeHandle LoadTypeHandleThrowing(NameHandle* pName, ClassLoadLevel level = CLASS_LOADED,
983 Module* pLookInThisModuleOnly=NULL);
984
985private:
986
987#ifndef DACCESS_COMPILE
988 // Perform a single phase of class loading
989 // If no type handle has yet been created, typeHnd is null.
990 static TypeHandle DoIncrementalLoad(TypeKey *pTypeKey,
991 TypeHandle typeHnd,
992 ClassLoadLevel workLevel);
993
994 // Phase CLASS_LOAD_CREATE of class loading
995 static TypeHandle CreateTypeHandleForTypeKey(TypeKey *pTypeKey,
996 AllocMemTracker *pamTracker);
997
998 // Publish the type in the loader's tables
999 static TypeHandle PublishType(TypeKey *pTypeKey, TypeHandle typeHnd);
1000
1001 // Notify profiler and debugger that a type load has completed
1002 // Also update perf counters
1003 static void Notify(TypeHandle typeHnd);
1004
1005 // Phase CLASS_LOAD_EXACTPARENTS of class loading
1006 // Load exact parents and interfaces and dependent structures (generics dictionary, vtable fixes)
1007 static void LoadExactParents(MethodTable *pMT);
1008
1009 static void LoadExactParentAndInterfacesTransitively(MethodTable *pMT);
1010
1011 // Create a non-canonical instantiation of a generic type based off the canonical instantiation
1012 // (For example, MethodTable for List<string> is based on the MethodTable for List<__Canon>)
1013 static TypeHandle CreateTypeHandleForNonCanonicalGenericInstantiation(TypeKey *pTypeKey,
1014 AllocMemTracker *pamTracker);
1015
1016 // Loads a class. This is the inner call from the multi-threaded load. This load must
1017 // be protected in some manner.
1018 // If we're attempting to load a fresh instantiated type then genericArgs should be filled in
1019
1020 static TypeHandle CreateTypeHandleForTypeDefThrowing(Module *pModule,
1021 mdTypeDef cl,
1022 Instantiation inst,
1023 AllocMemTracker *pamTracker);
1024
1025 // The token must be a type def. GC must be enabled.
1026 // If we're attempting to load a fresh instantiated type then genericArgs should be filled in
1027 TypeHandle LoadTypeHandleForTypeKey(TypeKey *pTypeKey,
1028 TypeHandle typeHnd,
1029 ClassLoadLevel level = CLASS_LOADED,
1030 const InstantiationContext *pInstContext = NULL);
1031
1032 TypeHandle LoadTypeHandleForTypeKeyNoLock(TypeKey *pTypeKey,
1033 ClassLoadLevel level = CLASS_LOADED,
1034 const InstantiationContext *pInstContext = NULL);
1035
1036 // Used for initial loading of parent class and implemented interfaces
1037 // When tok represents an instantiated type return an *approximate* instantiated
1038 // type (where reference type arguments are replaced by Object)
1039 static
1040 TypeHandle
1041 LoadApproxTypeThrowing(
1042 Module * pModule,
1043 mdToken tok,
1044 SigPointer * pSigInst,
1045 const SigTypeContext * pClassTypeContext);
1046
1047 // Returns the parent of a token. The token must be a typedef.
1048 // If the parent is a shared constructed type (e.g. class C : List<string>) then
1049 // only the canonical instantiation is loaded at this point.
1050 // This is to avoid cycles in the loader e.g. on class C : D<C> or class C<T> : D<C<T>>
1051 // We fix up the exact parent later in LoadInstantiatedInfo.
1052 static
1053 MethodTable *
1054 LoadApproxParentThrowing(
1055 Module * pModule,
1056 mdToken cl,
1057 SigPointer * pParentInst,
1058 const SigTypeContext * pClassTypeContext);
1059
1060 // Locates the enclosing class of a token if any. The token must be a typedef.
1061 static VOID GetEnclosingClassThrowing(IMDInternalImport *pInternalImport,
1062 Module *pModule,
1063 mdTypeDef cl,
1064 mdTypeDef *tdEnclosing);
1065
1066 // Insert the class in the classes hash table and if needed in the case insensitive one
1067 EEClassHashEntry_t *InsertValue(EEClassHashTable *pClassHash,
1068 EEClassHashTable *pClassCaseInsHash,
1069 LPCUTF8 pszNamespace,
1070 LPCUTF8 pszClassName,
1071 HashDatum Data,
1072 EEClassHashEntry_t *pEncloser,
1073 AllocMemTracker *pamTracker);
1074
1075 // don't call this directly.
1076 TypeHandle LoadTypeHandleForTypeKey_Body(TypeKey *pTypeKey,
1077 TypeHandle typeHnd,
1078 ClassLoadLevel targetLevel);
1079#endif //!DACCESS_COMPILE
1080
1081}; // class ClassLoader
1082
1083#endif /* _H_CLSLOAD */
1084