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 | |
8 | #include "common.h" |
9 | |
10 | #include "binder.h" |
11 | #include "ecall.h" |
12 | |
13 | #include "field.h" |
14 | #include "excep.h" |
15 | #include "eeconfig.h" |
16 | #include "runtimehandles.h" |
17 | #include "customattribute.h" |
18 | #include "debugdebugger.h" |
19 | #include "dllimport.h" |
20 | #include "nativeoverlapped.h" |
21 | #include "clrvarargs.h" |
22 | #include "sigbuilder.h" |
23 | |
24 | #ifdef FEATURE_PREJIT |
25 | #include "compile.h" |
26 | #endif |
27 | |
28 | // |
29 | // Retrieve structures from ID. |
30 | // |
31 | NOINLINE PTR_MethodTable MscorlibBinder::LookupClass(BinderClassID id) |
32 | { |
33 | WRAPPER_NO_CONTRACT; |
34 | return (&g_Mscorlib)->LookupClassLocal(id); |
35 | } |
36 | |
37 | PTR_MethodTable MscorlibBinder::GetClassLocal(BinderClassID id) |
38 | { |
39 | WRAPPER_NO_CONTRACT; |
40 | |
41 | PTR_MethodTable pMT = VolatileLoad(&(m_pClasses[id])); |
42 | if (pMT == NULL) |
43 | return LookupClassLocal(id); |
44 | return pMT; |
45 | } |
46 | |
47 | PTR_MethodTable MscorlibBinder::LookupClassLocal(BinderClassID id) |
48 | { |
49 | CONTRACTL |
50 | { |
51 | THROWS; |
52 | GC_TRIGGERS; |
53 | INJECT_FAULT(ThrowOutOfMemory()); |
54 | |
55 | PRECONDITION(id != CLASS__NIL); |
56 | PRECONDITION(id <= m_cClasses); |
57 | } |
58 | CONTRACTL_END; |
59 | |
60 | PTR_MethodTable pMT = NULL; |
61 | |
62 | // Binder methods are used for loading "known" types from mscorlib.dll. Thus they are unlikely to be part |
63 | // of a recursive cycle. This is used too broadly to force manual overrides at every callsite. |
64 | OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED); |
65 | |
66 | const MscorlibClassDescription *d = m_classDescriptions + (int)id; |
67 | |
68 | pMT = ClassLoader::LoadTypeByNameThrowing(GetModule()->GetAssembly(), d->nameSpace, d->name).AsMethodTable(); |
69 | |
70 | _ASSERTE(pMT->GetModule() == GetModule()); |
71 | |
72 | #ifndef DACCESS_COMPILE |
73 | VolatileStore(&m_pClasses[id], pMT); |
74 | #endif |
75 | |
76 | return pMT; |
77 | } |
78 | |
79 | NOINLINE MethodDesc * MscorlibBinder::LookupMethod(BinderMethodID id) |
80 | { |
81 | WRAPPER_NO_CONTRACT; |
82 | return (&g_Mscorlib)->LookupMethodLocal(id); |
83 | } |
84 | |
85 | MethodDesc * MscorlibBinder::GetMethodLocal(BinderMethodID id) |
86 | { |
87 | WRAPPER_NO_CONTRACT; |
88 | |
89 | MethodDesc * pMD = VolatileLoad(&(m_pMethods[id])); |
90 | if (pMD == NULL) |
91 | return LookupMethodLocal(id); |
92 | return pMD; |
93 | } |
94 | |
95 | MethodDesc * MscorlibBinder::LookupMethodLocal(BinderMethodID id) |
96 | { |
97 | CONTRACTL |
98 | { |
99 | THROWS; |
100 | GC_TRIGGERS; |
101 | INJECT_FAULT(ThrowOutOfMemory()); |
102 | |
103 | PRECONDITION(id != METHOD__NIL); |
104 | PRECONDITION(id <= m_cMethods); |
105 | } |
106 | CONTRACTL_END; |
107 | |
108 | #ifndef DACCESS_COMPILE |
109 | MethodDesc * pMD = NULL; |
110 | |
111 | const MscorlibMethodDescription *d = m_methodDescriptions + (id - 1); |
112 | |
113 | MethodTable * pMT = GetClassLocal(d->classID); |
114 | _ASSERTE(pMT != NULL && "Couldn't find a type in mscorlib!" ); |
115 | |
116 | if (d->sig != NULL) |
117 | { |
118 | Signature sig = GetSignatureLocal(d->sig); |
119 | |
120 | pMD = MemberLoader::FindMethod(pMT, d->name, sig.GetRawSig(), sig.GetRawSigLen(), GetModule()); |
121 | } |
122 | else |
123 | { |
124 | pMD = MemberLoader::FindMethodByName(pMT, d->name); |
125 | } |
126 | |
127 | |
128 | PREFIX_ASSUME_MSGF(pMD != NULL, ("EE expects method to exist: %s:%s Sig pointer: %p\n" , pMT->GetDebugClassName(), d->name, d->sig)); |
129 | |
130 | VolatileStore(&m_pMethods[id], pMD); |
131 | |
132 | return pMD; |
133 | #else |
134 | DacNotImpl(); |
135 | return NULL; |
136 | #endif |
137 | } |
138 | |
139 | NOINLINE FieldDesc * MscorlibBinder::LookupField(BinderFieldID id) |
140 | { |
141 | WRAPPER_NO_CONTRACT; |
142 | return (&g_Mscorlib)->LookupFieldLocal(id); |
143 | } |
144 | |
145 | FieldDesc * MscorlibBinder::GetFieldLocal(BinderFieldID id) |
146 | { |
147 | WRAPPER_NO_CONTRACT; |
148 | |
149 | FieldDesc * pFD = VolatileLoad(&(m_pFields[id])); |
150 | if (pFD == NULL) |
151 | return LookupFieldLocal(id); |
152 | return pFD; |
153 | } |
154 | |
155 | FieldDesc * MscorlibBinder::LookupFieldLocal(BinderFieldID id) |
156 | { |
157 | CONTRACTL |
158 | { |
159 | THROWS; |
160 | GC_TRIGGERS; |
161 | INJECT_FAULT(ThrowOutOfMemory()); |
162 | |
163 | PRECONDITION(id != FIELD__NIL); |
164 | PRECONDITION(id <= m_cFields); |
165 | } |
166 | CONTRACTL_END; |
167 | |
168 | FieldDesc * pFD = NULL; |
169 | |
170 | const MscorlibFieldDescription *d = m_fieldDescriptions + (id - 1); |
171 | |
172 | MethodTable * pMT = GetClassLocal(d->classID); |
173 | |
174 | pFD = MemberLoader::FindField(pMT, d->name, NULL, 0, NULL); |
175 | |
176 | #ifndef DACCESS_COMPILE |
177 | PREFIX_ASSUME_MSGF(pFD != NULL, ("EE expects field to exist: %s:%s\n" , pMT->GetDebugClassName(), d->name)); |
178 | |
179 | VolatileStore(&(m_pFields[id]), pFD); |
180 | #endif |
181 | |
182 | return pFD; |
183 | } |
184 | |
185 | NOINLINE PTR_MethodTable MscorlibBinder::LookupClassIfExist(BinderClassID id) |
186 | { |
187 | CONTRACTL |
188 | { |
189 | GC_NOTRIGGER; |
190 | NOTHROW; |
191 | FORBID_FAULT; |
192 | MODE_ANY; |
193 | |
194 | PRECONDITION(id != CLASS__NIL); |
195 | PRECONDITION(id <= (&g_Mscorlib)->m_cClasses); |
196 | } |
197 | CONTRACTL_END; |
198 | |
199 | // Run the class loader in non-load mode. |
200 | ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE(); |
201 | |
202 | // Binder methods are used for loading "known" types from mscorlib.dll. Thus they are unlikely to be part |
203 | // of a recursive cycle. This is used too broadly to force manual overrides at every callsite. |
204 | OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED); |
205 | |
206 | const MscorlibClassDescription *d = (&g_Mscorlib)->m_classDescriptions + (int)id; |
207 | |
208 | PTR_MethodTable pMT = ClassLoader::LoadTypeByNameThrowing(GetModule()->GetAssembly(), d->nameSpace, d->name, |
209 | ClassLoader::ReturnNullIfNotFound, ClassLoader::DontLoadTypes, CLASS_LOAD_UNRESTOREDTYPEKEY).AsMethodTable(); |
210 | |
211 | _ASSERTE((pMT == NULL) || (pMT->GetModule() == GetModule())); |
212 | |
213 | #ifndef DACCESS_COMPILE |
214 | if ((pMT != NULL) && pMT->IsFullyLoaded()) |
215 | VolatileStore(&(g_Mscorlib.m_pClasses[id]), pMT); |
216 | #endif |
217 | |
218 | return pMT; |
219 | } |
220 | |
221 | Signature MscorlibBinder::GetSignature(LPHARDCODEDMETASIG pHardcodedSig) |
222 | { |
223 | CONTRACTL |
224 | { |
225 | THROWS; |
226 | GC_TRIGGERS; |
227 | INJECT_FAULT(COMPlusThrowOM()); |
228 | MODE_ANY; |
229 | } |
230 | CONTRACTL_END |
231 | |
232 | // Make sure all HardCodedMetaSig's are global. Because there is no individual |
233 | // cleanup of converted binary sigs, using allocated HardCodedMetaSig's |
234 | // can lead to a quiet memory leak. |
235 | #ifdef _DEBUG_IMPL |
236 | |
237 | // This #include workaround generates a monster boolean expression that compares |
238 | // "this" against the address of every global defined in metasig.h |
239 | if (! (0 |
240 | #define METASIG_BODY(varname, types) || pHardcodedSig==&gsig_ ## varname |
241 | #include "metasig.h" |
242 | )) |
243 | { |
244 | _ASSERTE(!"The HardCodedMetaSig struct can only be declared as a global in metasig.h." ); |
245 | } |
246 | #endif |
247 | |
248 | return (&g_Mscorlib)->GetSignatureLocal(pHardcodedSig); |
249 | } |
250 | |
251 | Signature MscorlibBinder::GetTargetSignature(LPHARDCODEDMETASIG pHardcodedSig) |
252 | { |
253 | CONTRACTL |
254 | { |
255 | THROWS; |
256 | GC_TRIGGERS; |
257 | INJECT_FAULT(COMPlusThrowOM()); |
258 | MODE_ANY; |
259 | } |
260 | CONTRACTL_END |
261 | |
262 | #ifdef CROSSGEN_COMPILE |
263 | return GetModule()->m_pBinder->GetSignatureLocal(pHardcodedSig); |
264 | #else |
265 | return (&g_Mscorlib)->GetSignatureLocal(pHardcodedSig); |
266 | #endif |
267 | } |
268 | |
269 | // Get the metasig, do a one-time conversion if necessary |
270 | Signature MscorlibBinder::GetSignatureLocal(LPHARDCODEDMETASIG pHardcodedSig) |
271 | { |
272 | CONTRACTL |
273 | { |
274 | THROWS; |
275 | GC_TRIGGERS; |
276 | INJECT_FAULT(COMPlusThrowOM()); |
277 | MODE_ANY; |
278 | } |
279 | CONTRACTL_END |
280 | |
281 | PTR_CBYTE pMetaSig = PTR_CBYTE((TADDR)VolatileLoad(&pHardcodedSig->m_pMetaSig)); |
282 | |
283 | // To minimize code and data size, the hardcoded metasigs are baked as much as possible |
284 | // at compile time. Only the signatures with type references require one-time conversion at runtime. |
285 | |
286 | // the negative size means signature with unresolved type references |
287 | if ((INT8)*pMetaSig < 0) |
288 | { |
289 | #ifndef DACCESS_COMPILE |
290 | pMetaSig = ConvertSignature(pHardcodedSig, pMetaSig); |
291 | #else |
292 | DacNotImpl(); |
293 | #endif |
294 | } |
295 | |
296 | // The metasig has to be resolved at this point |
297 | INT8 cbSig = (INT8)*pMetaSig; |
298 | _ASSERTE(cbSig > 0); |
299 | |
300 | #ifdef DACCESS_COMPILE |
301 | PCCOR_SIGNATURE pSig = (PCCOR_SIGNATURE) |
302 | DacInstantiateTypeByAddress(dac_cast<TADDR>(pMetaSig + 1), |
303 | cbSig, |
304 | true); |
305 | #else |
306 | PCCOR_SIGNATURE pSig = pMetaSig+1; |
307 | #endif |
308 | |
309 | return Signature(pSig, cbSig); |
310 | } |
311 | |
312 | #ifndef DACCESS_COMPILE |
313 | |
314 | bool MscorlibBinder::ConvertType(const BYTE*& pSig, SigBuilder * pSigBuilder) |
315 | { |
316 | bool bSomethingResolved = false; |
317 | |
318 | Again: |
319 | CorElementType type = (CorElementType)*pSig++; |
320 | |
321 | switch (type) |
322 | { |
323 | case ELEMENT_TYPE_GENERICINST: |
324 | { |
325 | pSigBuilder->AppendElementType(type); |
326 | if (ConvertType(pSig, pSigBuilder)) |
327 | bSomethingResolved = true; |
328 | int arity = *pSig++; |
329 | pSigBuilder->AppendData(arity); |
330 | for (int i = 0; i < arity; i++) |
331 | { |
332 | if (ConvertType(pSig, pSigBuilder)) |
333 | bSomethingResolved = true; |
334 | } |
335 | } |
336 | break; |
337 | |
338 | case ELEMENT_TYPE_BYREF: |
339 | case ELEMENT_TYPE_PTR: |
340 | case ELEMENT_TYPE_SZARRAY: |
341 | pSigBuilder->AppendElementType(type); |
342 | if (ConvertType(pSig, pSigBuilder)) |
343 | bSomethingResolved = true; |
344 | break; |
345 | |
346 | case ELEMENT_TYPE_CMOD_OPT: |
347 | case ELEMENT_TYPE_CMOD_REQD: |
348 | { |
349 | // The binder class id may overflow 1 byte. Use 2 bytes to encode it. |
350 | BinderClassID id = (BinderClassID)(*pSig + 0x100 * *(pSig + 1)); |
351 | pSig += 2; |
352 | |
353 | pSigBuilder->AppendElementType(type); |
354 | pSigBuilder->AppendToken(GetClassLocal(id)->GetCl()); |
355 | bSomethingResolved = true; |
356 | } |
357 | goto Again; |
358 | |
359 | case ELEMENT_TYPE_CLASS: |
360 | case ELEMENT_TYPE_VALUETYPE: |
361 | { |
362 | // The binder class id may overflow 1 byte. Use 2 bytes to encode it. |
363 | BinderClassID id = (BinderClassID)(*pSig + 0x100 * *(pSig + 1)); |
364 | pSig += 2; |
365 | |
366 | pSigBuilder->AppendElementType(type); |
367 | pSigBuilder->AppendToken(GetClassLocal(id)->GetCl()); |
368 | bSomethingResolved = true; |
369 | } |
370 | break; |
371 | |
372 | case ELEMENT_TYPE_VAR: |
373 | case ELEMENT_TYPE_MVAR: |
374 | { |
375 | pSigBuilder->AppendElementType(type); |
376 | pSigBuilder->AppendData(*pSig++); |
377 | } |
378 | break; |
379 | |
380 | default: |
381 | pSigBuilder->AppendElementType(type); |
382 | break; |
383 | } |
384 | |
385 | return bSomethingResolved; |
386 | } |
387 | |
388 | //------------------------------------------------------------------ |
389 | // Resolve type references in the hardcoded metasig. |
390 | // Returns a new signature with type refences resolved. |
391 | //------------------------------------------------------------------ |
392 | void MscorlibBinder::BuildConvertedSignature(const BYTE* pSig, SigBuilder * pSigBuilder) |
393 | { |
394 | CONTRACTL |
395 | { |
396 | STANDARD_VM_CHECK; |
397 | PRECONDITION(CheckPointer(pSig)); |
398 | PRECONDITION(CheckPointer(pSigBuilder)); |
399 | } |
400 | CONTRACTL_END |
401 | |
402 | unsigned argCount; |
403 | unsigned callConv; |
404 | bool bSomethingResolved = false; |
405 | |
406 | // calling convention |
407 | callConv = *pSig++; |
408 | pSigBuilder->AppendData(callConv); |
409 | |
410 | if ((callConv & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_CS_CALLCONV_DEFAULT) { |
411 | // arg count |
412 | argCount = *pSig++; |
413 | pSigBuilder->AppendData(argCount); |
414 | } |
415 | else { |
416 | if ((callConv & IMAGE_CEE_CS_CALLCONV_MASK) != IMAGE_CEE_CS_CALLCONV_FIELD) |
417 | THROW_BAD_FORMAT(BFA_BAD_SIGNATURE, (Module*)NULL); |
418 | argCount = 0; |
419 | } |
420 | |
421 | // <= because we want to include the return value or the field |
422 | for (unsigned i = 0; i <= argCount; i++) { |
423 | if (ConvertType(pSig, pSigBuilder)) |
424 | bSomethingResolved = true; |
425 | } |
426 | |
427 | _ASSERTE(bSomethingResolved); |
428 | } |
429 | |
430 | const BYTE* MscorlibBinder::ConvertSignature(LPHARDCODEDMETASIG pHardcodedSig, const BYTE* pSig) |
431 | { |
432 | CONTRACTL |
433 | { |
434 | THROWS; |
435 | GC_TRIGGERS; |
436 | INJECT_FAULT(COMPlusThrowOM()); |
437 | MODE_ANY; |
438 | } |
439 | CONTRACTL_END |
440 | |
441 | GCX_PREEMP(); |
442 | |
443 | SigBuilder sigBuilder; |
444 | |
445 | BuildConvertedSignature(pSig+1, &sigBuilder); |
446 | |
447 | DWORD cbCount; |
448 | PVOID pSignature = sigBuilder.GetSignature(&cbCount); |
449 | |
450 | { |
451 | CrstHolder ch(&s_SigConvertCrst); |
452 | |
453 | if (*(INT8*)pHardcodedSig->m_pMetaSig < 0) { |
454 | |
455 | BYTE* pResolved = (BYTE*)(void*)(SystemDomain::GetGlobalLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(1) + S_SIZE_T(cbCount))); |
456 | |
457 | _ASSERTE(FitsIn<INT8>(cbCount)); |
458 | *(INT8*)pResolved = static_cast<INT8>(cbCount); |
459 | CopyMemory(pResolved+1, pSignature, cbCount); |
460 | |
461 | // this has to be last, overwrite the pointer to the metasig with the resolved one |
462 | VolatileStore<const BYTE *>(&const_cast<HardCodedMetaSig *>(pHardcodedSig)->m_pMetaSig, pResolved); |
463 | } |
464 | } |
465 | |
466 | return pHardcodedSig->m_pMetaSig; |
467 | } |
468 | |
469 | #endif // #ifndef DACCESS_COMPILE |
470 | |
471 | #ifdef _DEBUG |
472 | void MscorlibBinder::TriggerGCUnderStress() |
473 | { |
474 | CONTRACTL |
475 | { |
476 | THROWS; |
477 | GC_TRIGGERS; |
478 | SO_TOLERANT; |
479 | INJECT_FAULT(ThrowOutOfMemory()); |
480 | } |
481 | CONTRACTL_END; |
482 | |
483 | #ifndef DACCESS_COMPILE |
484 | _ASSERTE (GetThread ()); |
485 | TRIGGERSGC (); |
486 | // Force a GC here because GetClass could trigger GC nondeterminsticly |
487 | if (g_pConfig->GetGCStressLevel() != 0) |
488 | { |
489 | DEBUG_ONLY_REGION(); |
490 | Thread * pThread = GetThread (); |
491 | BOOL bInCoopMode = pThread->PreemptiveGCDisabled (); |
492 | GCX_COOP (); |
493 | if (bInCoopMode) |
494 | { |
495 | pThread->PulseGCMode (); |
496 | } |
497 | } |
498 | #endif //DACCESS_COMPILE |
499 | } |
500 | #endif // _DEBUG |
501 | |
502 | DWORD MscorlibBinder::GetFieldOffset(BinderFieldID id) |
503 | { |
504 | WRAPPER_NO_CONTRACT; |
505 | |
506 | return GetField(id)->GetOffset(); |
507 | } |
508 | |
509 | #ifndef DACCESS_COMPILE |
510 | |
511 | CrstStatic MscorlibBinder::s_SigConvertCrst; |
512 | |
513 | /*static*/ |
514 | void MscorlibBinder::Startup() |
515 | { |
516 | WRAPPER_NO_CONTRACT |
517 | s_SigConvertCrst.Init(CrstSigConvert); |
518 | } |
519 | |
520 | #if defined(_DEBUG) && !defined(CROSSGEN_COMPILE) |
521 | |
522 | // NoClass is used to suppress check for unmanaged and managed size match |
523 | #define NoClass char[USHRT_MAX] |
524 | |
525 | const MscorlibBinder::OffsetAndSizeCheck MscorlibBinder::OffsetsAndSizes[] = |
526 | { |
527 | #define DEFINE_CLASS_U(nameSpace, stringName, unmanagedType) \ |
528 | { PTR_CSTR((TADDR) g_ ## nameSpace ## NS ), PTR_CUTF8((TADDR) # stringName), sizeof(unmanagedType), 0, 0, 0 }, |
529 | |
530 | #define DEFINE_FIELD_U(stringName, unmanagedContainingType, unmanagedOffset) \ |
531 | { 0, 0, 0, PTR_CUTF8((TADDR) # stringName), offsetof(unmanagedContainingType, unmanagedOffset), sizeof(((unmanagedContainingType*)1)->unmanagedOffset) }, |
532 | #include "mscorlib.h" |
533 | }; |
534 | |
535 | // |
536 | // check the basic consistency between mscorlib and mscorwks |
537 | // |
538 | void MscorlibBinder::Check() |
539 | { |
540 | STANDARD_VM_CONTRACT; |
541 | |
542 | MethodTable * pMT = NULL; |
543 | |
544 | for (unsigned i = 0; i < NumItems(OffsetsAndSizes); i++) |
545 | { |
546 | const OffsetAndSizeCheck * p = OffsetsAndSizes + i; |
547 | |
548 | if (p->className != NULL) |
549 | { |
550 | pMT = ClassLoader::LoadTypeByNameThrowing(GetModule()->GetAssembly(), p->classNameSpace, p->className).AsMethodTable(); |
551 | |
552 | if (p->expectedClassSize == sizeof(NoClass)) |
553 | continue; |
554 | |
555 | // hidden size of the type that participates in the alignment calculation |
556 | DWORD hiddenSize = pMT->IsValueType() ? sizeof(MethodTable*) : 0; |
557 | |
558 | DWORD size = pMT->GetBaseSize() - (sizeof(ObjHeader)+hiddenSize); |
559 | |
560 | DWORD expectedsize = (DWORD)ALIGN_UP(p->expectedClassSize + (sizeof(ObjHeader) + hiddenSize), |
561 | DATA_ALIGNMENT) - (sizeof(ObjHeader) + hiddenSize); |
562 | |
563 | CONSISTENCY_CHECK_MSGF(size == expectedsize, |
564 | ("Managed object size does not match unmanaged object size\n" |
565 | "man: 0x%x, unman: 0x%x, Name: %s\n" , size, expectedsize, pMT->GetDebugClassName())); |
566 | } |
567 | else |
568 | if (p->fieldName != NULL) |
569 | { |
570 | // This assert will fire if there is DEFINE_FIELD_U macro without preceeding DEFINE_CLASS_U macro in mscorlib.h |
571 | _ASSERTE(pMT != NULL); |
572 | |
573 | FieldDesc * pFD = MemberLoader::FindField(pMT, p->fieldName, NULL, 0, NULL); |
574 | _ASSERTE(pFD != NULL); |
575 | |
576 | DWORD offset = pFD->GetOffset(); |
577 | |
578 | if (!pFD->IsFieldOfValueType()) |
579 | { |
580 | offset += Object::GetOffsetOfFirstField(); |
581 | } |
582 | |
583 | CONSISTENCY_CHECK_MSGF(offset == p->expectedFieldOffset, |
584 | ("Managed class field offset does not match unmanaged class field offset\n" |
585 | "man: 0x%x, unman: 0x%x, Class: %s, Name: %s\n" , offset, p->expectedFieldOffset, pFD->GetApproxEnclosingMethodTable()->GetDebugClassName(), pFD->GetName())); |
586 | |
587 | DWORD size = pFD->LoadSize(); |
588 | |
589 | CONSISTENCY_CHECK_MSGF(size == p->expectedFieldSize, |
590 | ("Managed class field size does not match unmanaged class field size\n" |
591 | "man: 0x%x, unman: 0x%x, Class: %s, Name: %s\n" , size, p->expectedFieldSize, pFD->GetApproxEnclosingMethodTable()->GetDebugClassName(), pFD->GetName())); |
592 | } |
593 | } |
594 | } |
595 | |
596 | #ifdef CHECK_FCALL_SIGNATURE |
597 | // |
598 | // check consistency of the unmanaged and managed fcall signatures |
599 | // |
600 | /* static */ FCSigCheck* FCSigCheck::g_pFCSigCheck; |
601 | const char * aType[] = |
602 | { |
603 | "void" , |
604 | "FC_BOOL_RET" , |
605 | "CLR_BOOL" , |
606 | "FC_CHAR_RET" , |
607 | "CLR_CHAR" , |
608 | "FC_INT8_RET" , |
609 | "INT8" , |
610 | "FC_UINT8_RET" , |
611 | "UINT8" , |
612 | "FC_INT16_RET" , |
613 | "INT16" , |
614 | "FC_UINT16_RET" , |
615 | "UINT16" , |
616 | "INT64" , |
617 | "VINT64" , |
618 | "UINT64" , |
619 | "VUINT64" , |
620 | "float" , |
621 | "Vfloat" , |
622 | "double" , |
623 | "Vdouble" |
624 | }; |
625 | |
626 | const char * aInt32Type[] = |
627 | { |
628 | "INT32" , |
629 | "UINT32" , // we might remove it to have a better check |
630 | "int" , |
631 | "unsigned int" , // we might remove it to have a better check |
632 | "DWORD" , // we might remove it to have a better check |
633 | "HRESULT" , // we might remove it to have a better check |
634 | "mdToken" , // we might remove it to have a better check |
635 | "ULONG" , // we might remove it to have a better check |
636 | "mdMemberRef" , // we might remove it to have a better check |
637 | "mdCustomAttribute" , // we might remove it to have a better check |
638 | "mdTypeDef" , // we might remove it to have a better check |
639 | "mdFieldDef" , // we might remove it to have a better check |
640 | "LONG" , |
641 | "CLR_I4" , |
642 | "LCID" // we might remove it to have a better check |
643 | }; |
644 | |
645 | const char * aUInt32Type[] = |
646 | { |
647 | "UINT32" , |
648 | "unsigned int" , |
649 | "DWORD" , |
650 | "INT32" , // we might remove it to have a better check |
651 | "ULONG" |
652 | }; |
653 | |
654 | static BOOL IsStrInArray(const char* sStr, size_t len, const char* aStrArray[], int nSize) |
655 | { |
656 | STANDARD_VM_CONTRACT; |
657 | for (int i = 0; i < nSize; i++) |
658 | { |
659 | if (SString::_strnicmp(aStrArray[i], sStr, (COUNT_T)len) == 0) |
660 | { |
661 | return TRUE; |
662 | } |
663 | } |
664 | return FALSE; |
665 | } |
666 | |
667 | static void FCallCheckSignature(MethodDesc* pMD, PCODE pImpl) |
668 | { |
669 | STANDARD_VM_CONTRACT; |
670 | |
671 | const char* pUnmanagedSig = NULL; |
672 | |
673 | FCSigCheck* pSigCheck = FCSigCheck::g_pFCSigCheck; |
674 | while (pSigCheck != NULL) |
675 | { |
676 | if (pImpl == (PCODE)pSigCheck->func) { |
677 | pUnmanagedSig = pSigCheck->signature; |
678 | break; |
679 | } |
680 | pSigCheck = pSigCheck->next; |
681 | } |
682 | |
683 | MetaSig msig(pMD); |
684 | int argIndex = -2; // start with return value |
685 | int enregisteredArguments = 0; |
686 | const char* pUnmanagedArg = pUnmanagedSig; |
687 | for (;;) |
688 | { |
689 | CorElementType argType = ELEMENT_TYPE_END; |
690 | TypeHandle argTypeHandle; |
691 | |
692 | if (argIndex == -2) |
693 | { |
694 | // return value |
695 | argType = msig.GetReturnType(); |
696 | if (argType == ELEMENT_TYPE_VALUETYPE) |
697 | argTypeHandle = msig.GetRetTypeHandleThrowing(); |
698 | } |
699 | |
700 | if (argIndex == -1) |
701 | { |
702 | // this ptr |
703 | if (msig.HasThis()) |
704 | argType = ELEMENT_TYPE_CLASS; |
705 | else |
706 | argIndex++; // move on to the first argument |
707 | } |
708 | |
709 | if (argIndex >= 0) |
710 | { |
711 | argType = msig.NextArg(); |
712 | if (argType == ELEMENT_TYPE_END) |
713 | break; |
714 | if (argType == ELEMENT_TYPE_VALUETYPE) |
715 | argTypeHandle = msig.GetLastTypeHandleThrowing(); |
716 | } |
717 | |
718 | const char* expectedType = NULL; |
719 | |
720 | switch (argType) |
721 | { |
722 | case ELEMENT_TYPE_VOID: |
723 | expectedType = pMD->IsCtor() ? NULL : "void" ; |
724 | break; |
725 | case ELEMENT_TYPE_BOOLEAN: |
726 | expectedType = (argIndex == -2) ? "FC_BOOL_RET" : "CLR_BOOL" ; |
727 | break; |
728 | case ELEMENT_TYPE_CHAR: |
729 | expectedType = (argIndex == -2) ? "FC_CHAR_RET" : "CLR_CHAR" ; |
730 | break; |
731 | case ELEMENT_TYPE_I1: |
732 | expectedType = (argIndex == -2) ? "FC_INT8_RET" : "INT8" ; |
733 | break; |
734 | case ELEMENT_TYPE_U1: |
735 | expectedType = (argIndex == -2) ? "FC_UINT8_RET" : "UINT8" ; |
736 | break; |
737 | case ELEMENT_TYPE_I2: |
738 | expectedType = (argIndex == -2) ? "FC_INT16_RET" : "INT16" ; |
739 | break; |
740 | case ELEMENT_TYPE_U2: |
741 | expectedType = (argIndex == -2) ? "FC_UINT16_RET" : "UINT16" ; |
742 | break; |
743 | //case ELEMENT_TYPE_I4: |
744 | // expectedType = "INT32"; |
745 | // break; |
746 | // case ELEMENT_TYPE_U4: |
747 | // expectedType = "UINT32"; |
748 | // break; |
749 | |
750 | // See the comments in fcall.h on what the "V" prefix means. |
751 | case ELEMENT_TYPE_I8: |
752 | expectedType = ((argIndex == -2) || (enregisteredArguments >= 2)) ? "INT64" : "VINT64" ; |
753 | break; |
754 | case ELEMENT_TYPE_U8: |
755 | expectedType = ((argIndex == -2) || (enregisteredArguments >= 2)) ? "UINT64" : "VUINT64" ; |
756 | break; |
757 | case ELEMENT_TYPE_R4: |
758 | expectedType = ((argIndex == -2) || (enregisteredArguments >= 2)) ? "float" : "Vfloat" ; |
759 | break; |
760 | case ELEMENT_TYPE_R8: |
761 | expectedType = ((argIndex == -2) || (enregisteredArguments >= 2)) ? "double" : "Vdouble" ; |
762 | break; |
763 | default: |
764 | // no checks for other types |
765 | break; |
766 | } |
767 | |
768 | // Count number of enregistered arguments for x86 |
769 | if ((argIndex != -2) && !((expectedType != NULL) && (*expectedType == 'V'))) |
770 | { |
771 | enregisteredArguments++; |
772 | } |
773 | |
774 | if (pUnmanagedSig != NULL) |
775 | { |
776 | CONSISTENCY_CHECK_MSGF(pUnmanagedArg != NULL, |
777 | ("Unexpected end of managed fcall signature\n" |
778 | "Method: %s:%s\n" , pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName)); |
779 | |
780 | const char* pUnmanagedArgEnd = strchr(pUnmanagedArg, ','); |
781 | |
782 | const char* pUnmanagedTypeEnd = (pUnmanagedArgEnd != NULL) ? |
783 | pUnmanagedArgEnd : (pUnmanagedArg + strlen(pUnmanagedArg)); |
784 | |
785 | if (argIndex != -2) |
786 | { |
787 | // skip argument name |
788 | while(pUnmanagedTypeEnd > pUnmanagedArg) |
789 | { |
790 | char c = *(pUnmanagedTypeEnd-1); |
791 | if ((c != '_') |
792 | && ((c < '0') || ('9' < c)) |
793 | && ((c < 'a') || ('z' < c)) |
794 | && ((c < 'A') || ('Z' < c))) |
795 | break; |
796 | pUnmanagedTypeEnd--; |
797 | } |
798 | } |
799 | |
800 | // skip whitespaces |
801 | while(pUnmanagedTypeEnd > pUnmanagedArg) |
802 | { |
803 | char c = *(pUnmanagedTypeEnd-1); |
804 | if ((c != 0x20) && (c != '\t') && (c != '\n') && (c != '\r')) |
805 | break; |
806 | pUnmanagedTypeEnd--; |
807 | } |
808 | |
809 | size_t len = pUnmanagedTypeEnd - pUnmanagedArg; |
810 | // generate the unmanaged argument signature to show them in the error message if possible |
811 | StackSString ssUnmanagedType(SString::Ascii, pUnmanagedArg, (COUNT_T)len); |
812 | StackScratchBuffer buffer; |
813 | const char * pUnManagedType = ssUnmanagedType.GetANSI(buffer); |
814 | |
815 | if (expectedType != NULL) |
816 | { |
817 | // when managed type is well known |
818 | if (!(strlen(expectedType) == len && SString::_strnicmp(expectedType, pUnmanagedArg, (COUNT_T)len) == 0)) |
819 | { |
820 | printf("CheckExtended: The managed and unmanaged fcall signatures do not match, Method: %s:%s. Argument: %d Expecting: %s Actual: %s\n" , pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, argIndex, expectedType, pUnManagedType); |
821 | } |
822 | } |
823 | else |
824 | { |
825 | // when managed type is not wellknown, we still can find sig mismatch if native type is a well known type |
826 | BOOL bSigError = false; |
827 | if (argType == ELEMENT_TYPE_VOID && pMD->IsCtor()) |
828 | { |
829 | bSigError = false; |
830 | } |
831 | else if (argType == ELEMENT_TYPE_I4) |
832 | { |
833 | bSigError = !IsStrInArray(pUnmanagedArg, len, aInt32Type, NumItems(aInt32Type)); |
834 | } |
835 | else if (argType == ELEMENT_TYPE_U4) |
836 | { |
837 | bSigError = !IsStrInArray(pUnmanagedArg, len, aUInt32Type, NumItems(aUInt32Type)); |
838 | } |
839 | else if (argType == ELEMENT_TYPE_VALUETYPE) |
840 | { |
841 | // we already did special check for value type |
842 | bSigError = false; |
843 | } |
844 | else |
845 | { |
846 | bSigError = IsStrInArray(pUnmanagedArg, len, aType, NumItems(aType)); |
847 | } |
848 | if (bSigError) |
849 | { |
850 | printf("CheckExtended: The managed and unmanaged fcall signatures do not match, Method: %s:%s. Argument: %d Expecting: (CorElementType)%d actual: %s\n" , pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, argIndex, argType, pUnManagedType); |
851 | } |
852 | } |
853 | pUnmanagedArg = (pUnmanagedArgEnd != NULL) ? (pUnmanagedArgEnd+1) : NULL; |
854 | } |
855 | |
856 | argIndex++; |
857 | } |
858 | |
859 | if (pUnmanagedSig != NULL) |
860 | { |
861 | if (msig.IsVarArg()) |
862 | { |
863 | if (!((pUnmanagedArg != NULL) && strcmp(pUnmanagedArg, "..." ) == 0)) |
864 | { |
865 | printf("CheckExtended: Expecting varargs in unmanaged fcall signature, Method: %s:%s\n" , pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName); |
866 | } |
867 | } |
868 | else |
869 | { |
870 | if (!(pUnmanagedArg == NULL)) |
871 | { |
872 | printf("CheckExtended: Unexpected end of unmanaged fcall signature, Method: %s:%s\n" , pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName); |
873 | } |
874 | } |
875 | } |
876 | } |
877 | #endif // CHECK_FCALL_SIGNATURE |
878 | |
879 | // |
880 | // extended check of consistency between mscorlib and mscorwks: |
881 | // - verifies that all references from mscorlib to mscorwks are present |
882 | // - verifies that all references from mscorwks to mscorlib are present |
883 | // - limited detection of mismatches between managed and unmanaged fcall signatures |
884 | // |
885 | void MscorlibBinder::CheckExtended() |
886 | { |
887 | STANDARD_VM_CONTRACT; |
888 | |
889 | // check the consistency of BCL and VM |
890 | // note: it is not enabled by default because of it is time consuming and |
891 | // changes the bootstrap sequence of the EE |
892 | if (!CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ConsistencyCheck)) |
893 | return; |
894 | |
895 | // |
896 | // VM referencing BCL (mscorlib.h) |
897 | // |
898 | for (BinderClassID cID = (BinderClassID) 1; (int)cID < m_cClasses; cID = (BinderClassID) (cID + 1)) |
899 | { |
900 | bool fError = false; |
901 | EX_TRY |
902 | { |
903 | if (MscorlibBinder::GetClassName(cID) != NULL) // Allow for CorSigElement entries with no classes |
904 | { |
905 | if (NULL == MscorlibBinder::GetClass(cID)) |
906 | { |
907 | fError = true; |
908 | } |
909 | } |
910 | } |
911 | EX_CATCH |
912 | { |
913 | fError = true; |
914 | } |
915 | EX_END_CATCH(SwallowAllExceptions) |
916 | |
917 | if (fError) |
918 | { |
919 | printf("CheckExtended: VM expects type to exist: %s.%s\n" , MscorlibBinder::GetClassNameSpace(cID), MscorlibBinder::GetClassName(cID)); |
920 | } |
921 | } |
922 | |
923 | for (BinderMethodID mID = (BinderMethodID) 1; mID < (BinderMethodID) MscorlibBinder::m_cMethods; mID = (BinderMethodID) (mID + 1)) |
924 | { |
925 | bool fError = false; |
926 | BinderClassID cID = m_methodDescriptions[mID-1].classID; |
927 | EX_TRY |
928 | { |
929 | if (NULL == MscorlibBinder::GetMethod(mID)) |
930 | { |
931 | fError = true; |
932 | } |
933 | } |
934 | EX_CATCH |
935 | { |
936 | fError = true; |
937 | } |
938 | EX_END_CATCH(SwallowAllExceptions) |
939 | |
940 | if (fError) |
941 | { |
942 | printf("CheckExtended: VM expects method to exist: %s.%s::%s\n" , MscorlibBinder::GetClassNameSpace(cID), MscorlibBinder::GetClassName(cID), MscorlibBinder::GetMethodName(mID)); |
943 | } |
944 | } |
945 | |
946 | for (BinderFieldID fID = (BinderFieldID) 1; fID < (BinderFieldID) MscorlibBinder::m_cFields; fID = (BinderFieldID) (fID + 1)) |
947 | { |
948 | bool fError = false; |
949 | BinderClassID cID = m_fieldDescriptions[fID-1].classID; |
950 | EX_TRY |
951 | { |
952 | if (NULL == MscorlibBinder::GetField(fID)) |
953 | { |
954 | fError = true; |
955 | } |
956 | } |
957 | EX_CATCH |
958 | { |
959 | fError = true; |
960 | } |
961 | EX_END_CATCH(SwallowAllExceptions) |
962 | |
963 | if (fError) |
964 | { |
965 | printf("CheckExtended: VM expects field to exist: %s.%s::%s\n" , MscorlibBinder::GetClassNameSpace(cID), MscorlibBinder::GetClassName(cID), MscorlibBinder::GetFieldName(fID)); |
966 | } |
967 | } |
968 | |
969 | // |
970 | // BCL referencing VM (ecall.cpp) |
971 | // |
972 | SetSHash<DWORD> usedECallIds; |
973 | |
974 | HRESULT hr = S_OK; |
975 | Module *pModule = MscorlibBinder::m_pModule; |
976 | IMDInternalImport *pInternalImport = pModule->GetMDImport(); |
977 | |
978 | HENUMInternal hEnum; |
979 | |
980 | // for all methods... |
981 | IfFailGo(pInternalImport->EnumAllInit(mdtMethodDef, &hEnum)); |
982 | |
983 | for (;;) { |
984 | mdTypeDef td; |
985 | mdTypeDef tdClass; |
986 | DWORD dwImplFlags; |
987 | DWORD dwMemberAttrs; |
988 | |
989 | if (!pInternalImport->EnumNext(&hEnum, &td)) |
990 | break; |
991 | |
992 | pInternalImport->GetMethodImplProps(td, NULL, &dwImplFlags); |
993 | |
994 | IfFailGo(pInternalImport->GetMethodDefProps(td, &dwMemberAttrs)); |
995 | |
996 | // ... that are internal calls ... |
997 | if (!IsMiInternalCall(dwImplFlags) && !IsMdPinvokeImpl(dwMemberAttrs)) |
998 | continue; |
999 | |
1000 | IfFailGo(pInternalImport->GetParentToken(td, &tdClass)); |
1001 | |
1002 | TypeHandle type; |
1003 | |
1004 | EX_TRY |
1005 | { |
1006 | type = ClassLoader::LoadTypeDefOrRefThrowing(pModule, tdClass, |
1007 | ClassLoader::ThrowIfNotFound, |
1008 | ClassLoader::PermitUninstDefOrRef); |
1009 | } |
1010 | EX_CATCH |
1011 | { |
1012 | LPCUTF8 pszClassName; |
1013 | LPCUTF8 pszNameSpace; |
1014 | if (FAILED(pInternalImport->GetNameOfTypeDef(tdClass, &pszClassName, &pszNameSpace))) |
1015 | { |
1016 | pszClassName = pszNameSpace = "Invalid TypeDef record" ; |
1017 | } |
1018 | printf("CheckExtended: Unable to load class from mscorlib: %s.%s\n" , pszNameSpace, pszClassName); |
1019 | } |
1020 | EX_END_CATCH(SwallowAllExceptions) |
1021 | |
1022 | MethodDesc *pMD = MemberLoader::FindMethod(type.AsMethodTable(), td); |
1023 | _ASSERTE(pMD); |
1024 | |
1025 | // Required to support generic FCalls (only instance methods on generic types constrained to "class" are allowed) |
1026 | if (type.IsGenericTypeDefinition()) { |
1027 | pMD = pMD->FindOrCreateTypicalSharedInstantiation(); |
1028 | } |
1029 | |
1030 | DWORD id = 0; |
1031 | |
1032 | if (pMD->IsFCall()) |
1033 | { |
1034 | id = ((FCallMethodDesc *)pMD)->GetECallID(); |
1035 | if (id == 0) { |
1036 | id = ECall::GetIDForMethod(pMD); |
1037 | } |
1038 | } |
1039 | else |
1040 | if (pMD->IsNDirect()) |
1041 | { |
1042 | PInvokeStaticSigInfo sigInfo; |
1043 | NDirect::PopulateNDirectMethodDesc((NDirectMethodDesc *)pMD, &sigInfo); |
1044 | |
1045 | if (pMD->IsQCall()) |
1046 | { |
1047 | id = ((NDirectMethodDesc *)pMD)->GetECallID(); |
1048 | if (id == 0) { |
1049 | id = ECall::GetIDForMethod(pMD); |
1050 | } |
1051 | } |
1052 | else |
1053 | { |
1054 | continue; |
1055 | } |
1056 | } |
1057 | else |
1058 | { |
1059 | continue; |
1060 | } |
1061 | |
1062 | // ... check that the method is in the fcall table. |
1063 | if (id == 0) { |
1064 | LPCUTF8 pszClassName; |
1065 | LPCUTF8 pszNameSpace; |
1066 | if (FAILED(pInternalImport->GetNameOfTypeDef(tdClass, &pszClassName, &pszNameSpace))) |
1067 | { |
1068 | pszClassName = pszNameSpace = "Invalid TypeDef record" ; |
1069 | } |
1070 | LPCUTF8 pszName; |
1071 | if (FAILED(pInternalImport->GetNameOfMethodDef(td, &pszName))) |
1072 | { |
1073 | pszName = "Invalid method name" ; |
1074 | } |
1075 | printf("CheckExtended: Unable to find internalcall implementation: %s.%s::%s\n" , pszNameSpace, pszClassName, pszName); |
1076 | } |
1077 | |
1078 | if (id != 0) |
1079 | { |
1080 | usedECallIds.Add(id); |
1081 | } |
1082 | |
1083 | #ifdef CHECK_FCALL_SIGNATURE |
1084 | if (pMD->IsFCall()) |
1085 | { |
1086 | FCallCheckSignature(pMD, ECall::GetFCallImpl(pMD)); |
1087 | } |
1088 | #endif // CHECK_FCALL_SIGNATURE |
1089 | } |
1090 | |
1091 | pInternalImport->EnumClose(&hEnum); |
1092 | |
1093 | // Verify that there are no unused entries in the ecall table |
1094 | ECall::CheckUnusedECalls(usedECallIds); |
1095 | |
1096 | // |
1097 | // Stub constants |
1098 | // |
1099 | #define ASMCONSTANTS_C_ASSERT(cond) |
1100 | #define ASMCONSTANTS_RUNTIME_ASSERT(cond) _ASSERTE(cond) |
1101 | #include "asmconstants.h" |
1102 | |
1103 | _ASSERTE(sizeof(VARIANT) == MscorlibBinder::GetClass(CLASS__NATIVEVARIANT)->GetNativeSize()); |
1104 | |
1105 | printf("CheckExtended: completed without exception.\n" ); |
1106 | |
1107 | ErrExit: |
1108 | _ASSERTE(SUCCEEDED(hr)); |
1109 | } |
1110 | |
1111 | #endif // _DEBUG && !CROSSGEN_COMPILE |
1112 | |
1113 | extern const MscorlibClassDescription c_rgMscorlibClassDescriptions[]; |
1114 | extern const USHORT c_nMscorlibClassDescriptions; |
1115 | |
1116 | extern const MscorlibMethodDescription c_rgMscorlibMethodDescriptions[]; |
1117 | extern const USHORT c_nMscorlibMethodDescriptions; |
1118 | |
1119 | extern const MscorlibFieldDescription c_rgMscorlibFieldDescriptions[]; |
1120 | extern const USHORT c_nMscorlibFieldDescriptions; |
1121 | |
1122 | #ifdef CROSSGEN_COMPILE |
1123 | namespace CrossGenMscorlib |
1124 | { |
1125 | extern const MscorlibClassDescription c_rgMscorlibClassDescriptions[]; |
1126 | extern const USHORT c_nMscorlibClassDescriptions; |
1127 | |
1128 | extern const MscorlibMethodDescription c_rgMscorlibMethodDescriptions[]; |
1129 | extern const USHORT c_nMscorlibMethodDescriptions; |
1130 | |
1131 | extern const MscorlibFieldDescription c_rgMscorlibFieldDescriptions[]; |
1132 | extern const USHORT c_nMscorlibFieldDescriptions; |
1133 | }; |
1134 | #endif |
1135 | |
1136 | void MscorlibBinder::AttachModule(Module * pModule) |
1137 | { |
1138 | STANDARD_VM_CONTRACT; |
1139 | |
1140 | MscorlibBinder * pGlobalBinder = &g_Mscorlib; |
1141 | |
1142 | pGlobalBinder->SetDescriptions(pModule, |
1143 | c_rgMscorlibClassDescriptions, c_nMscorlibClassDescriptions, |
1144 | c_rgMscorlibMethodDescriptions, c_nMscorlibMethodDescriptions, |
1145 | c_rgMscorlibFieldDescriptions, c_nMscorlibFieldDescriptions); |
1146 | |
1147 | #if defined(FEATURE_PREJIT) && !defined(CROSSGEN_COMPILE) |
1148 | MscorlibBinder * pPersistedBinder = pModule->m_pBinder; |
1149 | |
1150 | if (pPersistedBinder != NULL |
1151 | // Do not use persisted binder for profiling native images. See comment in code:MscorlibBinder::Fixup. |
1152 | && !(pModule->GetNativeImage()->GetNativeVersionInfo()->wConfigFlags & CORCOMPILE_CONFIG_PROFILING)) |
1153 | { |
1154 | pGlobalBinder->m_pClasses = pPersistedBinder->m_pClasses; |
1155 | pGlobalBinder->m_pMethods = pPersistedBinder->m_pMethods; |
1156 | pGlobalBinder->m_pFields = pPersistedBinder->m_pFields; |
1157 | |
1158 | pModule->m_pBinder = pGlobalBinder; |
1159 | return; |
1160 | } |
1161 | #endif // FEATURE_PREJIT && CROSSGEN_COMPILE |
1162 | |
1163 | pGlobalBinder->AllocateTables(); |
1164 | |
1165 | #ifdef CROSSGEN_COMPILE |
1166 | MscorlibBinder * pTargetBinder = (MscorlibBinder *)(void *) |
1167 | pModule->GetAssembly()->GetLowFrequencyHeap() |
1168 | ->AllocMem(S_SIZE_T(sizeof(MscorlibBinder))); |
1169 | |
1170 | pTargetBinder->SetDescriptions(pModule, |
1171 | CrossGenMscorlib::c_rgMscorlibClassDescriptions, CrossGenMscorlib::c_nMscorlibClassDescriptions, |
1172 | CrossGenMscorlib::c_rgMscorlibMethodDescriptions, CrossGenMscorlib::c_nMscorlibMethodDescriptions, |
1173 | CrossGenMscorlib::c_rgMscorlibFieldDescriptions, CrossGenMscorlib::c_nMscorlibFieldDescriptions); |
1174 | |
1175 | pTargetBinder->AllocateTables(); |
1176 | |
1177 | pModule->m_pBinder = pTargetBinder; |
1178 | #else |
1179 | pModule->m_pBinder = pGlobalBinder; |
1180 | #endif |
1181 | } |
1182 | |
1183 | void MscorlibBinder::SetDescriptions(Module * pModule, |
1184 | const MscorlibClassDescription * pClassDescriptions, USHORT nClasses, |
1185 | const MscorlibMethodDescription * pMethodDescriptions, USHORT nMethods, |
1186 | const MscorlibFieldDescription * pFieldDescriptions, USHORT nFields) |
1187 | { |
1188 | LIMITED_METHOD_CONTRACT; |
1189 | |
1190 | m_pModule = pModule; |
1191 | |
1192 | m_classDescriptions = pClassDescriptions; |
1193 | m_cClasses = nClasses; |
1194 | |
1195 | m_methodDescriptions = pMethodDescriptions; |
1196 | m_cMethods = nMethods; |
1197 | |
1198 | m_fieldDescriptions = pFieldDescriptions; |
1199 | m_cFields = nFields; |
1200 | } |
1201 | |
1202 | void MscorlibBinder::AllocateTables() |
1203 | { |
1204 | STANDARD_VM_CONTRACT; |
1205 | |
1206 | LoaderHeap * pHeap = m_pModule->GetAssembly()->GetLowFrequencyHeap(); |
1207 | |
1208 | m_pClasses = (MethodTable **)(void *) |
1209 | pHeap->AllocMem(S_SIZE_T(m_cClasses) * S_SIZE_T(sizeof(*m_pClasses))); |
1210 | // Note: Memory allocated on loader heap is zero filled |
1211 | // ZeroMemory(m_pClasses, m_cClasses * sizeof(*m_pClasses)); |
1212 | |
1213 | m_pMethods = (MethodDesc **)(void *) |
1214 | pHeap->AllocMem(S_SIZE_T(m_cMethods) * S_SIZE_T(sizeof(*m_pMethods))); |
1215 | // Note: Memory allocated on loader heap is zero filled |
1216 | // ZeroMemory(m_pMethods, m_cMethodMDs * sizeof(*m_pMethods)); |
1217 | |
1218 | m_pFields = (FieldDesc **)(void *) |
1219 | pHeap->AllocMem(S_SIZE_T(m_cFields) * S_SIZE_T(sizeof(*m_pFields))); |
1220 | // Note: Memory allocated on loader heap is zero filled |
1221 | // ZeroMemory(m_pFields, m_cFieldRIDs * sizeof(*m_pFields)); |
1222 | } |
1223 | |
1224 | PTR_MethodTable MscorlibBinder::LoadPrimitiveType(CorElementType et) |
1225 | { |
1226 | STANDARD_VM_CONTRACT; |
1227 | |
1228 | PTR_MethodTable pMT = g_Mscorlib.m_pClasses[et]; |
1229 | |
1230 | // Primitive types hit cyclic reference on binder during type loading so we have to load them in two steps |
1231 | if (pMT == NULL) |
1232 | { |
1233 | const MscorlibClassDescription *d = (&g_Mscorlib)->m_classDescriptions + (int)et; |
1234 | |
1235 | pMT = ClassLoader::LoadTypeByNameThrowing(GetModule()->GetAssembly(), d->nameSpace, d->name, |
1236 | ClassLoader::ThrowIfNotFound, ClassLoader::LoadTypes, CLASS_LOAD_APPROXPARENTS).AsMethodTable(); |
1237 | g_Mscorlib.m_pClasses[et] = pMT; |
1238 | |
1239 | ClassLoader::EnsureLoaded(pMT); |
1240 | } |
1241 | |
1242 | return pMT; |
1243 | } |
1244 | |
1245 | #ifdef FEATURE_NATIVE_IMAGE_GENERATION |
1246 | void MscorlibBinder::BindAll() |
1247 | { |
1248 | STANDARD_VM_CONTRACT; |
1249 | |
1250 | for (BinderClassID cID = (BinderClassID) 1; cID < m_cClasses; cID = (BinderClassID) (cID + 1)) |
1251 | { |
1252 | if (m_classDescriptions[cID].name != NULL) // Allow for CorSigElement entries with no classes |
1253 | GetClassLocal(cID); |
1254 | } |
1255 | |
1256 | for (BinderMethodID mID = (BinderMethodID) 1; mID < m_cMethods; mID = (BinderMethodID) (mID + 1)) |
1257 | GetMethodLocal(mID); |
1258 | |
1259 | for (BinderFieldID fID = (BinderFieldID) 1; fID < m_cFields; fID = (BinderFieldID) (fID + 1)) |
1260 | GetFieldLocal(fID); |
1261 | } |
1262 | |
1263 | void MscorlibBinder::Save(DataImage *image) |
1264 | { |
1265 | STANDARD_VM_CONTRACT; |
1266 | |
1267 | image->StoreStructure(this, sizeof(MscorlibBinder), |
1268 | DataImage::ITEM_BINDER); |
1269 | |
1270 | image->StoreStructure(m_pClasses, m_cClasses * sizeof(*m_pClasses), |
1271 | DataImage::ITEM_BINDER_ITEMS); |
1272 | |
1273 | image->StoreStructure(m_pMethods, m_cMethods * sizeof(*m_pMethods), |
1274 | DataImage::ITEM_BINDER_ITEMS); |
1275 | |
1276 | image->StoreStructure(m_pFields, m_cFields * sizeof(*m_pFields), |
1277 | DataImage::ITEM_BINDER_ITEMS); |
1278 | } |
1279 | |
1280 | void MscorlibBinder::Fixup(DataImage *image) |
1281 | { |
1282 | STANDARD_VM_CONTRACT; |
1283 | |
1284 | image->FixupPointerField(this, offsetof(MscorlibBinder, m_pModule)); |
1285 | |
1286 | int i; |
1287 | |
1288 | image->FixupPointerField(this, offsetof(MscorlibBinder, m_pClasses)); |
1289 | for (i = 1; i < m_cClasses; i++) |
1290 | { |
1291 | #if _DEBUG |
1292 | // |
1293 | // We do not want to check for restore at runtime for performance reasons. |
1294 | // If there is ever a case that requires restore, it should be special |
1295 | // cased here and restored explicitly by GetClass/GetField/GetMethod caller. |
1296 | // |
1297 | // Profiling NGen images force restore for all types. We are still going to save |
1298 | // the binder for nidump, but we are not going to use it at runtime. |
1299 | // |
1300 | if (m_pClasses[i] != NULL && !GetAppDomain()->ToCompilationDomain()->m_fForceProfiling) |
1301 | { |
1302 | _ASSERTE(!m_pClasses[i]->NeedsRestore(image)); |
1303 | } |
1304 | #endif |
1305 | image->FixupPointerField(m_pClasses, i * sizeof(m_pClasses[0])); |
1306 | } |
1307 | |
1308 | image->FixupPointerField(this, offsetof(MscorlibBinder, m_pMethods)); |
1309 | for (i = 1; i < m_cMethods; i++) |
1310 | { |
1311 | #if _DEBUG |
1312 | // See comment above. |
1313 | if (m_pMethods[i] != NULL && !GetAppDomain()->ToCompilationDomain()->m_fForceProfiling) |
1314 | { |
1315 | _ASSERTE(!m_pMethods[i]->NeedsRestore(image)); |
1316 | } |
1317 | #endif |
1318 | |
1319 | image->FixupPointerField(m_pMethods, i * sizeof(m_pMethods[0])); |
1320 | } |
1321 | |
1322 | image->FixupPointerField(this, offsetof(MscorlibBinder, m_pFields)); |
1323 | for (i = 1; i < m_cFields; i++) |
1324 | { |
1325 | image->FixupPointerField(m_pFields, i * sizeof(m_pFields[0])); |
1326 | } |
1327 | |
1328 | image->ZeroPointerField(this, offsetof(MscorlibBinder, m_classDescriptions)); |
1329 | image->ZeroPointerField(this, offsetof(MscorlibBinder, m_methodDescriptions)); |
1330 | image->ZeroPointerField(this, offsetof(MscorlibBinder, m_fieldDescriptions)); |
1331 | } |
1332 | #endif // FEATURE_NATIVE_IMAGE_GENERATION |
1333 | |
1334 | #endif // #ifndef DACCESS_COMPILE |
1335 | |
1336 | #ifdef DACCESS_COMPILE |
1337 | |
1338 | void |
1339 | MscorlibBinder::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) |
1340 | { |
1341 | SUPPORTS_DAC; |
1342 | DAC_ENUM_DTHIS(); |
1343 | |
1344 | DacEnumMemoryRegion(dac_cast<TADDR>(m_classDescriptions), |
1345 | m_cClasses * sizeof(MscorlibClassDescription)); |
1346 | DacEnumMemoryRegion(dac_cast<TADDR>(m_methodDescriptions), |
1347 | (m_cMethods - 1) * sizeof(MscorlibMethodDescription)); |
1348 | DacEnumMemoryRegion(dac_cast<TADDR>(m_fieldDescriptions), |
1349 | (m_cFields - 1) * sizeof(MscorlibFieldDescription)); |
1350 | |
1351 | if (m_pModule.IsValid()) |
1352 | { |
1353 | m_pModule->EnumMemoryRegions(flags, true); |
1354 | } |
1355 | |
1356 | DacEnumMemoryRegion(dac_cast<TADDR>(m_pClasses), |
1357 | m_cClasses * sizeof(PTR_MethodTable)); |
1358 | DacEnumMemoryRegion(dac_cast<TADDR>(m_pMethods), |
1359 | m_cMethods * sizeof(PTR_MethodDesc)); |
1360 | DacEnumMemoryRegion(dac_cast<TADDR>(m_pFields), |
1361 | m_cFields * sizeof(PTR_FieldDesc)); |
1362 | } |
1363 | |
1364 | #endif // #ifdef DACCESS_COMPILE |
1365 | |
1366 | GVAL_IMPL(MscorlibBinder, g_Mscorlib); |
1367 | |