summaryrefslogtreecommitdiff
path: root/src/vm/clsload.hpp
diff options
context:
space:
mode:
authorJiyoung Yun <jy910.yun@samsung.com>2016-11-23 19:09:09 +0900
committerJiyoung Yun <jy910.yun@samsung.com>2016-11-23 19:09:09 +0900
commit4b4aad7217d3292650e77eec2cf4c198ea9c3b4b (patch)
tree98110734c91668dfdbb126fcc0e15ddbd93738ca /src/vm/clsload.hpp
parentfa45f57ed55137c75ac870356a1b8f76c84b229c (diff)
downloadcoreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.tar.gz
coreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.tar.bz2
coreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.zip
Imported Upstream version 1.1.0upstream/1.1.0
Diffstat (limited to 'src/vm/clsload.hpp')
-rw-r--r--src/vm/clsload.hpp1148
1 files changed, 1148 insertions, 0 deletions
diff --git a/src/vm/clsload.hpp b/src/vm/clsload.hpp
new file mode 100644
index 0000000000..e2705ae2e4
--- /dev/null
+++ b/src/vm/clsload.hpp
@@ -0,0 +1,1148 @@
+// 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: clsload.hpp
+//
+
+
+
+//
+
+//
+// ============================================================================
+
+#ifndef _H_CLSLOAD
+#define _H_CLSLOAD
+
+#include "crst.h"
+#include "eehash.h"
+#include "vars.hpp"
+#include "stubmgr.h"
+#include "typehandle.h"
+#include "object.h" // only needed for def. of PTRARRAYREF
+#include "classloadlevel.h"
+#include "specstrings.h"
+#include "simplerwlock.hpp"
+#include "classhash.h"
+
+// SystemDomain is a friend of ClassLoader.
+class SystemDomain;
+class Assembly;
+class ClassLoader;
+class TypeKey;
+class PendingTypeLoadEntry;
+class PendingTypeLoadTable;
+class EEClass;
+class Thread;
+class EETypeHashTable;
+class IAssemblySecurityDescriptor;
+class DynamicResolver;
+class SigPointer;
+
+// Hash table parameter for unresolved class hash
+#define UNRESOLVED_CLASS_HASH_BUCKETS 8
+
+// This is information required to look up a type in the loader. Besides the
+// basic name there is the meta data information for the type, whether the
+// the name is case sensitive, and tokens not to load. This last item allows
+// the loader to prevent a type from being recursively loaded.
+typedef enum NameHandleTable
+{
+ nhCaseSensitive = 0,
+ nhCaseInsensitive = 1
+} NameHandleTable;
+
+class HashedTypeEntry
+{
+public:
+ typedef enum
+ {
+ IsNullEntry, // Uninitialized HashedTypeEntry
+ IsHashedTokenEntry, // Entry is a token value in a R2R hashtable in from the R2R module
+ IsHashedClassEntry // Entry is a EEClassHashEntry_t from the hashtable constructed at
+ // module load time (or from the hashtable loaded from the native image)
+ } EntryType;
+
+ typedef struct
+ {
+ mdToken m_TypeToken;
+ Module * m_pModule;
+ } TokenTypeEntry;
+
+private:
+ EntryType m_EntryType;
+ PTR_EEClassHashEntry m_pClassHashEntry;
+ TokenTypeEntry m_TokenAndModulePair;
+
+public:
+ HashedTypeEntry()
+ {
+ m_EntryType = EntryType::IsNullEntry;
+ m_pClassHashEntry = PTR_NULL;
+ }
+
+ EntryType GetEntryType() { return m_EntryType; }
+ bool IsNull() { return m_EntryType == EntryType::IsNullEntry; }
+
+ const HashedTypeEntry& SetClassHashBasedEntryValue(EEClassHashEntry_t * pClassHashEntry)
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ m_EntryType = EntryType::IsHashedClassEntry;
+ m_pClassHashEntry = dac_cast<PTR_EEClassHashEntry>(pClassHashEntry);
+ return *this;
+ }
+ EEClassHashEntry_t * GetClassHashBasedEntryValue()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ _ASSERT(m_EntryType == EntryType::IsHashedClassEntry);
+ return m_pClassHashEntry;
+ }
+
+ const HashedTypeEntry& SetTokenBasedEntryValue(mdTypeDef typeToken, Module * pModule)
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ m_EntryType = EntryType::IsHashedTokenEntry;
+ m_TokenAndModulePair.m_TypeToken = typeToken;
+ m_TokenAndModulePair.m_pModule = pModule;
+ return *this;
+ }
+ const TokenTypeEntry& GetTokenBasedEntryValue()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ _ASSERT(m_EntryType == EntryType::IsHashedTokenEntry);
+ return m_TokenAndModulePair;
+ }
+};
+
+class NameHandle
+{
+ friend class ClassLoader;
+
+ LPCUTF8 m_nameSpace;
+ LPCUTF8 m_name;
+
+ PTR_Module m_pTypeScope;
+ mdToken m_mdType;
+ mdToken m_mdTokenNotToLoad;
+ NameHandleTable m_WhichTable;
+ HashedTypeEntry m_Bucket;
+
+public:
+
+ NameHandle()
+ {
+ LIMITED_METHOD_CONTRACT;
+ memset((void*) this, NULL, sizeof(*this));
+ }
+
+ NameHandle(LPCUTF8 name) :
+ m_nameSpace(NULL),
+ m_name(name),
+ m_pTypeScope(PTR_NULL),
+ m_mdType(mdTokenNil),
+ m_mdTokenNotToLoad(tdNoTypes),
+ m_WhichTable(nhCaseSensitive),
+ m_Bucket()
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+ NameHandle(LPCUTF8 nameSpace, LPCUTF8 name) :
+ m_nameSpace(nameSpace),
+ m_name(name),
+ m_pTypeScope(PTR_NULL),
+ m_mdType(mdTokenNil),
+ m_mdTokenNotToLoad(tdNoTypes),
+ m_WhichTable(nhCaseSensitive),
+ m_Bucket()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC;
+ }
+
+ NameHandle(Module* pModule, mdToken token) :
+ m_nameSpace(NULL),
+ m_name(NULL),
+ m_pTypeScope(pModule),
+ m_mdType(token),
+ m_mdTokenNotToLoad(tdNoTypes),
+ m_WhichTable(nhCaseSensitive),
+ m_Bucket()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC;
+ }
+
+ NameHandle(const NameHandle & p)
+ {
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC;
+ m_nameSpace = p.m_nameSpace;
+ m_name = p.m_name;
+ m_pTypeScope = p.m_pTypeScope;
+ m_mdType = p.m_mdType;
+ m_mdTokenNotToLoad = p.m_mdTokenNotToLoad;
+ m_WhichTable = p.m_WhichTable;
+ m_Bucket = p.m_Bucket;
+ }
+
+ void SetName(LPCUTF8 pName)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_name = pName;
+ }
+
+ void SetName(LPCUTF8 pNameSpace, LPCUTF8 pName)
+ {
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC_HOST_ONLY;
+
+ m_nameSpace = pNameSpace;
+ m_name = pName;
+ }
+
+ LPCUTF8 GetName() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC;
+ return m_name;
+ }
+
+ LPCUTF8 GetNameSpace() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC;
+ return m_nameSpace;
+ }
+
+ void SetTypeToken(Module* pModule, mdToken mdToken)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_pTypeScope = dac_cast<PTR_Module>(pModule);
+ m_mdType = mdToken;
+ }
+
+ PTR_Module GetTypeModule() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC;
+ return m_pTypeScope;
+ }
+
+ mdToken GetTypeToken() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC;
+ return m_mdType;
+ }
+
+ void SetTokenNotToLoad(mdToken mdtok)
+ {
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC; // "this" must be a host address
+ m_mdTokenNotToLoad = mdtok;
+ }
+
+ mdToken GetTokenNotToLoad() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC;
+ return m_mdTokenNotToLoad;
+ }
+
+ void SetCaseInsensitive()
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_WhichTable = nhCaseInsensitive;
+ }
+
+ NameHandleTable GetTable() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC;
+ return m_WhichTable;
+ }
+
+ void SetBucket(const HashedTypeEntry& bucket)
+ {
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC; // "this" must be a host address
+ m_Bucket = bucket;
+ }
+
+
+ HashedTypeEntry& GetBucket()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC;
+ return m_Bucket;
+ }
+
+ static BOOL OKToLoad(mdToken token, mdToken tokenNotToLoad)
+ {
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC;
+
+ return (token == 0 || token != tokenNotToLoad) && tokenNotToLoad != tdAllTypes;
+ }
+
+ BOOL OKToLoad()
+ {
+ WRAPPER_NO_CONTRACT;
+ SUPPORTS_DAC;
+ return OKToLoad(m_mdType, m_mdTokenNotToLoad);
+ }
+
+};
+
+//-------------------------------------------------------------------------------------------
+//
+// Introducing AccessCheckContext so that we can defer caller resolution as much as possible.
+// Stack walk is expensive and we should avoid it if we can determine accessibility without
+// knowing the caller. For example, public transparent APIs without link demand should always
+// be accessible.
+// We will have two types of AccessCheckContext.
+// 1. StaticAccessCheckContext is used by JIT and other places where the caller is statically known.
+// 2. RefSecContext is used by reflection and resolves the caller by performing a stack walk.
+//
+//-------------------------------------------------------------------------------------------
+class AccessCheckContext
+{
+public:
+ virtual MethodDesc* GetCallerMethod() = 0; // The method that wants access.
+ virtual MethodTable* GetCallerMT() = 0; // The class that wants access; NULL if interop caller.
+ virtual Assembly* GetCallerAssembly() = 0; // Assembly containing that class.
+ virtual bool IsCalledFromInterop() = 0;
+ virtual bool IsCallerCritical() = 0; // Can we do a quick check for caller's transparency status?
+};
+
+class StaticAccessCheckContext : public AccessCheckContext
+{
+public:
+
+ StaticAccessCheckContext(MethodDesc* pCallerMethod, MethodTable* pCallerType, Assembly* pCallerAssembly)
+ : m_pCallerMethod(pCallerMethod),
+ m_pCallerMT(pCallerType),
+ m_pCallerAssembly(pCallerAssembly)
+ {
+ CONTRACTL
+ {
+ LIMITED_METHOD_CONTRACT;
+ PRECONDITION(CheckPointer(pCallerMethod, NULL_OK));
+ PRECONDITION(CheckPointer(pCallerType, NULL_OK));
+ PRECONDITION(CheckPointer(pCallerAssembly));
+ }
+ CONTRACTL_END;
+ }
+
+ StaticAccessCheckContext(MethodDesc* pCallerMethod);
+
+ StaticAccessCheckContext(MethodDesc* pCallerMethod, MethodTable* pCallerType);
+
+ virtual MethodDesc* GetCallerMethod()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_pCallerMethod;
+ }
+
+ virtual MethodTable* GetCallerMT()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_pCallerMT;
+ }
+
+ virtual Assembly* GetCallerAssembly()
+ {
+ WRAPPER_NO_CONTRACT;
+ return m_pCallerAssembly;
+ }
+
+ virtual bool IsCalledFromInterop()
+ {
+ WRAPPER_NO_CONTRACT;
+ return false;
+ }
+
+ virtual bool IsCallerCritical();
+
+private:
+ MethodDesc* m_pCallerMethod;
+ MethodTable* m_pCallerMT;
+ Assembly* m_pCallerAssembly;
+};
+
+//******************************************************************************
+// This type specifies the kind of accessibility checks to perform.
+// On failure, it can be configured to either return FALSE or to throw an exception.
+class AccessCheckOptions
+{
+public:
+ enum AccessCheckType
+ {
+ // Used by statically compiled code.
+ // Desktop: Just do normal accessibility checks. No security demands.
+ // CoreCLR: Just do normal accessibility checks.
+ kNormalAccessibilityChecks,
+
+ // Used only for resource loading and reflection inovcation when the target is remoted.
+ // Desktop: If normal accessiblity checks fail, return TRUE if a demand for MemberAccess succeeds
+ // CoreCLR: If normal accessiblity checks fail, return TRUE if a the caller is Security(Safe)Critical
+ kMemberAccess,
+
+ // Used by Reflection invocation and DynamicMethod with RestrictedSkipVisibility.
+ // Desktop: If normal accessiblity checks fail, return TRUE if a demand for RestrictedMemberAccess
+ // and grant set of the target assembly succeeds.
+ // CoreCLR: If normal accessiblity checks fail, return TRUE if the callee is App transparent code (in a user assembly)
+ kRestrictedMemberAccess,
+
+ // Used by normal DynamicMethods in full trust CoreCLR
+ // CoreCLR: Do normal visibility checks but bypass transparency checks.
+ kNormalAccessNoTransparency,
+
+ // Used by DynamicMethods with restrictedSkipVisibility in full trust CoreCLR
+ // CoreCLR: Do RestrictedMemberAcess visibility checks but bypass transparency checks.
+ kRestrictedMemberAccessNoTransparency,
+
+#ifndef FEATURE_CORECLR
+ // Used by DynamicMethod with kRestrictedMemberAccess in Win8 immersive mode.
+ // Desktop: Equals kNormalAccessibilityChecks for non-framework code calling framework code,
+ // kRestrictedMemberAccess otherwise.
+ kUserCodeOnlyRestrictedMemberAccess,
+
+ // A variation of kUserCodeOnlyRestrictedMemberAccess, but without transparency checks.
+ // This is used for reflection invocation in Win8 immersive when all domains on the call stack is full trust.
+ // This is an optimization to avoid stackwalks for transparency checks in full trust.
+ // Note that both kUserCodeOnlyRestrictedMemberAccess and kUserCodeOnlyRestrictedMemberAccessNoTransparency
+ // are needed because we restrict user code from accessing framework internals in Win8 immersive even in full trust.
+ kUserCodeOnlyRestrictedMemberAccessNoTransparency
+#endif
+ };
+
+ AccessCheckOptions(
+ AccessCheckType accessCheckType,
+ DynamicResolver * pAccessContext,
+ BOOL throwIfTargetIsInaccessible,
+ MethodTable * pTargetMT);
+
+ AccessCheckOptions(
+ AccessCheckType accessCheckType,
+ DynamicResolver * pAccessContext,
+ BOOL throwIfTargetIsInaccessible,
+ MethodDesc * pTargetMD);
+
+ AccessCheckOptions(
+ AccessCheckType accessCheckType,
+ DynamicResolver * pAccessContext,
+ BOOL throwIfTargetIsInaccessible,
+ FieldDesc * pTargetFD);
+
+ AccessCheckOptions(
+ const AccessCheckOptions & templateAccessCheckOptions,
+ BOOL throwIfTargetIsInaccessible,
+ BOOL skipCheckForCriticalCode = FALSE);
+
+ // Follow standard rules for doing accessability
+ BOOL DoNormalAccessibilityChecks() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_accessCheckType == kNormalAccessibilityChecks;
+ }
+
+ // Do visibility checks including security demands for reflection access to members
+ BOOL DoReflectionAccessibilityChecks() const
+ {
+ WRAPPER_NO_CONTRACT;
+ return !DoNormalAccessibilityChecks();
+ }
+
+ BOOL Throws() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_fThrowIfTargetIsInaccessible;
+ }
+
+ BOOL DemandMemberAccessOrFail(AccessCheckContext *pContext, MethodTable * pTargetMT, BOOL visibilityCheck) const;
+ BOOL FailOrThrow(AccessCheckContext *pContext) const;
+
+ BOOL TransparencyCheckNeeded() const
+ {
+ LIMITED_METHOD_CONTRACT;
+#ifdef FEATURE_CORECLR
+ return (m_accessCheckType != kNormalAccessNoTransparency && m_accessCheckType != kRestrictedMemberAccessNoTransparency);
+#else //FEATURE_CORECLR
+ return (m_accessCheckType != kUserCodeOnlyRestrictedMemberAccessNoTransparency);
+#endif //FEATURE_CORECLR
+ }
+
+ static AccessCheckOptions* s_pNormalAccessChecks;
+
+ static void Startup();
+
+private:
+ void Initialize(
+ AccessCheckType accessCheckType,
+ BOOL throwIfTargetIsInaccessible,
+ MethodTable * pTargetMT,
+ MethodDesc * pTargetMD,
+ FieldDesc * pTargetFD,
+ BOOL skipCheckForCriticalCode = FALSE);
+
+ BOOL DemandMemberAccess(AccessCheckContext *pContext, MethodTable * pTargetMT, BOOL visibilityCheck) const;
+
+ void ThrowAccessException(
+ AccessCheckContext* pContext,
+ MethodTable* pFailureMT = NULL,
+ Exception* pInnerException = NULL,
+ BOOL fAccessingFrameworkCode = FALSE) const;
+
+ MethodTable * m_pTargetMT;
+ MethodDesc * m_pTargetMethod;
+ FieldDesc * m_pTargetField;
+
+ AccessCheckType m_accessCheckType;
+ // The context used to determine if access is allowed. It is the resolver that carries the compressed-stack used to do the Demand.
+ // If this is NULL, the access is checked against the current call-stack.
+ // This is non-NULL only for m_accessCheckType==kRestrictedMemberAccess
+ DynamicResolver * m_pAccessContext;
+ // If the target is not accessible, should the API return FALSE, or should it throw an exception?
+ BOOL m_fThrowIfTargetIsInaccessible;
+ // flag to enable legacy behavior in ClassLoader::CanAccessMemberForExtraChecks.
+ BOOL m_fSkipCheckForCriticalCode;
+};
+
+void DECLSPEC_NORETURN ThrowFieldAccessException(MethodDesc *pCallerMD,
+ FieldDesc *pFD,
+ BOOL isTransparencyError,
+ UINT messageID = 0,
+ Exception *pInnerException = NULL,
+ BOOL fAccessingFrameworkCode = FALSE);
+
+void DECLSPEC_NORETURN ThrowMethodAccessException(MethodDesc *pCallerMD,
+ MethodDesc *pCalleeMD,
+ BOOL isTransparencyError,
+ UINT messageID = 0,
+ Exception *pInnerException = NULL,
+ BOOL fAccessingFrameworkCode = FALSE);
+
+void DECLSPEC_NORETURN ThrowTypeAccessException(MethodDesc *pCallerMD,
+ MethodTable *pMT,
+ BOOL isTransparencyError,
+ UINT messageID = 0,
+ Exception *pInnerException = NULL,
+ BOOL fAccessingFrameworkCode = FALSE);
+
+void DECLSPEC_NORETURN ThrowFieldAccessException(AccessCheckContext* pContext,
+ FieldDesc *pFD,
+ UINT messageID = 0,
+ Exception *pInnerException = NULL,
+ BOOL fAccessingFrameworkCode = FALSE);
+
+void DECLSPEC_NORETURN ThrowMethodAccessException(AccessCheckContext* pContext,
+ MethodDesc *pCalleeMD,
+ UINT messageID = 0,
+ Exception *pInnerException = NULL,
+ BOOL fAccessingFrameworkCode = FALSE);
+
+void DECLSPEC_NORETURN ThrowTypeAccessException(AccessCheckContext* pContext,
+ MethodTable *pMT,
+ UINT messageID = 0,
+ Exception *pInnerException = NULL,
+ BOOL fAccessingFrameworkCode = FALSE);
+
+
+//---------------------------------------------------------------------------------------
+//
+class ClassLoader
+{
+ friend class PendingTypeLoadEntry;
+ friend class MethodTableBuilder;
+ friend class AppDomain;
+ friend class Assembly;
+ friend class Module;
+ friend class CLRPrivTypeCacheWinRT;
+ friend class CLRPrivTypeCacheReflectionOnlyWinRT;
+
+ // the following two classes are friends because they will call LoadTypeHandleForTypeKey by token directly
+ friend class COMDynamicWrite;
+ friend class COMModule;
+
+private:
+ // Classes for which load is in progress
+ PendingTypeLoadTable * m_pUnresolvedClassHash;
+ CrstExplicitInit m_UnresolvedClassLock;
+
+ // Protects addition of elements to module's m_pAvailableClasses.
+ // (indeed thus protects addition of elements to any m_pAvailableClasses in any
+ // of the modules managed by this loader)
+ CrstExplicitInit m_AvailableClassLock;
+
+ CrstExplicitInit m_AvailableTypesLock;
+
+ // Do we have any modules which need to have their classes added to
+ // the available list?
+ Volatile<LONG> m_cUnhashedModules;
+
+ // Back reference to the assembly
+ PTR_Assembly m_pAssembly;
+
+public:
+
+#ifdef _DEBUG
+ DWORD m_dwDebugMethods;
+ DWORD m_dwDebugFieldDescs; // Doesn't include anything we don't allocate a FieldDesc for
+ DWORD m_dwDebugClasses;
+ DWORD m_dwDebugDuplicateInterfaceSlots;
+ DWORD m_dwGCSize;
+ DWORD m_dwInterfaceMapSize;
+ DWORD m_dwMethodTableSize;
+ DWORD m_dwVtableData;
+ DWORD m_dwStaticFieldData;
+ DWORD m_dwFieldDescData;
+ DWORD m_dwMethodDescData;
+ size_t m_dwEEClassData;
+#endif
+
+public:
+ ClassLoader(Assembly *pAssembly);
+ ~ClassLoader();
+
+private:
+
+ VOID PopulateAvailableClassHashTable(Module *pModule,
+ AllocMemTracker *pamTracker);
+
+ void LazyPopulateCaseSensitiveHashTables();
+ void LazyPopulateCaseInsensitiveHashTables();
+
+ // Lookup the hash table entry from the hash table
+ void GetClassValue(NameHandleTable nhTable,
+ NameHandle *pName,
+ HashDatum *pData,
+ EEClassHashTable **ppTable,
+ Module* pLookInThisModuleOnly,
+ HashedTypeEntry* pFoundEntry,
+ Loader::LoadFlag loadFlag,
+ BOOL& needsToBuildHashtable);
+
+
+public:
+ //#LoaderModule
+ // LoaderModule determines in which module an item gets placed.
+ // For everything except paramaterized types and methods the choice is easy.
+ //
+ // If NGEN'ing we may choose to place the item into the current module (which is different from runtime behavior).
+ //
+ // The rule for determining the loader module must ensure that a type or method never outlives its loader module
+ // with respect to app-domain unloading
+ static Module * ComputeLoaderModule(MethodTable * pMT,
+ mdToken token, // the token of the method
+ Instantiation methodInst); // the type arguments to the method (if any)
+ static Module * ComputeLoaderModule(TypeKey * typeKey);
+ inline static PTR_Module ComputeLoaderModuleForFunctionPointer(TypeHandle * pRetAndArgTypes, DWORD NumArgsPlusRetType);
+ inline static PTR_Module ComputeLoaderModuleForParamType(TypeHandle paramType);
+
+private:
+ static PTR_Module ComputeLoaderModuleWorker(Module *pDefinitionModule, // the module that declares the generic type or method
+ mdToken token,
+ Instantiation classInst, // the type arguments to the type (if any)
+ Instantiation methodInst); // the type arguments to the method (if any)
+
+ BOOL FindClassModuleThrowing(
+ const NameHandle * pName,
+ TypeHandle * pType,
+ mdToken * pmdClassToken,
+ Module ** ppModule,
+ mdToken * pmdFoundExportedType,
+ HashedTypeEntry * pEntry,
+ Module * pLookInThisModuleOnly,
+ Loader::LoadFlag loadFlag);
+
+ static PTR_Module ComputeLoaderModuleForCompilation(Module *pDefinitionModule, // the module that declares the generic type or method
+ mdToken token,
+ Instantiation classInst, // the type arguments to the type (if any)
+ Instantiation methodInst); // the type arguments to the method (if any)
+
+public:
+ void Init(AllocMemTracker *pamTracker);
+
+ PTR_Assembly GetAssembly();
+ DomainAssembly* GetDomainAssembly(AppDomain *pDomain = NULL);
+
+ void FreeModules();
+
+#ifdef DACCESS_COMPILE
+ void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
+#endif
+
+ //==================================================================================
+ // Main entry points to class loader
+ // Organized as follows:
+ // by token:
+ // TypeDef
+ // TypeDefOrRef
+ // TypeDefOrRefOrSpec
+ // by constructed type:
+ // ArrayType
+ // PointerOrByrefType
+ // FnPtrType
+ // GenericInstantiation
+ // by name:
+ // ByName
+ // Each takes a parameter comes, with the following semantics:
+ // fLoadTypes=DontLoadTypes: if type isn't already in the loader's table, return NULL
+ // fLoadTypes=LoadTypes: if type isn't already in the loader's table, then create it
+ // Each comes in two variants, LoadXThrowing and LoadXNoThrow, the latter being just
+ // a exception-handling wrapper around the former.
+ //
+ // Each also allows types to be loaded only up to a particular level (see classloadlevel.h).
+ // The class loader itself makes use of these levels to "break" recursion across
+ // generic instantiations. External clients should leave the parameter at its default
+ // value (CLASS_LOADED).
+ //==================================================================================
+
+public:
+
+ // We use enums for these flags so that we can easily search the codebase to
+ // determine where the flags are set to their non-default values.
+ //
+ // This enum tells us what to do if the load fails. If ThrowIfNotFound is used
+ // with a HRESULT-returning NOTHROW function then it actually indicates that
+ // an error-HRESULT will be returned.
+ // The ThrowButNullV11McppWorkaround value means ThrowIfNotFound, except when the case
+ // of a Nil ResolutionScope for a value type (erroneously generated by Everett MCPP
+ // compiler.)
+ typedef enum { ThrowIfNotFound, ReturnNullIfNotFound, ThrowButNullV11McppWorkaround } NotFoundAction;
+
+ // This flag indicates whether we should accept an uninstantiatednaked TypeDef or TypeRef
+ // for a generic type definition, where "uninstantiated" means "not used as part of
+ // a TypeSpec"
+ typedef enum { FailIfUninstDefOrRef, PermitUninstDefOrRef } PermitUninstantiatedFlag;
+
+ // This flag indicates whether we want to "load" the type if it isn't already in the
+ // loader's tables and has reached the load level desired.
+ typedef enum { LoadTypes, DontLoadTypes } LoadTypesFlag;
+
+
+ // Load types by token (Def, Ref and Spec)
+ static TypeHandle LoadTypeDefThrowing(Module *pModule,
+ mdToken typeDef,
+ NotFoundAction fNotFound = ThrowIfNotFound,
+ PermitUninstantiatedFlag fUninstantiated = FailIfUninstDefOrRef,
+ mdToken tokenNotToLoad = tdNoTypes,
+ ClassLoadLevel level = CLASS_LOADED,
+ Instantiation * pTargetInstantiation = NULL /* used to verify arity of the loaded type */);
+
+ static TypeHandle LoadTypeDefOrRefThrowing(Module *pModule,
+ mdToken typeRefOrDef,
+ NotFoundAction fNotFound = ThrowIfNotFound,
+ PermitUninstantiatedFlag fUninstantiated = FailIfUninstDefOrRef,
+ mdToken tokenNotToLoad = tdNoTypes,
+ ClassLoadLevel level = CLASS_LOADED);
+
+ static TypeHandle LoadTypeDefOrRefOrSpecThrowing(Module *pModule,
+ mdToken typeRefOrDefOrSpec,
+ const SigTypeContext *pTypeContext,
+ NotFoundAction fNotFound = ThrowIfNotFound,
+ PermitUninstantiatedFlag fUninstantiated = FailIfUninstDefOrRef,
+ LoadTypesFlag fLoadTypes = LoadTypes,
+ ClassLoadLevel level = CLASS_LOADED,
+ BOOL dropGenericArgumentLevel = FALSE,
+ const Substitution *pSubst = NULL /* substitution to apply if the token is a type spec with generic variables */ );
+
+ // Load constructed types by providing their constituents
+ static TypeHandle LoadPointerOrByrefTypeThrowing(CorElementType typ,
+ TypeHandle baseType,
+ LoadTypesFlag fLoadTypes = LoadTypes,
+ ClassLoadLevel level = CLASS_LOADED);
+
+ // The resulting type behaves like the unmanaged view of a given value type.
+ static TypeHandle LoadNativeValueTypeThrowing(TypeHandle baseType,
+ LoadTypesFlag fLoadTypes = LoadTypes,
+ ClassLoadLevel level = CLASS_LOADED);
+
+ static TypeHandle LoadArrayTypeThrowing(TypeHandle baseType,
+ CorElementType typ = ELEMENT_TYPE_SZARRAY,
+ unsigned rank = 0,
+ LoadTypesFlag fLoadTypes = LoadTypes,
+ ClassLoadLevel level = CLASS_LOADED);
+
+ static TypeHandle LoadFnptrTypeThrowing(BYTE callConv,
+ DWORD numArgs,
+ TypeHandle* retAndArgTypes,
+ LoadTypesFlag fLoadTypes = LoadTypes,
+ ClassLoadLevel level = CLASS_LOADED);
+
+ // Load types by name
+ static TypeHandle LoadTypeByNameThrowing(Assembly *pAssembly,
+ LPCUTF8 nameSpace,
+ LPCUTF8 name,
+ NotFoundAction fNotFound = ThrowIfNotFound,
+ LoadTypesFlag fLoadTypes = LoadTypes,
+ ClassLoadLevel level = CLASS_LOADED);
+
+ // Resolve a TypeRef to a TypeDef
+ // (Just a no-op on TypeDefs)
+ // Return FALSE if operation failed (e.g. type does not exist)
+ // *pfUsesTypeForwarder is set to TRUE if a type forwarder is found. It is never set to FALSE.
+ static BOOL ResolveTokenToTypeDefThrowing(Module * pTypeRefModule,
+ mdTypeRef typeRefToken,
+ Module ** ppTypeDefModule,
+ mdTypeDef * pTypeDefToken,
+ Loader::LoadFlag loadFlag = Loader::Load,
+ BOOL * pfUsesTypeForwarder = NULL);
+
+ // Resolve a name to a TypeDef
+ // Return FALSE if operation failed (e.g. type does not exist)
+ // *pfUsesTypeForwarder is set to TRUE if a type forwarder is found. It is never set to FALSE.
+ static BOOL ResolveNameToTypeDefThrowing(Module * pTypeRefModule,
+ NameHandle * pName,
+ Module ** ppTypeDefModule,
+ mdTypeDef * pTypeDefToken,
+ Loader::LoadFlag loadFlag = Loader::Load,
+ BOOL * pfUsesTypeForwarder = NULL);
+
+ static void EnsureLoaded(TypeHandle typeHnd, ClassLoadLevel level = CLASS_LOADED);
+ static void TryEnsureLoaded(TypeHandle typeHnd, ClassLoadLevel level = CLASS_LOADED);
+
+public:
+ // Look up a class by name
+ //
+ // Guaranteed to only return NULL if pName->OKToLoad() returns FALSE.
+ // Thus when type loads are enabled this will return non-null.
+ TypeHandle LoadTypeHandleThrowIfFailed(NameHandle* pName, ClassLoadLevel level = CLASS_LOADED,
+ Module* pLookInThisModuleOnly=NULL);
+
+public:
+ // Looks up class in the local module table, if it is there it succeeds,
+ // Otherwise it fails, This is meant only for optimizations etc
+ static TypeHandle LookupTypeDefOrRefInModule(Module *pModule, mdToken cl, ClassLoadLevel *pLoadLevel = NULL);
+
+private:
+
+ VOID AddAvailableClassDontHaveLock(Module *pModule,
+ mdTypeDef classdef,
+ AllocMemTracker *pamTracker);
+
+ VOID AddAvailableClassHaveLock(Module * pModule,
+ mdTypeDef classdef,
+ AllocMemTracker * pamTracker,
+ LPCSTR szWinRtNamespacePrefix,
+ DWORD cchWinRtNamespacePrefix);
+
+ VOID AddExportedTypeDontHaveLock(Module *pManifestModule,
+ mdExportedType cl,
+ AllocMemTracker *pamTracker);
+
+ VOID AddExportedTypeHaveLock(Module *pManifestModule,
+ mdExportedType cl,
+ AllocMemTracker *pamTracker);
+
+public:
+
+ // For an generic type instance return the representative within the class of
+ // all type handles that share code. For example,
+ // <int> --> <int>,
+ // <object> --> <__Canon>,
+ // <string> --> <__Canon>,
+ // <List<string>> --> <__Canon>,
+ // <Struct<string>> --> <Struct<__Canon>>
+ //
+ // If the code for the type handle is not shared then return
+ // the type handle itself.
+ static TypeHandle CanonicalizeGenericArg(TypeHandle genericArg);
+
+ // Determine if the specified type representation induces a sharable
+ // set of compatible instantiations when used as a type parameter to
+ // a generic type or method.
+ //
+ // For example, when sharing at reference types "object" and "Struct<object>"
+ // both induce sets of compatible instantiations, e.g. when used to build types
+ // "List<object>" and "List<Struct<object>>" respectively.
+ static BOOL IsSharableInstantiation(Instantiation inst);
+
+ // Determine if it is normalized canonical generic instantiation.
+ // Dictionary<__Canon, __Canon> -> TRUE
+ // Dictionary<__Canon, int> -> TRUE
+ // Dictionary<__Canon, String> -> FALSE
+ static BOOL IsCanonicalGenericInstantiation(Instantiation inst);
+
+ // Determine if it is the entirely-canonical generic instantiation
+ // Dictionary<__Canon, __Canon> -> TRUE
+ // Dictionary<anything else> -> FALSE
+ static BOOL IsTypicalSharedInstantiation(Instantiation inst);
+
+ // Return TRUE if inst is the typical instantiation for the type or method specified by pModule/token
+ static BOOL IsTypicalInstantiation(Module *pModule, mdToken token, Instantiation inst);
+
+ // Load canonical shared instantiation for type key (each instantiation argument is
+ // substituted by CanonicalizeGenericArg)
+ static TypeHandle LoadCanonicalGenericInstantiation(TypeKey *pTypeKey,
+ LoadTypesFlag fLoadTypes/*=LoadTypes*/,
+ ClassLoadLevel level/*=CLASS_LOADED*/);
+
+ // Create a generic instantiation.
+ // If typeDef is not a generic type then throw an exception
+ // If its arity does not match nGenericClassArgCount then throw an exception
+ // The pointer to the instantiation is not persisted e.g. the type parameters can be stack-allocated.
+ // If inst=NULL then <__Canon,...,__Canon> is assumed
+ // If fLoadTypes=DontLoadTypes then the type handle is not created if it is not
+ // already present in the tables.
+ static TypeHandle LoadGenericInstantiationThrowing(Module *pModule,
+ mdTypeDef typeDef,
+ Instantiation inst,
+ LoadTypesFlag fLoadTypes = LoadTypes,
+ ClassLoadLevel level = CLASS_LOADED,
+ const InstantiationContext *pInstContext = NULL,
+ BOOL fFromNativeImage = FALSE);
+
+// Public access Check APIs
+public:
+
+ static BOOL CanAccessClass(
+ AccessCheckContext* pContext,
+ MethodTable* pTargetClass,
+ Assembly* pTargetAssembly,
+ const AccessCheckOptions & accessCheckOptions = *AccessCheckOptions::s_pNormalAccessChecks,
+ BOOL checkTargetTypeTransparency = TRUE);
+
+ static BOOL CanAccess(
+ AccessCheckContext* pContext,
+ MethodTable* pTargetClass,
+ Assembly* pTargetAssembly,
+ DWORD dwMemberAttrs,
+ MethodDesc* pOptionalTargetMethod,
+ FieldDesc* pOptionalTargetField,
+ const AccessCheckOptions & accessCheckOptions = *AccessCheckOptions::s_pNormalAccessChecks,
+ BOOL checkTargetMethodTransparency = TRUE,
+ BOOL checkTargetTypeTransparency = TRUE);
+
+ static BOOL CanAccessClassForExtraChecks(
+ AccessCheckContext* pContext,
+ MethodTable* pTargetClass,
+ Assembly* pTargetAssembly,
+ const AccessCheckOptions & accessCheckOptions,
+ BOOL checkTargetTypeTransparency);
+
+ static BOOL CanAccessFamilyVerification(
+ TypeHandle thCurrentClass,
+ TypeHandle thInstanceClass);
+
+private:
+ // Access check helpers
+ static BOOL CanAccessMethodInstantiation(
+ AccessCheckContext* pContext,
+ MethodDesc* pOptionalTargetMethod,
+ const AccessCheckOptions & accessCheckOptions);
+
+ static BOOL CanAccessMemberForExtraChecks(
+ AccessCheckContext* pContext,
+ MethodTable* pTargetExactMT,
+ MethodDesc* pOptionalTargetMethod,
+ FieldDesc* pOptionalTargetField,
+ const AccessCheckOptions & accessCheckOptions,
+ BOOL checkTargetMethodTransparency);
+
+ static BOOL CanAccessSigForExtraChecks(
+ AccessCheckContext* pContext,
+ MethodDesc* pTargetMethodSig,
+ MethodTable* pTargetExactMT,
+ const AccessCheckOptions & accessCheckOptions,
+ BOOL checkTargetTransparency);
+
+ static BOOL CanAccessFamily(
+ MethodTable* pCurrentClass,
+ MethodTable* pTargetClass);
+
+ static BOOL CheckAccessMember(
+ AccessCheckContext* pContext,
+ MethodTable* pTargetClass,
+ Assembly* pTargetAssembly,
+ DWORD dwMemberAttrs,
+ MethodDesc* pOptionalTargetMethod,
+ FieldDesc* pOptionalTargetField,
+ const AccessCheckOptions & accessCheckOptions = *AccessCheckOptions::s_pNormalAccessChecks,
+ BOOL checkTargetMethodTransparency = TRUE,
+ BOOL checkTargetTypeTransparency = TRUE);
+
+
+public:
+ //Creates a key with both the namespace and name converted to lowercase and
+ //made into a proper namespace-path.
+ VOID CreateCanonicallyCasedKey(LPCUTF8 pszNameSpace, LPCUTF8 pszName,
+ __out LPUTF8 *ppszOutNameSpace, __out LPUTF8 *ppszOutName);
+
+ static HRESULT FindTypeDefByExportedType(IMDInternalImport *pCTImport,
+ mdExportedType mdCurrent,
+ IMDInternalImport *pTDImport,
+ mdTypeDef *mtd);
+
+ class AvailableClasses_LockHolder : public CrstHolder
+ {
+ public:
+ AvailableClasses_LockHolder(ClassLoader *classLoader)
+ : CrstHolder(&classLoader->m_AvailableClassLock)
+ {
+ WRAPPER_NO_CONTRACT;
+ }
+ };
+
+ friend class AvailableClasses_LockHolder;
+
+private:
+ static TypeHandle LoadConstructedTypeThrowing(TypeKey *pKey,
+ LoadTypesFlag fLoadTypes = LoadTypes,
+ ClassLoadLevel level = CLASS_LOADED,
+ const InstantiationContext *pInstContext = NULL);
+
+ static TypeHandle LookupTypeKeyUnderLock(TypeKey *pKey,
+ EETypeHashTable *pTable,
+ CrstBase *pLock);
+
+ static TypeHandle LookupTypeKey(TypeKey *pKey,
+ EETypeHashTable *pTable,
+ CrstBase *pLock,
+ BOOL fCheckUnderLock);
+
+ static TypeHandle LookupInLoaderModule(TypeKey* pKey, BOOL fCheckUnderLock);
+#ifdef FEATURE_PREJIT
+ static TypeHandle LookupInPreferredZapModule(TypeKey* pKey, BOOL fCheckUnderLock);
+#endif // FEATURE_PREJIT
+
+ // Lookup a handle in the appropriate table
+ // (declaring module for TypeDef or loader-module for constructed types)
+ static TypeHandle LookupTypeHandleForTypeKey(TypeKey *pTypeKey);
+ static TypeHandle LookupTypeHandleForTypeKeyInner(TypeKey *pTypeKey, BOOL fCheckUnderLock);
+
+ static void DECLSPEC_NORETURN ThrowTypeLoadException(TypeKey *pKey, UINT resIDWhy);
+
+
+ BOOL IsNested(NameHandle* pName, mdToken *mdEncloser);
+ static BOOL IsNested(Module *pModude, mdToken typeDefOrRef, mdToken *mdEncloser);
+
+public:
+ // Helpers for FindClassModule()
+ BOOL CompareNestedEntryWithTypeDef(IMDInternalImport *pImport,
+ mdTypeDef mdCurrent,
+ EEClassHashTable *pClassHash,
+ PTR_EEClassHashEntry pEntry);
+ BOOL CompareNestedEntryWithTypeRef(IMDInternalImport *pImport,
+ mdTypeRef mdCurrent,
+ EEClassHashTable *pClassHash,
+ PTR_EEClassHashEntry pEntry);
+ BOOL CompareNestedEntryWithExportedType(IMDInternalImport *pImport,
+ mdExportedType mdCurrent,
+ EEClassHashTable *pClassHash,
+ PTR_EEClassHashEntry pEntry);
+
+ //Attempts to find/load/create a type handle but does not throw
+ // if used in "find" mode.
+ TypeHandle LoadTypeHandleThrowing(NameHandle* pName, ClassLoadLevel level = CLASS_LOADED,
+ Module* pLookInThisModuleOnly=NULL);
+
+private:
+
+#ifndef DACCESS_COMPILE
+ // Perform a single phase of class loading
+ // If no type handle has yet been created, typeHnd is null.
+ static TypeHandle DoIncrementalLoad(TypeKey *pTypeKey,
+ TypeHandle typeHnd,
+ ClassLoadLevel workLevel);
+
+ // Phase CLASS_LOAD_CREATE of class loading
+ static TypeHandle CreateTypeHandleForTypeKey(TypeKey *pTypeKey,
+ AllocMemTracker *pamTracker);
+
+ // Publish the type in the loader's tables
+ static TypeHandle PublishType(TypeKey *pTypeKey, TypeHandle typeHnd);
+
+ // Notify profiler and debugger that a type load has completed
+ // Also update perf counters
+ static void Notify(TypeHandle typeHnd);
+
+ // Phase CLASS_LOAD_EXACTPARENTS of class loading
+ // Load exact parents and interfaces and dependent structures (generics dictionary, vtable fixes)
+ static void LoadExactParents(MethodTable *pMT);
+
+ static void LoadExactParentAndInterfacesTransitively(MethodTable *pMT);
+
+
+ static TypeHandle TryFindDynLinkZapType(TypeKey* pKey);
+
+ // Create a non-canonical instantiation of a generic type based off the canonical instantiation
+ // (For example, MethodTable for List<string> is based on the MethodTable for List<__Canon>)
+ static TypeHandle CreateTypeHandleForNonCanonicalGenericInstantiation(TypeKey *pTypeKey,
+ AllocMemTracker *pamTracker);
+
+ // Loads a class. This is the inner call from the multi-threaded load. This load must
+ // be protected in some manner.
+ // If we're attempting to load a fresh instantiated type then genericArgs should be filled in
+
+ static TypeHandle CreateTypeHandleForTypeDefThrowing(Module *pModule,
+ mdTypeDef cl,
+ Instantiation inst,
+ AllocMemTracker *pamTracker);
+
+ // The token must be a type def. GC must be enabled.
+ // If we're attempting to load a fresh instantiated type then genericArgs should be filled in
+ TypeHandle LoadTypeHandleForTypeKey(TypeKey *pTypeKey,
+ TypeHandle typeHnd,
+ ClassLoadLevel level = CLASS_LOADED,
+ const InstantiationContext *pInstContext = NULL);
+
+ TypeHandle LoadTypeHandleForTypeKeyNoLock(TypeKey *pTypeKey,
+ ClassLoadLevel level = CLASS_LOADED,
+ const InstantiationContext *pInstContext = NULL);
+
+ // Used for initial loading of parent class and implemented interfaces
+ // When tok represents an instantiated type return an *approximate* instantiated
+ // type (where reference type arguments are replaced by Object)
+ static
+ TypeHandle
+ LoadApproxTypeThrowing(
+ Module * pModule,
+ mdToken tok,
+ SigPointer * pSigInst,
+ const SigTypeContext * pClassTypeContext);
+
+ // Returns the parent of a token. The token must be a typedef.
+ // If the parent is a shared constructed type (e.g. class C : List<string>) then
+ // only the canonical instantiation is loaded at this point.
+ // This is to avoid cycles in the loader e.g. on class C : D<C> or class C<T> : D<C<T>>
+ // We fix up the exact parent later in LoadInstantiatedInfo.
+ static
+ MethodTable *
+ LoadApproxParentThrowing(
+ Module * pModule,
+ mdToken cl,
+ SigPointer * pParentInst,
+ const SigTypeContext * pClassTypeContext);
+
+ // Locates the enclosing class of a token if any. The token must be a typedef.
+ static VOID GetEnclosingClassThrowing(IMDInternalImport *pInternalImport,
+ Module *pModule,
+ mdTypeDef cl,
+ mdTypeDef *tdEnclosing);
+
+ // Insert the class in the classes hash table and if needed in the case insensitive one
+ EEClassHashEntry_t *InsertValue(EEClassHashTable *pClassHash,
+ EEClassHashTable *pClassCaseInsHash,
+ LPCUTF8 pszNamespace,
+ LPCUTF8 pszClassName,
+ HashDatum Data,
+ EEClassHashEntry_t *pEncloser,
+ AllocMemTracker *pamTracker);
+
+ // don't call this directly.
+ TypeHandle LoadTypeHandleForTypeKey_Body(TypeKey *pTypeKey,
+ TypeHandle typeHnd,
+ ClassLoadLevel targetLevel);
+#endif //!DACCESS_COMPILE
+
+}; // class ClassLoader
+
+#endif /* _H_CLSLOAD */