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 | /*============================================================ |
6 | ** |
7 | ** Header: AssemblySpec.hpp |
8 | ** |
9 | ** Purpose: Implements classes used to bind to assemblies |
10 | ** |
11 | ** |
12 | |
13 | |
14 | ** |
15 | ===========================================================*/ |
16 | #ifndef _ASSEMBLYSPEC_H |
17 | #define _ASSEMBLYSPEC_H |
18 | #include "hash.h" |
19 | #include "memorypool.h" |
20 | #include "assemblyspecbase.h" |
21 | #include "domainfile.h" |
22 | #include "genericstackprobe.h" |
23 | #include "holder.h" |
24 | |
25 | class AppDomain; |
26 | class Assembly; |
27 | class DomainAssembly; |
28 | enum FileLoadLevel; |
29 | |
30 | class AssemblySpec : public BaseAssemblySpec |
31 | { |
32 | private: |
33 | |
34 | friend class AppDomain; |
35 | friend class AssemblyNameNative; |
36 | |
37 | AppDomain *m_pAppDomain; |
38 | SBuffer m_HashForControl; |
39 | DWORD m_dwHashAlg; |
40 | DomainAssembly *m_pParentAssembly; |
41 | |
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; |
44 | |
45 | // Flag to indicate if we should prefer the fallback load context binder for binding or not. |
46 | bool m_fPreferFallbackLoadContextBinder; |
47 | |
48 | BOOL IsValidAssemblyName(); |
49 | |
50 | HRESULT InitializeSpecInternal(mdToken kAssemblyRefOrDef, |
51 | IMDInternalImport *pImport, |
52 | DomainAssembly *pStaticParent, |
53 | BOOL fAllowAllocation); |
54 | |
55 | // InitializeSpecInternal should be used very carefully so it's made private. |
56 | // functions that take special care (and thus are allowed to use the function) are listed below |
57 | friend Assembly * Module::GetAssemblyIfLoaded( |
58 | mdAssemblyRef kAssemblyRef, |
59 | LPCSTR szWinRtNamespace, |
60 | LPCSTR szWinRtClassName, |
61 | IMDInternalImport * pMDImportOverride, |
62 | BOOL , |
63 | ICLRPrivBinder *pBindingContextForLoadedAssembly); |
64 | |
65 | public: |
66 | |
67 | #ifndef DACCESS_COMPILE |
68 | AssemblySpec() : m_pAppDomain(::GetAppDomain()) |
69 | { |
70 | LIMITED_METHOD_CONTRACT; |
71 | m_pParentAssembly = NULL; |
72 | |
73 | m_pFallbackLoadContextBinder = NULL; |
74 | m_fPreferFallbackLoadContextBinder = false; |
75 | |
76 | } |
77 | #endif //!DACCESS_COMPILE |
78 | |
79 | AssemblySpec(AppDomain *pAppDomain) : m_pAppDomain(pAppDomain) |
80 | { |
81 | LIMITED_METHOD_CONTRACT |
82 | m_pParentAssembly = NULL; |
83 | |
84 | m_pFallbackLoadContextBinder = NULL; |
85 | m_fPreferFallbackLoadContextBinder = false; |
86 | |
87 | } |
88 | |
89 | |
90 | DomainAssembly* GetParentAssembly(); |
91 | |
92 | ICLRPrivBinder* GetBindingContextFromParentAssembly(AppDomain *pDomain); |
93 | |
94 | bool HasParentAssembly() |
95 | { WRAPPER_NO_CONTRACT; return GetParentAssembly() != NULL; } |
96 | |
97 | void InitializeSpec(mdToken kAssemblyRefOrDef, |
98 | IMDInternalImport *pImport, |
99 | DomainAssembly *pStaticParent = NULL) |
100 | { |
101 | CONTRACTL |
102 | { |
103 | INSTANCE_CHECK; |
104 | GC_TRIGGERS; |
105 | THROWS; |
106 | MODE_ANY; |
107 | } |
108 | CONTRACTL_END; |
109 | HRESULT hr=InitializeSpecInternal(kAssemblyRefOrDef, pImport,pStaticParent,TRUE); |
110 | if(FAILED(hr)) |
111 | EEFileLoadException::Throw(this,hr); |
112 | }; |
113 | |
114 | |
115 | void InitializeSpec(PEAssembly *pFile); |
116 | HRESULT InitializeSpec(StackingAllocator* alloc, |
117 | ASSEMBLYNAMEREF* pName, |
118 | BOOL fParse = TRUE); |
119 | |
120 | void AssemblyNameInit(ASSEMBLYNAMEREF* pName, PEImage* pImageInfo); //[in,out], [in] |
121 | |
122 | |
123 | void SetCodeBase(LPCWSTR szCodeBase) |
124 | { |
125 | WRAPPER_NO_CONTRACT; |
126 | BaseAssemblySpec::SetCodeBase(szCodeBase); |
127 | } |
128 | void SetCodeBase(StackingAllocator* alloc, STRINGREF *pCodeBase); |
129 | |
130 | void SetParentAssembly(DomainAssembly *pAssembly) |
131 | { |
132 | CONTRACTL |
133 | { |
134 | INSTANCE_CHECK; |
135 | GC_NOTRIGGER; |
136 | NOTHROW; |
137 | MODE_ANY; |
138 | } |
139 | CONTRACTL_END; |
140 | |
141 | m_pParentAssembly = pAssembly; |
142 | } |
143 | |
144 | void SetFallbackLoadContextBinderForRequestingAssembly(ICLRPrivBinder *pFallbackLoadContextBinder) |
145 | { |
146 | LIMITED_METHOD_CONTRACT; |
147 | |
148 | m_pFallbackLoadContextBinder = pFallbackLoadContextBinder; |
149 | } |
150 | |
151 | ICLRPrivBinder* GetFallbackLoadContextBinderForRequestingAssembly() |
152 | { |
153 | LIMITED_METHOD_CONTRACT; |
154 | |
155 | return m_pFallbackLoadContextBinder; |
156 | } |
157 | |
158 | void SetPreferFallbackLoadContextBinder() |
159 | { |
160 | LIMITED_METHOD_CONTRACT; |
161 | |
162 | m_fPreferFallbackLoadContextBinder = true; |
163 | } |
164 | |
165 | bool GetPreferFallbackLoadContextBinder() |
166 | { |
167 | LIMITED_METHOD_CONTRACT; |
168 | |
169 | return m_fPreferFallbackLoadContextBinder; |
170 | } |
171 | |
172 | // Note that this method does not clone the fields! |
173 | void CopyFrom(AssemblySpec* pSource) |
174 | { |
175 | CONTRACTL |
176 | { |
177 | INSTANCE_CHECK; |
178 | THROWS; |
179 | MODE_ANY; |
180 | } |
181 | CONTRACTL_END; |
182 | |
183 | BaseAssemblySpec::CopyFrom(pSource); |
184 | |
185 | SetParentAssembly(pSource->GetParentAssembly()); |
186 | |
187 | // Copy the details of the fallback load context binder |
188 | SetFallbackLoadContextBinderForRequestingAssembly(pSource->GetFallbackLoadContextBinderForRequestingAssembly()); |
189 | m_fPreferFallbackLoadContextBinder = pSource->GetPreferFallbackLoadContextBinder(); |
190 | |
191 | m_HashForControl = pSource->m_HashForControl; |
192 | m_dwHashAlg = pSource->m_dwHashAlg; |
193 | } |
194 | |
195 | |
196 | HRESULT CheckFriendAssemblyName(); |
197 | |
198 | |
199 | HRESULT EmitToken(IMetaDataAssemblyEmit *pEmit, |
200 | mdAssemblyRef *pToken, |
201 | BOOL fUsePublicKeyToken = TRUE, |
202 | BOOL fMustBeBindable = FALSE /*(used only by FusionBind's implementation)*/); |
203 | |
204 | // Make sure this matches in the managed Assembly.DemandPermission() |
205 | enum FilePermFlag { |
206 | FILE_PATHDISCOVERY = 0x0, |
207 | FILE_READ = 0x1, |
208 | FILE_READANDPATHDISC = 0x2, |
209 | FILE_WEBPERM = 0x3 |
210 | }; |
211 | |
212 | |
213 | |
214 | VOID Bind( |
215 | AppDomain* pAppDomain, |
216 | BOOL fThrowOnFileNotFound, |
217 | CoreBindResult* pBindResult, |
218 | BOOL fNgenExplicitBind = FALSE, |
219 | BOOL fExplicitBindToNativeImage = FALSE); |
220 | |
221 | Assembly *LoadAssembly(FileLoadLevel targetLevel, |
222 | BOOL fThrowOnFileNotFound = TRUE); |
223 | DomainAssembly *LoadDomainAssembly(FileLoadLevel targetLevel, |
224 | BOOL fThrowOnFileNotFound = TRUE); |
225 | |
226 | //**************************************************************************************** |
227 | // |
228 | // Creates and loads an assembly based on the name and context. |
229 | static Assembly *LoadAssembly(LPCSTR pSimpleName, |
230 | AssemblyMetaDataInternal* pContext, |
231 | const BYTE * pbPublicKeyOrToken, |
232 | DWORD cbPublicKeyOrToken, |
233 | DWORD dwFlags); |
234 | |
235 | |
236 | // Load an assembly based on an explicit path |
237 | static Assembly *LoadAssembly(LPCWSTR pFilePath); |
238 | |
239 | |
240 | private: |
241 | void MatchRetargetedPublicKeys(Assembly *pAssembly); |
242 | public: |
243 | void MatchPublicKeys(Assembly *pAssembly); |
244 | PEAssembly *ResolveAssemblyFile(AppDomain *pAppDomain); |
245 | |
246 | AppDomain *GetAppDomain() |
247 | { |
248 | LIMITED_METHOD_CONTRACT; |
249 | return m_pAppDomain; |
250 | } |
251 | |
252 | HRESULT SetHashForControl(PBYTE pHashForControl, DWORD dwHashForControl, DWORD dwHashAlg) |
253 | { |
254 | CONTRACTL |
255 | { |
256 | THROWS; |
257 | GC_NOTRIGGER; |
258 | PRECONDITION(CheckPointer(pHashForControl)); |
259 | } |
260 | CONTRACTL_END; |
261 | |
262 | m_HashForControl.Set(pHashForControl, dwHashForControl); |
263 | m_dwHashAlg=dwHashAlg; |
264 | return S_OK; |
265 | } |
266 | |
267 | void ParseEncodedName(); |
268 | |
269 | void SetWindowsRuntimeType(LPCUTF8 szNamespace, LPCUTF8 szClassName); |
270 | void SetWindowsRuntimeType(SString const & _ssTypeName); |
271 | |
272 | inline HRESULT SetContentType(AssemblyContentType type) |
273 | { |
274 | LIMITED_METHOD_CONTRACT; |
275 | if (type == AssemblyContentType_Default) |
276 | { |
277 | m_dwFlags = (m_dwFlags & ~afContentType_Mask) | afContentType_Default; |
278 | return S_OK; |
279 | } |
280 | else if (type == AssemblyContentType_WindowsRuntime) |
281 | { |
282 | m_dwFlags = (m_dwFlags & ~afContentType_Mask) | afContentType_WindowsRuntime; |
283 | return S_OK; |
284 | } |
285 | else |
286 | { |
287 | _ASSERTE(!"Unexpected content type." ); |
288 | return E_UNEXPECTED; |
289 | } |
290 | } |
291 | |
292 | // Returns true if the object can be used to bind to the target assembly. |
293 | // One case in which this is not true is when the content type is WinRT |
294 | // but no type name has been set. |
295 | inline bool HasBindableIdentity() const |
296 | { |
297 | STATIC_CONTRACT_LIMITED_METHOD; |
298 | #ifdef FEATURE_COMINTEROP |
299 | return (HasUniqueIdentity() || |
300 | (IsContentType_WindowsRuntime() && (GetWinRtTypeClassName() != NULL))); |
301 | #else |
302 | return TRUE; |
303 | #endif |
304 | } |
305 | |
306 | inline BOOL CanUseWithBindingCache() const |
307 | { |
308 | STATIC_CONTRACT_LIMITED_METHOD; |
309 | return HasUniqueIdentity(); |
310 | } |
311 | |
312 | inline ICLRPrivBinder *GetHostBinder() const |
313 | { |
314 | LIMITED_METHOD_CONTRACT; |
315 | return m_pHostBinder; |
316 | } |
317 | |
318 | inline void SetHostBinder(ICLRPrivBinder *pHostBinder) |
319 | { |
320 | LIMITED_METHOD_CONTRACT; |
321 | m_pHostBinder = pHostBinder; |
322 | } |
323 | |
324 | }; |
325 | |
326 | #define INITIAL_ASM_SPEC_HASH_SIZE 7 |
327 | class AssemblySpecHash |
328 | { |
329 | LoaderHeap *m_pHeap; |
330 | PtrHashMap m_map; |
331 | |
332 | public: |
333 | |
334 | #ifndef DACCESS_COMPILE |
335 | AssemblySpecHash(LoaderHeap *pHeap = NULL) |
336 | : m_pHeap(pHeap) |
337 | { |
338 | CONTRACTL |
339 | { |
340 | CONSTRUCTOR_CHECK; |
341 | THROWS; |
342 | GC_NOTRIGGER; |
343 | MODE_ANY; |
344 | } |
345 | CONTRACTL_END; |
346 | |
347 | m_map.Init(INITIAL_ASM_SPEC_HASH_SIZE, CompareSpecs, FALSE, NULL); |
348 | } |
349 | |
350 | ~AssemblySpecHash(); |
351 | #endif |
352 | |
353 | #ifndef DACCESS_COMPILE |
354 | // |
355 | // Returns TRUE if the spec was already in the table |
356 | // |
357 | |
358 | BOOL Store(AssemblySpec *pSpec, AssemblySpec **ppStoredSpec = NULL) |
359 | { |
360 | CONTRACTL |
361 | { |
362 | THROWS; |
363 | GC_TRIGGERS; |
364 | MODE_ANY; |
365 | INJECT_FAULT(COMPlusThrowOM()); |
366 | } |
367 | CONTRACTL_END |
368 | |
369 | DWORD key = pSpec->Hash(); |
370 | |
371 | AssemblySpec *entry = (AssemblySpec *) m_map.LookupValue(key, pSpec); |
372 | |
373 | if (entry == (AssemblySpec*) INVALIDENTRY) |
374 | { |
375 | if (m_pHeap != NULL) |
376 | entry = new (m_pHeap->AllocMem(S_SIZE_T(sizeof(AssemblySpec)))) AssemblySpec; |
377 | else |
378 | entry = new AssemblySpec; |
379 | |
380 | GCX_PREEMP(); |
381 | entry->CopyFrom(pSpec); |
382 | entry->CloneFields(AssemblySpec::ALL_OWNED); |
383 | |
384 | m_map.InsertValue(key, entry); |
385 | |
386 | if (ppStoredSpec != NULL) |
387 | *ppStoredSpec = entry; |
388 | |
389 | return FALSE; |
390 | } |
391 | else |
392 | { |
393 | if (ppStoredSpec != NULL) |
394 | *ppStoredSpec = entry; |
395 | return TRUE; |
396 | } |
397 | } |
398 | #endif // DACCESS_COMPILE |
399 | |
400 | DWORD Hash(AssemblySpec *pSpec) |
401 | { |
402 | WRAPPER_NO_CONTRACT; |
403 | return pSpec->Hash(); |
404 | } |
405 | |
406 | static BOOL CompareSpecs(UPTR u1, UPTR u2); |
407 | }; |
408 | |
409 | |
410 | class AssemblySpecBindingCache |
411 | { |
412 | friend class AssemblyBindingHolder; |
413 | struct AssemblyBinding |
414 | { |
415 | public: |
416 | ~AssemblyBinding() |
417 | { |
418 | WRAPPER_NO_CONTRACT; |
419 | |
420 | if (m_pFile != NULL) |
421 | m_pFile->Release(); |
422 | |
423 | if (m_exceptionType==EXTYPE_EE) |
424 | delete m_pException; |
425 | }; |
426 | |
427 | void OnAppDomainUnload() |
428 | { |
429 | LIMITED_METHOD_CONTRACT; |
430 | if (m_exceptionType == EXTYPE_EE) |
431 | { |
432 | m_exceptionType = EXTYPE_NONE; |
433 | delete m_pException; |
434 | m_pException = NULL; |
435 | } |
436 | }; |
437 | |
438 | inline DomainAssembly* GetAssembly(){ LIMITED_METHOD_CONTRACT; return m_pAssembly;}; |
439 | inline void SetAssembly(DomainAssembly* pAssembly){ LIMITED_METHOD_CONTRACT; m_pAssembly=pAssembly;}; |
440 | inline PEAssembly* GetFile(){ LIMITED_METHOD_CONTRACT; return m_pFile;}; |
441 | inline BOOL IsError(){ LIMITED_METHOD_CONTRACT; return (m_exceptionType!=EXTYPE_NONE);}; |
442 | |
443 | // bound to the file, but failed later |
444 | inline BOOL IsPostBindError(){ LIMITED_METHOD_CONTRACT; return IsError() && GetFile()!=NULL;}; |
445 | |
446 | inline void ThrowIfError() |
447 | { |
448 | CONTRACTL |
449 | { |
450 | THROWS; |
451 | GC_TRIGGERS; |
452 | MODE_ANY; |
453 | } |
454 | CONTRACTL_END; |
455 | |
456 | switch(m_exceptionType) |
457 | { |
458 | case EXTYPE_NONE: return; |
459 | case EXTYPE_HR: ThrowHR(m_hr); |
460 | case EXTYPE_EE: PAL_CPP_THROW(Exception *, m_pException->DomainBoundClone()); |
461 | default: _ASSERTE(!"Unexpected exception type" ); |
462 | } |
463 | }; |
464 | inline void Init(AssemblySpec* pSpec, PEAssembly* pFile, DomainAssembly* pAssembly, Exception* pEx, LoaderHeap *pHeap, AllocMemTracker *pamTracker) |
465 | { |
466 | CONTRACTL |
467 | { |
468 | THROWS; |
469 | WRAPPER(GC_TRIGGERS); |
470 | MODE_ANY; |
471 | } |
472 | CONTRACTL_END; |
473 | |
474 | InitInternal(pSpec,pFile,pAssembly); |
475 | if (pHeap != NULL) |
476 | { |
477 | m_spec.CloneFieldsToLoaderHeap(AssemblySpec::ALL_OWNED,pHeap, pamTracker); |
478 | } |
479 | else |
480 | { |
481 | m_spec.CloneFields(m_spec.ALL_OWNED); |
482 | } |
483 | InitException(pEx); |
484 | |
485 | } |
486 | |
487 | inline HRESULT GetHR() |
488 | { |
489 | LIMITED_METHOD_CONTRACT; |
490 | switch(m_exceptionType) |
491 | { |
492 | case EXTYPE_NONE: return S_OK; |
493 | case EXTYPE_HR: return m_hr; |
494 | case EXTYPE_EE: return m_pException->GetHR(); |
495 | default: _ASSERTE(!"Unexpected exception type" ); |
496 | } |
497 | return E_UNEXPECTED; |
498 | }; |
499 | |
500 | inline void InitException(Exception* pEx) |
501 | { |
502 | CONTRACTL |
503 | { |
504 | THROWS; |
505 | WRAPPER(GC_TRIGGERS); |
506 | MODE_ANY; |
507 | } |
508 | CONTRACTL_END; |
509 | |
510 | _ASSERTE(m_exceptionType==EXTYPE_NONE); |
511 | |
512 | if (pEx==NULL) |
513 | return; |
514 | |
515 | _ASSERTE(!pEx->IsTransient()); |
516 | |
517 | EX_TRY |
518 | { |
519 | m_pException = pEx->DomainBoundClone(); |
520 | _ASSERTE(m_pException); |
521 | m_exceptionType=EXTYPE_EE; |
522 | } |
523 | EX_CATCH |
524 | { |
525 | InitException(pEx->GetHR()); |
526 | } |
527 | EX_END_CATCH(RethrowTransientExceptions); |
528 | |
529 | }; |
530 | |
531 | inline void InitException(HRESULT hr) |
532 | { |
533 | LIMITED_METHOD_CONTRACT; |
534 | _ASSERTE(m_exceptionType==EXTYPE_NONE); |
535 | if (FAILED(hr)) |
536 | { |
537 | m_exceptionType=EXTYPE_HR; |
538 | m_hr=hr; |
539 | } |
540 | }; |
541 | protected: |
542 | |
543 | inline void InitInternal(AssemblySpec* pSpec, PEAssembly* pFile, DomainAssembly* pAssembly ) |
544 | { |
545 | WRAPPER_NO_CONTRACT; |
546 | m_spec.CopyFrom(pSpec); |
547 | m_pFile = pFile; |
548 | if (m_pFile) |
549 | m_pFile->AddRef(); |
550 | m_pAssembly = pAssembly; |
551 | m_exceptionType=EXTYPE_NONE; |
552 | } |
553 | |
554 | AssemblySpec m_spec; |
555 | PEAssembly *m_pFile; |
556 | DomainAssembly *m_pAssembly; |
557 | enum{ |
558 | EXTYPE_NONE = 0x00000000, |
559 | EXTYPE_HR = 0x00000001, |
560 | EXTYPE_EE = 0x00000002, |
561 | }; |
562 | INT m_exceptionType; |
563 | union |
564 | { |
565 | HRESULT m_hr; |
566 | Exception* m_pException; |
567 | }; |
568 | }; |
569 | |
570 | PtrHashMap m_map; |
571 | LoaderHeap *m_pHeap; |
572 | |
573 | AssemblySpecBindingCache::AssemblyBinding* LookupInternal(AssemblySpec* pSpec, BOOL fThrow = FALSE); |
574 | |
575 | public: |
576 | |
577 | AssemblySpecBindingCache() DAC_EMPTY(); |
578 | ~AssemblySpecBindingCache() DAC_EMPTY(); |
579 | |
580 | void Init(CrstBase *pCrst, LoaderHeap *pHeap = NULL); |
581 | void Clear(); |
582 | |
583 | void OnAppDomainUnload(); |
584 | |
585 | BOOL Contains(AssemblySpec *pSpec); |
586 | |
587 | DomainAssembly *LookupAssembly(AssemblySpec *pSpec, BOOL fThrow=TRUE); |
588 | PEAssembly *LookupFile(AssemblySpec *pSpec, BOOL fThrow = TRUE); |
589 | |
590 | BOOL StoreAssembly(AssemblySpec *pSpec, DomainAssembly *pAssembly); |
591 | BOOL StoreFile(AssemblySpec *pSpec, PEAssembly *pFile); |
592 | |
593 | BOOL StoreException(AssemblySpec *pSpec, Exception* pEx); |
594 | |
595 | BOOL RemoveAssembly(DomainAssembly* pAssembly); |
596 | |
597 | DWORD Hash(AssemblySpec *pSpec) |
598 | { |
599 | WRAPPER_NO_CONTRACT; |
600 | return pSpec->Hash(); |
601 | } |
602 | |
603 | #if !defined(DACCESS_COMPILE) |
604 | void GetAllAssemblies(SetSHash<PTR_DomainAssembly>& assemblyList) |
605 | { |
606 | PtrHashMap::PtrIterator i = m_map.begin(); |
607 | while (!i.end()) |
608 | { |
609 | AssemblyBinding *b = (AssemblyBinding*) i.GetValue(); |
610 | if(!b->IsError() && b->GetAssembly() != NULL) |
611 | assemblyList.AddOrReplace(b->GetAssembly()); |
612 | ++i; |
613 | } |
614 | } |
615 | #endif // !defined(DACCESS_COMPILE) |
616 | |
617 | static BOOL CompareSpecs(UPTR u1, UPTR u2); |
618 | }; |
619 | |
620 | #define INITIAL_DOMAIN_ASSEMBLY_CACHE_SIZE 17 |
621 | class DomainAssemblyCache |
622 | { |
623 | struct AssemblyEntry { |
624 | AssemblySpec spec; |
625 | LPVOID pData[2]; // Can be an Assembly, PEAssembly, or an Unmanaged DLL |
626 | |
627 | DWORD Hash() |
628 | { |
629 | WRAPPER_NO_CONTRACT; |
630 | return spec.Hash(); |
631 | } |
632 | }; |
633 | |
634 | PtrHashMap m_Table; |
635 | AppDomain* m_pDomain; |
636 | |
637 | public: |
638 | |
639 | static BOOL CompareBindingSpec(UPTR spec1, UPTR spec2); |
640 | |
641 | void InitializeTable(AppDomain* pDomain, CrstBase *pCrst) |
642 | { |
643 | WRAPPER_NO_CONTRACT; |
644 | _ASSERTE(pDomain); |
645 | m_pDomain = pDomain; |
646 | |
647 | LockOwner lock = {pCrst, IsOwnerOfCrst}; |
648 | m_Table.Init(INITIAL_DOMAIN_ASSEMBLY_CACHE_SIZE, &CompareBindingSpec, true, &lock); |
649 | } |
650 | |
651 | AssemblyEntry* LookupEntry(AssemblySpec* pSpec); |
652 | |
653 | LPVOID LookupEntry(AssemblySpec* pSpec, UINT index) |
654 | { |
655 | WRAPPER_NO_CONTRACT; |
656 | _ASSERTE(index < 2); |
657 | AssemblyEntry* ptr = LookupEntry(pSpec); |
658 | if(ptr == NULL) |
659 | return NULL; |
660 | else |
661 | return ptr->pData[index]; |
662 | } |
663 | |
664 | VOID InsertEntry(AssemblySpec* pSpec, LPVOID pData1, LPVOID pData2 = NULL); |
665 | |
666 | private: |
667 | |
668 | }; |
669 | |
670 | #endif |
671 | |