1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | // |
5 | // File: methodtable.inl |
6 | // |
7 | |
8 | |
9 | // |
10 | |
11 | // |
12 | // ============================================================================ |
13 | |
14 | #ifndef _METHODTABLE_INL_ |
15 | #define _METHODTABLE_INL_ |
16 | |
17 | #include "methodtable.h" |
18 | #include "genericdict.h" |
19 | #include "threadstatics.h" |
20 | |
21 | //========================================================================================== |
22 | inline PTR_EEClass MethodTable::GetClass_NoLogging() |
23 | { |
24 | LIMITED_METHOD_DAC_CONTRACT; |
25 | |
26 | TADDR addr = ReadPointer(this, &MethodTable::m_pCanonMT); |
27 | |
28 | #ifdef _DEBUG |
29 | LowBits lowBits = union_getLowBits(addr); |
30 | if (lowBits == UNION_EECLASS) |
31 | { |
32 | return PTR_EEClass(addr); |
33 | } |
34 | else if (lowBits == UNION_METHODTABLE) |
35 | { |
36 | // pointer to canonical MethodTable. |
37 | TADDR canonicalMethodTable = union_getPointer(addr); |
38 | return PTR_EEClass(ReadPointer((MethodTable *) PTR_MethodTable(canonicalMethodTable), &MethodTable::m_pCanonMT)); |
39 | } |
40 | #ifdef FEATURE_PREJIT |
41 | else if (lowBits == UNION_INDIRECTION) |
42 | { |
43 | // pointer to indirection cell that points to canonical MethodTable |
44 | TADDR canonicalMethodTable = *PTR_TADDR(union_getPointer(addr)); |
45 | return PTR_EEClass(ReadPointer((MethodTable *) PTR_MethodTable(canonicalMethodTable), &MethodTable::m_pCanonMT)); |
46 | } |
47 | #endif |
48 | #ifdef DACCESS_COMPILE |
49 | // Minidumps don't guarantee that every member of every class will be able to work here. |
50 | #else |
51 | _ASSERTE(!"Malformed m_pEEClass in MethodTable" ); |
52 | #endif |
53 | return NULL; |
54 | |
55 | #else |
56 | |
57 | if ((addr & 2) == 0) |
58 | { |
59 | // pointer to EEClass |
60 | return PTR_EEClass(addr); |
61 | } |
62 | |
63 | #ifdef FEATURE_PREJIT |
64 | if ((addr & 1) != 0) |
65 | { |
66 | // pointer to indirection cell that points to canonical MethodTable |
67 | TADDR canonicalMethodTable = *PTR_TADDR(addr - 3); |
68 | return PTR_EEClass(ReadPointer((MethodTable *) PTR_MethodTable(canonicalMethodTable), &MethodTable::m_pCanonMT)); |
69 | } |
70 | #endif |
71 | |
72 | // pointer to canonical MethodTable. |
73 | return PTR_EEClass(ReadPointer((MethodTable *) PTR_MethodTable(addr - 2), &MethodTable::m_pCanonMT)); |
74 | #endif |
75 | } |
76 | |
77 | //========================================================================================== |
78 | inline PTR_EEClass MethodTable::GetClass() |
79 | { |
80 | LIMITED_METHOD_DAC_CONTRACT; |
81 | |
82 | _ASSERTE_IMPL(GetClass_NoLogging() != NULL); |
83 | |
84 | g_IBCLogger.LogEEClassAndMethodTableAccess(this); |
85 | return GetClass_NoLogging(); |
86 | } |
87 | |
88 | //========================================================================================== |
89 | inline Assembly * MethodTable::GetAssembly() |
90 | { |
91 | WRAPPER_NO_CONTRACT; |
92 | return GetModule()->GetAssembly(); |
93 | } |
94 | |
95 | //========================================================================================== |
96 | // DO NOT ADD ANY ASSERTS OR ANY OTHER CODE TO THIS METHOD. |
97 | // DO NOT USE THIS METHOD. |
98 | // Yes folks, for better or worse the debugger pokes supposed object addresses |
99 | // to try to see if objects are valid, possibly firing an AccessViolation or |
100 | // worse. Thus it is "correct" behaviour for this to AV, and incorrect |
101 | // behaviour for it to assert if called on an invalid pointer. |
102 | inline PTR_EEClass MethodTable::GetClassWithPossibleAV() |
103 | { |
104 | CANNOT_HAVE_CONTRACT; |
105 | SUPPORTS_DAC; |
106 | return GetClass_NoLogging(); |
107 | } |
108 | |
109 | //========================================================================================== |
110 | inline BOOL MethodTable::IsClassPointerValid() |
111 | { |
112 | WRAPPER_NO_CONTRACT; |
113 | SUPPORTS_DAC; |
114 | |
115 | TADDR addr = ReadPointer(this, &MethodTable::m_pCanonMT); |
116 | |
117 | LowBits lowBits = union_getLowBits(addr); |
118 | if (lowBits == UNION_EECLASS) |
119 | { |
120 | return !m_pEEClass.IsNull(); |
121 | } |
122 | else if (lowBits == UNION_METHODTABLE) |
123 | { |
124 | // pointer to canonical MethodTable. |
125 | TADDR canonicalMethodTable = union_getPointer(addr); |
126 | return !PTR_MethodTable(canonicalMethodTable)->m_pEEClass.IsNull(); |
127 | } |
128 | #ifdef FEATURE_PREJIT |
129 | else if (lowBits == UNION_INDIRECTION) |
130 | { |
131 | // pointer to indirection cell that points to canonical MethodTable |
132 | TADDR canonicalMethodTable = *PTR_TADDR(union_getPointer(addr)); |
133 | if (CORCOMPILE_IS_POINTER_TAGGED(canonicalMethodTable)) |
134 | return FALSE; |
135 | return !PTR_MethodTable(canonicalMethodTable)->m_pEEClass.IsNull(); |
136 | } |
137 | #endif |
138 | _ASSERTE(!"Malformed m_pEEClass in MethodTable" ); |
139 | return FALSE; |
140 | } |
141 | |
142 | //========================================================================================== |
143 | // Does this immediate item live in an NGEN module? |
144 | inline BOOL MethodTable::IsZapped() |
145 | { |
146 | LIMITED_METHOD_DAC_CONTRACT; |
147 | |
148 | #ifdef FEATURE_PREJIT |
149 | return GetFlag(enum_flag_IsZapped); |
150 | #else |
151 | return FALSE; |
152 | #endif |
153 | } |
154 | |
155 | //========================================================================================== |
156 | // For types that are part of an ngen-ed assembly this gets the |
157 | // Module* that contains this methodtable. |
158 | inline PTR_Module MethodTable::GetZapModule() |
159 | { |
160 | LIMITED_METHOD_DAC_CONTRACT; |
161 | |
162 | PTR_Module zapModule = NULL; |
163 | if (IsZapped()) |
164 | { |
165 | zapModule = ReadPointer(this, &MethodTable::m_pLoaderModule); |
166 | } |
167 | |
168 | return zapModule; |
169 | } |
170 | |
171 | //========================================================================================== |
172 | inline PTR_Module MethodTable::GetLoaderModule() |
173 | { |
174 | LIMITED_METHOD_DAC_CONTRACT; |
175 | return ReadPointer(this, &MethodTable::m_pLoaderModule); |
176 | } |
177 | |
178 | inline PTR_LoaderAllocator MethodTable::GetLoaderAllocator() |
179 | { |
180 | LIMITED_METHOD_DAC_CONTRACT; |
181 | return GetLoaderModule()->GetLoaderAllocator(); |
182 | } |
183 | |
184 | |
185 | |
186 | #ifndef DACCESS_COMPILE |
187 | //========================================================================================== |
188 | inline void MethodTable::SetLoaderModule(Module* pModule) |
189 | { |
190 | WRAPPER_NO_CONTRACT; |
191 | m_pLoaderModule.SetValue(pModule); |
192 | } |
193 | |
194 | inline void MethodTable::SetLoaderAllocator(LoaderAllocator* pAllocator) |
195 | { |
196 | LIMITED_METHOD_CONTRACT; |
197 | _ASSERTE(pAllocator == GetLoaderAllocator()); |
198 | |
199 | if (pAllocator->IsCollectible()) |
200 | { |
201 | SetFlag(enum_flag_Collectible); |
202 | } |
203 | } |
204 | |
205 | #endif |
206 | |
207 | //========================================================================================== |
208 | inline WORD MethodTable::GetNumNonVirtualSlots() |
209 | { |
210 | LIMITED_METHOD_DAC_CONTRACT; |
211 | return HasNonVirtualSlots() ? GetClass()->GetNumNonVirtualSlots() : 0; |
212 | } |
213 | |
214 | //========================================================================================== |
215 | inline WORD MethodTable::GetNumInstanceFields() |
216 | { |
217 | WRAPPER_NO_CONTRACT; |
218 | return (GetClass()->GetNumInstanceFields()); |
219 | } |
220 | |
221 | //========================================================================================== |
222 | inline WORD MethodTable::GetNumStaticFields() |
223 | { |
224 | LIMITED_METHOD_DAC_CONTRACT; |
225 | return (GetClass()->GetNumStaticFields()); |
226 | } |
227 | |
228 | //========================================================================================== |
229 | inline WORD MethodTable::GetNumThreadStaticFields() |
230 | { |
231 | LIMITED_METHOD_DAC_CONTRACT; |
232 | return (GetClass()->GetNumThreadStaticFields()); |
233 | } |
234 | |
235 | //========================================================================================== |
236 | inline DWORD MethodTable::GetNumInstanceFieldBytes() |
237 | { |
238 | LIMITED_METHOD_DAC_CONTRACT; |
239 | return(GetBaseSize() - GetClass()->GetBaseSizePadding()); |
240 | } |
241 | |
242 | //========================================================================================== |
243 | inline WORD MethodTable::GetNumIntroducedInstanceFields() |
244 | { |
245 | LIMITED_METHOD_DAC_CONTRACT; |
246 | |
247 | WORD wNumFields = GetNumInstanceFields(); |
248 | |
249 | MethodTable * pParentMT = GetParentMethodTable(); |
250 | if (pParentMT != NULL) |
251 | { |
252 | WORD wNumParentFields = pParentMT->GetNumInstanceFields(); |
253 | |
254 | // If this assert fires, then our bookkeeping is bad. Perhaps we incremented the count |
255 | // of fields on the base class w/o incrementing the count in the derived class. (EnC scenarios). |
256 | _ASSERTE(wNumFields >= wNumParentFields); |
257 | |
258 | wNumFields -= wNumParentFields; |
259 | } |
260 | |
261 | return(wNumFields); |
262 | } |
263 | |
264 | //========================================================================================== |
265 | inline DWORD MethodTable::GetAlignedNumInstanceFieldBytes() |
266 | { |
267 | WRAPPER_NO_CONTRACT; |
268 | return((GetNumInstanceFieldBytes() + 3) & (~3)); |
269 | } |
270 | |
271 | //========================================================================================== |
272 | inline PTR_FieldDesc MethodTable::GetApproxFieldDescListRaw() |
273 | { |
274 | WRAPPER_NO_CONTRACT; |
275 | // Careful about using this method. If it's possible that fields may have been added via EnC, then |
276 | // must use the FieldDescIterator as any fields added via EnC won't be in the raw list |
277 | |
278 | return GetClass()->GetFieldDescList(); |
279 | } |
280 | |
281 | #ifdef FEATURE_COMINTEROP |
282 | //========================================================================================== |
283 | inline DWORD MethodTable::IsComClassInterface() |
284 | { |
285 | WRAPPER_NO_CONTRACT; |
286 | return GetClass()->IsComClassInterface(); |
287 | } |
288 | |
289 | //========================================================================================== |
290 | inline DWORD MethodTable::IsComImport() |
291 | { |
292 | WRAPPER_NO_CONTRACT; |
293 | return GetClass()->IsComImport(); |
294 | } |
295 | |
296 | //========================================================================================== |
297 | // Sparse VTables. These require a SparseVTableMap in the EEClass in |
298 | // order to record how the CLR's vtable slots map across to COM |
299 | // Interop slots. |
300 | // |
301 | inline int MethodTable::IsSparseForCOMInterop() |
302 | { |
303 | WRAPPER_NO_CONTRACT; |
304 | return GetClass()->IsSparseForCOMInterop(); |
305 | } |
306 | |
307 | //========================================================================================== |
308 | inline int MethodTable::IsComEventItfType() |
309 | { |
310 | WRAPPER_NO_CONTRACT; |
311 | _ASSERTE(GetClass()); |
312 | return GetClass()->IsComEventItfType(); |
313 | } |
314 | |
315 | #endif // FEATURE_COMINTEROP |
316 | |
317 | //========================================================================================== |
318 | inline DWORD MethodTable::GetAttrClass() |
319 | { |
320 | WRAPPER_NO_CONTRACT; |
321 | return GetClass()->GetAttrClass(); |
322 | } |
323 | |
324 | //========================================================================================== |
325 | inline BOOL MethodTable::SupportsGenericInterop(TypeHandle::InteropKind interopKind, |
326 | MethodTable::Mode mode /*= modeAll*/) |
327 | { |
328 | LIMITED_METHOD_CONTRACT; |
329 | |
330 | #ifdef FEATURE_COMINTEROP |
331 | return ((IsInterface() || IsDelegate()) && // interface or delegate |
332 | HasInstantiation() && // generic |
333 | !IsSharedByGenericInstantiations() && // unshared |
334 | !ContainsGenericVariables() && // closed over concrete types |
335 | // defined in .winmd or one of the redirected mscorlib interfaces |
336 | ((((mode & modeProjected) != 0) && IsProjectedFromWinRT()) || |
337 | (((mode & modeRedirected) != 0) && (IsWinRTRedirectedInterface(interopKind) || IsWinRTRedirectedDelegate())))); |
338 | #else // FEATURE_COMINTEROP |
339 | return FALSE; |
340 | #endif // FEATURE_COMINTEROP |
341 | } |
342 | |
343 | |
344 | //========================================================================================== |
345 | inline BOOL MethodTable::IsNotTightlyPacked() |
346 | { |
347 | WRAPPER_NO_CONTRACT; |
348 | return GetClass()->IsNotTightlyPacked(); |
349 | } |
350 | |
351 | //========================================================================================== |
352 | inline BOOL MethodTable::HasFieldsWhichMustBeInited() |
353 | { |
354 | WRAPPER_NO_CONTRACT; |
355 | return GetClass()->HasFieldsWhichMustBeInited(); |
356 | } |
357 | |
358 | //========================================================================================== |
359 | inline BOOL MethodTable::IsAbstract() |
360 | { |
361 | WRAPPER_NO_CONTRACT; |
362 | return GetClass()->IsAbstract(); |
363 | } |
364 | |
365 | //========================================================================================== |
366 | |
367 | #ifdef FEATURE_COMINTEROP |
368 | //========================================================================================== |
369 | inline void MethodTable::SetHasGuidInfo() |
370 | { |
371 | LIMITED_METHOD_CONTRACT; |
372 | _ASSERTE(IsInterface() || (HasCCWTemplate() && IsDelegate())); |
373 | |
374 | // for delegates, having CCW template implies having GUID info |
375 | if (IsInterface()) |
376 | SetFlag(enum_flag_IfInterfaceThenHasGuidInfo); |
377 | } |
378 | |
379 | //========================================================================================== |
380 | inline BOOL MethodTable::HasGuidInfo() |
381 | { |
382 | LIMITED_METHOD_DAC_CONTRACT; |
383 | |
384 | if (IsInterface()) |
385 | return GetFlag(enum_flag_IfInterfaceThenHasGuidInfo); |
386 | |
387 | // HasCCWTemplate() is intentionally checked first here to avoid hitting |
388 | // g_pMulticastDelegateClass == NULL inside IsDelegate() during startup |
389 | return HasCCWTemplate() && IsDelegate(); |
390 | } |
391 | |
392 | //========================================================================================== |
393 | // True IFF the type has a GUID explicitly assigned to it (including WinRT generic interfaces |
394 | // where the GUID is computed). |
395 | inline BOOL MethodTable::HasExplicitGuid() |
396 | { |
397 | CONTRACTL { |
398 | THROWS; |
399 | GC_TRIGGERS; |
400 | MODE_ANY; |
401 | SUPPORTS_DAC; |
402 | } CONTRACTL_END; |
403 | |
404 | GUID guid; |
405 | GetGuid(&guid, FALSE); |
406 | return (guid != GUID_NULL); |
407 | } |
408 | |
409 | //========================================================================================== |
410 | inline void MethodTable::SetHasCCWTemplate() |
411 | { |
412 | LIMITED_METHOD_CONTRACT; |
413 | SetFlag(enum_flag_HasCCWTemplate); |
414 | } |
415 | |
416 | //========================================================================================== |
417 | inline BOOL MethodTable::HasCCWTemplate() |
418 | { |
419 | LIMITED_METHOD_DAC_CONTRACT; |
420 | return GetFlag(enum_flag_HasCCWTemplate); |
421 | } |
422 | |
423 | //========================================================================================== |
424 | inline void MethodTable::SetHasRCWPerTypeData() |
425 | { |
426 | LIMITED_METHOD_CONTRACT; |
427 | SetFlag(enum_flag_HasRCWPerTypeData); |
428 | } |
429 | |
430 | //========================================================================================== |
431 | inline BOOL MethodTable::HasRCWPerTypeData() |
432 | { |
433 | LIMITED_METHOD_DAC_CONTRACT; |
434 | return GetFlag(enum_flag_HasRCWPerTypeData); |
435 | } |
436 | |
437 | //========================================================================================== |
438 | // Get the GUID used for WinRT interop |
439 | // * if the type is not a WinRT type or a redirected interfae return FALSE |
440 | inline BOOL MethodTable::GetGuidForWinRT(GUID *pGuid) |
441 | { |
442 | CONTRACTL { |
443 | THROWS; |
444 | GC_TRIGGERS; |
445 | MODE_ANY; |
446 | SUPPORTS_DAC; |
447 | } CONTRACTL_END; |
448 | |
449 | BOOL bRes = FALSE; |
450 | if ((IsProjectedFromWinRT() && !HasInstantiation()) || |
451 | (SupportsGenericInterop(TypeHandle::Interop_NativeToManaged) && IsLegalNonArrayWinRTType())) |
452 | { |
453 | bRes = SUCCEEDED(GetGuidNoThrow(pGuid, TRUE, FALSE)); |
454 | } |
455 | |
456 | return bRes; |
457 | } |
458 | |
459 | #endif // FEATURE_COMINTEROP |
460 | |
461 | //========================================================================================== |
462 | // Is pParentMT System.Enum? (Cannot be called before System.Enum is loaded.) |
463 | inline BOOL MethodTable::IsEnum() |
464 | { |
465 | LIMITED_METHOD_DAC_CONTRACT; |
466 | |
467 | // We should not be calling this before our parent method table pointer |
468 | // is valid . |
469 | _ASSERTE_IMPL(IsParentMethodTablePointerValid()); |
470 | |
471 | PTR_MethodTable pParentMT = GetParentMethodTable(); |
472 | |
473 | // Make sure that we are not using this method during startup |
474 | _ASSERTE(g_pEnumClass != NULL); |
475 | |
476 | return (pParentMT == g_pEnumClass); |
477 | } |
478 | |
479 | //========================================================================================== |
480 | // Is pParentMT either System.ValueType or System.Enum? |
481 | inline BOOL MethodTable::IsValueType() |
482 | { |
483 | LIMITED_METHOD_DAC_CONTRACT; |
484 | |
485 | g_IBCLogger.LogMethodTableAccess(this); |
486 | |
487 | return GetFlag(enum_flag_Category_ValueType_Mask) == enum_flag_Category_ValueType; |
488 | } |
489 | |
490 | //========================================================================================== |
491 | inline CorElementType MethodTable::GetArrayElementType() |
492 | { |
493 | WRAPPER_NO_CONTRACT; |
494 | |
495 | _ASSERTE (IsArray()); |
496 | return dac_cast<PTR_ArrayClass>(GetClass())->GetArrayElementType(); |
497 | } |
498 | |
499 | //========================================================================================== |
500 | inline DWORD MethodTable::GetRank() |
501 | { |
502 | LIMITED_METHOD_DAC_CONTRACT; |
503 | |
504 | _ASSERTE (IsArray()); |
505 | if (GetFlag(enum_flag_Category_IfArrayThenSzArray)) |
506 | return 1; // ELEMENT_TYPE_SZARRAY |
507 | else |
508 | return dac_cast<PTR_ArrayClass>(GetClass())->GetRank(); |
509 | } |
510 | |
511 | //========================================================================================== |
512 | inline BOOL MethodTable::IsTruePrimitive() |
513 | { |
514 | LIMITED_METHOD_DAC_CONTRACT; |
515 | return GetFlag(enum_flag_Category_Mask) == enum_flag_Category_TruePrimitive; |
516 | } |
517 | |
518 | //========================================================================================== |
519 | inline void MethodTable::SetIsTruePrimitive() |
520 | { |
521 | LIMITED_METHOD_DAC_CONTRACT; |
522 | SetFlag(enum_flag_Category_TruePrimitive); |
523 | } |
524 | |
525 | //========================================================================================== |
526 | inline BOOL MethodTable::IsBlittable() |
527 | { |
528 | WRAPPER_NO_CONTRACT; |
529 | #ifndef DACCESS_COMPILE |
530 | _ASSERTE(GetClass()); |
531 | return GetClass()->IsBlittable(); |
532 | #else // DACCESS_COMPILE |
533 | DacNotImpl(); |
534 | return false; |
535 | #endif // DACCESS_COMPILE |
536 | } |
537 | |
538 | //========================================================================================== |
539 | inline BOOL MethodTable::HasClassConstructor() |
540 | { |
541 | WRAPPER_NO_CONTRACT; |
542 | return GetFlag(enum_flag_HasCctor); |
543 | } |
544 | |
545 | //========================================================================================== |
546 | inline void MethodTable::SetHasClassConstructor() |
547 | { |
548 | WRAPPER_NO_CONTRACT; |
549 | return SetFlag(enum_flag_HasCctor); |
550 | } |
551 | |
552 | //========================================================================================== |
553 | inline WORD MethodTable::GetClassConstructorSlot() |
554 | { |
555 | WRAPPER_NO_CONTRACT; |
556 | _ASSERTE(HasClassConstructor()); |
557 | |
558 | // The class constructor slot is the first non-vtable slot |
559 | return GetNumVirtuals(); |
560 | } |
561 | |
562 | //========================================================================================== |
563 | inline BOOL MethodTable::HasDefaultConstructor() |
564 | { |
565 | WRAPPER_NO_CONTRACT; |
566 | return GetFlag(enum_flag_HasDefaultCtor); |
567 | } |
568 | |
569 | //========================================================================================== |
570 | inline void MethodTable::SetHasDefaultConstructor() |
571 | { |
572 | WRAPPER_NO_CONTRACT; |
573 | return SetFlag(enum_flag_HasDefaultCtor); |
574 | } |
575 | |
576 | //========================================================================================== |
577 | inline WORD MethodTable::GetDefaultConstructorSlot() |
578 | { |
579 | WRAPPER_NO_CONTRACT; |
580 | _ASSERTE(HasDefaultConstructor()); |
581 | |
582 | // The default ctor slot is right after cctor slot if there is one |
583 | return GetNumVirtuals() + (HasClassConstructor() ? 1 : 0); |
584 | } |
585 | |
586 | //========================================================================================== |
587 | inline BOOL MethodTable::HasLayout() |
588 | { |
589 | WRAPPER_NO_CONTRACT; |
590 | _ASSERTE(GetClass()); |
591 | return GetClass()->HasLayout(); |
592 | } |
593 | |
594 | //========================================================================================== |
595 | inline MethodDesc* MethodTable::GetMethodDescForSlot(DWORD slot) |
596 | { |
597 | CONTRACTL |
598 | { |
599 | NOTHROW; |
600 | GC_NOTRIGGER; |
601 | SO_TOLERANT; |
602 | MODE_ANY; |
603 | } |
604 | CONTRACTL_END; |
605 | |
606 | PCODE pCode = GetRestoredSlot(slot); |
607 | |
608 | // This is an optimization that we can take advantage of if we're trying to get the MethodDesc |
609 | // for an interface virtual, since their slots usually point to stub. |
610 | if (IsInterface() && slot < GetNumVirtuals()) |
611 | { |
612 | return MethodDesc::GetMethodDescFromStubAddr(pCode); |
613 | } |
614 | |
615 | return MethodTable::GetMethodDescForSlotAddress(pCode); |
616 | } |
617 | |
618 | #ifndef DACCESS_COMPILE |
619 | |
620 | //========================================================================================== |
621 | inline INT32 MethodTable::MethodIterator::GetNumMethods() const |
622 | { |
623 | LIMITED_METHOD_CONTRACT; |
624 | // assert that number of methods hasn't changed during the iteration |
625 | CONSISTENCY_CHECK( m_pMethodData->GetNumMethods() == static_cast< UINT32 >( m_iMethods ) ); |
626 | return m_iMethods; |
627 | } |
628 | |
629 | //========================================================================================== |
630 | // Returns TRUE if it's valid to request data from the current position |
631 | inline BOOL MethodTable::MethodIterator::IsValid() const |
632 | { |
633 | LIMITED_METHOD_CONTRACT; |
634 | return m_iCur >= 0 && m_iCur < GetNumMethods(); |
635 | } |
636 | |
637 | //========================================================================================== |
638 | inline BOOL MethodTable::MethodIterator::MoveTo(UINT32 idx) |
639 | { |
640 | LIMITED_METHOD_CONTRACT; |
641 | m_iCur = (INT32)idx; |
642 | return IsValid(); |
643 | } |
644 | |
645 | //========================================================================================== |
646 | inline BOOL MethodTable::MethodIterator::Prev() |
647 | { |
648 | WRAPPER_NO_CONTRACT; |
649 | if (IsValid()) |
650 | --m_iCur; |
651 | return (IsValid()); |
652 | } |
653 | |
654 | //========================================================================================== |
655 | inline BOOL MethodTable::MethodIterator::Next() |
656 | { |
657 | WRAPPER_NO_CONTRACT; |
658 | if (IsValid()) |
659 | ++m_iCur; |
660 | return (IsValid()); |
661 | } |
662 | |
663 | //========================================================================================== |
664 | inline void MethodTable::MethodIterator::MoveToBegin() |
665 | { |
666 | WRAPPER_NO_CONTRACT; |
667 | m_iCur = 0; |
668 | } |
669 | |
670 | //========================================================================================== |
671 | inline void MethodTable::MethodIterator::MoveToEnd() |
672 | { |
673 | WRAPPER_NO_CONTRACT; |
674 | m_iCur = GetNumMethods() - 1; |
675 | } |
676 | |
677 | //========================================================================================== |
678 | inline UINT32 MethodTable::MethodIterator::GetSlotNumber() const { |
679 | LIMITED_METHOD_CONTRACT; |
680 | CONSISTENCY_CHECK(IsValid()); |
681 | return (UINT32)m_iCur; |
682 | } |
683 | |
684 | //========================================================================================== |
685 | inline UINT32 MethodTable::MethodIterator::GetImplSlotNumber() const { |
686 | WRAPPER_NO_CONTRACT; |
687 | CONSISTENCY_CHECK(IsValid()); |
688 | return (UINT32)m_pMethodData->GetImplSlotNumber(m_iCur); |
689 | } |
690 | |
691 | //========================================================================================== |
692 | inline BOOL MethodTable::MethodIterator::IsVirtual() const { |
693 | LIMITED_METHOD_CONTRACT; |
694 | CONSISTENCY_CHECK(IsValid()); |
695 | return m_iCur < (INT32)(GetNumVirtuals()); |
696 | } |
697 | |
698 | //========================================================================================== |
699 | inline UINT32 MethodTable::MethodIterator::GetNumVirtuals() const { |
700 | LIMITED_METHOD_CONTRACT; |
701 | return m_pMethodData->GetNumVirtuals();; |
702 | } |
703 | |
704 | //========================================================================================== |
705 | inline DispatchSlot MethodTable::MethodIterator::GetTarget() const { |
706 | LIMITED_METHOD_CONTRACT; |
707 | CONSISTENCY_CHECK(IsValid()); |
708 | return m_pMethodData->GetImplSlot(m_iCur); |
709 | } |
710 | |
711 | //========================================================================================== |
712 | inline MethodDesc *MethodTable::MethodIterator::GetMethodDesc() const { |
713 | LIMITED_METHOD_CONTRACT; |
714 | CONSISTENCY_CHECK(IsValid()); |
715 | MethodDesc *pMD = m_pMethodData->GetImplMethodDesc(m_iCur); |
716 | CONSISTENCY_CHECK(CheckPointer(pMD)); |
717 | return pMD; |
718 | } |
719 | |
720 | //========================================================================================== |
721 | inline MethodDesc *MethodTable::MethodIterator::GetDeclMethodDesc() const { |
722 | LIMITED_METHOD_CONTRACT; |
723 | CONSISTENCY_CHECK(IsValid()); |
724 | MethodDesc *pMD = m_pMethodData->GetDeclMethodDesc(m_iCur); |
725 | CONSISTENCY_CHECK(CheckPointer(pMD)); |
726 | CONSISTENCY_CHECK(pMD->GetSlot() == GetSlotNumber()); |
727 | return pMD; |
728 | } |
729 | |
730 | #endif // DACCESS_COMPILE |
731 | |
732 | //========================================================================================== |
733 | // Non-canonical types share the method bodies with the canonical type. So the canonical |
734 | // type can be said to own the method bodies. Hence, by default, IntroducedMethodIterator |
735 | // only lets you iterate methods of the canonical type. You have to pass in |
736 | // restrictToCanonicalTypes=FALSE to iterate methods through a non-canonical type. |
737 | |
738 | inline MethodTable::IntroducedMethodIterator::IntroducedMethodIterator( |
739 | MethodTable *pMT, |
740 | BOOL restrictToCanonicalTypes /* = TRUE */ ) |
741 | { |
742 | WRAPPER_NO_CONTRACT; |
743 | CONSISTENCY_CHECK(pMT->IsCanonicalMethodTable() || !restrictToCanonicalTypes); |
744 | |
745 | SetChunk(pMT->GetClass()->GetChunks()); |
746 | } |
747 | |
748 | //========================================================================================== |
749 | FORCEINLINE BOOL MethodTable::IntroducedMethodIterator::Next() |
750 | { |
751 | WRAPPER_NO_CONTRACT; |
752 | CONSISTENCY_CHECK(IsValid()); |
753 | |
754 | // Check whether the next MethodDesc is still within the bounds of the current chunk |
755 | TADDR pNext = dac_cast<TADDR>(m_pMethodDesc) + m_pMethodDesc->SizeOf(); |
756 | |
757 | if (pNext < m_pChunkEnd) |
758 | { |
759 | // Just skip to the next method in the same chunk |
760 | m_pMethodDesc = PTR_MethodDesc(pNext); |
761 | } |
762 | else |
763 | { |
764 | _ASSERTE(pNext == m_pChunkEnd); |
765 | |
766 | // We have walked all the methods in the current chunk. Move on |
767 | // to the next chunk. |
768 | SetChunk(m_pChunk->GetNextChunk()); |
769 | } |
770 | |
771 | return IsValid(); |
772 | } |
773 | |
774 | //========================================================================================== |
775 | inline BOOL MethodTable::IntroducedMethodIterator::IsValid() const |
776 | { |
777 | LIMITED_METHOD_CONTRACT; |
778 | return m_pMethodDesc != NULL; |
779 | } |
780 | |
781 | //========================================================================================== |
782 | inline MethodDesc * MethodTable::IntroducedMethodIterator::GetMethodDesc() const |
783 | { |
784 | WRAPPER_NO_CONTRACT; |
785 | CONSISTENCY_CHECK(IsValid()); |
786 | return m_pMethodDesc; |
787 | } |
788 | |
789 | //========================================================================================== |
790 | inline DWORD MethodTable::GetIndexOfVtableIndirection(DWORD slotNum) |
791 | { |
792 | LIMITED_METHOD_DAC_CONTRACT; |
793 | _ASSERTE((1 << VTABLE_SLOTS_PER_CHUNK_LOG2) == VTABLE_SLOTS_PER_CHUNK); |
794 | |
795 | return slotNum >> VTABLE_SLOTS_PER_CHUNK_LOG2; |
796 | } |
797 | |
798 | //========================================================================================== |
799 | inline DWORD MethodTable::GetStartSlotForVtableIndirection(UINT32 indirectionIndex, DWORD wNumVirtuals) |
800 | { |
801 | LIMITED_METHOD_DAC_CONTRACT; |
802 | _ASSERTE(indirectionIndex < GetNumVtableIndirections(wNumVirtuals)); |
803 | |
804 | return indirectionIndex * VTABLE_SLOTS_PER_CHUNK; |
805 | } |
806 | |
807 | //========================================================================================== |
808 | inline DWORD MethodTable::GetEndSlotForVtableIndirection(UINT32 indirectionIndex, DWORD wNumVirtuals) |
809 | { |
810 | LIMITED_METHOD_DAC_CONTRACT; |
811 | _ASSERTE(indirectionIndex < GetNumVtableIndirections(wNumVirtuals)); |
812 | |
813 | DWORD end = (indirectionIndex + 1) * VTABLE_SLOTS_PER_CHUNK; |
814 | |
815 | if (end > wNumVirtuals) |
816 | { |
817 | end = wNumVirtuals; |
818 | } |
819 | |
820 | return end; |
821 | } |
822 | |
823 | //========================================================================================== |
824 | inline UINT32 MethodTable::GetIndexAfterVtableIndirection(UINT32 slotNum) |
825 | { |
826 | LIMITED_METHOD_DAC_CONTRACT; |
827 | _ASSERTE((1 << VTABLE_SLOTS_PER_CHUNK_LOG2) == VTABLE_SLOTS_PER_CHUNK); |
828 | |
829 | return (slotNum & (VTABLE_SLOTS_PER_CHUNK - 1)); |
830 | } |
831 | |
832 | //========================================================================================== |
833 | inline DWORD MethodTable::GetNumVtableIndirections(DWORD wNumVirtuals) |
834 | { |
835 | LIMITED_METHOD_DAC_CONTRACT; |
836 | _ASSERTE((1 << VTABLE_SLOTS_PER_CHUNK_LOG2) == VTABLE_SLOTS_PER_CHUNK); |
837 | |
838 | return (wNumVirtuals + (VTABLE_SLOTS_PER_CHUNK - 1)) >> VTABLE_SLOTS_PER_CHUNK_LOG2; |
839 | } |
840 | |
841 | //========================================================================================== |
842 | inline DPTR(MethodTable::VTableIndir_t) MethodTable::GetVtableIndirections() |
843 | { |
844 | LIMITED_METHOD_DAC_CONTRACT; |
845 | return dac_cast<DPTR(VTableIndir_t)>(dac_cast<TADDR>(this) + sizeof(MethodTable)); |
846 | } |
847 | |
848 | //========================================================================================== |
849 | inline DWORD MethodTable::GetNumVtableIndirections() |
850 | { |
851 | WRAPPER_NO_CONTRACT; |
852 | |
853 | return GetNumVtableIndirections(GetNumVirtuals_NoLogging()); |
854 | } |
855 | |
856 | //========================================================================================== |
857 | inline MethodTable::VtableIndirectionSlotIterator::VtableIndirectionSlotIterator(MethodTable *pMT) |
858 | : m_pSlot(pMT->GetVtableIndirections()), |
859 | m_i((DWORD) -1), |
860 | m_count(pMT->GetNumVtableIndirections()), |
861 | m_pMT(pMT) |
862 | { |
863 | WRAPPER_NO_CONTRACT; |
864 | } |
865 | |
866 | //========================================================================================== |
867 | inline MethodTable::VtableIndirectionSlotIterator::VtableIndirectionSlotIterator(MethodTable *pMT, DWORD index) |
868 | : m_pSlot(pMT->GetVtableIndirections() + index), |
869 | m_i(index), |
870 | m_count(pMT->GetNumVtableIndirections()), |
871 | m_pMT(pMT) |
872 | { |
873 | WRAPPER_NO_CONTRACT; |
874 | PRECONDITION(index != (DWORD) -1 && index < m_count); |
875 | } |
876 | |
877 | //========================================================================================== |
878 | inline BOOL MethodTable::VtableIndirectionSlotIterator::Next() |
879 | { |
880 | LIMITED_METHOD_DAC_CONTRACT; |
881 | PRECONDITION(!Finished()); |
882 | if (m_i != (DWORD) -1) |
883 | m_pSlot++; |
884 | return (++m_i < m_count); |
885 | } |
886 | |
887 | //========================================================================================== |
888 | inline BOOL MethodTable::VtableIndirectionSlotIterator::Finished() |
889 | { |
890 | LIMITED_METHOD_DAC_CONTRACT; |
891 | return (m_i == m_count); |
892 | } |
893 | |
894 | //========================================================================================== |
895 | inline DWORD MethodTable::VtableIndirectionSlotIterator::GetIndex() |
896 | { |
897 | LIMITED_METHOD_DAC_CONTRACT; |
898 | return m_i; |
899 | } |
900 | |
901 | //========================================================================================== |
902 | inline DWORD MethodTable::VtableIndirectionSlotIterator::GetOffsetFromMethodTable() |
903 | { |
904 | WRAPPER_NO_CONTRACT; |
905 | PRECONDITION(m_i != (DWORD) -1 && m_i < m_count); |
906 | |
907 | return GetVtableOffset() + sizeof(VTableIndir_t) * m_i; |
908 | } |
909 | |
910 | //========================================================================================== |
911 | inline DPTR(MethodTable::VTableIndir2_t) MethodTable::VtableIndirectionSlotIterator::GetIndirectionSlot() |
912 | { |
913 | LIMITED_METHOD_DAC_CONTRACT; |
914 | PRECONDITION(m_i != (DWORD) -1 && m_i < m_count); |
915 | |
916 | return m_pSlot->GetValueMaybeNull(dac_cast<TADDR>(m_pSlot)); |
917 | } |
918 | |
919 | //========================================================================================== |
920 | #ifndef DACCESS_COMPILE |
921 | inline void MethodTable::VtableIndirectionSlotIterator::SetIndirectionSlot(DPTR(MethodTable::VTableIndir2_t) pChunk) |
922 | { |
923 | LIMITED_METHOD_CONTRACT; |
924 | m_pSlot->SetValueMaybeNull(pChunk); |
925 | } |
926 | #endif |
927 | |
928 | //========================================================================================== |
929 | inline DWORD MethodTable::VtableIndirectionSlotIterator::GetStartSlot() |
930 | { |
931 | WRAPPER_NO_CONTRACT; |
932 | PRECONDITION(m_i != (DWORD) -1 && m_i < m_count); |
933 | |
934 | return GetStartSlotForVtableIndirection(m_i, m_pMT->GetNumVirtuals()); |
935 | } |
936 | |
937 | //========================================================================================== |
938 | inline DWORD MethodTable::VtableIndirectionSlotIterator::GetEndSlot() |
939 | { |
940 | WRAPPER_NO_CONTRACT; |
941 | PRECONDITION(m_i != (DWORD) -1 && m_i < m_count); |
942 | |
943 | return GetEndSlotForVtableIndirection(m_i, m_pMT->GetNumVirtuals()); |
944 | } |
945 | |
946 | //========================================================================================== |
947 | inline DWORD MethodTable::VtableIndirectionSlotIterator::GetNumSlots() |
948 | { |
949 | WRAPPER_NO_CONTRACT; |
950 | |
951 | return GetEndSlot() - GetStartSlot(); |
952 | } |
953 | |
954 | //========================================================================================== |
955 | inline DWORD MethodTable::VtableIndirectionSlotIterator::GetSize() |
956 | { |
957 | WRAPPER_NO_CONTRACT; |
958 | |
959 | return GetNumSlots() * sizeof(PCODE); |
960 | } |
961 | |
962 | //========================================================================================== |
963 | // Create a new iterator over the vtable indirection slots |
964 | // The iterator starts just before the first item |
965 | inline MethodTable::VtableIndirectionSlotIterator MethodTable::IterateVtableIndirectionSlots() |
966 | { |
967 | WRAPPER_NO_CONTRACT; |
968 | return VtableIndirectionSlotIterator(this); |
969 | } |
970 | |
971 | //========================================================================================== |
972 | // Create a new iterator over the vtable indirection slots, starting at the index specified |
973 | inline MethodTable::VtableIndirectionSlotIterator MethodTable::IterateVtableIndirectionSlotsFrom(DWORD index) |
974 | { |
975 | WRAPPER_NO_CONTRACT; |
976 | return VtableIndirectionSlotIterator(this, index); |
977 | } |
978 | |
979 | #ifndef DACCESS_COMPILE |
980 | #ifdef FEATURE_COMINTEROP |
981 | |
982 | //========================================================================================== |
983 | inline ComCallWrapperTemplate *MethodTable::GetComCallWrapperTemplate() |
984 | { |
985 | LIMITED_METHOD_CONTRACT; |
986 | if (HasCCWTemplate()) |
987 | { |
988 | return *GetCCWTemplatePtr(); |
989 | } |
990 | return GetClass()->GetComCallWrapperTemplate(); |
991 | } |
992 | |
993 | //========================================================================================== |
994 | inline BOOL MethodTable::SetComCallWrapperTemplate(ComCallWrapperTemplate *pTemplate) |
995 | { |
996 | CONTRACTL |
997 | { |
998 | THROWS; |
999 | GC_NOTRIGGER; |
1000 | MODE_ANY; |
1001 | } |
1002 | CONTRACTL_END; |
1003 | |
1004 | if (HasCCWTemplate()) |
1005 | { |
1006 | TypeHandle th(this); |
1007 | g_IBCLogger.LogTypeMethodTableWriteableAccess(&th); |
1008 | return (InterlockedCompareExchangeT(EnsureWritablePages(GetCCWTemplatePtr()), pTemplate, NULL) == NULL); |
1009 | } |
1010 | g_IBCLogger.LogEEClassCOWTableAccess(this); |
1011 | return GetClass_NoLogging()->SetComCallWrapperTemplate(pTemplate); |
1012 | } |
1013 | |
1014 | #ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION |
1015 | //========================================================================================== |
1016 | inline ClassFactoryBase *MethodTable::GetComClassFactory() |
1017 | { |
1018 | LIMITED_METHOD_CONTRACT; |
1019 | return GetClass()->GetComClassFactory(); |
1020 | } |
1021 | |
1022 | //========================================================================================== |
1023 | inline BOOL MethodTable::SetComClassFactory(ClassFactoryBase *pFactory) |
1024 | { |
1025 | CONTRACTL |
1026 | { |
1027 | THROWS; |
1028 | GC_NOTRIGGER; |
1029 | MODE_ANY; |
1030 | } |
1031 | CONTRACTL_END; |
1032 | |
1033 | g_IBCLogger.LogEEClassCOWTableAccess(this); |
1034 | return GetClass_NoLogging()->SetComClassFactory(pFactory); |
1035 | } |
1036 | #endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION |
1037 | #endif // FEATURE_COMINTEROP |
1038 | #endif // DACCESS_COMPILE |
1039 | |
1040 | #ifdef FEATURE_COMINTEROP |
1041 | //========================================================================================== |
1042 | inline BOOL MethodTable::IsProjectedFromWinRT() |
1043 | { |
1044 | LIMITED_METHOD_DAC_CONTRACT; |
1045 | _ASSERTE(GetClass()); |
1046 | return GetClass()->IsProjectedFromWinRT(); |
1047 | } |
1048 | |
1049 | //========================================================================================== |
1050 | inline BOOL MethodTable::IsExportedToWinRT() |
1051 | { |
1052 | LIMITED_METHOD_DAC_CONTRACT; |
1053 | _ASSERTE(GetClass()); |
1054 | return GetClass()->IsExportedToWinRT(); |
1055 | } |
1056 | |
1057 | //========================================================================================== |
1058 | inline BOOL MethodTable::IsWinRTDelegate() |
1059 | { |
1060 | LIMITED_METHOD_DAC_CONTRACT; |
1061 | return (IsProjectedFromWinRT() && IsDelegate()) || IsWinRTRedirectedDelegate(); |
1062 | } |
1063 | |
1064 | #else // FEATURE_COMINTEROP |
1065 | |
1066 | //========================================================================================== |
1067 | inline BOOL MethodTable::IsProjectedFromWinRT() |
1068 | { |
1069 | LIMITED_METHOD_DAC_CONTRACT; |
1070 | return FALSE; |
1071 | } |
1072 | |
1073 | //========================================================================================== |
1074 | inline BOOL MethodTable::IsExportedToWinRT() |
1075 | { |
1076 | LIMITED_METHOD_DAC_CONTRACT; |
1077 | return FALSE; |
1078 | } |
1079 | |
1080 | //========================================================================================== |
1081 | inline BOOL MethodTable::IsWinRTDelegate() |
1082 | { |
1083 | LIMITED_METHOD_DAC_CONTRACT; |
1084 | return FALSE; |
1085 | } |
1086 | |
1087 | #endif // FEATURE_COMINTEROP |
1088 | |
1089 | //========================================================================================== |
1090 | inline UINT32 MethodTable::GetNativeSize() |
1091 | { |
1092 | LIMITED_METHOD_CONTRACT; |
1093 | _ASSERTE(GetClass()); |
1094 | return GetClass()->GetNativeSize(); |
1095 | } |
1096 | |
1097 | //========================================================================================== |
1098 | inline PTR_MethodTable MethodTable::GetCanonicalMethodTable() |
1099 | { |
1100 | LIMITED_METHOD_DAC_CONTRACT; |
1101 | |
1102 | TADDR addr = ReadPointer(this, &MethodTable::m_pCanonMT); |
1103 | |
1104 | #ifdef _DEBUG |
1105 | LowBits lowBits = union_getLowBits(addr); |
1106 | if (lowBits == UNION_EECLASS) |
1107 | { |
1108 | return dac_cast<PTR_MethodTable>(this); |
1109 | } |
1110 | else if (lowBits == UNION_METHODTABLE) |
1111 | { |
1112 | // pointer to canonical MethodTable. |
1113 | return PTR_MethodTable(union_getPointer(addr)); |
1114 | } |
1115 | #ifdef FEATURE_PREJIT |
1116 | else if (lowBits == UNION_INDIRECTION) |
1117 | { |
1118 | return PTR_MethodTable(*PTR_TADDR(union_getPointer(addr))); |
1119 | } |
1120 | #endif |
1121 | _ASSERTE(!"Malformed m_pCanonMT in MethodTable" ); |
1122 | return NULL; |
1123 | #else |
1124 | |
1125 | if ((addr & 2) == 0) |
1126 | return dac_cast<PTR_MethodTable>(this); |
1127 | |
1128 | #ifdef FEATURE_PREJIT |
1129 | if ((addr & 1) != 0) |
1130 | return PTR_MethodTable(*PTR_TADDR(addr - 3)); |
1131 | #endif |
1132 | |
1133 | return PTR_MethodTable(addr - 2); |
1134 | #endif |
1135 | } |
1136 | |
1137 | //========================================================================================== |
1138 | inline TADDR MethodTable::GetCanonicalMethodTableFixup() |
1139 | { |
1140 | LIMITED_METHOD_DAC_CONTRACT; |
1141 | |
1142 | #ifdef FEATURE_PREJIT |
1143 | TADDR addr = ReadPointer(this, &MethodTable::m_pCanonMT); |
1144 | LowBits lowBits = union_getLowBits(addr); |
1145 | if (lowBits == UNION_INDIRECTION) |
1146 | { |
1147 | // pointer to canonical MethodTable. |
1148 | return *PTR_TADDR(union_getPointer(addr)); |
1149 | } |
1150 | else |
1151 | #endif |
1152 | { |
1153 | return NULL; |
1154 | } |
1155 | } |
1156 | |
1157 | //========================================================================================== |
1158 | #ifndef DACCESS_COMPILE |
1159 | FORCEINLINE BOOL MethodTable::IsEquivalentTo(MethodTable *pOtherMT COMMA_INDEBUG(TypeHandlePairList *pVisited /*= NULL*/)) |
1160 | { |
1161 | WRAPPER_NO_CONTRACT; |
1162 | |
1163 | if (this == pOtherMT) |
1164 | return TRUE; |
1165 | |
1166 | #ifdef FEATURE_TYPEEQUIVALENCE |
1167 | // bail early for normal types |
1168 | if (!HasTypeEquivalence() || !pOtherMT->HasTypeEquivalence()) |
1169 | return FALSE; |
1170 | |
1171 | if (IsEquivalentTo_Worker(pOtherMT COMMA_INDEBUG(pVisited))) |
1172 | return TRUE; |
1173 | #endif // FEATURE_TYPEEQUIVALENCE |
1174 | |
1175 | return FALSE; |
1176 | } |
1177 | #endif |
1178 | |
1179 | //========================================================================================== |
1180 | inline IMDInternalImport* MethodTable::GetMDImport() |
1181 | { |
1182 | LIMITED_METHOD_CONTRACT; |
1183 | return GetModule()->GetMDImport(); |
1184 | } |
1185 | |
1186 | //========================================================================================== |
1187 | inline BOOL MethodTable::IsSealed() |
1188 | { |
1189 | LIMITED_METHOD_CONTRACT; |
1190 | return GetClass()->IsSealed(); |
1191 | } |
1192 | |
1193 | //========================================================================================== |
1194 | inline BOOL MethodTable::IsManagedSequential() |
1195 | { |
1196 | LIMITED_METHOD_CONTRACT; |
1197 | return GetClass()->IsManagedSequential(); |
1198 | } |
1199 | |
1200 | //========================================================================================== |
1201 | inline BOOL MethodTable::HasExplicitSize() |
1202 | { |
1203 | LIMITED_METHOD_CONTRACT; |
1204 | return GetClass()->HasExplicitSize(); |
1205 | } |
1206 | |
1207 | //========================================================================================== |
1208 | inline DWORD MethodTable::GetPerInstInfoSize() |
1209 | { |
1210 | LIMITED_METHOD_DAC_CONTRACT; |
1211 | return GetNumDicts() * sizeof(PerInstInfoElem_t); |
1212 | } |
1213 | |
1214 | //========================================================================================== |
1215 | inline EEClassLayoutInfo *MethodTable::GetLayoutInfo() |
1216 | { |
1217 | LIMITED_METHOD_CONTRACT; |
1218 | PRECONDITION(HasLayout()); |
1219 | return GetClass()->GetLayoutInfo(); |
1220 | } |
1221 | |
1222 | //========================================================================================== |
1223 | // These come after the pointers to the generic dictionaries (if any) |
1224 | inline DWORD MethodTable::GetInterfaceMapSize() |
1225 | { |
1226 | LIMITED_METHOD_DAC_CONTRACT; |
1227 | |
1228 | DWORD cbIMap = GetNumInterfaces() * sizeof(InterfaceInfo_t); |
1229 | #ifdef FEATURE_COMINTEROP |
1230 | cbIMap += (HasDynamicInterfaceMap() ? sizeof(DWORD_PTR) : 0); |
1231 | #endif |
1232 | return cbIMap; |
1233 | } |
1234 | |
1235 | //========================================================================================== |
1236 | // These are the generic dictionaries themselves and are come after |
1237 | // the interface map. In principle they need not be inline in the method table. |
1238 | inline DWORD MethodTable::GetInstAndDictSize() |
1239 | { |
1240 | LIMITED_METHOD_DAC_CONTRACT; |
1241 | |
1242 | if (!HasInstantiation()) |
1243 | return 0; |
1244 | else |
1245 | return DictionaryLayout::GetFirstDictionaryBucketSize(GetNumGenericArgs(), GetClass()->GetDictionaryLayout()); |
1246 | } |
1247 | |
1248 | //========================================================================================== |
1249 | inline BOOL MethodTable::IsSharedByGenericInstantiations() |
1250 | { |
1251 | LIMITED_METHOD_DAC_CONTRACT; |
1252 | |
1253 | g_IBCLogger.LogMethodTableAccess(this); |
1254 | |
1255 | return TestFlagWithMask(enum_flag_GenericsMask, enum_flag_GenericsMask_SharedInst); |
1256 | } |
1257 | |
1258 | //========================================================================================== |
1259 | inline BOOL MethodTable::IsCanonicalMethodTable() |
1260 | { |
1261 | LIMITED_METHOD_DAC_CONTRACT; |
1262 | |
1263 | return (union_getLowBits(ReadPointer(this, &MethodTable::m_pCanonMT)) == UNION_EECLASS); |
1264 | } |
1265 | |
1266 | //========================================================================================== |
1267 | FORCEINLINE BOOL MethodTable::HasInstantiation() |
1268 | { |
1269 | LIMITED_METHOD_DAC_CONTRACT; |
1270 | |
1271 | // Generics flags cannot be expressed in terms of GetFlag() |
1272 | return !TestFlagWithMask(enum_flag_GenericsMask, enum_flag_GenericsMask_NonGeneric); |
1273 | } |
1274 | |
1275 | //========================================================================================== |
1276 | inline void MethodTable::SetHasInstantiation(BOOL fTypicalInstantiation, BOOL fSharedByGenericInstantiations) |
1277 | { |
1278 | LIMITED_METHOD_CONTRACT; |
1279 | _ASSERTE(!IsStringOrArray()); |
1280 | SetFlag(fTypicalInstantiation ? enum_flag_GenericsMask_TypicalInst : |
1281 | (fSharedByGenericInstantiations ? enum_flag_GenericsMask_SharedInst : enum_flag_GenericsMask_GenericInst)); |
1282 | } |
1283 | //========================================================================================== |
1284 | inline BOOL MethodTable::IsGenericTypeDefinition() |
1285 | { |
1286 | LIMITED_METHOD_DAC_CONTRACT; |
1287 | |
1288 | // Generics flags cannot be expressed in terms of GetFlag() |
1289 | return TestFlagWithMask(enum_flag_GenericsMask, enum_flag_GenericsMask_TypicalInst); |
1290 | } |
1291 | |
1292 | //========================================================================================== |
1293 | inline PTR_InterfaceInfo MethodTable::GetInterfaceMap() |
1294 | { |
1295 | LIMITED_METHOD_DAC_CONTRACT; |
1296 | |
1297 | return ReadPointer(this, &MethodTable::m_pInterfaceMap); |
1298 | } |
1299 | |
1300 | //========================================================================================== |
1301 | FORCEINLINE TADDR MethodTable::GetMultipurposeSlotPtr(WFLAGS2_ENUM flag, const BYTE * offsets) |
1302 | { |
1303 | LIMITED_METHOD_DAC_CONTRACT; |
1304 | |
1305 | _ASSERTE(GetFlag(flag)); |
1306 | |
1307 | DWORD offset = offsets[GetFlag((WFLAGS2_ENUM)(flag - 1))]; |
1308 | |
1309 | if (offset >= sizeof(MethodTable)) { |
1310 | offset += GetNumVtableIndirections() * sizeof(VTableIndir_t); |
1311 | } |
1312 | |
1313 | return dac_cast<TADDR>(this) + offset; |
1314 | } |
1315 | |
1316 | //========================================================================================== |
1317 | // This method is dependent on the declared order of optional members |
1318 | // If you add or remove an optional member or reorder them please change this method |
1319 | FORCEINLINE DWORD MethodTable::GetOffsetOfOptionalMember(OptionalMemberId id) |
1320 | { |
1321 | LIMITED_METHOD_CONTRACT; |
1322 | |
1323 | DWORD offset = c_OptionalMembersStartOffsets[GetFlag(enum_flag_MultipurposeSlotsMask)]; |
1324 | |
1325 | offset += GetNumVtableIndirections() * sizeof(VTableIndir_t); |
1326 | |
1327 | #undef METHODTABLE_OPTIONAL_MEMBER |
1328 | #define METHODTABLE_OPTIONAL_MEMBER(NAME, TYPE, GETTER) \ |
1329 | if (id == OptionalMember_##NAME) { \ |
1330 | return offset; \ |
1331 | } \ |
1332 | C_ASSERT(sizeof(TYPE) % sizeof(UINT_PTR) == 0); /* To insure proper alignment */ \ |
1333 | if (Has##NAME()) { \ |
1334 | offset += sizeof(TYPE); \ |
1335 | } |
1336 | |
1337 | METHODTABLE_OPTIONAL_MEMBERS() |
1338 | |
1339 | _ASSERTE(!"Wrong optional member" || id == OptionalMember_Count); |
1340 | return offset; |
1341 | } |
1342 | |
1343 | //========================================================================================== |
1344 | inline DWORD MethodTable::GetOptionalMembersAllocationSize(DWORD dwMultipurposeSlotsMask, |
1345 | BOOL needsGenericsStaticsInfo, |
1346 | BOOL needsGuidInfo, |
1347 | BOOL needsCCWTemplate, |
1348 | BOOL needsRCWPerTypeData, |
1349 | BOOL needsTokenOverflow) |
1350 | { |
1351 | LIMITED_METHOD_CONTRACT; |
1352 | |
1353 | DWORD size = c_OptionalMembersStartOffsets[dwMultipurposeSlotsMask] - sizeof(MethodTable); |
1354 | |
1355 | if (needsGenericsStaticsInfo) |
1356 | size += sizeof(GenericsStaticsInfo); |
1357 | if (needsGuidInfo) |
1358 | size += sizeof(UINT_PTR); |
1359 | if (needsCCWTemplate) |
1360 | size += sizeof(UINT_PTR); |
1361 | if (needsRCWPerTypeData) |
1362 | size += sizeof(UINT_PTR); |
1363 | if (dwMultipurposeSlotsMask & enum_flag_HasInterfaceMap) |
1364 | size += sizeof(UINT_PTR); |
1365 | if (needsTokenOverflow) |
1366 | size += sizeof(UINT_PTR); |
1367 | |
1368 | return size; |
1369 | } |
1370 | |
1371 | inline DWORD MethodTable::() |
1372 | { |
1373 | WRAPPER_NO_CONTRACT; |
1374 | |
1375 | return GetEndOffsetOfOptionalMembers() - GetStartOffsetOfOptionalMembers(); |
1376 | } |
1377 | |
1378 | #ifndef DACCESS_COMPILE |
1379 | |
1380 | //========================================================================================== |
1381 | inline PTR_BYTE MethodTable::GetNonGCStaticsBasePointer() |
1382 | { |
1383 | WRAPPER_NO_CONTRACT; |
1384 | return GetDomainLocalModule()->GetNonGCStaticsBasePointer(this); |
1385 | } |
1386 | |
1387 | //========================================================================================== |
1388 | inline PTR_BYTE MethodTable::GetGCStaticsBasePointer() |
1389 | { |
1390 | WRAPPER_NO_CONTRACT; |
1391 | return GetDomainLocalModule()->GetGCStaticsBasePointer(this); |
1392 | } |
1393 | |
1394 | //========================================================================================== |
1395 | inline PTR_BYTE MethodTable::GetNonGCThreadStaticsBasePointer() |
1396 | { |
1397 | CONTRACTL |
1398 | { |
1399 | NOTHROW; |
1400 | GC_NOTRIGGER; |
1401 | MODE_ANY; |
1402 | } |
1403 | CONTRACTL_END; |
1404 | |
1405 | // Get the current thread |
1406 | PTR_Thread pThread = dac_cast<PTR_Thread>(GetThread()); |
1407 | |
1408 | // Get the current module's ModuleIndex |
1409 | ModuleIndex index = GetModuleForStatics()->GetModuleIndex(); |
1410 | |
1411 | PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread); |
1412 | |
1413 | PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index); |
1414 | if (pTLM == NULL) |
1415 | return NULL; |
1416 | |
1417 | return pTLM->GetNonGCStaticsBasePointer(this); |
1418 | } |
1419 | |
1420 | //========================================================================================== |
1421 | inline PTR_BYTE MethodTable::GetGCThreadStaticsBasePointer() |
1422 | { |
1423 | CONTRACTL |
1424 | { |
1425 | NOTHROW; |
1426 | GC_NOTRIGGER; |
1427 | MODE_COOPERATIVE; |
1428 | } |
1429 | CONTRACTL_END; |
1430 | |
1431 | // Get the current thread |
1432 | PTR_Thread pThread = dac_cast<PTR_Thread>(GetThread()); |
1433 | |
1434 | // Get the current module's ModuleIndex |
1435 | ModuleIndex index = GetModuleForStatics()->GetModuleIndex(); |
1436 | |
1437 | PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread); |
1438 | |
1439 | PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index); |
1440 | if (pTLM == NULL) |
1441 | return NULL; |
1442 | |
1443 | return pTLM->GetGCStaticsBasePointer(this); |
1444 | } |
1445 | |
1446 | #endif //!DACCESS_COMPILE |
1447 | |
1448 | //========================================================================================== |
1449 | inline PTR_BYTE MethodTable::GetNonGCThreadStaticsBasePointer(PTR_Thread pThread) |
1450 | { |
1451 | LIMITED_METHOD_DAC_CONTRACT; |
1452 | |
1453 | // Get the current module's ModuleIndex |
1454 | ModuleIndex index = GetModuleForStatics()->GetModuleIndex(); |
1455 | |
1456 | PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread); |
1457 | |
1458 | PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index); |
1459 | if (pTLM == NULL) |
1460 | return NULL; |
1461 | |
1462 | return pTLM->GetNonGCStaticsBasePointer(this); |
1463 | } |
1464 | |
1465 | //========================================================================================== |
1466 | inline PTR_BYTE MethodTable::GetGCThreadStaticsBasePointer(PTR_Thread pThread) |
1467 | { |
1468 | LIMITED_METHOD_DAC_CONTRACT; |
1469 | |
1470 | // Get the current module's ModuleIndex |
1471 | ModuleIndex index = GetModuleForStatics()->GetModuleIndex(); |
1472 | |
1473 | PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread); |
1474 | |
1475 | PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index); |
1476 | if (pTLM == NULL) |
1477 | return NULL; |
1478 | |
1479 | return pTLM->GetGCStaticsBasePointer(this); |
1480 | } |
1481 | |
1482 | //========================================================================================== |
1483 | inline PTR_DomainLocalModule MethodTable::GetDomainLocalModule(AppDomain * pAppDomain) |
1484 | { |
1485 | WRAPPER_NO_CONTRACT; |
1486 | return GetModuleForStatics()->GetDomainLocalModule(pAppDomain); |
1487 | } |
1488 | |
1489 | #ifndef DACCESS_COMPILE |
1490 | //========================================================================================== |
1491 | inline PTR_DomainLocalModule MethodTable::GetDomainLocalModule() |
1492 | { |
1493 | WRAPPER_NO_CONTRACT; |
1494 | return GetModuleForStatics()->GetDomainLocalModule(); |
1495 | } |
1496 | #endif //!DACCESS_COMPILE |
1497 | |
1498 | //========================================================================================== |
1499 | inline OBJECTREF MethodTable::AllocateNoChecks() |
1500 | { |
1501 | CONTRACTL |
1502 | { |
1503 | MODE_COOPERATIVE; |
1504 | GC_TRIGGERS; |
1505 | THROWS; |
1506 | } |
1507 | CONTRACTL_END; |
1508 | |
1509 | // we know an instance of this class already exists in the same appdomain |
1510 | // therefore, some checks become redundant. |
1511 | // this currently only happens for Delegate.Combine |
1512 | CONSISTENCY_CHECK(IsRestored_NoLogging()); |
1513 | |
1514 | CONSISTENCY_CHECK(CheckInstanceActivated()); |
1515 | |
1516 | return AllocateObject(this); |
1517 | } |
1518 | |
1519 | |
1520 | //========================================================================================== |
1521 | inline DWORD MethodTable::GetClassIndex() |
1522 | { |
1523 | WRAPPER_NO_CONTRACT; |
1524 | return GetClassIndexFromToken(GetCl()); |
1525 | } |
1526 | |
1527 | #ifndef DACCESS_COMPILE |
1528 | //========================================================================================== |
1529 | // unbox src into dest, making sure src is of the correct type. |
1530 | |
1531 | inline BOOL MethodTable::UnBoxInto(void *dest, OBJECTREF src) |
1532 | { |
1533 | CONTRACTL |
1534 | { |
1535 | NOTHROW; |
1536 | GC_NOTRIGGER; |
1537 | SO_TOLERANT; |
1538 | MODE_COOPERATIVE; |
1539 | } |
1540 | CONTRACTL_END; |
1541 | |
1542 | if (Nullable::IsNullableType(TypeHandle(this))) |
1543 | return Nullable::UnBoxNoGC(dest, src, this); |
1544 | else |
1545 | { |
1546 | if (src == NULL || src->GetMethodTable() != this) |
1547 | return FALSE; |
1548 | |
1549 | CopyValueClass(dest, src->UnBox(), this, src->GetAppDomain()); |
1550 | } |
1551 | return TRUE; |
1552 | } |
1553 | |
1554 | //========================================================================================== |
1555 | // unbox src into argument, making sure src is of the correct type. |
1556 | |
1557 | inline BOOL MethodTable::UnBoxIntoArg(ArgDestination *argDest, OBJECTREF src) |
1558 | { |
1559 | CONTRACTL |
1560 | { |
1561 | NOTHROW; |
1562 | GC_NOTRIGGER; |
1563 | SO_TOLERANT; |
1564 | MODE_COOPERATIVE; |
1565 | } |
1566 | CONTRACTL_END; |
1567 | |
1568 | if (Nullable::IsNullableType(TypeHandle(this))) |
1569 | return Nullable::UnBoxIntoArgNoGC(argDest, src, this); |
1570 | else |
1571 | { |
1572 | if (src == NULL || src->GetMethodTable() != this) |
1573 | return FALSE; |
1574 | |
1575 | CopyValueClassArg(argDest, src->UnBox(), this, src->GetAppDomain(), 0); |
1576 | } |
1577 | return TRUE; |
1578 | } |
1579 | |
1580 | //========================================================================================== |
1581 | // unbox src into dest, No checks are done |
1582 | |
1583 | inline void MethodTable::UnBoxIntoUnchecked(void *dest, OBJECTREF src) |
1584 | { |
1585 | CONTRACTL |
1586 | { |
1587 | NOTHROW; |
1588 | GC_NOTRIGGER; |
1589 | SO_TOLERANT; |
1590 | MODE_COOPERATIVE; |
1591 | } |
1592 | CONTRACTL_END; |
1593 | |
1594 | if (Nullable::IsNullableType(TypeHandle(this))) { |
1595 | BOOL ret; |
1596 | ret = Nullable::UnBoxNoGC(dest, src, this); |
1597 | _ASSERTE(ret); |
1598 | } |
1599 | else |
1600 | { |
1601 | _ASSERTE(src->GetMethodTable()->GetNumInstanceFieldBytes() == GetNumInstanceFieldBytes()); |
1602 | |
1603 | CopyValueClass(dest, src->UnBox(), this, src->GetAppDomain()); |
1604 | } |
1605 | } |
1606 | #endif |
1607 | //========================================================================================== |
1608 | __forceinline TypeHandle::CastResult MethodTable::CanCastToClassOrInterfaceNoGC(MethodTable *pTargetMT) |
1609 | { |
1610 | CONTRACTL |
1611 | { |
1612 | NOTHROW; |
1613 | GC_NOTRIGGER; |
1614 | MODE_ANY; |
1615 | INSTANCE_CHECK; |
1616 | SO_TOLERANT; |
1617 | PRECONDITION(CheckPointer(pTargetMT)); |
1618 | PRECONDITION(!pTargetMT->IsArray()); |
1619 | } |
1620 | CONTRACTL_END |
1621 | |
1622 | if (pTargetMT->IsInterface()) |
1623 | return CanCastToInterfaceNoGC(pTargetMT); |
1624 | else |
1625 | return CanCastToClassNoGC(pTargetMT); |
1626 | } |
1627 | |
1628 | //========================================================================================== |
1629 | inline BOOL MethodTable::CanCastToClassOrInterface(MethodTable *pTargetMT, TypeHandlePairList *pVisited) |
1630 | { |
1631 | CONTRACTL |
1632 | { |
1633 | THROWS; |
1634 | GC_TRIGGERS; |
1635 | MODE_ANY; |
1636 | INSTANCE_CHECK; |
1637 | PRECONDITION(CheckPointer(pTargetMT)); |
1638 | PRECONDITION(!pTargetMT->IsArray()); |
1639 | PRECONDITION(IsRestored_NoLogging()); |
1640 | } |
1641 | CONTRACTL_END |
1642 | |
1643 | if (pTargetMT->IsInterface()) |
1644 | return CanCastToInterface(pTargetMT, pVisited); |
1645 | else |
1646 | return CanCastToClass(pTargetMT, pVisited); |
1647 | } |
1648 | |
1649 | //========================================================================================== |
1650 | FORCEINLINE PTR_Module MethodTable::GetGenericsStaticsModuleAndID(DWORD * pID) |
1651 | { |
1652 | CONTRACTL |
1653 | { |
1654 | NOTHROW; |
1655 | GC_NOTRIGGER; |
1656 | MODE_ANY; |
1657 | SO_TOLERANT; |
1658 | SUPPORTS_DAC; |
1659 | } |
1660 | CONTRACTL_END |
1661 | |
1662 | _ASSERTE(HasGenericsStaticsInfo()); |
1663 | |
1664 | #ifdef FEATURE_PREJIT |
1665 | // This is performance sensitive codepath inlined into JIT helpers. Test the flag directly without |
1666 | // checking IsStringOrArray() first. IsStringOrArray() will always be false here. |
1667 | _ASSERTE(!IsStringOrArray()); |
1668 | if (m_dwFlags & enum_flag_StaticsMask_IfGenericsThenCrossModule) |
1669 | { |
1670 | CrossModuleGenericsStaticsInfo *pInfo = ReadPointer(this, &MethodTable::m_pWriteableData)->GetCrossModuleGenericsStaticsInfo(); |
1671 | _ASSERTE(FitsIn<DWORD>(pInfo->m_DynamicTypeID) || pInfo->m_DynamicTypeID == (SIZE_T)-1); |
1672 | *pID = static_cast<DWORD>(pInfo->m_DynamicTypeID); |
1673 | return pInfo->m_pModuleForStatics; |
1674 | } |
1675 | #endif // FEATURE_PREJIT |
1676 | |
1677 | _ASSERTE(FitsIn<DWORD>(GetGenericsStaticsInfo()->m_DynamicTypeID) || GetGenericsStaticsInfo()->m_DynamicTypeID == (SIZE_T)-1); |
1678 | *pID = static_cast<DWORD>(GetGenericsStaticsInfo()->m_DynamicTypeID); |
1679 | return GetLoaderModule(); |
1680 | } |
1681 | |
1682 | //========================================================================================== |
1683 | inline OBJECTHANDLE MethodTable::GetLoaderAllocatorObjectHandle() |
1684 | { |
1685 | LIMITED_METHOD_CONTRACT; |
1686 | return GetLoaderAllocator()->GetLoaderAllocatorObjectHandle(); |
1687 | } |
1688 | |
1689 | //========================================================================================== |
1690 | FORCEINLINE OBJECTREF MethodTable::GetManagedClassObjectIfExists() |
1691 | { |
1692 | LIMITED_METHOD_CONTRACT; |
1693 | |
1694 | // Logging will be done by the slow path |
1695 | LOADERHANDLE handle = GetWriteableData_NoLogging()->GetExposedClassObjectHandle(); |
1696 | |
1697 | OBJECTREF retVal; |
1698 | |
1699 | // GET_LOADERHANDLE_VALUE_FAST macro is inlined here to let us give hint to the compiler |
1700 | // when the return value is not null. |
1701 | if (!LoaderAllocator::GetHandleValueFast(handle, &retVal) && |
1702 | !GetLoaderAllocator()->GetHandleValueFastPhase2(handle, &retVal)) |
1703 | { |
1704 | return NULL; |
1705 | } |
1706 | |
1707 | COMPILER_ASSUME(retVal != NULL); |
1708 | return retVal; |
1709 | } |
1710 | |
1711 | //========================================================================================== |
1712 | inline void MethodTable::SetIsArray(CorElementType arrayType, CorElementType elementType) |
1713 | { |
1714 | STANDARD_VM_CONTRACT; |
1715 | |
1716 | DWORD category = enum_flag_Category_Array; |
1717 | if (arrayType == ELEMENT_TYPE_SZARRAY) |
1718 | category |= enum_flag_Category_IfArrayThenSzArray; |
1719 | |
1720 | _ASSERTE((m_dwFlags & enum_flag_Category_Mask) == 0); |
1721 | m_dwFlags |= category; |
1722 | |
1723 | _ASSERTE(GetInternalCorElementType() == arrayType); |
1724 | } |
1725 | |
1726 | //========================================================================================== |
1727 | FORCEINLINE BOOL MethodTable::ImplementsInterfaceInline(MethodTable *pInterface) |
1728 | { |
1729 | CONTRACTL |
1730 | { |
1731 | NOTHROW; |
1732 | GC_NOTRIGGER; |
1733 | SO_TOLERANT; |
1734 | PRECONDITION(pInterface->IsInterface()); // class we are looking up should be an interface |
1735 | } |
1736 | CONTRACTL_END; |
1737 | |
1738 | // |
1739 | // Inline InterfaceMapIterator here for performance reasons |
1740 | // |
1741 | |
1742 | DWORD numInterfaces = GetNumInterfaces(); |
1743 | if (numInterfaces == 0) |
1744 | return FALSE; |
1745 | |
1746 | InterfaceInfo_t *pInfo = GetInterfaceMap(); |
1747 | |
1748 | do |
1749 | { |
1750 | if (pInfo->GetMethodTable() == pInterface) |
1751 | { |
1752 | // Extensible RCW's need to be handled specially because they can have interfaces |
1753 | // in their map that are added at runtime. These interfaces will have a start offset |
1754 | // of -1 to indicate this. We cannot take for granted that every instance of this |
1755 | // COM object has this interface so FindInterface on these interfaces is made to fail. |
1756 | // |
1757 | // However, we are only considering the statically available slots here |
1758 | // (m_wNumInterface doesn't contain the dynamic slots), so we can safely |
1759 | // ignore this detail. |
1760 | return TRUE; |
1761 | } |
1762 | pInfo++; |
1763 | } |
1764 | while (--numInterfaces); |
1765 | |
1766 | return FALSE; |
1767 | } |
1768 | |
1769 | #endif // !_METHODTABLE_INL_ |
1770 | |