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.
5 /*============================================================
7 ** Header: AssemblySpec.hpp
9 ** Purpose: Implements classes used to bind to assemblies
15 ===========================================================*/
16 #ifndef _ASSEMBLYSPEC_H
17 #define _ASSEMBLYSPEC_H
19 #include "memorypool.h"
20 #include "assemblyspecbase.h"
21 #include "domainfile.h"
22 #include "genericstackprobe.h"
30 class AssemblySpec : public BaseAssemblySpec
34 friend class AppDomain;
35 friend class AssemblyNameNative;
37 AppDomain *m_pAppDomain;
38 SBuffer m_HashForControl;
40 DomainAssembly *m_pParentAssembly;
42 // Contains the reference to the fallback load context associated with RefEmitted assembly requesting the load of another assembly (static or dynamic)
43 ICLRPrivBinder *m_pFallbackLoadContextBinder;
45 // Flag to indicate if we should prefer the fallback load context binder for binding or not.
46 bool m_fPreferFallbackLoadContextBinder;
48 BOOL IsValidAssemblyName();
50 HRESULT InitializeSpecInternal(mdToken kAssemblyRefOrDef,
51 IMDInternalImport *pImport,
52 DomainAssembly *pStaticParent,
53 BOOL fIntrospectionOnly,
54 BOOL fAllowAllocation);
56 // InitializeSpecInternal should be used very carefully so it's made private.
57 // functions that take special care (and thus are allowed to use the function) are listed below
58 friend Assembly * Module::GetAssemblyIfLoaded(
59 mdAssemblyRef kAssemblyRef,
60 LPCSTR szWinRtNamespace,
61 LPCSTR szWinRtClassName,
62 IMDInternalImport * pMDImportOverride,
63 BOOL fDoNotUtilizeExtraChecks,
64 ICLRPrivBinder *pBindingContextForLoadedAssembly);
68 #ifndef DACCESS_COMPILE
69 AssemblySpec() : m_pAppDomain(::GetAppDomain())
71 LIMITED_METHOD_CONTRACT;
72 m_pParentAssembly = NULL;
74 m_pFallbackLoadContextBinder = NULL;
75 m_fPreferFallbackLoadContextBinder = false;
78 #endif //!DACCESS_COMPILE
80 AssemblySpec(AppDomain *pAppDomain) : m_pAppDomain(pAppDomain)
82 LIMITED_METHOD_CONTRACT
83 m_pParentAssembly = NULL;
85 m_pFallbackLoadContextBinder = NULL;
86 m_fPreferFallbackLoadContextBinder = false;
91 DomainAssembly* GetParentAssembly();
93 ICLRPrivBinder* GetBindingContextFromParentAssembly(AppDomain *pDomain);
95 bool HasParentAssembly()
96 { WRAPPER_NO_CONTRACT; return GetParentAssembly() != NULL; }
98 void InitializeSpec(mdToken kAssemblyRefOrDef,
99 IMDInternalImport *pImport,
100 DomainAssembly *pStaticParent = NULL,
101 BOOL fIntrospectionOnly = FALSE)
111 HRESULT hr=InitializeSpecInternal(kAssemblyRefOrDef, pImport,pStaticParent,fIntrospectionOnly,TRUE);
113 EEFileLoadException::Throw(this,hr);
117 void InitializeSpec(PEAssembly *pFile);
118 HRESULT InitializeSpec(StackingAllocator* alloc,
119 ASSEMBLYNAMEREF* pName,
121 BOOL fIntrospectionOnly = FALSE);
123 void AssemblyNameInit(ASSEMBLYNAMEREF* pName, PEImage* pImageInfo); //[in,out], [in]
126 void SetCodeBase(LPCWSTR szCodeBase)
129 BaseAssemblySpec::SetCodeBase(szCodeBase);
131 void SetCodeBase(StackingAllocator* alloc, STRINGREF *pCodeBase);
133 void SetParentAssembly(DomainAssembly *pAssembly)
144 m_pParentAssembly = pAssembly;
147 void SetFallbackLoadContextBinderForRequestingAssembly(ICLRPrivBinder *pFallbackLoadContextBinder)
149 LIMITED_METHOD_CONTRACT;
151 m_pFallbackLoadContextBinder = pFallbackLoadContextBinder;
154 ICLRPrivBinder* GetFallbackLoadContextBinderForRequestingAssembly()
156 LIMITED_METHOD_CONTRACT;
158 return m_pFallbackLoadContextBinder;
161 void SetPreferFallbackLoadContextBinder()
163 LIMITED_METHOD_CONTRACT;
165 m_fPreferFallbackLoadContextBinder = true;
168 bool GetPreferFallbackLoadContextBinder()
170 LIMITED_METHOD_CONTRACT;
172 return m_fPreferFallbackLoadContextBinder;
175 // Note that this method does not clone the fields!
176 void CopyFrom(AssemblySpec* pSource)
186 BaseAssemblySpec::CopyFrom(pSource);
188 SetIntrospectionOnly(pSource->IsIntrospectionOnly());
189 SetParentAssembly(pSource->GetParentAssembly());
191 // Copy the details of the fallback load context binder
192 SetFallbackLoadContextBinderForRequestingAssembly(pSource->GetFallbackLoadContextBinderForRequestingAssembly());
193 m_fPreferFallbackLoadContextBinder = pSource->GetPreferFallbackLoadContextBinder();
195 m_HashForControl = pSource->m_HashForControl;
196 m_dwHashAlg = pSource->m_dwHashAlg;
200 HRESULT CheckFriendAssemblyName();
203 HRESULT EmitToken(IMetaDataAssemblyEmit *pEmit,
204 mdAssemblyRef *pToken,
205 BOOL fUsePublicKeyToken = TRUE,
206 BOOL fMustBeBindable = FALSE /*(used only by FusionBind's implementation)*/);
208 // Make sure this matches in the managed Assembly.DemandPermission()
210 FILE_PATHDISCOVERY = 0x0,
212 FILE_READANDPATHDISC = 0x2,
219 AppDomain* pAppDomain,
220 BOOL fThrowOnFileNotFound,
221 CoreBindResult* pBindResult,
222 BOOL fNgenExplicitBind = FALSE,
223 BOOL fExplicitBindToNativeImage = FALSE,
224 StackCrawlMark *pCallerStackMark = NULL );
226 Assembly *LoadAssembly(FileLoadLevel targetLevel,
227 BOOL fThrowOnFileNotFound = TRUE,
228 BOOL fRaisePrebindEvents = TRUE,
229 StackCrawlMark *pCallerStackMark = NULL);
230 DomainAssembly *LoadDomainAssembly(FileLoadLevel targetLevel,
231 BOOL fThrowOnFileNotFound = TRUE,
232 BOOL fRaisePrebindEvents = TRUE,
233 StackCrawlMark *pCallerStackMark = NULL);
235 //****************************************************************************************
237 // Creates and loads an assembly based on the name and context.
238 static Assembly *LoadAssembly(LPCSTR pSimpleName,
239 AssemblyMetaDataInternal* pContext,
240 const BYTE * pbPublicKeyOrToken,
241 DWORD cbPublicKeyOrToken,
245 // Load an assembly based on an explicit path
246 static Assembly *LoadAssembly(LPCWSTR pFilePath);
250 void MatchRetargetedPublicKeys(Assembly *pAssembly);
252 void MatchPublicKeys(Assembly *pAssembly);
253 PEAssembly *ResolveAssemblyFile(AppDomain *pAppDomain, BOOL fPreBind);
255 AppDomain *GetAppDomain()
257 LIMITED_METHOD_CONTRACT;
261 HRESULT SetHashForControl(PBYTE pHashForControl, DWORD dwHashForControl, DWORD dwHashAlg)
267 PRECONDITION(CheckPointer(pHashForControl));
271 m_HashForControl.Set(pHashForControl, dwHashForControl);
272 m_dwHashAlg=dwHashAlg;
276 void ParseEncodedName();
278 void SetWindowsRuntimeType(LPCUTF8 szNamespace, LPCUTF8 szClassName);
279 void SetWindowsRuntimeType(SString const & _ssTypeName);
281 inline HRESULT SetContentType(AssemblyContentType type)
283 LIMITED_METHOD_CONTRACT;
284 if (type == AssemblyContentType_Default)
286 m_dwFlags = (m_dwFlags & ~afContentType_Mask) | afContentType_Default;
289 else if (type == AssemblyContentType_WindowsRuntime)
291 m_dwFlags = (m_dwFlags & ~afContentType_Mask) | afContentType_WindowsRuntime;
296 _ASSERTE(!"Unexpected content type.");
301 // Returns true if the object can be used to bind to the target assembly.
302 // One case in which this is not true is when the content type is WinRT
303 // but no type name has been set.
304 inline bool HasBindableIdentity() const
306 STATIC_CONTRACT_LIMITED_METHOD;
307 #ifdef FEATURE_COMINTEROP
308 return (HasUniqueIdentity() ||
309 (IsContentType_WindowsRuntime() && (GetWinRtTypeClassName() != NULL)));
315 inline BOOL CanUseWithBindingCache() const
317 STATIC_CONTRACT_LIMITED_METHOD;
318 return HasUniqueIdentity();
321 inline ICLRPrivBinder *GetHostBinder() const
323 LIMITED_METHOD_CONTRACT;
324 return m_pHostBinder;
327 inline void SetHostBinder(ICLRPrivBinder *pHostBinder)
329 LIMITED_METHOD_CONTRACT;
330 m_pHostBinder = pHostBinder;
335 #define INITIAL_ASM_SPEC_HASH_SIZE 7
336 class AssemblySpecHash
343 #ifndef DACCESS_COMPILE
344 AssemblySpecHash(LoaderHeap *pHeap = NULL)
356 m_map.Init(INITIAL_ASM_SPEC_HASH_SIZE, CompareSpecs, FALSE, NULL);
362 #ifndef DACCESS_COMPILE
364 // Returns TRUE if the spec was already in the table
367 BOOL Store(AssemblySpec *pSpec, AssemblySpec **ppStoredSpec = NULL)
374 INJECT_FAULT(COMPlusThrowOM());
378 DWORD key = pSpec->Hash();
380 AssemblySpec *entry = (AssemblySpec *) m_map.LookupValue(key, pSpec);
382 if (entry == (AssemblySpec*) INVALIDENTRY)
385 entry = new (m_pHeap->AllocMem(S_SIZE_T(sizeof(AssemblySpec)))) AssemblySpec;
387 entry = new AssemblySpec;
390 entry->CopyFrom(pSpec);
391 entry->CloneFields(AssemblySpec::ALL_OWNED);
393 m_map.InsertValue(key, entry);
395 if (ppStoredSpec != NULL)
396 *ppStoredSpec = entry;
402 if (ppStoredSpec != NULL)
403 *ppStoredSpec = entry;
407 #endif // DACCESS_COMPILE
409 DWORD Hash(AssemblySpec *pSpec)
412 return pSpec->Hash();
415 static BOOL CompareSpecs(UPTR u1, UPTR u2);
419 class AssemblySpecBindingCache
421 friend class AssemblyBindingHolder;
422 struct AssemblyBinding
432 if (m_exceptionType==EXTYPE_EE)
436 void OnAppDomainUnload()
438 LIMITED_METHOD_CONTRACT;
439 if (m_exceptionType == EXTYPE_EE)
441 m_exceptionType = EXTYPE_NONE;
447 inline DomainAssembly* GetAssembly(){ LIMITED_METHOD_CONTRACT; return m_pAssembly;};
448 inline void SetAssembly(DomainAssembly* pAssembly){ LIMITED_METHOD_CONTRACT; m_pAssembly=pAssembly;};
449 inline PEAssembly* GetFile(){ LIMITED_METHOD_CONTRACT; return m_pFile;};
450 inline BOOL IsError(){ LIMITED_METHOD_CONTRACT; return (m_exceptionType!=EXTYPE_NONE);};
452 // bound to the file, but failed later
453 inline BOOL IsPostBindError(){ LIMITED_METHOD_CONTRACT; return IsError() && GetFile()!=NULL;};
455 inline void ThrowIfError()
465 switch(m_exceptionType)
467 case EXTYPE_NONE: return;
468 case EXTYPE_HR: ThrowHR(m_hr);
469 case EXTYPE_EE: PAL_CPP_THROW(Exception *, m_pException->DomainBoundClone());
470 default: _ASSERTE(!"Unexpected exception type");
473 inline void Init(AssemblySpec* pSpec, PEAssembly* pFile, DomainAssembly* pAssembly, Exception* pEx, LoaderHeap *pHeap, AllocMemTracker *pamTracker)
478 WRAPPER(GC_TRIGGERS);
483 InitInternal(pSpec,pFile,pAssembly);
486 m_spec.CloneFieldsToLoaderHeap(AssemblySpec::ALL_OWNED,pHeap, pamTracker);
490 m_spec.CloneFields(m_spec.ALL_OWNED);
496 inline HRESULT GetHR()
498 LIMITED_METHOD_CONTRACT;
499 switch(m_exceptionType)
501 case EXTYPE_NONE: return S_OK;
502 case EXTYPE_HR: return m_hr;
503 case EXTYPE_EE: return m_pException->GetHR();
504 default: _ASSERTE(!"Unexpected exception type");
509 inline void InitException(Exception* pEx)
514 WRAPPER(GC_TRIGGERS);
519 _ASSERTE(m_exceptionType==EXTYPE_NONE);
524 _ASSERTE(!pEx->IsTransient());
528 m_pException = pEx->DomainBoundClone();
529 _ASSERTE(m_pException);
530 m_exceptionType=EXTYPE_EE;
534 InitException(pEx->GetHR());
536 EX_END_CATCH(RethrowTransientExceptions);
540 inline void InitException(HRESULT hr)
542 LIMITED_METHOD_CONTRACT;
543 _ASSERTE(m_exceptionType==EXTYPE_NONE);
546 m_exceptionType=EXTYPE_HR;
552 inline void InitInternal(AssemblySpec* pSpec, PEAssembly* pFile, DomainAssembly* pAssembly )
555 m_spec.CopyFrom(pSpec);
559 m_pAssembly = pAssembly;
560 m_exceptionType=EXTYPE_NONE;
565 DomainAssembly *m_pAssembly;
567 EXTYPE_NONE = 0x00000000,
568 EXTYPE_HR = 0x00000001,
569 EXTYPE_EE = 0x00000002,
575 Exception* m_pException;
582 AssemblySpecBindingCache::AssemblyBinding* GetAssemblyBindingEntryForAssemblySpec(AssemblySpec* pSpec, BOOL fThrow);
586 AssemblySpecBindingCache() DAC_EMPTY();
587 ~AssemblySpecBindingCache() DAC_EMPTY();
589 void Init(CrstBase *pCrst, LoaderHeap *pHeap = NULL);
592 void OnAppDomainUnload();
594 BOOL Contains(AssemblySpec *pSpec);
596 DomainAssembly *LookupAssembly(AssemblySpec *pSpec, BOOL fThrow=TRUE);
597 PEAssembly *LookupFile(AssemblySpec *pSpec, BOOL fThrow = TRUE);
599 BOOL StoreAssembly(AssemblySpec *pSpec, DomainAssembly *pAssembly);
600 BOOL StoreFile(AssemblySpec *pSpec, PEAssembly *pFile);
602 BOOL StoreException(AssemblySpec *pSpec, Exception* pEx);
604 DWORD Hash(AssemblySpec *pSpec)
607 return pSpec->Hash();
610 #if !defined(DACCESS_COMPILE)
611 void GetAllAssemblies(SetSHash<PTR_DomainAssembly>& assemblyList)
613 PtrHashMap::PtrIterator i = m_map.begin();
616 AssemblyBinding *b = (AssemblyBinding*) i.GetValue();
617 if(!b->IsError() && b->GetAssembly() != NULL)
618 assemblyList.AddOrReplace(b->GetAssembly());
622 #endif // !defined(DACCESS_COMPILE)
624 static BOOL CompareSpecs(UPTR u1, UPTR u2);
627 #define INITIAL_DOMAIN_ASSEMBLY_CACHE_SIZE 17
628 class DomainAssemblyCache
630 struct AssemblyEntry {
632 LPVOID pData[2]; // Can be an Assembly, PEAssembly, or an Unmanaged DLL
642 AppDomain* m_pDomain;
646 static BOOL CompareBindingSpec(UPTR spec1, UPTR spec2);
648 void InitializeTable(AppDomain* pDomain, CrstBase *pCrst)
654 LockOwner lock = {pCrst, IsOwnerOfCrst};
655 m_Table.Init(INITIAL_DOMAIN_ASSEMBLY_CACHE_SIZE, &CompareBindingSpec, true, &lock);
658 AssemblyEntry* LookupEntry(AssemblySpec* pSpec);
660 LPVOID LookupEntry(AssemblySpec* pSpec, UINT index)
664 AssemblyEntry* ptr = LookupEntry(pSpec);
668 return ptr->pData[index];
671 VOID InsertEntry(AssemblySpec* pSpec, LPVOID pData1, LPVOID pData2 = NULL);