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// method.hpp
6//
7
8//
9// See the book of the runtime entry for overall design:
10// file:../../doc/BookOfTheRuntime/ClassLoader/MethodDescDesign.doc
11//
12
13#ifndef _METHOD_H
14#define _METHOD_H
15
16#include "cor.h"
17#include "util.hpp"
18#include "clsload.hpp"
19#include "codeman.h"
20#include "class.h"
21#include "siginfo.hpp"
22#include "declsec.h"
23#include "methodimpl.h"
24#include "typedesc.h"
25#include <stddef.h>
26#include "eeconfig.h"
27#include "precode.h"
28#include "codeversion.h"
29
30#ifndef FEATURE_PREJIT
31#include "fixuppointer.h"
32#endif
33
34class Stub;
35class FCallMethodDesc;
36class FieldDesc;
37class NDirect;
38class MethodDescChunk;
39struct LayoutRawFieldInfo;
40class InstantiatedMethodDesc;
41class DictionaryLayout;
42class Dictionary;
43class GCCoverageInfo;
44class DynamicMethodDesc;
45class ReJitManager;
46class CodeVersionManager;
47class PrepareCodeConfig;
48class CallCounter;
49
50typedef DPTR(FCallMethodDesc) PTR_FCallMethodDesc;
51typedef DPTR(ArrayMethodDesc) PTR_ArrayMethodDesc;
52typedef DPTR(DynamicMethodDesc) PTR_DynamicMethodDesc;
53typedef DPTR(InstantiatedMethodDesc) PTR_InstantiatedMethodDesc;
54typedef DPTR(GCCoverageInfo) PTR_GCCoverageInfo; // see code:GCCoverageInfo::savedCode
55
56#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
57GVAL_DECL(DWORD, g_MiniMetaDataBuffMaxSize);
58GVAL_DECL(TADDR, g_MiniMetaDataBuffAddress);
59#endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
60
61EXTERN_C VOID STDCALL NDirectImportThunk();
62
63#define METHOD_TOKEN_REMAINDER_BIT_COUNT 14
64#define METHOD_TOKEN_REMAINDER_MASK ((1 << METHOD_TOKEN_REMAINDER_BIT_COUNT) - 1)
65#define METHOD_TOKEN_RANGE_BIT_COUNT (24 - METHOD_TOKEN_REMAINDER_BIT_COUNT)
66#define METHOD_TOKEN_RANGE_MASK ((1 << METHOD_TOKEN_RANGE_BIT_COUNT) - 1)
67
68//=============================================================
69// Splits methoddef token into two pieces for
70// storage inside a methoddesc.
71//=============================================================
72FORCEINLINE UINT16 GetTokenRange(mdToken tok)
73{
74 LIMITED_METHOD_CONTRACT;
75 return (UINT16)((tok>>METHOD_TOKEN_REMAINDER_BIT_COUNT) & METHOD_TOKEN_RANGE_MASK);
76}
77
78FORCEINLINE VOID SplitToken(mdToken tok, UINT16 *ptokrange, UINT16 *ptokremainder)
79{
80 LIMITED_METHOD_CONTRACT;
81 *ptokrange = (UINT16)((tok>>METHOD_TOKEN_REMAINDER_BIT_COUNT) & METHOD_TOKEN_RANGE_MASK);
82 *ptokremainder = (UINT16)(tok & METHOD_TOKEN_REMAINDER_MASK);
83}
84
85FORCEINLINE mdToken MergeToken(UINT16 tokrange, UINT16 tokremainder)
86{
87 LIMITED_METHOD_DAC_CONTRACT;
88 return (tokrange << METHOD_TOKEN_REMAINDER_BIT_COUNT) | tokremainder | mdtMethodDef;
89}
90
91// The MethodDesc is a union of several types. The following
92// 3-bit field determines which type it is. Note that JIT'ed/non-JIT'ed
93// is not represented here because this isn't known until the
94// method is executed for the first time. Because any thread could
95// change this bit, it has to be done in a place where access is
96// synchronized.
97
98// **** NOTE: if you add any new flags, make sure you add them to ClearFlagsOnUpdate
99// so that when a method is replaced its relevant flags are updated
100
101// Used in MethodDesc
102enum MethodClassification
103{
104 mcIL = 0, // IL
105 mcFCall = 1, // FCall (also includes tlbimped ctor, Delegate ctor)
106 mcNDirect = 2, // N/Direct
107 mcEEImpl = 3, // special method; implementation provided by EE (like Delegate Invoke)
108 mcArray = 4, // Array ECall
109 mcInstantiated = 5, // Instantiated generic methods, including descriptors
110 // for both shared and unshared code (see InstantiatedMethodDesc)
111
112#ifdef FEATURE_COMINTEROP
113 // This needs a little explanation. There are MethodDescs on MethodTables
114 // which are Interfaces. These have the mdcInterface bit set. Then there
115 // are MethodDescs on MethodTables that are Classes, where the method is
116 // exposed through an interface. These do not have the mdcInterface bit set.
117 //
118 // So, today, a dispatch through an 'mdcInterface' MethodDesc is either an
119 // error (someone forgot to look up the method in a class' VTable) or it is
120 // a case of COM Interop.
121
122 mcComInterop = 6,
123#endif // FEATURE_COMINTEROP
124 mcDynamic = 7, // for method desc with no metadata behind
125 mcCount,
126};
127
128
129// All flags in the MethodDesc now reside in a single 16-bit field.
130
131enum MethodDescClassification
132{
133 // Method is IL, FCall etc., see MethodClassification above.
134 mdcClassification = 0x0007,
135 mdcClassificationCount = mdcClassification+1,
136
137 // Note that layout of code:MethodDesc::s_ClassificationSizeTable depends on the exact values
138 // of mdcHasNonVtableSlot and mdcMethodImpl
139
140 // Has local slot (vs. has real slot in MethodTable)
141 mdcHasNonVtableSlot = 0x0008,
142
143 // Method is a body for a method impl (MI_MethodDesc, MI_NDirectMethodDesc, etc)
144 // where the function explicitly implements IInterface.foo() instead of foo().
145 mdcMethodImpl = 0x0010,
146
147 // Method is static
148 mdcStatic = 0x0020,
149
150 // unused = 0x0040,
151 // unused = 0x0080,
152 // unused = 0x0100,
153 // unused = 0x0200,
154
155 // Duplicate method. When a method needs to be placed in multiple slots in the
156 // method table, because it could not be packed into one slot. For eg, a method
157 // providing implementation for two interfaces, MethodImpl, etc
158 mdcDuplicate = 0x0400,
159
160 // Has this method been verified?
161 mdcVerifiedState = 0x0800,
162
163 // Is the method verifiable? It needs to be verified first to determine this
164 mdcVerifiable = 0x1000,
165
166 // Is this method ineligible for inlining?
167 mdcNotInline = 0x2000,
168
169 // Is the method synchronized
170 mdcSynchronized = 0x4000,
171
172 // Does the method's slot number require all 16 bits
173 mdcRequiresFullSlotNumber = 0x8000
174};
175
176#define METHOD_MAX_RVA 0x7FFFFFFF
177
178
179// The size of this structure needs to be a multiple of MethodDesc::ALIGNMENT
180//
181// @GENERICS:
182// Method descriptors for methods belonging to instantiated types may be shared between compatible instantiations
183// Hence for reflection and elsewhere where exact types are important it's necessary to pair a method desc
184// with the exact owning type handle.
185//
186// See genmeth.cpp for details of instantiated generic method descriptors.
187//
188// A MethodDesc is the representation of a method of a type. These live in code:MethodDescChunk which in
189// turn lives in code:EEClass. They are conceptually cold (we do not expect to access them in normal
190// program exectution, but we often fall short of that goal.
191//
192// A Method desc knows how to get at its metadata token code:GetMemberDef, its chunk
193// code:MethodDescChunk, which in turns knows how to get at its type code:MethodTable.
194// It also knows how to get at its IL code (code:IMAGE_COR_ILMETHOD)
195class MethodDesc
196{
197 friend class EEClass;
198 friend class MethodTableBuilder;
199 friend class ArrayClass;
200 friend class NDirect;
201 friend class MethodDescChunk;
202 friend class InstantiatedMethodDesc;
203 friend class MethodImpl;
204 friend class CheckAsmOffsets;
205 friend class ClrDataAccess;
206
207 friend class MethodDescCallSite;
208#ifdef DACCESS_COMPILE
209 friend class NativeImageDumper;
210#endif
211
212public:
213
214 enum
215 {
216#ifdef _WIN64
217 ALIGNMENT_SHIFT = 3,
218#else
219 ALIGNMENT_SHIFT = 2,
220#endif
221 ALIGNMENT = (1<<ALIGNMENT_SHIFT),
222 ALIGNMENT_MASK = (ALIGNMENT-1)
223 };
224
225#ifdef _DEBUG
226
227 // These are set only for MethodDescs but every time we want to use the debugger
228 // to examine these fields, the code has the thing stored in a MethodDesc*.
229 // So...
230 LPCUTF8 m_pszDebugMethodName;
231 LPCUTF8 m_pszDebugClassName;
232 LPCUTF8 m_pszDebugMethodSignature;
233 FixupPointer<PTR_MethodTable> m_pDebugMethodTable;
234
235 PTR_GCCoverageInfo m_GcCover;
236
237#endif // _DEBUG
238
239 inline BOOL HasStableEntryPoint()
240 {
241 LIMITED_METHOD_DAC_CONTRACT;
242
243 return (m_bFlags2 & enum_flag2_HasStableEntryPoint) != 0;
244 }
245
246 inline PCODE GetStableEntryPoint()
247 {
248 LIMITED_METHOD_DAC_CONTRACT;
249
250 _ASSERTE(HasStableEntryPoint());
251 return GetMethodEntryPoint();
252 }
253
254 BOOL SetStableEntryPointInterlocked(PCODE addr);
255
256 BOOL HasTemporaryEntryPoint();
257 PCODE GetTemporaryEntryPoint();
258
259 void SetTemporaryEntryPoint(LoaderAllocator *pLoaderAllocator, AllocMemTracker *pamTracker);
260
261 inline BOOL HasPrecode()
262 {
263 LIMITED_METHOD_DAC_CONTRACT;
264
265 return (m_bFlags2 & enum_flag2_HasPrecode) != 0;
266 }
267
268 inline Precode* GetPrecode()
269 {
270 LIMITED_METHOD_DAC_CONTRACT;
271
272 PRECONDITION(HasPrecode());
273 Precode* pPrecode = Precode::GetPrecodeFromEntryPoint(GetStableEntryPoint());
274 PREFIX_ASSUME(pPrecode != NULL);
275 return pPrecode;
276 }
277
278 inline BOOL MayHavePrecode()
279 {
280 CONTRACTL
281 {
282 THROWS;
283 GC_TRIGGERS;
284 MODE_ANY;
285 }
286 CONTRACTL_END
287
288 return !MayHaveNativeCode() || IsVersionableWithPrecode();
289 }
290
291 void InterlockedUpdateFlags2(BYTE bMask, BOOL fSet);
292
293 Precode* GetOrCreatePrecode();
294
295#ifdef FEATURE_PREJIT
296 Precode * GetSavedPrecode(DataImage *image);
297 Precode * GetSavedPrecodeOrNull(DataImage *image);
298#endif // FEATURE_PREJIT
299
300 // Given a code address return back the MethodDesc whenever possible
301 //
302 static MethodDesc * GetMethodDescFromStubAddr(PCODE addr, BOOL fSpeculative = FALSE);
303
304
305 DWORD GetAttrs() const;
306
307 DWORD GetImplAttrs();
308
309 // This function can lie if a method impl was used to implement
310 // more than one method on this class. Use GetName(int) to indicate
311 // which slot you are interested in.
312 // See the TypeString class for better control over name formatting.
313 LPCUTF8 GetName();
314
315 LPCUTF8 GetName(USHORT slot);
316
317 void PrecomputeNameHash();
318 BOOL MightHaveName(ULONG nameHashValue);
319
320 FORCEINLINE LPCUTF8 GetNameOnNonArrayClass()
321 {
322 WRAPPER_NO_CONTRACT;
323 LPCSTR szName;
324 if (FAILED(GetMDImport()->GetNameOfMethodDef(GetMemberDef(), &szName)))
325 {
326 szName = NULL;
327 }
328 return szName;
329 }
330
331 COUNT_T GetStableHash();
332
333 // Non-zero for InstantiatedMethodDescs
334 DWORD GetNumGenericMethodArgs();
335
336 // Return the number of class type parameters that are in scope for this method
337 DWORD GetNumGenericClassArgs()
338 {
339 WRAPPER_NO_CONTRACT;
340 SUPPORTS_DAC;
341 return GetMethodTable()->GetNumGenericArgs();
342 }
343
344 // True if this is a method descriptor for an instantiated generic method
345 // whose method type arguments are the formal type parameters of the generic method
346 // NOTE: the declaring class may not be the generic type definition e.g. consider C<int>.m<T>
347 BOOL IsGenericMethodDefinition() const;
348
349 // True if the declaring type or instantiation of method (if any) contains formal generic type parameters
350 BOOL ContainsGenericVariables();
351
352 Module* GetDefiningModuleForOpenMethod();
353
354 // True if this is a class and method instantiation that on <__Canon,...,__Canon>
355 BOOL IsTypicalSharedInstantiation();
356
357
358 // True if and only if this is a method desriptor for :
359 // 1. a non-generic method or a generic method at its typical method instantiation
360 // 2. in a non-generic class or a typical instantiation of a generic class
361 // This method can be called on a non-restored method desc
362 BOOL IsTypicalMethodDefinition() const;
363
364 // Force a load of the (typical) constraints on the type parameters of a typical method definition,
365 // detecting cyclic bounds on class and method type parameters.
366 void LoadConstraintsForTypicalMethodDefinition(BOOL *pfHasCircularClassConstraints,
367 BOOL *pfHasCircularMethodConstraints,
368 ClassLoadLevel level = CLASS_LOADED);
369
370 DWORD IsClassConstructor()
371 {
372 WRAPPER_NO_CONTRACT;
373 return IsMdClassConstructor(GetAttrs(), GetName());
374 }
375
376 DWORD IsClassConstructorOrCtor()
377 {
378 WRAPPER_NO_CONTRACT;
379 DWORD dwAttrs = GetAttrs();
380 if (IsMdRTSpecialName(dwAttrs))
381 {
382 LPCUTF8 name = GetName();
383 return IsMdInstanceInitializer(dwAttrs, name) || IsMdClassConstructor(dwAttrs, name);
384 }
385 return FALSE;
386 }
387
388 inline void SetHasMethodImplSlot()
389 {
390 m_wFlags |= mdcMethodImpl;
391 }
392
393 inline BOOL HasMethodImplSlot()
394 {
395 LIMITED_METHOD_DAC_CONTRACT;
396 return (mdcMethodImpl & m_wFlags);
397 }
398
399 FORCEINLINE BOOL IsMethodImpl()
400 {
401 LIMITED_METHOD_DAC_CONTRACT;
402 // Once we stop allocating dummy MethodImplSlot in MethodTableBuilder::WriteMethodImplData,
403 // the check for NULL will become unnecessary.
404 return HasMethodImplSlot() && (GetMethodImpl()->GetSlots() != NULL);
405 }
406
407 inline DWORD IsStatic()
408 {
409 LIMITED_METHOD_DAC_CONTRACT;
410
411 // This bit caches the IsMdStatic(GetAttrs()) check. We used to assert it here, but not doing it anymore. GetAttrs()
412 // accesses metadata that is not compatible with contracts of this method. The metadata access can fail, the metadata
413 // are not available during shutdown, the metadata access can take locks. It is not worth it to code around all these
414 // just for the assert.
415 // _ASSERTE((((m_wFlags & mdcStatic) != 0) == (IsMdStatic(flags) != 0)));
416
417 return (m_wFlags & mdcStatic) != 0;
418 }
419
420 inline void SetStatic()
421 {
422 LIMITED_METHOD_CONTRACT;
423 m_wFlags |= mdcStatic;
424 }
425
426 inline void ClearStatic()
427 {
428 LIMITED_METHOD_CONTRACT;
429 m_wFlags &= ~mdcStatic;
430 }
431
432 inline BOOL IsIL()
433 {
434 LIMITED_METHOD_DAC_CONTRACT;
435 return mcIL == GetClassification() || mcInstantiated == GetClassification();
436 }
437
438 //================================================================
439 // Generics-related predicates etc.
440
441 // True if the method descriptor is an instantiation of a generic method.
442 inline BOOL HasMethodInstantiation() const;
443
444 // True if the method descriptor is either an instantiation of
445 // a generic method or is an instance method in an instantiated class (or both).
446 BOOL HasClassOrMethodInstantiation()
447 {
448 LIMITED_METHOD_DAC_CONTRACT;
449 return (HasClassInstantiation() || HasMethodInstantiation());
450 }
451
452 BOOL HasClassOrMethodInstantiation_NoLogging() const
453 {
454 LIMITED_METHOD_DAC_CONTRACT;
455 return (HasClassInstantiation_NoLogging() || HasMethodInstantiation());
456 }
457
458 inline BOOL HasClassInstantiation() const
459 {
460 LIMITED_METHOD_DAC_CONTRACT;
461 return GetMethodTable()->HasInstantiation();
462 }
463
464 inline BOOL HasClassInstantiation_NoLogging() const
465 {
466 LIMITED_METHOD_DAC_CONTRACT;
467 return GetMethodTable_NoLogging()->HasInstantiation();
468 }
469
470 // Return the instantiation for an instantiated generic method
471 // Return NULL if not an instantiated method
472 // To get the (representative) instantiation of the declaring class use GetMethodTable()->GetInstantiation()
473 // NOTE: This will assert if you try to get the instantiation of a generic method def in a non-typical class
474 // e.g. C<int>.m<U> will fail but C<T>.m<U> will succeed
475 Instantiation GetMethodInstantiation() const;
476
477 // As above, but will succeed on C<int>.m<U>
478 // To do this it might force a load of the typical parent
479 Instantiation LoadMethodInstantiation();
480
481 // Return a pointer to the method dictionary for an instantiated generic method
482 // The initial slots in a method dictionary are the type arguments themselves
483 // Return NULL if not an instantiated method
484 Dictionary* GetMethodDictionary();
485 DictionaryLayout* GetDictionaryLayout();
486
487 InstantiatedMethodDesc* AsInstantiatedMethodDesc() const;
488
489 BaseDomain *GetDomain();
490
491#ifdef FEATURE_CODE_VERSIONING
492 CodeVersionManager* GetCodeVersionManager();
493#endif
494#ifdef FEATURE_TIERED_COMPILATION
495 CallCounter* GetCallCounter();
496#endif
497
498 PTR_LoaderAllocator GetLoaderAllocator();
499
500 // GetLoaderAllocatorForCode returns the allocator with the responsibility for allocation.
501 // This is called from GetMulticallableAddrOfCode when allocating a small trampoline stub for the method.
502 // Normally a method in a shared domain will allocate memory for stubs in the shared domain.
503 // That has to be different for DynamicMethod as they need to be allocated always in the AppDomain
504 // that created the method.
505 LoaderAllocator * GetLoaderAllocatorForCode();
506
507 // GetDomainSpecificLoaderAllocator returns the collectable loader allocator for collectable types
508 // and the loader allocator in the current domain for non-collectable types
509 LoaderAllocator * GetDomainSpecificLoaderAllocator();
510
511 Module* GetLoaderModule();
512
513 Module* GetZapModule();
514
515 // Does this immediate item live in an NGEN module?
516 BOOL IsZapped();
517
518 // Strip off method and class instantiation if present and replace by the typical instantiation
519 // e.g. C<int>.m<string> -> C<T>.m<U>. Does not modify the MethodDesc, but returns
520 // the appropriate stripped MethodDesc.
521 // This is the identity function on non-instantiated method descs in non-instantiated classes
522 MethodDesc* LoadTypicalMethodDefinition();
523
524 // Strip off the method instantiation (if present) and replace by the typical instantiation
525 // e.g. // C<int>.m<string> -> C<int>.m<U>. Does not modify the MethodDesc, but returns
526 // the appropriate stripped MethodDesc.
527 // This is the identity function on non-instantiated method descs
528 MethodDesc* StripMethodInstantiation();
529
530 // Return the instantiation of a method's enclosing class
531 // Return NULL if the enclosing class is not instantiated
532 // If the method code is shared then this might be a *representative* instantiation
533 //
534 // See GetExactClassInstantiation if you need to get the exact
535 // instantiation of a shared method desc.
536 Instantiation GetClassInstantiation() const;
537
538 // Is the code shared between multiple instantiations of class or method?
539 // If so, then when compiling the code we might need to look up tokens
540 // in the class or method dictionary. Also, when debugging the exact generic arguments
541 // need to be ripped off the stack, either from the this pointer or from one of the
542 // extra args below.
543 BOOL IsSharedByGenericInstantiations(); // shared code of any kind
544
545 BOOL IsSharedByGenericMethodInstantiations(); // shared due to method instantiation
546
547 // How does a method shared between generic instantiations get at
548 // the extra instantiation information at runtime? Only one of the following three
549 // will ever hold:
550 //
551 // AcquiresInstMethodTableFromThis()
552 // The method is in a generic class but is not itself a
553 // generic method (the normal case). Furthermore a "this" pointer
554 // is available and we can get the exact instantiation from it.
555 //
556 // RequiresInstMethodTableArg()
557 // The method is shared between generic classes but is not
558 // itself generic. Furthermore no "this" pointer is given
559 // (e.g. a value type method), so we pass in the exact-instantiation
560 // method table as an extra argument.
561 // i.e. per-inst static methods in shared-code instantiated generic
562 // classes (e.g. static void MyClass<string>::m())
563 // i.e. shared-code instance methods in instantiated generic
564 // structs (e.g. void MyValueType<string>::m())
565 //
566 // RequiresInstMethodDescArg()
567 // The method is itself generic and is shared between generic
568 // instantiations but is not itself generic. Furthermore
569 // no "this" pointer is given (e.g. a value type method), so we pass in the
570 // exact-instantiation method table as an extra argument.
571 // i.e. shared-code instantiated generic methods
572 //
573 // These are used for direct calls to instantiated generic methods
574 // e.g. call void C::m<string>() implemented by calculating dict(m<string>) at compile-time and passing it as an extra parameter
575 // call void C::m<!0>() implemented by calculating dict(m<!0>) at run-time (if the caller lives in shared-class code)
576
577 BOOL AcquiresInstMethodTableFromThis();
578 BOOL RequiresInstMethodTableArg();
579 BOOL RequiresInstMethodDescArg();
580 BOOL RequiresInstArg();
581
582 // Can this method handle be given out to reflection for use in a MethodInfo
583 // object?
584 BOOL IsRuntimeMethodHandle();
585
586 // Given a method table of an object and a method that comes from some
587 // superclass of the class of that object, find that superclass.
588 MethodTable * GetExactDeclaringType(MethodTable * ownerOrSubType);
589
590 // Given a type handle of an object and a method that comes from some
591 // superclass of the class of that object, find the instantiation of
592 // that superclass, i.e. the class instantiation which will be relevant
593 // to interpreting the signature of the method. The type handle of
594 // the object does not need to be given in all circumstances, in
595 // particular it is only needed for MethodDescs pMD that
596 // return true for pMD->RequiresInstMethodTableArg() or
597 // pMD->RequiresInstMethodDescArg(). In other cases it is
598 // allowed to be null.
599 //
600 // Will return NULL if the method is not in a generic class.
601 Instantiation GetExactClassInstantiation(TypeHandle possibleObjType);
602
603
604 BOOL SatisfiesMethodConstraints(TypeHandle thParent, BOOL fThrowIfNotSatisfied = FALSE);
605
606
607 BOOL HasSameMethodDefAs(MethodDesc * pMD);
608
609 //================================================================
610 // Classifications of kinds of MethodDescs.
611
612 inline BOOL IsRuntimeSupplied()
613 {
614 LIMITED_METHOD_DAC_CONTRACT;
615 return mcFCall == GetClassification()
616 || mcArray == GetClassification();
617 }
618
619
620 inline DWORD IsArray() const
621 {
622 LIMITED_METHOD_DAC_CONTRACT;
623 return mcArray == GetClassification();
624 }
625
626 inline DWORD IsEEImpl() const
627 {
628 LIMITED_METHOD_DAC_CONTRACT;
629 return mcEEImpl == GetClassification();
630 }
631
632 inline DWORD IsNoMetadata() const
633 {
634 LIMITED_METHOD_DAC_CONTRACT;
635 return (mcDynamic == GetClassification());
636 }
637
638 inline PTR_DynamicMethodDesc AsDynamicMethodDesc();
639 inline bool IsDynamicMethod();
640 inline bool IsILStub();
641 inline bool IsLCGMethod();
642
643 inline DWORD IsNDirect()
644 {
645 LIMITED_METHOD_DAC_CONTRACT;
646 return mcNDirect == GetClassification();
647 }
648
649 inline DWORD IsInterface()
650 {
651 WRAPPER_NO_CONTRACT;
652 return GetMethodTable()->IsInterface();
653 }
654
655 void ComputeSuppressUnmanagedCodeAccessAttr(IMDInternalImport *pImport);
656 BOOL HasNativeCallableAttribute();
657
658#ifdef FEATURE_COMINTEROP
659 inline DWORD IsComPlusCall()
660 {
661 WRAPPER_NO_CONTRACT;
662 return mcComInterop == GetClassification();
663 }
664 inline DWORD IsGenericComPlusCall();
665 inline void SetupGenericComPlusCall();
666#else // !FEATURE_COMINTEROP
667 // hardcoded to return FALSE to improve code readibility
668 inline DWORD IsComPlusCall()
669 {
670 LIMITED_METHOD_CONTRACT;
671 return FALSE;
672 }
673 inline DWORD IsGenericComPlusCall()
674 {
675 LIMITED_METHOD_CONTRACT;
676 return FALSE;
677 }
678#endif // !FEATURE_COMINTEROP
679
680 // Update flags in a thread safe manner.
681 WORD InterlockedUpdateFlags(WORD wMask, BOOL fSet);
682
683 // If the method is in an Edit and Contine (EnC) module, then
684 // we DON'T want to backpatch this, ever. We MUST always call
685 // through the precode so that we can update the method.
686 inline DWORD IsEnCMethod()
687 {
688 WRAPPER_NO_CONTRACT;
689 Module *pModule = GetModule();
690 PREFIX_ASSUME(pModule != NULL);
691 return pModule->IsEditAndContinueEnabled();
692 }
693
694 inline BOOL IsNotInline()
695 {
696 LIMITED_METHOD_CONTRACT;
697 return (m_wFlags & mdcNotInline);
698 }
699
700 inline void SetNotInline(BOOL set)
701 {
702 WRAPPER_NO_CONTRACT;
703 InterlockedUpdateFlags(mdcNotInline, set);
704 }
705
706#ifndef DACCESS_COMPILE
707 VOID EnsureActive();
708#endif
709 CHECK CheckActivated();
710
711 //================================================================
712 // FCalls.
713 BOOL IsFCall()
714 {
715 WRAPPER_NO_CONTRACT;
716 return mcFCall == GetClassification();
717 }
718
719 BOOL IsFCallOrIntrinsic();
720
721 BOOL IsQCall();
722
723 //================================================================
724 //
725
726 inline void ClearFlagsOnUpdate()
727 {
728 WRAPPER_NO_CONTRACT;
729 SetNotInline(FALSE);
730 }
731
732 // Restore the MethodDesc to it's initial, pristine state, so that
733 // it can be reused for new code (eg. for EnC, method rental, etc.)
734 //
735 // Things to think about before calling this:
736 //
737 // Does the caller need to free up the jitted code for the old IL
738 // (including any other IJitManager datastructures) ?
739 // Does the caller guarantee thread-safety ?
740 //
741 void Reset();
742
743 //================================================================
744 // About the signature.
745
746 BOOL IsVarArg();
747 BOOL IsVoid();
748 BOOL HasRetBuffArg();
749
750 // Returns the # of bytes of stack used by arguments. Does not include
751 // arguments passed in registers.
752 UINT SizeOfArgStack();
753
754 // Returns the # of bytes of stack used by arguments in a call from native to this function.
755 // Does not include arguments passed in registers.
756 UINT SizeOfNativeArgStack();
757
758 // Returns the # of bytes to pop after a call. Not necessary the
759 // same as SizeOfArgStack()!
760 UINT CbStackPop();
761
762 //================================================================
763 // Unboxing stubs.
764 //
765 // Return TRUE if this is this a special stub used to implement delegates to an
766 // instance method in a value class and/or virtual methods on a value class.
767 //
768 // For every BoxedEntryPointStub there is associated unboxed-this-MethodDesc
769 // which accepts an unboxed "this" pointer.
770 //
771 // The action of a typical BoxedEntryPointStub is to
772 // bump up the this pointer by one word so that it points to the interior of the object
773 // and then call the underlying unboxed-this-MethodDesc.
774 //
775 // Additionally, if the non-BoxedEntryPointStub is RequiresInstMethodTableArg()
776 // then pass on the MethodTable as an extra argument to the
777 // underlying unboxed-this-MethodDesc.
778 BOOL IsUnboxingStub()
779 {
780 LIMITED_METHOD_DAC_CONTRACT;
781
782 return (m_bFlags2 & enum_flag2_IsUnboxingStub) != 0;
783 }
784
785 void SetIsUnboxingStub()
786 {
787 LIMITED_METHOD_CONTRACT;
788 m_bFlags2 |= enum_flag2_IsUnboxingStub;
789 }
790
791
792 //================================================================
793 // Instantiating Stubs
794 //
795 // Return TRUE if this is this a special stub used to implement an
796 // instantiated generic method or per-instantiation static method.
797 // The action of an instantiating stub is
798 // * pass on a MethodTable or InstantiatedMethodDesc extra argument to shared code
799 BOOL IsInstantiatingStub();
800
801
802 // A wrapper stub is either an unboxing stub or an instantiating stub
803 BOOL IsWrapperStub();
804 MethodDesc *GetWrappedMethodDesc();
805 MethodDesc *GetExistingWrappedMethodDesc();
806
807 //==================================================================
808 // Access the underlying metadata
809
810 BOOL HasILHeader()
811 {
812 CONTRACTL
813 {
814 NOTHROW;
815 GC_NOTRIGGER;
816 SO_TOLERANT;
817 MODE_ANY;
818 }
819 CONTRACTL_END;
820 return IsIL() && !IsUnboxingStub() && GetRVA();
821 }
822
823 COR_ILMETHOD* GetILHeader(BOOL fAllowOverrides = FALSE);
824
825 BOOL HasStoredSig()
826 {
827 LIMITED_METHOD_DAC_CONTRACT;
828 return IsEEImpl() || IsArray() || IsNoMetadata();
829 }
830
831 PCCOR_SIGNATURE GetSig();
832
833 void GetSig(PCCOR_SIGNATURE *ppSig, DWORD *pcSig);
834 SigParser GetSigParser();
835
836 // Convenience methods for common signature wrapper types.
837 SigPointer GetSigPointer();
838 Signature GetSignature();
839
840
841 void GetSigFromMetadata(IMDInternalImport * importer,
842 PCCOR_SIGNATURE * ppSig,
843 DWORD * pcSig);
844
845
846 IMDInternalImport* GetMDImport() const
847 {
848 WRAPPER_NO_CONTRACT;
849 Module *pModule = GetModule();
850 PREFIX_ASSUME(pModule != NULL);
851 return pModule->GetMDImport();
852 }
853
854#ifndef DACCESS_COMPILE
855 IMetaDataEmit* GetEmitter()
856 {
857 WRAPPER_NO_CONTRACT;
858 Module *pModule = GetModule();
859 PREFIX_ASSUME(pModule != NULL);
860 return pModule->GetEmitter();
861 }
862
863 IMetaDataImport* GetRWImporter()
864 {
865 WRAPPER_NO_CONTRACT;
866 Module *pModule = GetModule();
867 PREFIX_ASSUME(pModule != NULL);
868 return pModule->GetRWImporter();
869 }
870#endif // !DACCESS_COMPILE
871
872#ifdef FEATURE_COMINTEROP
873 WORD GetComSlot();
874 LONG GetComDispid();
875#endif // FEATURE_COMINTEROP
876
877 inline DWORD IsCtor()
878 {
879 WRAPPER_NO_CONTRACT;
880 return IsMdInstanceInitializer(GetAttrs(), GetName());
881 }
882
883 inline DWORD IsFinal()
884 {
885 WRAPPER_NO_CONTRACT;
886 return IsMdFinal(GetAttrs());
887 }
888
889 inline DWORD IsPrivate()
890 {
891 WRAPPER_NO_CONTRACT;
892 return IsMdPrivate(GetAttrs());
893 }
894
895 inline DWORD IsPublic() const
896 {
897 WRAPPER_NO_CONTRACT;
898 return IsMdPublic(GetAttrs());
899 }
900
901 inline DWORD IsProtected() const
902 {
903 WRAPPER_NO_CONTRACT;
904 return IsMdFamily(GetAttrs());
905 }
906
907 inline DWORD IsVirtual()
908 {
909 WRAPPER_NO_CONTRACT;
910 return IsMdVirtual(GetAttrs());
911 }
912
913 inline DWORD IsAbstract()
914 {
915 WRAPPER_NO_CONTRACT;
916 return IsMdAbstract(GetAttrs());
917 }
918
919 //==================================================================
920 // Flags..
921
922 inline void SetSynchronized()
923 {
924 LIMITED_METHOD_CONTRACT;
925 m_wFlags |= mdcSynchronized;
926 }
927
928 inline DWORD IsSynchronized()
929 {
930 LIMITED_METHOD_DAC_CONTRACT;
931 return (m_wFlags & mdcSynchronized) != 0;
932 }
933
934 // Be careful about races with profiler when using this method. The profiler can
935 // replace preimplemented code of the method with jitted code.
936 // Avoid code patterns like if(IsPreImplemented()) { PCODE pCode = GetPreImplementedCode(); ... }.
937 // Use PCODE pCode = GetPreImplementedCode(); if (pCode != NULL) { ... } instead.
938 BOOL IsPreImplemented()
939 {
940 LIMITED_METHOD_DAC_CONTRACT;
941
942 return GetPreImplementedCode() != NULL;
943 }
944
945 //==================================================================
946 // The MethodDesc in relation to the VTable it is associated with.
947 // WARNING: Not all MethodDescs have slots, nor do they all have
948 // entries in MethodTables. Beware.
949
950 // Does the method has virtual slot? Note that methods implementing interfaces
951 // on value types do not have virtual slots, but they are marked as virtual in metadata.
952 inline BOOL IsVtableMethod()
953 {
954 LIMITED_METHOD_CONTRACT;
955 MethodTable *pMT = GetMethodTable();
956 g_IBCLogger.LogMethodTableAccess(pMT);
957 return
958 !IsEnCAddedMethod()
959 // The slot numbers are currently meaningless for
960 // some unboxed-this-generic-method-instantiations
961 && !(pMT->IsValueType() && !IsStatic() && !IsUnboxingStub())
962 && GetSlot() < pMT->GetNumVirtuals();
963 }
964
965 // Is this a default interface method (virtual non-abstract instance method)
966 inline BOOL IsDefaultInterfaceMethod()
967 {
968 LIMITED_METHOD_CONTRACT;
969
970#ifdef FEATURE_DEFAULT_INTERFACES
971 return (GetMethodTable()->IsInterface() && !IsStatic() && IsVirtual() && !IsAbstract());
972#else
973 return false;
974#endif // FEATURE_DEFAULT_INTERFACES
975 }
976
977 inline BOOL HasNonVtableSlot();
978
979 void SetHasNonVtableSlot()
980 {
981 LIMITED_METHOD_CONTRACT;
982 m_wFlags |= mdcHasNonVtableSlot;
983 }
984
985 // duplicate methods
986 inline BOOL IsDuplicate()
987 {
988 LIMITED_METHOD_CONTRACT;
989 return (m_wFlags & mdcDuplicate) == mdcDuplicate;
990 }
991
992 void SetDuplicate()
993 {
994 LIMITED_METHOD_CONTRACT;
995 // method table is not setup yet
996 //_ASSERTE(!GetClass()->IsInterface());
997 m_wFlags |= mdcDuplicate;
998 }
999
1000 //==================================================================
1001 // EnC
1002
1003 inline BOOL IsEnCAddedMethod();
1004
1005 //==================================================================
1006 //
1007
1008 inline EEClass* GetClass()
1009 {
1010 WRAPPER_NO_CONTRACT;
1011 MethodTable *pMT = GetMethodTable_NoLogging();
1012 g_IBCLogger.LogEEClassAndMethodTableAccess(pMT);
1013 EEClass *pClass = pMT->GetClass_NoLogging();
1014 PREFIX_ASSUME(pClass != NULL);
1015 return pClass;
1016 }
1017
1018 inline PTR_MethodTable GetMethodTable() const;
1019 inline PTR_MethodTable GetMethodTable_NoLogging() const;
1020
1021 inline DPTR(RelativeFixupPointer<PTR_MethodTable>) GetMethodTablePtr() const;
1022
1023 public:
1024 inline MethodDescChunk* GetMethodDescChunk() const;
1025 inline int GetMethodDescIndex() const;
1026 // If this is an method desc. (whether non-generic shared-instantiated or exact-instantiated)
1027 // inside a shared class then get the method table for the representative
1028 // class.
1029 inline MethodTable* GetCanonicalMethodTable();
1030
1031 Module *GetModule() const;
1032 Module *GetModule_NoLogging() const;
1033
1034 Assembly *GetAssembly() const
1035 {
1036 WRAPPER_NO_CONTRACT;
1037 Module *pModule = GetModule();
1038 PREFIX_ASSUME(pModule != NULL);
1039 return pModule->GetAssembly();
1040 }
1041
1042 //==================================================================
1043 // The slot number of this method in the corresponding method table.
1044 //
1045 // Use with extreme caution. The slot number will not be
1046 // valid for EnC code or for MethodDescs representing instantiation
1047 // of generic methods. It may also not mean what you think it will mean
1048 // for strange method descs such as BoxedEntryPointStubs.
1049 //
1050 // In any case we should be moving to use slot numbers a lot less
1051 // since they make the EE code inflexible.
1052
1053 inline WORD GetSlot()
1054 {
1055 LIMITED_METHOD_DAC_CONTRACT;
1056#ifndef DACCESS_COMPILE
1057 // The DAC build uses this method to test for "sanity" of a MethodDesc, and
1058 // doesn't need the assert.
1059 _ASSERTE(! IsEnCAddedMethod() || !"Cannot get slot for method added via EnC");
1060#endif // !DACCESS_COMPILE
1061
1062 // Check if this MD is using the packed slot layout
1063 if (!RequiresFullSlotNumber())
1064 {
1065 return (m_wSlotNumber & enum_packedSlotLayout_SlotMask);
1066 }
1067
1068 return m_wSlotNumber;
1069 }
1070
1071 inline VOID SetSlot(WORD wSlotNum)
1072 {
1073 LIMITED_METHOD_CONTRACT;
1074
1075 // Check if we have to avoid using the packed slot layout
1076 if (wSlotNum > enum_packedSlotLayout_SlotMask)
1077 {
1078 SetRequiresFullSlotNumber();
1079 }
1080
1081 // Set only the portion of m_wSlotNumber we are using
1082 if (!RequiresFullSlotNumber())
1083 {
1084 m_wSlotNumber &= ~enum_packedSlotLayout_SlotMask;
1085 m_wSlotNumber |= wSlotNum;
1086 }
1087 else
1088 {
1089 m_wSlotNumber = wSlotNum;
1090 }
1091 }
1092
1093 inline BOOL IsVirtualSlot()
1094 {
1095 return GetSlot() < GetMethodTable()->GetNumVirtuals();
1096 }
1097 inline BOOL IsVtableSlot()
1098 {
1099 return IsVirtualSlot() && !HasNonVtableSlot();
1100 }
1101
1102 TADDR GetAddrOfSlot();
1103
1104 PTR_MethodDesc GetDeclMethodDesc(UINT32 slotNumber);
1105
1106protected:
1107 inline void SetRequiresFullSlotNumber()
1108 {
1109 LIMITED_METHOD_CONTRACT;
1110 m_wFlags |= mdcRequiresFullSlotNumber;
1111 }
1112
1113 inline DWORD RequiresFullSlotNumber()
1114 {
1115 LIMITED_METHOD_DAC_CONTRACT;
1116 return (m_wFlags & mdcRequiresFullSlotNumber) != 0;
1117 }
1118
1119public:
1120 mdMethodDef GetMemberDef() const;
1121 mdMethodDef GetMemberDef_NoLogging() const;
1122
1123#ifdef _DEBUG
1124 BOOL SanityCheck();
1125#endif // _DEBUG
1126
1127public:
1128
1129 void SetMemberDef(mdMethodDef mb);
1130
1131 //================================================================
1132 // Set the offset of this method desc in a chunk table (which allows us
1133 // to work back to the method table/module pointer stored at the head of
1134 // the table.
1135 void SetChunkIndex(MethodDescChunk *pChunk);
1136
1137 BOOL IsPointingToPrestub();
1138
1139public:
1140
1141 // TRUE iff it is possible to change the code this method will run using
1142 // the CodeVersionManager.
1143 // Note: EnC currently returns FALSE here because it uses its own seperate
1144 // scheme to manage versionability. We will likely want to converge them
1145 // at some point.
1146 BOOL IsVersionable()
1147 {
1148#ifndef FEATURE_CODE_VERSIONING
1149 return FALSE;
1150#else
1151 return IsVersionableWithPrecode() || IsVersionableWithJumpStamp();
1152#endif
1153 }
1154
1155 // If true, these methods version using the CodeVersionManager and
1156 // switch between different code versions by updating the target of the precode.
1157 // Note: EnC returns FALSE - even though it uses precode updates it does not
1158 // use the CodeVersionManager right now
1159 BOOL IsVersionableWithPrecode()
1160 {
1161#ifdef FEATURE_CODE_VERSIONING
1162 return
1163 // policy: which things do we want to version with a precode if possible
1164 IsEligibleForTieredCompilation() &&
1165
1166 // functional requirements:
1167 !IsZapped() && // NGEN directly invokes the pre-generated native code.
1168 // without necessarily going through the prestub or
1169 // precode
1170 HasNativeCodeSlot(); // the stable entry point will need to point at our
1171 // precode and not directly contain the native code.
1172#else
1173 return FALSE;
1174#endif
1175 }
1176
1177 // If true, these methods version using the CodeVersionManager and switch between
1178 // different code versions by overwriting the first bytes of the method's initial
1179 // native code with a jmp instruction.
1180 BOOL IsVersionableWithJumpStamp()
1181 {
1182#if defined(FEATURE_CODE_VERSIONING) && defined(FEATURE_JUMPSTAMP)
1183 return
1184 // for native image code this is policy, but for jitted code it is a functional requirement
1185 // to ensure the prolog is sufficiently large
1186 ReJitManager::IsReJITEnabled() &&
1187
1188 // functional requirement - the runtime doesn't expect both options to be possible
1189 !IsVersionableWithPrecode() &&
1190
1191 // functional requirement - we must be able to evacuate the prolog and the prolog must be big
1192 // enough, both of which are only designed to work on jitted code
1193 (IsIL() || IsNoMetadata()) &&
1194 !IsUnboxingStub() &&
1195 !IsInstantiatingStub() &&
1196
1197 // functional requirement - code version manager can't handle what would happen if the code
1198 // was collected
1199 !GetLoaderAllocator()->IsCollectible();
1200#else
1201 return FALSE;
1202#endif
1203 }
1204
1205#ifdef FEATURE_TIERED_COMPILATION
1206 // Is this method allowed to be recompiled and the entrypoint redirected so that we
1207 // can optimize its performance? Eligibility is invariant for the lifetime of a method.
1208 BOOL IsEligibleForTieredCompilation()
1209 {
1210 LIMITED_METHOD_DAC_CONTRACT;
1211
1212 // Keep in-sync with MethodTableBuilder::NeedsNativeCodeSlot(bmtMDMethod * pMDMethod)
1213 // to ensure native slots are available where needed.
1214 return g_pConfig->TieredCompilation() &&
1215 !IsZapped() &&
1216 !IsEnCMethod() &&
1217 HasNativeCodeSlot() &&
1218 !IsUnboxingStub() &&
1219 !IsInstantiatingStub() &&
1220 !IsDynamicMethod() &&
1221 !GetLoaderAllocator()->IsCollectible() &&
1222 !CORDisableJITOptimizations(GetModule()->GetDebuggerInfoBits()) &&
1223 !CORProfilerDisableTieredCompilation();
1224 }
1225#endif
1226
1227 bool RequestedAggressiveOptimization()
1228 {
1229 WRAPPER_NO_CONTRACT;
1230
1231 return
1232 IsIL() && // only makes sense for IL methods, and this implies !IsNoMetadata()
1233 IsMiAggressiveOptimization(GetImplAttrs());
1234 }
1235
1236 // Does this method force the NativeCodeSlot to stay fixed after it
1237 // is first initialized to native code? Consumers of the native code
1238 // pointer need to be very careful about if and when they cache it
1239 // if it is not stable.
1240 //
1241 // The stability of the native code pointer is separate from the
1242 // stability of the entrypoint. A stable entrypoint can be a precode
1243 // which dispatches to an unstable native code pointer.
1244 BOOL IsNativeCodeStableAfterInit()
1245 {
1246 LIMITED_METHOD_DAC_CONTRACT;
1247
1248#if defined(FEATURE_JIT_PITCHING)
1249 if (IsPitchable())
1250 return false;
1251#endif
1252
1253 return
1254#ifdef FEATURE_TIERED_COMPILATION
1255 !IsEligibleForTieredCompilation() &&
1256#endif
1257 !IsEnCMethod();
1258 }
1259
1260 //Is this method currently pointing to native code that will never change?
1261 BOOL IsPointingToStableNativeCode()
1262 {
1263 LIMITED_METHOD_DAC_CONTRACT;
1264
1265 if (!IsNativeCodeStableAfterInit())
1266 return FALSE;
1267
1268 return IsPointingToNativeCode();
1269 }
1270
1271 // Note: We are skipping the prestub based on addition information from the JIT.
1272 // (e.g. that the call is on same this ptr or that the this ptr is not null).
1273 // Thus we can end up with a running NGENed method for which IsPointingToNativeCode is false!
1274 BOOL IsPointingToNativeCode()
1275 {
1276 LIMITED_METHOD_DAC_CONTRACT;
1277
1278 if (!HasStableEntryPoint())
1279 return FALSE;
1280
1281 if (!HasPrecode())
1282 return TRUE;
1283
1284 return GetPrecode()->IsPointingToNativeCode(GetNativeCode());
1285 }
1286
1287 // Be careful about races with profiler when using this method. The profiler can
1288 // replace preimplemented code of the method with jitted code.
1289 // Avoid code patterns like if(HasNativeCode()) { PCODE pCode = GetNativeCode(); ... }.
1290 // Use PCODE pCode = GetNativeCode(); if (pCode != NULL) { ... } instead.
1291 BOOL HasNativeCode()
1292 {
1293 LIMITED_METHOD_DAC_CONTRACT;
1294
1295 return GetNativeCode() != NULL;
1296 }
1297
1298 BOOL SetNativeCodeInterlocked(PCODE addr, PCODE pExpected = NULL);
1299
1300 TADDR GetAddrOfNativeCodeSlot();
1301
1302 BOOL MayHaveNativeCode();
1303
1304 ULONG GetRVA();
1305
1306public:
1307
1308 // Returns preimplemented code of the method if method has one.
1309 // Returns NULL if method has no preimplemented code.
1310 // Be careful about races with profiler when using this method. The profiler can
1311 // replace preimplemented code of the method with jitted code.
1312 PCODE GetPreImplementedCode();
1313
1314 // Returns address of code to call. The address is good for one immediate invocation only.
1315 // Use GetMultiCallableAddrOfCode() to get address that can be invoked multiple times.
1316 //
1317 // Only call GetSingleCallableAddrOfCode() if you can guarantee that no virtualization is
1318 // necessary, or if you can guarantee that it has already happened. For instance, the frame of a
1319 // stackwalk has obviously been virtualized as much as it will be.
1320 //
1321 PCODE GetSingleCallableAddrOfCode()
1322 {
1323 WRAPPER_NO_CONTRACT;
1324 _ASSERTE(!IsGenericMethodDefinition());
1325 return GetMethodEntryPoint();
1326 }
1327
1328 // This one is used to implement "ldftn".
1329 PCODE GetMultiCallableAddrOfCode(CORINFO_ACCESS_FLAGS accessFlags = CORINFO_ACCESS_LDFTN);
1330
1331 // Internal version of GetMultiCallableAddrOfCode. Returns NULL if attempt to acquire directly
1332 // callable entrypoint would result into unnecesary allocation of indirection stub. Caller should use
1333 // indirect call via slot in this case.
1334 PCODE TryGetMultiCallableAddrOfCode(CORINFO_ACCESS_FLAGS accessFlags);
1335
1336 // These return an address after resolving "virtual methods" correctly, including any
1337 // handling of context proxies, other thunking layers and also including
1338 // instantiation of generic virtual methods if required.
1339 // The first one returns an address which cannot be invoked
1340 // multiple times. Use GetMultiCallableAddrOfVirtualizedCode() for that.
1341 //
1342 // The code that implements these was taken verbatim from elsewhere in the
1343 // codebase, and there may be subtle differences between the two, e.g. with
1344 // regard to thunking.
1345 PCODE GetSingleCallableAddrOfVirtualizedCode(OBJECTREF *orThis, TypeHandle staticTH);
1346 PCODE GetMultiCallableAddrOfVirtualizedCode(OBJECTREF *orThis, TypeHandle staticTH);
1347
1348 // The current method entrypoint. It is simply the value of the current method slot.
1349 // GetMethodEntryPoint() should be used to get an opaque method entrypoint, for instance
1350 // when copying or searching vtables. It should not be used to get address to call.
1351 //
1352 // GetSingleCallableAddrOfCode() and GetStableEntryPoint() are aliases with stricter preconditions.
1353 // Use of these aliases is as appropriate.
1354 //
1355 PCODE GetMethodEntryPoint();
1356
1357 //*******************************************************************************
1358 // Returns the address of the native code. The native code can be one of:
1359 // - jitted code if !IsPreImplemented()
1360 // - ngened code if IsPreImplemented()
1361 PCODE GetNativeCode();
1362
1363#if defined(FEATURE_JIT_PITCHING)
1364 bool IsPitchable();
1365 void PitchNativeCode();
1366#endif
1367
1368 //================================================================
1369 // FindOrCreateAssociatedMethodDesc
1370 //
1371 // You might think that every MethodDef in the metadata had
1372 // one and only one MethodDesc in the source... Well, how wrong
1373 // you are :-)
1374 //
1375 // Some MethodDefs can be associated with more than one MethodDesc.
1376 // This can happen because:
1377 // (1) The method is an instance method in a struct, which
1378 // can be called with either an unboxed "this" pointer or
1379 // a "boxed" this pointer.. There is a different MethodDesc for
1380 // these two cases.
1381 // (2) The method is a generic method. There is one primary
1382 // MethodDesc for each generic method, called the GenericMethodDefinition.
1383 // This is the one stored in the vtable. New MethodDescs will
1384 // be created for instantiations according to the scheme described
1385 // elsewhere in this file.
1386 // There are also various other stubs associated with MethodDesc, but these stubs
1387 // do not result in new MethodDescs.
1388 //
1389 // All of the above MethodDescs are called "associates" of the primary MethodDesc.
1390 // Note that the primary MethodDesc for an instance method on a struct is
1391 // the one that accepts an unboxed "this" pointer.
1392 //
1393 // FindOrCreateAssociatedMethodDesc is the _primary_ routine
1394 // in the codebase for getting an associated MethodDesc from a primary MethodDesc.
1395 // You should treat this routine as a black box, i.e. just specify the right
1396 // parameters and it will do all the hard work of finding the right
1397 // MethodDesc for you.
1398 //
1399 // This routine can be used for "normal" MethodDescs that have nothing
1400 // to do with generics. For example, if you need an BoxedEntryPointStub then
1401 // you may call this routine to get it. It may also return
1402 // the Primary MethodDesc itself if that MethodDesc is suitable given the
1403 // parameters.
1404 //
1405 // NOTE: The behaviour of this method is not thoroughly defined
1406 // if pPrimaryMD is not really a "primary" MD. Primary MDs are:
1407 // 1. Primary MDs are:never a generic method instantiation,
1408 // but are instead the "uninstantiated" generic MD.
1409 // 2. Primary MDs are never instantiating stubs.
1410 // 3. Primary MDs are never BoxedEntryPointStubs.
1411 //
1412 // We assert if cases (1) or (2) occur. However, some places in the
1413 // code pass in an BoxedEntryPointStub when pPrimaryMD is a virtual/interface method on
1414 // a struct. These cases are confusing and should be rooted
1415 // out: it is probably preferable in terms
1416 // of correctness to pass in the the corresponding non-unboxing MD.
1417 //
1418 // allowCreate may be set to FALSE to enforce that the method searched
1419 // should already be in existence - thus preventing creation and GCs during
1420 // inappropriate times.
1421 //
1422 static MethodDesc* FindOrCreateAssociatedMethodDesc(MethodDesc* pPrimaryMD,
1423 MethodTable *pExactMT,
1424 BOOL forceBoxedEntryPoint,
1425 Instantiation methodInst,
1426 BOOL allowInstParam,
1427 BOOL forceRemotableMethod = FALSE,
1428 BOOL allowCreate = TRUE,
1429 ClassLoadLevel level = CLASS_LOADED);
1430
1431 // Normalize methoddesc for reflection
1432 static MethodDesc* FindOrCreateAssociatedMethodDescForReflection(MethodDesc *pMethod,
1433 TypeHandle instType,
1434 Instantiation methodInst);
1435
1436 // True if a MD is an funny BoxedEntryPointStub (not from the method table) or
1437 // an MD for a generic instantiation...In other words the MethodDescs and the
1438 // MethodTable are guaranteed to be "tightly-knit", i.e. if one is present in
1439 // an NGEN image then then other will be, and if one is "used" at runtime then
1440 // the other will be too.
1441 BOOL IsTightlyBoundToMethodTable();
1442
1443 // For method descriptors which are non-generic this is the identity function
1444 // (except it returns the primary descriptor, not an BoxedEntryPointStub).
1445 //
1446 // For a generic method definition C<T>.m<U> this will return
1447 // C<__Canon>.m<__Canon>
1448 //
1449 // allowCreate may be set to FALSE to enforce that the method searched
1450 // should already be in existence - thus preventing creation and GCs during
1451 // inappropriate times.
1452 //
1453 MethodDesc * FindOrCreateTypicalSharedInstantiation(BOOL allowCreate = TRUE);
1454
1455 // Given an object and an method descriptor for an instantiation of
1456 // a virtualized generic method, get the
1457 // corresponding instantiation of the target of a call.
1458 MethodDesc *ResolveGenericVirtualMethod(OBJECTREF *orThis);
1459
1460
1461public:
1462
1463 // does this function return an object reference?
1464 MetaSig::RETURNTYPE ReturnsObject(
1465#ifdef _DEBUG
1466 bool supportStringConstructors = false,
1467#endif
1468 MethodTable** pMT = NULL
1469 );
1470
1471
1472 void Destruct();
1473
1474public:
1475 // In general you don't want to call GetCallTarget - you want to
1476 // use either "call" directly or call MethodDesc::GetSingleCallableAddrOfVirtualizedCode and
1477 // then "CallTarget". Note that GetCallTarget is approximately GetSingleCallableAddrOfCode
1478 // but the additional wierdness that class-based-virtual calls (but not interface calls nor calls
1479 // on proxies) are resolved to their target. Because of this, many clients of "Call" (see above)
1480 // end up doing some resolution for interface calls and/or proxies themselves.
1481 PCODE GetCallTarget(OBJECTREF* pThisObj, TypeHandle ownerType = TypeHandle());
1482
1483 MethodImpl *GetMethodImpl();
1484
1485
1486#if defined(FEATURE_PREJIT ) && !defined(DACCESS_COMPILE)
1487 //================================================================
1488 // Precompilation (NGEN)
1489
1490 void Save(DataImage *image);
1491 void Fixup(DataImage *image);
1492 void FixupSlot(DataImage *image, PVOID p, SSIZE_T offset, ZapRelocationType type = IMAGE_REL_BASED_PTR);
1493
1494 //
1495 // Helper class used to regroup MethodDesc chunks before saving them into NGen image.
1496 // The regrouping takes into account IBC data and optional NGen-specific MethodDesc members.
1497 //
1498 class SaveChunk
1499 {
1500 DataImage * m_pImage;
1501
1502 ZapStoredStructure * m_pFirstNode;
1503 MethodDescChunk * m_pLastChunk;
1504
1505 typedef enum _MethodPriorityEnum
1506 {
1507 NoFlags = -1,
1508 HotMethodDesc = 0x0,
1509 WriteableMethodDesc = 0x1,
1510 ColdMethodDesc = 0x2,
1511 ColdWriteableMethodDesc= ColdMethodDesc | WriteableMethodDesc
1512
1513 } MethodPriorityEnum;
1514
1515 struct MethodInfo
1516 {
1517 MethodDesc * m_pMD;
1518 //MethodPriorityEnum
1519 BYTE m_priority;
1520
1521 BOOL m_fHasPrecode:1;
1522 BOOL m_fHasNativeCodeSlot:1;
1523 BOOL m_fHasFixupList:1;
1524 };
1525
1526 InlineSArray<MethodInfo, 20> m_methodInfos;
1527
1528 static int __cdecl MethodInfoCmp(const void* a_, const void* b_);
1529
1530 SIZE_T GetSavedMethodDescSize(MethodInfo * pMethodInfo);
1531
1532 void SaveOneChunk(COUNT_T start, COUNT_T count, ULONG size, DWORD priority);
1533
1534 public:
1535 SaveChunk(DataImage * image)
1536 : m_pImage(image), m_pFirstNode(NULL), m_pLastChunk(NULL)
1537 {
1538 LIMITED_METHOD_CONTRACT;
1539 }
1540
1541 void Append(MethodDesc * pMD);
1542
1543 ZapStoredStructure * Save();
1544 };
1545
1546 bool CanSkipDoPrestub(MethodDesc * callerMD,
1547 CorInfoIndirectCallReason *pReason,
1548 CORINFO_ACCESS_FLAGS accessFlags = CORINFO_ACCESS_ANY);
1549
1550 // This is different from !IsRestored() in that it checks if restoring
1551 // will ever be needed for this ngened data-structure.
1552 // This is to be used at ngen time of a dependent module to determine
1553 // if it can be accessed directly, or if the restoring mechanism needs
1554 // to be hooked in.
1555 BOOL NeedsRestore(DataImage *image, BOOL fAssumeMethodTableRestored = FALSE)
1556 {
1557 WRAPPER_NO_CONTRACT;
1558 return ComputeNeedsRestore(image, NULL, fAssumeMethodTableRestored);
1559 }
1560
1561 BOOL ComputeNeedsRestore(DataImage *image, TypeHandleList *pVisited, BOOL fAssumeMethodTableRestored = FALSE);
1562
1563 //
1564 // After the zapper compiles all code in a module it may attempt
1565 // to populate entries in all dictionaries
1566 // associated with instantiations of generic methods. This is an optional step - nothing will
1567 // go wrong at runtime except we may get more one-off calls to JIT_GenericHandle.
1568 // Although these are one-off we prefer to avoid them since they touch metadata
1569 // pages.
1570 //
1571 // Fully populating a dictionary may in theory load more types, methods etc. However
1572 // for the moment only those entries that refer to things that
1573 // are already loaded will be filled in.
1574 void PrepopulateDictionary(DataImage * image, BOOL nonExpansive);
1575
1576#endif // FEATURE_PREJIT && !DACCESS_COMPILE
1577
1578 TADDR GetFixupList();
1579
1580 BOOL IsRestored_NoLogging();
1581 BOOL IsRestored();
1582 void CheckRestore(ClassLoadLevel level = CLASS_LOADED);
1583
1584 //================================================================
1585 // Running the Prestub preparation step.
1586
1587 // The stub produced by prestub requires method desc to be passed
1588 // in dedicated register. Used to implement stubs shared between
1589 // MethodDescs (e.g. PInvoke stubs)
1590 BOOL RequiresMethodDescCallingConvention(BOOL fEstimateForChunk = FALSE);
1591
1592 // Returns true if the method has to have stable entrypoint always.
1593 BOOL RequiresStableEntryPoint(BOOL fEstimateForChunk = FALSE);
1594
1595 //
1596 // Backpatch method slots
1597 //
1598 // Arguments:
1599 // pMT - cached value of code:MethodDesc::GetMethodTable()
1600 // pDispatchingMT - method table of the object that the method is being dispatched on, can be NULL.
1601 // fFullBackPatch - indicates whether to patch all possible slots, including the ones
1602 // expensive to patch
1603 //
1604 // Return value:
1605 // stable entry point (code:MethodDesc::GetStableEntryPoint())
1606 //
1607 PCODE DoBackpatch(MethodTable * pMT, MethodTable * pDispatchingMT, BOOL fFullBackPatch);
1608
1609 PCODE DoPrestub(MethodTable *pDispatchingMT);
1610
1611 VOID GetMethodInfo(SString &namespaceOrClassName, SString &methodName, SString &methodSignature);
1612 VOID GetMethodInfoWithNewSig(SString &namespaceOrClassName, SString &methodName, SString &methodSignature);
1613 VOID GetMethodInfoNoSig(SString &namespaceOrClassName, SString &methodName);
1614 VOID GetFullMethodInfo(SString& fullMethodSigName);
1615
1616 BOOL HasTypeEquivalentStructParameters();
1617
1618 typedef void (*WalkValueTypeParameterFnPtr)(Module *pModule, mdToken token, Module *pDefModule, mdToken tkDefToken, const SigParser *ptr, SigTypeContext *pTypeContext, void *pData);
1619
1620 void WalkValueTypeParameters(MethodTable *pMT, WalkValueTypeParameterFnPtr function, void *pData);
1621
1622 void PrepareForUseAsADependencyOfANativeImage()
1623 {
1624 WRAPPER_NO_CONTRACT;
1625 if (!IsZapped() && !HaveValueTypeParametersBeenWalked())
1626 PrepareForUseAsADependencyOfANativeImageWorker();
1627 }
1628
1629 void PrepareForUseAsADependencyOfANativeImageWorker();
1630
1631 //================================================================
1632 // The actual data stored in a MethodDesc follows.
1633
1634protected:
1635 enum {
1636 // There are flags available for use here (currently 5 flags bits are available); however, new bits are hard to come by, so any new flags bits should
1637 // have a fairly strong justification for existence.
1638 enum_flag3_TokenRemainderMask = 0x3FFF, // This must equal METHOD_TOKEN_REMAINDER_MASK calculated higher in this file
1639 // These are seperate to allow the flags space available and used to be obvious here
1640 // and for the logic that splits the token to be algorithmically generated based on the
1641 // #define
1642 enum_flag3_HasForwardedValuetypeParameter = 0x4000, // Indicates that a type-forwarded type is used as a valuetype parameter (this flag is only valid for ngenned items)
1643 enum_flag3_ValueTypeParametersWalked = 0x4000, // Indicates that all typeref's in the signature of the method have been resolved to typedefs (or that process failed) (this flag is only valid for non-ngenned methods)
1644 enum_flag3_DoesNotHaveEquivalentValuetypeParameters = 0x8000, // Indicates that we have verified that there are no equivalent valuetype parameters for this method
1645 };
1646 UINT16 m_wFlags3AndTokenRemainder;
1647
1648 BYTE m_chunkIndex;
1649
1650 enum {
1651 // enum_flag2_HasPrecode implies that enum_flag2_HasStableEntryPoint is set.
1652 enum_flag2_HasStableEntryPoint = 0x01, // The method entrypoint is stable (either precode or actual code)
1653 enum_flag2_HasPrecode = 0x02, // Precode has been allocated for this method
1654
1655 enum_flag2_IsUnboxingStub = 0x04,
1656 enum_flag2_HasNativeCodeSlot = 0x08, // Has slot for native code
1657
1658 enum_flag2_IsJitIntrinsic = 0x10, // Jit may expand method as an intrinsic
1659
1660 // unused = 0x20,
1661 // unused = 0x40,
1662 // unused = 0x80,
1663 };
1664 BYTE m_bFlags2;
1665
1666 // The slot number of this MethodDesc in the vtable array.
1667 // Note that we may store other information in the high bits if available --
1668 // see enum_packedSlotLayout and mdcRequiresFullSlotNumber for details.
1669 WORD m_wSlotNumber;
1670
1671 enum {
1672 enum_packedSlotLayout_SlotMask = 0x03FF,
1673 enum_packedSlotLayout_NameHashMask = 0xFC00
1674 };
1675
1676 WORD m_wFlags;
1677
1678
1679
1680public:
1681#ifdef DACCESS_COMPILE
1682 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
1683#endif
1684
1685public:
1686 inline DWORD GetClassification() const
1687 {
1688 LIMITED_METHOD_DAC_CONTRACT;
1689
1690 return (m_wFlags & mdcClassification);
1691 }
1692
1693 inline void SetClassification(DWORD classification)
1694 {
1695 LIMITED_METHOD_CONTRACT;
1696 _ASSERTE((m_wFlags & mdcClassification) == 0);
1697 m_wFlags |= classification;
1698 }
1699
1700 inline BOOL HasNativeCodeSlot()
1701 {
1702 LIMITED_METHOD_DAC_CONTRACT;
1703 return (m_bFlags2 & enum_flag2_HasNativeCodeSlot) != 0;
1704 }
1705
1706 inline void SetHasNativeCodeSlot()
1707 {
1708 LIMITED_METHOD_CONTRACT;
1709 m_bFlags2 |= enum_flag2_HasNativeCodeSlot;
1710 }
1711
1712 inline BOOL IsJitIntrinsic()
1713 {
1714 LIMITED_METHOD_DAC_CONTRACT;
1715 return (m_bFlags2 & enum_flag2_IsJitIntrinsic) != 0;
1716 }
1717
1718 inline void SetIsJitIntrinsic()
1719 {
1720 LIMITED_METHOD_CONTRACT;
1721 m_bFlags2 |= enum_flag2_IsJitIntrinsic;
1722 }
1723
1724 static const SIZE_T s_ClassificationSizeTable[];
1725
1726 static SIZE_T GetBaseSize(DWORD classification)
1727 {
1728 LIMITED_METHOD_DAC_CONTRACT;
1729 _ASSERTE(classification < mdcClassificationCount);
1730 return s_ClassificationSizeTable[classification];
1731 }
1732
1733 SIZE_T GetBaseSize()
1734 {
1735 LIMITED_METHOD_DAC_CONTRACT;
1736 return GetBaseSize(GetClassification());
1737 }
1738
1739 SIZE_T SizeOf();
1740
1741 WORD InterlockedUpdateFlags3(WORD wMask, BOOL fSet);
1742
1743#ifdef FEATURE_TYPEEQUIVALENCE
1744 inline BOOL DoesNotHaveEquivalentValuetypeParameters()
1745 {
1746 LIMITED_METHOD_DAC_CONTRACT;
1747 return (m_wFlags3AndTokenRemainder & enum_flag3_DoesNotHaveEquivalentValuetypeParameters) != 0;
1748 }
1749
1750 inline void SetDoesNotHaveEquivalentValuetypeParameters()
1751 {
1752 LIMITED_METHOD_CONTRACT;
1753 InterlockedUpdateFlags3(enum_flag3_DoesNotHaveEquivalentValuetypeParameters, TRUE);
1754 }
1755#endif // FEATURE_TYPEEQUIVALENCE
1756
1757 inline BOOL HasForwardedValuetypeParameter()
1758 {
1759 LIMITED_METHOD_DAC_CONTRACT;
1760 // This should only be asked of Zapped MethodDescs
1761 _ASSERTE(IsZapped());
1762 return (m_wFlags3AndTokenRemainder & enum_flag3_HasForwardedValuetypeParameter) != 0;
1763 }
1764
1765 inline void SetHasForwardedValuetypeParameter()
1766 {
1767 LIMITED_METHOD_CONTRACT;
1768 InterlockedUpdateFlags3(enum_flag3_HasForwardedValuetypeParameter, TRUE);
1769 }
1770
1771 inline BOOL HaveValueTypeParametersBeenWalked()
1772 {
1773 LIMITED_METHOD_DAC_CONTRACT;
1774
1775 // This should only be asked of non-Zapped MethodDescs, and only during execution (not compilation)
1776 _ASSERTE(!IsZapped() && !IsCompilationProcess());
1777
1778 return (m_wFlags3AndTokenRemainder & enum_flag3_ValueTypeParametersWalked) != 0;
1779 }
1780
1781 inline void SetValueTypeParametersWalked()
1782 {
1783 LIMITED_METHOD_CONTRACT;
1784
1785 _ASSERTE(!IsZapped() && !IsCompilationProcess());
1786
1787 InterlockedUpdateFlags3(enum_flag3_ValueTypeParametersWalked, TRUE);
1788 }
1789
1790 //
1791 // Optional MethodDesc slots appear after the end of base MethodDesc in this order:
1792 //
1793
1794 // class MethodImpl; // Present if HasMethodImplSlot() is true
1795
1796 typedef RelativePointer<PCODE> NonVtableSlot; // Present if HasNonVtableSlot() is true
1797 // RelativePointer for NGen, PCODE for JIT
1798
1799#define FIXUP_LIST_MASK 1
1800 typedef RelativePointer<TADDR> NativeCodeSlot; // Present if HasNativeCodeSlot() is true
1801 // lower order bit (FIXUP_LIST_MASK) used to determine if FixupListSlot is present
1802 typedef RelativePointer<TADDR> FixupListSlot;
1803
1804// Stub Dispatch code
1805public:
1806 MethodDesc *GetInterfaceMD();
1807
1808// StubMethodInfo for use in creating RuntimeMethodHandles
1809 REFLECTMETHODREF GetStubMethodInfo();
1810
1811 PrecodeType GetPrecodeType();
1812
1813
1814 // ---------------------------------------------------------------------------------
1815 // IL based Code generation pipeline
1816 // ---------------------------------------------------------------------------------
1817
1818#ifndef DACCESS_COMPILE
1819public:
1820 PCODE PrepareInitialCode();
1821 PCODE PrepareCode(NativeCodeVersion codeVersion);
1822 PCODE PrepareCode(PrepareCodeConfig* pConfig);
1823
1824private:
1825 PCODE PrepareILBasedCode(PrepareCodeConfig* pConfig);
1826 PCODE GetPrecompiledCode(PrepareCodeConfig* pConfig);
1827 PCODE GetPrecompiledNgenCode(PrepareCodeConfig* pConfig);
1828 PCODE GetPrecompiledR2RCode(PrepareCodeConfig* pConfig);
1829 PCODE GetMulticoreJitCode();
1830 COR_ILMETHOD_DECODER* GetAndVerifyILHeader(PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pIlDecoderMemory);
1831 COR_ILMETHOD_DECODER* GetAndVerifyMetadataILHeader(PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pIlDecoderMemory);
1832 COR_ILMETHOD_DECODER* GetAndVerifyNoMetadataILHeader();
1833 PCODE JitCompileCode(PrepareCodeConfig* pConfig);
1834 PCODE JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, JitListLockEntry* pEntry);
1835 PCODE JitCompileCodeLocked(PrepareCodeConfig* pConfig, JitListLockEntry* pLockEntry, ULONG* pSizeOfCode, CORJIT_FLAGS* pFlags);
1836#endif // DACCESS_COMPILE
1837
1838#ifdef HAVE_GCCOVER
1839private:
1840 static CrstStatic m_GCCoverCrst;
1841
1842public:
1843 static void Init();
1844#endif
1845};
1846
1847#ifndef DACCESS_COMPILE
1848class PrepareCodeConfig
1849{
1850public:
1851 PrepareCodeConfig();
1852 PrepareCodeConfig(NativeCodeVersion nativeCodeVersion, BOOL needsMulticoreJitNotification, BOOL mayUsePrecompiledCode);
1853 MethodDesc* GetMethodDesc();
1854 NativeCodeVersion GetCodeVersion();
1855 BOOL NeedsMulticoreJitNotification();
1856 BOOL MayUsePrecompiledCode();
1857 virtual PCODE IsJitCancellationRequested();
1858 virtual BOOL SetNativeCode(PCODE pCode, PCODE * ppAlternateCodeToUse);
1859 virtual COR_ILMETHOD* GetILHeader();
1860 virtual CORJIT_FLAGS GetJitCompilationFlags();
1861 BOOL ProfilerRejectedPrecompiledCode();
1862 BOOL ReadyToRunRejectedPrecompiledCode();
1863 void SetProfilerRejectedPrecompiledCode();
1864 void SetReadyToRunRejectedPrecompiledCode();
1865
1866protected:
1867 MethodDesc* m_pMethodDesc;
1868 NativeCodeVersion m_nativeCodeVersion;
1869 BOOL m_needsMulticoreJitNotification;
1870 BOOL m_mayUsePrecompiledCode;
1871 BOOL m_ProfilerRejectedPrecompiledCode;
1872 BOOL m_ReadyToRunRejectedPrecompiledCode;
1873};
1874
1875#ifdef FEATURE_CODE_VERSIONING
1876class VersionedPrepareCodeConfig : public PrepareCodeConfig
1877{
1878public:
1879 VersionedPrepareCodeConfig();
1880 VersionedPrepareCodeConfig(NativeCodeVersion codeVersion);
1881 HRESULT FinishConfiguration();
1882 virtual PCODE IsJitCancellationRequested();
1883 virtual BOOL SetNativeCode(PCODE pCode, PCODE * ppAlternateCodeToUse);
1884 virtual COR_ILMETHOD* GetILHeader();
1885 virtual CORJIT_FLAGS GetJitCompilationFlags();
1886private:
1887 ILCodeVersion m_ilCodeVersion;
1888};
1889#endif // FEATURE_CODE_VERSIONING
1890#endif // DACCESS_COMPILE
1891
1892/******************************************************************/
1893
1894// A code:MethodDescChunk is a container that holds one or more code:MethodDesc. Logically it is just
1895// compression. Basically fields that are common among methods descs in the chunk are stored in the chunk
1896// and the MethodDescs themselves just store and index that allows them to find their Chunk. Semantically
1897// a code:MethodDescChunk is just a set of code:MethodDesc.
1898class MethodDescChunk
1899{
1900 friend class MethodDesc;
1901 friend class CheckAsmOffsets;
1902#if defined(FEATURE_PREJIT) && !defined(DACCESS_COMPILE)
1903 friend class MethodDesc::SaveChunk;
1904#endif
1905#ifdef DACCESS_COMPILE
1906 friend class NativeImageDumper;
1907#endif // DACCESS_COMPILE
1908
1909 enum {
1910 enum_flag_TokenRangeMask = 0x03FF, // This must equal METHOD_TOKEN_RANGE_MASK calculated higher in this file
1911 // These are seperate to allow the flags space available and used to be obvious here
1912 // and for the logic that splits the token to be algorithmically generated based on the
1913 // #define
1914 enum_flag_HasCompactEntrypoints = 0x4000, // Compact temporary entry points
1915 enum_flag_IsZapped = 0x8000, // This chunk lives in NGen module
1916 };
1917
1918public:
1919 //
1920 // Allocates methodDescCount identical MethodDescs in smallest possible number of chunks.
1921 // If methodDescCount is zero, one chunk with maximum number of MethodDescs is allocated.
1922 //
1923 static MethodDescChunk *CreateChunk(LoaderHeap *pHeap, DWORD methodDescCount,
1924 DWORD classification,
1925 BOOL fNonVtableSlot,
1926 BOOL fNativeCodeSlot,
1927 BOOL fComPlusCallInfo,
1928 MethodTable *initialMT,
1929 class AllocMemTracker *pamTracker);
1930
1931 BOOL HasTemporaryEntryPoints()
1932 {
1933 LIMITED_METHOD_CONTRACT;
1934 return !IsZapped();
1935 }
1936
1937 TADDR GetTemporaryEntryPoints()
1938 {
1939 LIMITED_METHOD_CONTRACT;
1940 _ASSERTE(HasTemporaryEntryPoints());
1941 return *(dac_cast<DPTR(TADDR)>(this) - 1);
1942 }
1943
1944 PCODE GetTemporaryEntryPoint(int index);
1945
1946 void EnsureTemporaryEntryPointsCreated(LoaderAllocator *pLoaderAllocator, AllocMemTracker *pamTracker)
1947 {
1948 CONTRACTL
1949 {
1950 THROWS;
1951 GC_NOTRIGGER;
1952 MODE_ANY;
1953 }
1954 CONTRACTL_END;
1955
1956 if (GetTemporaryEntryPoints() == NULL)
1957 CreateTemporaryEntryPoints(pLoaderAllocator, pamTracker);
1958 }
1959
1960 void CreateTemporaryEntryPoints(LoaderAllocator *pLoaderAllocator, AllocMemTracker *pamTracker);
1961
1962#ifdef HAS_COMPACT_ENTRYPOINTS
1963 //
1964 // There two implementation options for temporary entrypoints:
1965 //
1966 // (1) Compact entrypoints. They provide as dense entrypoints as possible, but can't be patched
1967 // to point to the final code. The call to unjitted method is indirect call via slot.
1968 //
1969 // (2) Precodes. The precode will be patched to point to the final code eventually, thus
1970 // the temporary entrypoint can be embedded in the code. The call to unjitted method is
1971 // direct call to direct jump.
1972 //
1973 // We use (1) for x86 and (2) for 64-bit to get the best performance on each platform.
1974 // For ARM (1) is used.
1975
1976 TADDR AllocateCompactEntryPoints(LoaderAllocator *pLoaderAllocator, AllocMemTracker *pamTracker);
1977
1978 static MethodDesc* GetMethodDescFromCompactEntryPoint(PCODE addr, BOOL fSpeculative = FALSE);
1979 static SIZE_T SizeOfCompactEntryPoints(int count);
1980
1981 static BOOL IsCompactEntryPointAtAddress(PCODE addr);
1982
1983#ifdef _TARGET_ARM_
1984 static int GetCompactEntryPointMaxCount ();
1985#endif // _TARGET_ARM_
1986#endif // HAS_COMPACT_ENTRYPOINTS
1987
1988 FORCEINLINE PTR_MethodTable GetMethodTable()
1989 {
1990 LIMITED_METHOD_DAC_CONTRACT;
1991 return m_methodTable.GetValue(PTR_HOST_MEMBER_TADDR(MethodDescChunk, this, m_methodTable));
1992 }
1993
1994 inline DPTR(RelativeFixupPointer<PTR_MethodTable>) GetMethodTablePtr() const
1995 {
1996 LIMITED_METHOD_DAC_CONTRACT;
1997 return dac_cast<DPTR(RelativeFixupPointer<PTR_MethodTable>)>(PTR_HOST_MEMBER_TADDR(MethodDescChunk, this, m_methodTable));
1998 }
1999
2000#ifndef DACCESS_COMPILE
2001 inline void SetMethodTable(MethodTable * pMT)
2002 {
2003 LIMITED_METHOD_CONTRACT;
2004 _ASSERTE(m_methodTable.IsNull());
2005 _ASSERTE(pMT != NULL);
2006 m_methodTable.SetValue(pMT);
2007 }
2008
2009 inline void SetSizeAndCount(ULONG sizeOfMethodDescs, COUNT_T methodDescCount)
2010 {
2011 LIMITED_METHOD_CONTRACT;
2012
2013 _ASSERTE(FitsIn<BYTE>((sizeOfMethodDescs / MethodDesc::ALIGNMENT) - 1));
2014 m_size = static_cast<BYTE>((sizeOfMethodDescs / MethodDesc::ALIGNMENT) - 1);
2015 _ASSERTE(SizeOf() == sizeof(MethodDescChunk) + sizeOfMethodDescs);
2016
2017 _ASSERTE(FitsIn<BYTE>(methodDescCount - 1));
2018 m_count = static_cast<BYTE>(methodDescCount - 1);
2019 _ASSERTE(GetCount() == methodDescCount);
2020 }
2021#endif // !DACCESS_COMPILE
2022
2023#ifdef FEATURE_PREJIT
2024#ifndef DACCESS_COMPILE
2025 inline void RestoreMTPointer(ClassLoadLevel level = CLASS_LOADED)
2026 {
2027 LIMITED_METHOD_CONTRACT;
2028 Module::RestoreMethodTablePointer(&m_methodTable, NULL, level);
2029 }
2030#endif // !DACCESS_COMPILE
2031#endif // FEATURE_PREJIT
2032
2033#ifndef DACCESS_COMPILE
2034 void SetNextChunk(MethodDescChunk *chunk)
2035 {
2036 LIMITED_METHOD_CONTRACT;
2037 m_next.SetValueMaybeNull(chunk);
2038 }
2039#endif // !DACCESS_COMPILE
2040
2041 PTR_MethodDescChunk GetNextChunk()
2042 {
2043 LIMITED_METHOD_CONTRACT;
2044 return m_next.GetValueMaybeNull(PTR_HOST_MEMBER_TADDR(MethodDescChunk, this, m_next));
2045 }
2046
2047 UINT32 GetCount()
2048 {
2049 LIMITED_METHOD_DAC_CONTRACT;
2050 return m_count + 1;
2051 }
2052
2053 BOOL IsZapped()
2054 {
2055 LIMITED_METHOD_DAC_CONTRACT;
2056#ifdef FEATURE_PREJIT
2057 return (m_flagsAndTokenRange & enum_flag_IsZapped) != 0;
2058#else
2059 return FALSE;
2060#endif
2061 }
2062
2063 inline BOOL HasCompactEntryPoints()
2064 {
2065 LIMITED_METHOD_DAC_CONTRACT;
2066
2067#ifdef HAS_COMPACT_ENTRYPOINTS
2068 return (m_flagsAndTokenRange & enum_flag_HasCompactEntrypoints) != 0;
2069#else
2070 return FALSE;
2071#endif
2072 }
2073
2074 inline UINT16 GetTokRange()
2075 {
2076 LIMITED_METHOD_DAC_CONTRACT;
2077 return m_flagsAndTokenRange & enum_flag_TokenRangeMask;
2078 }
2079
2080 inline SIZE_T SizeOf()
2081 {
2082 LIMITED_METHOD_DAC_CONTRACT;
2083 return sizeof(MethodDescChunk) + (m_size + 1) * MethodDesc::ALIGNMENT;
2084 }
2085
2086 inline MethodDesc *GetFirstMethodDesc()
2087 {
2088 LIMITED_METHOD_DAC_CONTRACT;
2089 return PTR_MethodDesc(dac_cast<TADDR>(this) + sizeof(MethodDescChunk));
2090 }
2091
2092 // Maximum size of one chunk (corresponts to the maximum of m_size = 0xFF)
2093 static const SIZE_T MaxSizeOfMethodDescs = 0x100 * MethodDesc::ALIGNMENT;
2094
2095#ifdef DACCESS_COMPILE
2096 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
2097#endif
2098
2099private:
2100 void SetIsZapped()
2101 {
2102 LIMITED_METHOD_CONTRACT;
2103 m_flagsAndTokenRange |= enum_flag_IsZapped;
2104 }
2105
2106 void SetHasCompactEntryPoints()
2107 {
2108 LIMITED_METHOD_CONTRACT;
2109 m_flagsAndTokenRange |= enum_flag_HasCompactEntrypoints;
2110 }
2111
2112 void SetTokenRange(UINT16 tokenRange)
2113 {
2114 LIMITED_METHOD_CONTRACT;
2115 _ASSERTE((tokenRange & ~enum_flag_TokenRangeMask) == 0);
2116 static_assert_no_msg(enum_flag_TokenRangeMask == METHOD_TOKEN_RANGE_MASK);
2117 m_flagsAndTokenRange = (m_flagsAndTokenRange & ~enum_flag_TokenRangeMask) | tokenRange;
2118 }
2119
2120 RelativeFixupPointer<PTR_MethodTable> m_methodTable;
2121
2122 RelativePointer<PTR_MethodDescChunk> m_next;
2123
2124 BYTE m_size; // The size of this chunk minus 1 (in multiples of MethodDesc::ALIGNMENT)
2125 BYTE m_count; // The number of MethodDescs in this chunk minus 1
2126 UINT16 m_flagsAndTokenRange;
2127
2128 // Followed by array of method descs...
2129};
2130
2131inline int MethodDesc::GetMethodDescIndex() const
2132{
2133 LIMITED_METHOD_DAC_CONTRACT;
2134
2135 return m_chunkIndex;
2136}
2137
2138inline MethodDescChunk *MethodDesc::GetMethodDescChunk() const
2139{
2140 LIMITED_METHOD_DAC_CONTRACT;
2141
2142 return
2143 PTR_MethodDescChunk(dac_cast<TADDR>(this) -
2144 (sizeof(MethodDescChunk) + (GetMethodDescIndex() * MethodDesc::ALIGNMENT)));
2145}
2146
2147// convert an entry point into a MethodDesc
2148MethodDesc* Entry2MethodDesc(PCODE entryPoint, MethodTable *pMT);
2149
2150
2151typedef DPTR(class StoredSigMethodDesc) PTR_StoredSigMethodDesc;
2152class StoredSigMethodDesc : public MethodDesc
2153{
2154 public:
2155 // Put the sig RVA in here - this allows us to avoid
2156 // touching the method desc table when mscorlib is prejitted.
2157
2158 RelativePointer<TADDR> m_pSig;
2159 DWORD m_cSig;
2160#ifdef _WIN64
2161 // m_dwExtendedFlags is not used by StoredSigMethodDesc itself.
2162 // It is used by child classes. We allocate the space here to get
2163 // optimal layout.
2164 DWORD m_dwExtendedFlags;
2165#endif
2166
2167 TADDR GetSigRVA()
2168 {
2169 LIMITED_METHOD_DAC_CONTRACT;
2170 return RelativePointer<TADDR>::GetValueMaybeNullAtPtr(PTR_HOST_MEMBER_TADDR(StoredSigMethodDesc, this, m_pSig));
2171 }
2172
2173 bool HasStoredMethodSig(void)
2174 {
2175 LIMITED_METHOD_DAC_CONTRACT;
2176 return !m_pSig.IsNull();
2177 }
2178 PCCOR_SIGNATURE GetStoredMethodSig(DWORD* sigLen = NULL)
2179 {
2180 LIMITED_METHOD_DAC_CONTRACT;
2181 if (sigLen)
2182 {
2183 *sigLen = m_cSig;
2184 }
2185#ifdef DACCESS_COMPILE
2186 return (PCCOR_SIGNATURE)
2187 DacInstantiateTypeByAddress(GetSigRVA(), m_cSig, true);
2188#else // !DACCESS_COMPILE
2189 g_IBCLogger.LogNDirectCodeAccess(this);
2190 return (PCCOR_SIGNATURE) m_pSig.GetValueMaybeNull();
2191#endif // !DACCESS_COMPILE
2192 }
2193 void SetStoredMethodSig(PCCOR_SIGNATURE sig, DWORD sigBytes)
2194 {
2195#ifndef DACCESS_COMPILE
2196 m_pSig.SetValueMaybeNull((TADDR)sig);
2197 m_cSig = sigBytes;
2198#endif // !DACCESS_COMPILE
2199 }
2200
2201#ifdef DACCESS_COMPILE
2202 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
2203#endif
2204};
2205
2206//-----------------------------------------------------------------------
2207// Operations specific to FCall methods. We use a derived class to get
2208// the compiler involved in enforcing proper method type usage.
2209// DO NOT ADD FIELDS TO THIS CLASS.
2210//-----------------------------------------------------------------------
2211
2212class FCallMethodDesc : public MethodDesc
2213{
2214#ifdef DACCESS_COMPILE
2215 friend class NativeImageDumper;
2216#endif
2217
2218 DWORD m_dwECallID;
2219#ifdef _WIN64
2220 DWORD m_padding;
2221#endif
2222
2223public:
2224 void SetECallID(DWORD dwID)
2225 {
2226 LIMITED_METHOD_CONTRACT;
2227 m_dwECallID = dwID;
2228 }
2229
2230 DWORD GetECallID()
2231 {
2232 LIMITED_METHOD_CONTRACT;
2233 return m_dwECallID;
2234 }
2235};
2236
2237class HostCodeHeap;
2238class LCGMethodResolver;
2239typedef DPTR(LCGMethodResolver) PTR_LCGMethodResolver;
2240class ILStubResolver;
2241typedef DPTR(ILStubResolver) PTR_ILStubResolver;
2242class DynamicResolver;
2243typedef DPTR(DynamicResolver) PTR_DynamicResolver;
2244
2245class DynamicMethodDesc : public StoredSigMethodDesc
2246{
2247 friend class ILStubCache;
2248 friend class ILStubState;
2249 friend class DynamicMethodTable;
2250 friend class MethodDesc;
2251#ifdef DACCESS_COMPILE
2252 friend class NativeImageDumper;
2253#endif
2254
2255protected:
2256 RelativePointer<PTR_CUTF8> m_pszMethodName;
2257 PTR_DynamicResolver m_pResolver;
2258
2259#ifndef _WIN64
2260 // We use m_dwExtendedFlags from StoredSigMethodDesc on WIN64
2261 DWORD m_dwExtendedFlags; // see DynamicMethodDesc::ExtendedFlags enum
2262#endif
2263
2264 typedef enum ExtendedFlags
2265 {
2266 nomdAttrs = 0x0000FFFF, // method attributes (LCG)
2267 nomdILStubAttrs = mdMemberAccessMask | mdStatic, // method attributes (IL stubs)
2268
2269 // attributes (except mdStatic and mdMemberAccessMask) have different meaning for IL stubs
2270 // mdMemberAccessMask = 0x0007,
2271 nomdReverseStub = 0x0008,
2272 // mdStatic = 0x0010,
2273 nomdCALLIStub = 0x0020,
2274 nomdDelegateStub = 0x0040,
2275 nomdCopyCtorArgs = 0x0080,
2276 nomdUnbreakable = 0x0100,
2277 nomdDelegateCOMStub = 0x0200, // CLR->COM or COM->CLR call via a delegate (WinRT specific)
2278 nomdSignatureNeedsRestore = 0x0400,
2279 nomdStubNeedsCOMStarted = 0x0800, // EnsureComStarted must be called before executing the method
2280 nomdMulticastStub = 0x1000,
2281 nomdUnboxingILStub = 0x2000,
2282 nomdSecureDelegateStub = 0x4000,
2283
2284 nomdILStub = 0x00010000,
2285 nomdLCGMethod = 0x00020000,
2286 nomdStackArgSize = 0xFFFC0000, // native stack arg size for IL stubs
2287 } ExtendedFlags;
2288
2289public:
2290 bool IsILStub() { LIMITED_METHOD_DAC_CONTRACT; return !!(m_dwExtendedFlags & nomdILStub); }
2291 bool IsLCGMethod() { LIMITED_METHOD_DAC_CONTRACT; return !!(m_dwExtendedFlags & nomdLCGMethod); }
2292
2293 inline PTR_DynamicResolver GetResolver();
2294 inline PTR_LCGMethodResolver GetLCGMethodResolver();
2295 inline PTR_ILStubResolver GetILStubResolver();
2296
2297 PTR_CUTF8 GetMethodName()
2298 {
2299 LIMITED_METHOD_DAC_CONTRACT;
2300 return RelativePointer<PTR_CUTF8>::GetValueMaybeNullAtPtr(PTR_HOST_MEMBER_TADDR(DynamicMethodDesc, this, m_pszMethodName));
2301 }
2302
2303 WORD GetAttrs()
2304 {
2305 LIMITED_METHOD_CONTRACT;
2306 return (IsILStub() ? (m_dwExtendedFlags & nomdILStubAttrs) : (m_dwExtendedFlags & nomdAttrs));
2307 }
2308
2309 DWORD GetExtendedFlags()
2310 {
2311 LIMITED_METHOD_CONTRACT;
2312 return m_dwExtendedFlags;
2313 }
2314
2315 WORD GetNativeStackArgSize()
2316 {
2317 LIMITED_METHOD_DAC_CONTRACT;
2318 _ASSERTE(IsILStub());
2319 return (WORD)((m_dwExtendedFlags & nomdStackArgSize) >> 16);
2320 }
2321
2322 void SetNativeStackArgSize(WORD cbArgSize)
2323 {
2324 LIMITED_METHOD_CONTRACT;
2325 _ASSERTE(IsILStub() && (cbArgSize % sizeof(SLOT)) == 0);
2326 m_dwExtendedFlags = (m_dwExtendedFlags & ~nomdStackArgSize) | ((DWORD)cbArgSize << 16);
2327 }
2328
2329 void SetHasCopyCtorArgs(bool value)
2330 {
2331 LIMITED_METHOD_CONTRACT;
2332 if (value)
2333 {
2334 m_dwExtendedFlags |= nomdCopyCtorArgs;
2335 }
2336 }
2337
2338 void SetUnbreakable(bool value)
2339 {
2340 LIMITED_METHOD_CONTRACT;
2341 if (value)
2342 {
2343 m_dwExtendedFlags |= nomdUnbreakable;
2344 }
2345 }
2346
2347 void SetSignatureNeedsRestore(bool value)
2348 {
2349 LIMITED_METHOD_CONTRACT;
2350 if (value)
2351 {
2352 m_dwExtendedFlags |= nomdSignatureNeedsRestore;
2353 }
2354 }
2355
2356 void SetStubNeedsCOMStarted(bool value)
2357 {
2358 LIMITED_METHOD_CONTRACT;
2359 if (value)
2360 {
2361 m_dwExtendedFlags |= nomdStubNeedsCOMStarted;
2362 }
2363 }
2364
2365 bool IsRestored()
2366 {
2367 LIMITED_METHOD_CONTRACT;
2368
2369 if (IsSignatureNeedsRestore())
2370 {
2371 // Since we don't update the signatreNeedsRestore bit when we actually
2372 // restore the signature, the bit will have a stall value. The signature
2373 // bit in the metadata will always contain the correct, up-to-date
2374 // information.
2375 Volatile<BYTE> *pVolatileSig = (Volatile<BYTE> *)GetStoredMethodSig();
2376 if ((*pVolatileSig & IMAGE_CEE_CS_CALLCONV_NEEDSRESTORE) != 0)
2377 return false;
2378 }
2379
2380 return true;
2381 }
2382
2383 bool IsReverseStub() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(IsILStub()); return (0 != (m_dwExtendedFlags & nomdReverseStub)); }
2384 bool IsCALLIStub() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(IsILStub()); return (0 != (m_dwExtendedFlags & nomdCALLIStub)); }
2385 bool IsDelegateStub() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(IsILStub()); return (0 != (m_dwExtendedFlags & nomdDelegateStub)); }
2386 bool IsCLRToCOMStub() { LIMITED_METHOD_CONTRACT; _ASSERTE(IsILStub()); return ((0 == (m_dwExtendedFlags & mdStatic)) && !IsReverseStub() && !IsDelegateStub()); }
2387 bool IsCOMToCLRStub() { LIMITED_METHOD_CONTRACT; _ASSERTE(IsILStub()); return ((0 == (m_dwExtendedFlags & mdStatic)) && IsReverseStub()); }
2388 bool IsPInvokeStub() { LIMITED_METHOD_CONTRACT; _ASSERTE(IsILStub()); return ((0 != (m_dwExtendedFlags & mdStatic)) && !IsReverseStub() && !IsCALLIStub()); }
2389 bool HasCopyCtorArgs() { LIMITED_METHOD_CONTRACT; _ASSERTE(IsILStub()); return (0 != (m_dwExtendedFlags & nomdCopyCtorArgs)); }
2390 bool IsUnbreakable() { LIMITED_METHOD_CONTRACT; _ASSERTE(IsILStub()); return (0 != (m_dwExtendedFlags & nomdUnbreakable)); }
2391 bool IsDelegateCOMStub() { LIMITED_METHOD_CONTRACT; _ASSERTE(IsILStub()); return (0 != (m_dwExtendedFlags & nomdDelegateCOMStub)); }
2392 bool IsSignatureNeedsRestore() { LIMITED_METHOD_CONTRACT; _ASSERTE(IsILStub()); return (0 != (m_dwExtendedFlags & nomdSignatureNeedsRestore)); }
2393 bool IsStubNeedsCOMStarted() { LIMITED_METHOD_CONTRACT; _ASSERTE(IsILStub()); return (0 != (m_dwExtendedFlags & nomdStubNeedsCOMStarted)); }
2394#ifdef FEATURE_MULTICASTSTUB_AS_IL
2395 bool IsMulticastStub() {
2396 LIMITED_METHOD_DAC_CONTRACT;
2397 _ASSERTE(IsILStub());
2398 return !!(m_dwExtendedFlags & nomdMulticastStub);
2399 }
2400#endif
2401#ifdef FEATURE_STUBS_AS_IL
2402 bool IsSecureDelegateStub() {
2403 LIMITED_METHOD_DAC_CONTRACT;
2404 _ASSERTE(IsILStub());
2405 return !!(m_dwExtendedFlags & nomdSecureDelegateStub);
2406 }
2407 bool IsUnboxingILStub() {
2408 LIMITED_METHOD_DAC_CONTRACT;
2409 _ASSERTE(IsILStub());
2410 return !!(m_dwExtendedFlags & nomdUnboxingILStub);
2411 }
2412#endif
2413
2414 // Whether the stub takes a context argument that is an interop MethodDesc.
2415 bool HasMDContextArg()
2416 {
2417 LIMITED_METHOD_CONTRACT;
2418 return ((IsCLRToCOMStub() && !IsDelegateCOMStub()) || IsPInvokeStub());
2419 }
2420
2421 void Restore();
2422 void Fixup(DataImage* image);
2423 //
2424 // following implementations defined in DynamicMethod.cpp
2425 //
2426 void Destroy(BOOL fDomainUnload = FALSE);
2427};
2428
2429
2430class ArrayMethodDesc : public StoredSigMethodDesc
2431{
2432public:
2433 // The VTABLE for an array look like
2434
2435 // System.Object Vtable
2436 // System.Array Vtable
2437 // type[] Vtable
2438 // Get(<rank specific)
2439 // Set(<rank specific)
2440 // Address(<rank specific)
2441 // .ctor(int) // Possibly more
2442
2443 enum {
2444 ARRAY_FUNC_GET = 0,
2445 ARRAY_FUNC_SET = 1,
2446 ARRAY_FUNC_ADDRESS = 2,
2447 ARRAY_FUNC_CTOR = 3, // Anything >= ARRAY_FUNC_CTOR is .ctor
2448 };
2449
2450 // Get the index of runtime provided array method
2451 DWORD GetArrayFuncIndex()
2452 {
2453 LIMITED_METHOD_DAC_CONTRACT;
2454
2455 // The ru
2456 DWORD dwSlot = GetSlot();
2457 DWORD dwVirtuals = GetMethodTable()->GetNumVirtuals();
2458 _ASSERTE(dwSlot >= dwVirtuals);
2459 return dwSlot - dwVirtuals;
2460 }
2461
2462 LPCUTF8 GetMethodName();
2463 DWORD GetAttrs();
2464 CorInfoIntrinsics GetIntrinsicID();
2465};
2466
2467#ifdef HAS_NDIRECT_IMPORT_PRECODE
2468typedef NDirectImportPrecode NDirectImportThunkGlue;
2469#else // HAS_NDIRECT_IMPORT_PRECODE
2470
2471class NDirectImportThunkGlue
2472{
2473 PVOID m_dummy; // Dummy field to make the alignment right
2474
2475public:
2476 LPVOID GetEntrypoint()
2477 {
2478 LIMITED_METHOD_CONTRACT;
2479 return NULL;
2480 }
2481 void Init(MethodDesc *pMethod)
2482 {
2483 LIMITED_METHOD_CONTRACT;
2484 }
2485};
2486#ifdef FEATURE_PREJIT
2487PORTABILITY_WARNING("NDirectImportThunkGlue");
2488#endif // FEATURE_PREJIT
2489
2490#endif // HAS_NDIRECT_IMPORT_PRECODE
2491
2492typedef DPTR(NDirectImportThunkGlue) PTR_NDirectImportThunkGlue;
2493
2494
2495//
2496// This struct consolidates the writeable parts of the NDirectMethodDesc
2497// so that we can eventually layout a read-only NDirectMethodDesc with a pointer
2498// to the writeable parts in an ngen image
2499//
2500class NDirectWriteableData
2501{
2502public:
2503 // The JIT generates an indirect call through this location in some cases.
2504 // Initialized to NDirectImportThunkGlue. Patched to the true target or
2505 // host interceptor stub or alignment thunk after linking.
2506 LPVOID m_pNDirectTarget;
2507};
2508
2509typedef DPTR(NDirectWriteableData) PTR_NDirectWriteableData;
2510
2511//-----------------------------------------------------------------------
2512// Operations specific to NDirect methods. We use a derived class to get
2513// the compiler involved in enforcing proper method type usage.
2514// DO NOT ADD FIELDS TO THIS CLASS.
2515//-----------------------------------------------------------------------
2516class NDirectMethodDesc : public MethodDesc
2517{
2518public:
2519 struct temp1
2520 {
2521 // If we are hosted, stack imbalance MDA is active, or alignment thunks are needed,
2522 // we will intercept m_pNDirectTarget. The true target is saved here.
2523 LPVOID m_pNativeNDirectTarget;
2524
2525 // Information about the entrypoint
2526 RelativePointer<PTR_CUTF8> m_pszEntrypointName;
2527
2528 union
2529 {
2530 RelativePointer<PTR_CUTF8> m_pszLibName;
2531 DWORD m_dwECallID; // ECallID for QCalls
2532 };
2533
2534 // The writeable part of the methoddesc.
2535#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
2536 RelativePointer<PTR_NDirectWriteableData> m_pWriteableData;
2537#else
2538 PlainPointer<PTR_NDirectWriteableData> m_pWriteableData;
2539#endif
2540
2541#ifdef HAS_NDIRECT_IMPORT_PRECODE
2542 RelativePointer<PTR_NDirectImportThunkGlue> m_pImportThunkGlue;
2543#else // HAS_NDIRECT_IMPORT_PRECODE
2544 NDirectImportThunkGlue m_ImportThunkGlue;
2545#endif // HAS_NDIRECT_IMPORT_PRECODE
2546
2547 ULONG m_DefaultDllImportSearchPathsAttributeValue; // DefaultDllImportSearchPathsAttribute is saved.
2548
2549 // Various attributes needed at runtime.
2550 WORD m_wFlags;
2551
2552#if defined(_TARGET_X86_)
2553 // Size of outgoing arguments (on stack). Note that in order to get the @n stdcall name decoration,
2554 // it may be necessary to subtract 4 as the hidden large structure pointer parameter does not count.
2555 // See code:kStdCallWithRetBuf
2556 WORD m_cbStackArgumentSize;
2557#endif // defined(_TARGET_X86_)
2558
2559 // This field gets set only when this MethodDesc is marked as PreImplemented
2560 RelativePointer<PTR_MethodDesc> m_pStubMD;
2561
2562 } ndirect;
2563
2564 enum Flags
2565 {
2566 // There are two groups of flag bits here each which gets initialized
2567 // at different times.
2568
2569 //
2570 // Group 1: The init group.
2571 //
2572 // This group is set during MethodDesc construction. No race issues
2573 // here since they are initialized before the MD is ever published
2574 // and never change after that.
2575
2576 kEarlyBound = 0x0001, // IJW managed->unmanaged thunk. Standard [sysimport] stuff otherwise.
2577
2578 kHasSuppressUnmanagedCodeAccess = 0x0002,
2579
2580 kDefaultDllImportSearchPathsIsCached = 0x0004, // set if we cache attribute value.
2581
2582 // kUnusedMask = 0x0008
2583
2584 //
2585 // Group 2: The runtime group.
2586 //
2587 // This group is set during runtime potentially by multiple threads
2588 // at the same time. All flags in this category has to be set via interlocked operation.
2589 //
2590 kIsMarshalingRequiredCached = 0x0010, // Set if we have cached the results of marshaling required computation
2591 kCachedMarshalingRequired = 0x0020, // The result of the marshaling required computation
2592
2593 kNativeAnsi = 0x0040,
2594
2595 kLastError = 0x0080, // setLastError keyword specified
2596 kNativeNoMangle = 0x0100, // nomangle keyword specified
2597
2598 kVarArgs = 0x0200,
2599 kStdCall = 0x0400,
2600 kThisCall = 0x0800,
2601
2602 kIsQCall = 0x1000,
2603
2604 kDefaultDllImportSearchPathsStatus = 0x2000, // either method has custom attribute or not.
2605
2606 kHasCopyCtorArgs = 0x4000,
2607
2608 kStdCallWithRetBuf = 0x8000, // Call returns large structure, only valid if kStdCall is also set
2609
2610 };
2611
2612 // Retrieves the cached result of marshaling required computation, or performs the computation
2613 // if the result is not cached yet.
2614 BOOL MarshalingRequired()
2615 {
2616 STANDARD_VM_CONTRACT;
2617
2618 if ((ndirect.m_wFlags & kIsMarshalingRequiredCached) == 0)
2619 {
2620 // Compute the flag and cache the result
2621 InterlockedSetNDirectFlags(kIsMarshalingRequiredCached |
2622 (ComputeMarshalingRequired() ? kCachedMarshalingRequired : 0));
2623 }
2624 _ASSERTE((ndirect.m_wFlags & kIsMarshalingRequiredCached) != 0);
2625 return (ndirect.m_wFlags & kCachedMarshalingRequired) != 0;
2626 }
2627
2628 BOOL ComputeMarshalingRequired();
2629
2630 // Atomically set specified flags. Only setting of the bits is supported.
2631 void InterlockedSetNDirectFlags(WORD wFlags);
2632
2633 void SetIsEarlyBound()
2634 {
2635 LIMITED_METHOD_CONTRACT;
2636 ndirect.m_wFlags |= kEarlyBound;
2637 }
2638
2639 BOOL IsEarlyBound()
2640 {
2641 LIMITED_METHOD_CONTRACT;
2642 return (ndirect.m_wFlags & kEarlyBound) != 0;
2643 }
2644
2645 BOOL IsNativeAnsi() const
2646 {
2647 LIMITED_METHOD_CONTRACT;
2648
2649 return (ndirect.m_wFlags & kNativeAnsi) != 0;
2650 }
2651
2652 BOOL IsNativeNoMangled() const
2653 {
2654 LIMITED_METHOD_CONTRACT;
2655
2656 return (ndirect.m_wFlags & kNativeNoMangle) != 0;
2657 }
2658
2659
2660 DWORD GetECallID() const
2661 {
2662 LIMITED_METHOD_CONTRACT;
2663
2664 _ASSERTE(IsQCall());
2665 return ndirect.m_dwECallID;
2666 }
2667
2668 void SetECallID(DWORD dwID)
2669 {
2670 LIMITED_METHOD_CONTRACT;
2671
2672 _ASSERTE(IsQCall());
2673 ndirect.m_dwECallID = dwID;
2674 }
2675
2676 PTR_CUTF8 GetLibNameRaw()
2677 {
2678 LIMITED_METHOD_DAC_CONTRACT;
2679
2680 return RelativePointer<PTR_CUTF8>::GetValueMaybeNullAtPtr(PTR_HOST_MEMBER_TADDR(NDirectMethodDesc, this, ndirect.m_pszLibName));
2681 }
2682
2683#ifndef DACCESS_COMPILE
2684 LPCUTF8 GetLibName() const
2685 {
2686 LIMITED_METHOD_CONTRACT;
2687
2688 return IsQCall() ? "QCall" : ndirect.m_pszLibName.GetValueMaybeNull();
2689 }
2690#endif // !DACCESS_COMPILE
2691
2692 PTR_CUTF8 GetEntrypointName() const
2693 {
2694 LIMITED_METHOD_DAC_CONTRACT;
2695
2696 return RelativePointer<PTR_CUTF8>::GetValueMaybeNullAtPtr(PTR_HOST_MEMBER_TADDR(NDirectMethodDesc, this, ndirect.m_pszEntrypointName));
2697 }
2698
2699 BOOL IsVarArgs() const
2700 {
2701 LIMITED_METHOD_DAC_CONTRACT;
2702
2703 return (ndirect.m_wFlags & kVarArgs) != 0;
2704 }
2705
2706 BOOL IsStdCall() const
2707 {
2708 LIMITED_METHOD_DAC_CONTRACT;
2709
2710 return (ndirect.m_wFlags & kStdCall) != 0;
2711 }
2712
2713 BOOL IsThisCall() const
2714 {
2715 LIMITED_METHOD_DAC_CONTRACT;
2716
2717 return (ndirect.m_wFlags & kThisCall) != 0;
2718 }
2719
2720 // Returns TRUE if this MethodDesc is internal call from mscorlib to mscorwks
2721 BOOL IsQCall() const
2722 {
2723 LIMITED_METHOD_DAC_CONTRACT;
2724
2725 return (ndirect.m_wFlags & kIsQCall) != 0;
2726 }
2727
2728 BOOL HasDefaultDllImportSearchPathsAttribute();
2729
2730 BOOL IsDefaultDllImportSearchPathsAttributeCached()
2731 {
2732 LIMITED_METHOD_CONTRACT;
2733 return (ndirect.m_wFlags & kDefaultDllImportSearchPathsIsCached) != 0;
2734 }
2735
2736 ULONG DefaultDllImportSearchPathsAttributeCachedValue()
2737 {
2738 LIMITED_METHOD_CONTRACT;
2739 return ndirect.m_DefaultDllImportSearchPathsAttributeValue & 0xFFFFFFFD;
2740 }
2741
2742 BOOL DllImportSearchAssemblyDirectory()
2743 {
2744 LIMITED_METHOD_CONTRACT;
2745 return (ndirect.m_DefaultDllImportSearchPathsAttributeValue & 0x2) != 0;
2746 }
2747
2748 BOOL HasCopyCtorArgs() const
2749 {
2750 LIMITED_METHOD_DAC_CONTRACT;
2751
2752 return (ndirect.m_wFlags & kHasCopyCtorArgs) != 0;
2753 }
2754
2755 void SetHasCopyCtorArgs(BOOL value)
2756 {
2757 WRAPPER_NO_CONTRACT;
2758
2759 if (value)
2760 {
2761 InterlockedSetNDirectFlags(kHasCopyCtorArgs);
2762 }
2763 }
2764
2765 BOOL IsStdCallWithRetBuf() const
2766 {
2767 LIMITED_METHOD_DAC_CONTRACT;
2768
2769 return (ndirect.m_wFlags & kStdCallWithRetBuf) != 0;
2770 }
2771
2772 PTR_NDirectWriteableData GetWriteableData() const
2773 {
2774 LIMITED_METHOD_DAC_CONTRACT;
2775
2776 return ReadPointer(this, &NDirectMethodDesc::ndirect, &decltype(NDirectMethodDesc::ndirect)::m_pWriteableData);
2777 }
2778
2779 PTR_NDirectImportThunkGlue GetNDirectImportThunkGlue()
2780 {
2781 LIMITED_METHOD_DAC_CONTRACT;
2782
2783 TADDR base = PTR_HOST_MEMBER_TADDR(NDirectMethodDesc, this, ndirect.m_pImportThunkGlue);
2784
2785#ifdef HAS_NDIRECT_IMPORT_PRECODE
2786 return RelativePointer<PTR_NDirectImportThunkGlue>::GetValueAtPtr(base);
2787#else
2788 return dac_cast<PTR_NDirectImportThunkGlue>(base);
2789#endif
2790 }
2791
2792 LPVOID GetNDirectTarget()
2793 {
2794 LIMITED_METHOD_CONTRACT;
2795
2796 _ASSERTE(IsNDirect());
2797 return GetWriteableData()->m_pNDirectTarget;
2798 }
2799
2800 LPVOID GetNativeNDirectTarget()
2801 {
2802 LIMITED_METHOD_CONTRACT;
2803
2804 _ASSERTE(IsNDirect());
2805 _ASSERTE_IMPL(!NDirectTargetIsImportThunk());
2806
2807 LPVOID pNativeNDirectTarget = ndirect.m_pNativeNDirectTarget;
2808 if (pNativeNDirectTarget != NULL)
2809 return pNativeNDirectTarget;
2810
2811 return GetNDirectTarget();
2812 }
2813
2814 VOID SetNDirectTarget(LPVOID pTarget);
2815
2816#ifndef DACCESS_COMPILE
2817 BOOL NDirectTargetIsImportThunk()
2818 {
2819 WRAPPER_NO_CONTRACT;
2820
2821 _ASSERTE(IsNDirect());
2822
2823 return (GetNDirectTarget() == GetNDirectImportThunkGlue()->GetEntrypoint());
2824 }
2825#endif // !DACCESS_COMPILE
2826
2827 // Find the entry point name and function address
2828 // based on the module and data from NDirectMethodDesc
2829 //
2830 LPVOID FindEntryPoint(HINSTANCE hMod) const;
2831
2832private:
2833 FARPROC FindEntryPointWithMangling(HINSTANCE mod, PTR_CUTF8 entryPointName) const;
2834
2835#ifdef MDA_SUPPORTED
2836 Stub* GenerateStubForMDA(LPVOID pNativeTarget, Stub *pInnerStub);
2837#endif // MDA_SUPPORTED
2838
2839public:
2840
2841 void SetStackArgumentSize(WORD cbDstBuffer, CorPinvokeMap unmgdCallConv)
2842 {
2843 LIMITED_METHOD_CONTRACT;
2844
2845#if defined(_TARGET_X86_)
2846 // thiscall passes the this pointer in ECX
2847 if (unmgdCallConv == pmCallConvThiscall)
2848 {
2849 _ASSERTE(cbDstBuffer >= sizeof(SLOT));
2850 cbDstBuffer -= sizeof(SLOT);
2851 }
2852
2853 // Don't write to the field if it's already initialized to avoid creating private pages (NGEN)
2854 if (ndirect.m_cbStackArgumentSize == 0xFFFF)
2855 {
2856 ndirect.m_cbStackArgumentSize = cbDstBuffer;
2857 }
2858 else
2859 {
2860 _ASSERTE(ndirect.m_cbStackArgumentSize == cbDstBuffer);
2861 }
2862#endif // defined(_TARGET_X86_)
2863 }
2864
2865#if defined(_TARGET_X86_)
2866 WORD GetStackArgumentSize() const
2867 {
2868 LIMITED_METHOD_DAC_CONTRACT;
2869
2870 _ASSERTE(ndirect.m_cbStackArgumentSize != 0xFFFF);
2871
2872 // If we have a methoddesc, stackArgSize is the number of bytes of
2873 // the outgoing marshalling buffer.
2874 return ndirect.m_cbStackArgumentSize;
2875 }
2876#endif // defined(_TARGET_X86_)
2877
2878 VOID InitEarlyBoundNDirectTarget();
2879
2880 // In AppDomains, we can trigger declarer's cctor when we link the P/Invoke,
2881 // which takes care of inlined calls as well. See code:NDirect.NDirectLink.
2882 // Although the cctor is guaranteed to run in the shared domain before the
2883 // target is invoked (code:IsClassConstructorTriggeredByILStub), we will
2884 // trigger at it link time as well because linking may depend on it - the
2885 // cctor may change the target DLL, change DLL search path etc.
2886 BOOL IsClassConstructorTriggeredAtLinkTime()
2887 {
2888 LIMITED_METHOD_CONTRACT;
2889 MethodTable * pMT = GetMethodTable();
2890 // Try to avoid touching the EEClass if possible
2891 if (pMT->IsClassPreInited())
2892 return FALSE;
2893 return !pMT->GetClass()->IsBeforeFieldInit();
2894 }
2895
2896#ifndef DACCESS_COMPILE
2897 // In the shared domain and in NGENed code, we will trigger declarer's cctor
2898 // in the marshaling stub by calling code:StubHelpers.InitDeclaringType. If
2899 // this returns TRUE, the call must not be inlined.
2900 BOOL IsClassConstructorTriggeredByILStub()
2901 {
2902 WRAPPER_NO_CONTRACT;
2903
2904 return (IsClassConstructorTriggeredAtLinkTime() &&
2905 (IsZapped() || GetDomain()->IsSharedDomain() || SystemDomain::GetCurrentDomain()->IsCompilationDomain()));
2906 }
2907#endif //!DACCESS_COMPILE
2908}; //class NDirectMethodDesc
2909
2910
2911//-----------------------------------------------------------------------
2912// Operations specific to EEImplCall methods. We use a derived class to get
2913// the compiler involved in enforcing proper method type usage.
2914//
2915// For now, the only EE impl is the delegate Invoke method. If we
2916// add other EE impl types in the future, may need a discriminator
2917// field here.
2918//-----------------------------------------------------------------------
2919class EEImplMethodDesc : public StoredSigMethodDesc
2920{ };
2921
2922#ifdef FEATURE_COMINTEROP
2923
2924// This is the extra information needed to be associated with a method in order to use it for
2925// CLR->COM calls. It is currently used by code:ComPlusCallMethodDesc (ordinary CLR->COM calls),
2926// code:InstantiatedMethodDesc (optional field, CLR->COM calls on shared generic interfaces),
2927// and code:DelegateEEClass (delegate->COM calls for WinRT).
2928typedef DPTR(struct ComPlusCallInfo) PTR_ComPlusCallInfo;
2929struct ComPlusCallInfo
2930{
2931 // Returns ComPlusCallInfo associated with a method. pMD must be a ComPlusCallMethodDesc or
2932 // EEImplMethodDesc that has already been initialized for COM interop.
2933 inline static ComPlusCallInfo *FromMethodDesc(MethodDesc *pMD);
2934
2935 enum Flags
2936 {
2937 kHasSuppressUnmanagedCodeAccess = 0x1,
2938 kRequiresArgumentWrapping = 0x2,
2939 kHasCopyCtorArgs = 0x4,
2940 };
2941
2942 union
2943 {
2944 // IL stub for CLR to COM call
2945 PCODE m_pILStub;
2946
2947 // MethodDesc of the COM event provider to forward the call to (COM event interfaces)
2948 MethodDesc *m_pEventProviderMD;
2949 };
2950
2951 // method table of the interface which this represents
2952 PTR_MethodTable m_pInterfaceMT;
2953
2954 // We need only 3 bits here, see enum Flags below.
2955 BYTE m_flags;
2956
2957 // ComSlot() (is cached when we first invoke the method and generate
2958 // the stubs for it. There's probably a better place to do this
2959 // caching but I'm not sure I know all the places these things are
2960 // created.)
2961 WORD m_cachedComSlot;
2962
2963 PCODE * GetAddrOfILStubField()
2964 {
2965 LIMITED_METHOD_CONTRACT;
2966 return &m_pILStub;
2967 }
2968
2969#ifdef _TARGET_X86_
2970 // Size of outgoing arguments (on stack). This is currently used only
2971 // on x86 when we have an InlinedCallFrame representing a CLR->COM call.
2972 WORD m_cbStackArgumentSize;
2973
2974 void SetHasCopyCtorArgs(BOOL value)
2975 {
2976 LIMITED_METHOD_CONTRACT;
2977 if (value)
2978 FastInterlockOr(reinterpret_cast<DWORD *>(&m_flags), kHasCopyCtorArgs);
2979 }
2980
2981 BOOL HasCopyCtorArgs()
2982 {
2983 LIMITED_METHOD_CONTRACT;
2984 return ((m_flags & kHasCopyCtorArgs) != 0);
2985 }
2986
2987 void InitStackArgumentSize()
2988 {
2989 LIMITED_METHOD_CONTRACT;
2990
2991 m_cbStackArgumentSize = 0xFFFF;
2992 }
2993
2994 void SetStackArgumentSize(WORD cbDstBuffer)
2995 {
2996 LIMITED_METHOD_CONTRACT;
2997
2998 // Don't write to the field if it's already initialized to avoid creating private pages (NGEN)
2999 if (m_cbStackArgumentSize == 0xFFFF)
3000 {
3001 m_cbStackArgumentSize = cbDstBuffer;
3002 }
3003 _ASSERTE(m_cbStackArgumentSize == cbDstBuffer);
3004 }
3005
3006 WORD GetStackArgumentSize()
3007 {
3008 LIMITED_METHOD_DAC_CONTRACT;
3009
3010 _ASSERTE(m_cbStackArgumentSize != 0xFFFF);
3011 return m_cbStackArgumentSize;
3012 }
3013
3014 union
3015 {
3016 LPVOID m_pRetThunk; // used for late-bound calls
3017 LPVOID m_pInterceptStub; // used for early-bound IL stub calls
3018 };
3019
3020#else // _TARGET_X86_
3021 void InitStackArgumentSize()
3022 {
3023 LIMITED_METHOD_CONTRACT;
3024 }
3025
3026 void SetStackArgumentSize(WORD cbDstBuffer)
3027 {
3028 LIMITED_METHOD_CONTRACT;
3029 }
3030#endif // _TARGET_X86_
3031
3032 // This field gets set only when this MethodDesc is marked as PreImplemented
3033 RelativePointer<PTR_MethodDesc> m_pStubMD;
3034
3035#ifdef FEATURE_PREJIT
3036 BOOL ShouldSave(DataImage *image);
3037 void Fixup(DataImage *image);
3038#endif
3039};
3040
3041
3042//-----------------------------------------------------------------------
3043// Operations specific to ComPlusCall methods. We use a derived class to get
3044// the compiler involved in enforcing proper method type usage.
3045// DO NOT ADD FIELDS TO THIS CLASS.
3046//-----------------------------------------------------------------------
3047class ComPlusCallMethodDesc : public MethodDesc
3048{
3049public:
3050 ComPlusCallInfo *m_pComPlusCallInfo; // initialized in code:ComPlusCall.PopulateComPlusCallMethodDesc
3051
3052 void InitRetThunk();
3053 void InitComEventCallInfo();
3054
3055 PCODE * GetAddrOfILStubField()
3056 {
3057 LIMITED_METHOD_CONTRACT;
3058 return m_pComPlusCallInfo->GetAddrOfILStubField();
3059 }
3060
3061 MethodTable* GetInterfaceMethodTable()
3062 {
3063 LIMITED_METHOD_CONTRACT;
3064 _ASSERTE(m_pComPlusCallInfo->m_pInterfaceMT != NULL);
3065 return m_pComPlusCallInfo->m_pInterfaceMT;
3066 }
3067
3068 MethodDesc* GetEventProviderMD()
3069 {
3070 LIMITED_METHOD_CONTRACT;
3071
3072 return m_pComPlusCallInfo->m_pEventProviderMD;
3073 }
3074
3075
3076 BOOL RequiresArgumentWrapping()
3077 {
3078 LIMITED_METHOD_CONTRACT;
3079
3080 return (m_pComPlusCallInfo->m_flags & ComPlusCallInfo::kRequiresArgumentWrapping) != 0;
3081 }
3082
3083 void SetLateBoundFlags(BYTE newFlags)
3084 {
3085 LIMITED_METHOD_CONTRACT;
3086
3087 FastInterlockOr(reinterpret_cast<DWORD *>(&m_pComPlusCallInfo->m_flags), newFlags);
3088 }
3089
3090#ifdef _TARGET_X86_
3091 BOOL HasCopyCtorArgs()
3092 {
3093 LIMITED_METHOD_CONTRACT;
3094 return m_pComPlusCallInfo->HasCopyCtorArgs();
3095 }
3096
3097 void SetHasCopyCtorArgs(BOOL value)
3098 {
3099 LIMITED_METHOD_CONTRACT;
3100 m_pComPlusCallInfo->SetHasCopyCtorArgs(value);
3101 }
3102
3103 WORD GetStackArgumentSize()
3104 {
3105 LIMITED_METHOD_DAC_CONTRACT;
3106 return m_pComPlusCallInfo->GetStackArgumentSize();
3107 }
3108
3109 void SetStackArgumentSize(WORD cbDstBuffer)
3110 {
3111 LIMITED_METHOD_CONTRACT;
3112 m_pComPlusCallInfo->SetStackArgumentSize(cbDstBuffer);
3113 }
3114#else // _TARGET_X86_
3115 void SetStackArgumentSize(WORD cbDstBuffer)
3116 {
3117 LIMITED_METHOD_CONTRACT;
3118 }
3119#endif // _TARGET_X86_
3120};
3121#endif // FEATURE_COMINTEROP
3122
3123//-----------------------------------------------------------------------
3124// InstantiatedMethodDesc's are used for generics and
3125// come in four flavours, discriminated by the
3126// low order bits of the first field:
3127//
3128// 00 --> GenericMethodDefinition
3129// 01 --> UnsharedMethodInstantiation
3130// 10 --> SharedMethodInstantiation
3131// 11 --> WrapperStubWithInstantiations - and unboxing or instantiating stub
3132//
3133// A SharedMethodInstantiation descriptor extends MethodDesc
3134// with a pointer to dictionary layout and a representative instantiation.
3135//
3136// A GenericMethodDefinition is the instantiation of a
3137// generic method at its formals, used for verifying the method and
3138// also for reflection.
3139//
3140// A WrapperStubWithInstantiations extends MethodDesc with:
3141// (1) a method instantiation
3142// (2) an "underlying" method descriptor.
3143// A WrapperStubWithInstantiations may be placed in a MethodChunk for
3144// a method table which specifies an exact instantiation for the class/struct.
3145// A WrapperStubWithInstantiations may be either
3146// an BoxedEntryPointStub or an exact-instantiation stub.
3147//
3148// Exact-instantiation stubs are used as extra type-context parameters. When
3149// used as an entry, instantiating stubs pass an instantiation
3150// dictionary on to the underlying method. These entries are required to
3151// implement ldftn instructions on instantiations of shared generic
3152// methods, as the InstantiatingStub's pointer does not expect a
3153// dictionary argument; instead, it passes itself on to the shared
3154// code as the dictionary.
3155//
3156// An UnsharedMethodInstantiation contains just an instantiation.
3157// These are fully-specialized wrt method and class type parameters.
3158// These satisfy (!IMD_IsGenericMethodDefinition() &&
3159// !IMD_IsSharedByGenericMethodInstantiations() &&
3160// !IMD_IsWrapperStubWithInstantiations())
3161//
3162// Note that plain MethodDescs may represent shared code w.r.t. class type
3163// parameters (see MethodDesc::IsSharedByGenericInstantiations()).
3164//-----------------------------------------------------------------------
3165
3166class InstantiatedMethodDesc : public MethodDesc
3167{
3168#ifdef DACCESS_COMPILE
3169 friend class NativeImageDumper;
3170#endif
3171
3172public:
3173
3174 // All varities of InstantiatedMethodDesc's support this method.
3175 BOOL IMD_HasMethodInstantiation()
3176 {
3177 LIMITED_METHOD_DAC_CONTRACT;
3178
3179 if (IMD_IsGenericMethodDefinition())
3180 return TRUE;
3181 else
3182 return !m_pPerInstInfo.IsNull();
3183 }
3184
3185 // All varieties of InstantiatedMethodDesc's support this method.
3186 Instantiation IMD_GetMethodInstantiation()
3187 {
3188 LIMITED_METHOD_DAC_CONTRACT;
3189
3190 return Instantiation(IMD_GetMethodDictionary()->GetInstantiation(), m_wNumGenericArgs);
3191 }
3192
3193 PTR_Dictionary IMD_GetMethodDictionary()
3194 {
3195 LIMITED_METHOD_DAC_CONTRACT;
3196
3197 return ReadPointerMaybeNull(this, &InstantiatedMethodDesc::m_pPerInstInfo);
3198 }
3199
3200 PTR_Dictionary IMD_GetMethodDictionaryNonNull()
3201 {
3202 LIMITED_METHOD_DAC_CONTRACT;
3203
3204 return ReadPointer(this, &InstantiatedMethodDesc::m_pPerInstInfo);
3205 }
3206
3207 BOOL IMD_IsGenericMethodDefinition()
3208 {
3209 LIMITED_METHOD_DAC_CONTRACT;
3210
3211 return((m_wFlags2 & KindMask) == GenericMethodDefinition);
3212 }
3213
3214 BOOL IMD_IsSharedByGenericMethodInstantiations()
3215 {
3216 LIMITED_METHOD_DAC_CONTRACT;
3217
3218 return((m_wFlags2 & KindMask) == SharedMethodInstantiation);
3219 }
3220 BOOL IMD_IsWrapperStubWithInstantiations()
3221 {
3222 LIMITED_METHOD_DAC_CONTRACT;
3223
3224 return((m_wFlags2 & KindMask) == WrapperStubWithInstantiations);
3225 }
3226
3227 BOOL IMD_IsEnCAddedMethod()
3228 {
3229 LIMITED_METHOD_CONTRACT;
3230
3231#ifdef EnC_SUPPORTED
3232 return((m_wFlags2 & KindMask) == EnCAddedMethod);
3233#else
3234 return FALSE;
3235#endif
3236 }
3237
3238#ifdef FEATURE_COMINTEROP
3239 BOOL IMD_HasComPlusCallInfo()
3240 {
3241 LIMITED_METHOD_CONTRACT;
3242 return ((m_wFlags2 & HasComPlusCallInfo) != 0);
3243 }
3244
3245 void IMD_SetupGenericComPlusCall()
3246 {
3247 LIMITED_METHOD_CONTRACT;
3248
3249 m_wFlags2 |= InstantiatedMethodDesc::HasComPlusCallInfo;
3250
3251 IMD_GetComPlusCallInfo()->InitStackArgumentSize();
3252 }
3253
3254 PTR_ComPlusCallInfo IMD_GetComPlusCallInfo()
3255 {
3256 LIMITED_METHOD_CONTRACT;
3257
3258 _ASSERTE(IMD_HasComPlusCallInfo());
3259 SIZE_T size = s_ClassificationSizeTable[m_wFlags & (mdcClassification | mdcHasNonVtableSlot | mdcMethodImpl)];
3260
3261 if (HasNativeCodeSlot())
3262 {
3263 size += (*dac_cast<PTR_TADDR>(dac_cast<TADDR>(this) + size) & FIXUP_LIST_MASK) ?
3264 (sizeof(NativeCodeSlot) + sizeof(FixupListSlot)) : sizeof(NativeCodeSlot);
3265 }
3266
3267 return dac_cast<PTR_ComPlusCallInfo>(dac_cast<TADDR>(this) + size);
3268 }
3269#endif // FEATURE_COMINTEROP
3270
3271 PTR_DictionaryLayout GetDictLayoutRaw()
3272 {
3273 LIMITED_METHOD_DAC_CONTRACT;
3274 return RelativePointer<PTR_DictionaryLayout>::GetValueMaybeNullAtPtr(PTR_HOST_MEMBER_TADDR(InstantiatedMethodDesc, this, m_pDictLayout));
3275 }
3276
3277 PTR_MethodDesc IMD_GetWrappedMethodDesc()
3278 {
3279 LIMITED_METHOD_DAC_CONTRACT;
3280
3281 _ASSERTE(IMD_IsWrapperStubWithInstantiations());
3282 return RelativeFixupPointer<PTR_MethodDesc>::GetValueAtPtr(PTR_HOST_MEMBER_TADDR(InstantiatedMethodDesc, this, m_pWrappedMethodDesc));
3283 }
3284
3285#ifndef DACCESS_COMPILE
3286 // Get the dictionary layout, if there is one
3287 DictionaryLayout* IMD_GetDictionaryLayout()
3288 {
3289 WRAPPER_NO_CONTRACT;
3290 if (IMD_IsWrapperStubWithInstantiations() && IMD_HasMethodInstantiation())
3291 {
3292 InstantiatedMethodDesc* pIMD = IMD_GetWrappedMethodDesc()->AsInstantiatedMethodDesc();
3293 return pIMD->m_pDictLayout.GetValueMaybeNull();
3294 }
3295 else
3296 if (IMD_IsSharedByGenericMethodInstantiations())
3297 return m_pDictLayout.GetValueMaybeNull();
3298 else
3299 return NULL;
3300 }
3301#endif // !DACCESS_COMPILE
3302
3303 // Setup the IMD as shared code
3304 void SetupSharedMethodInstantiation(DWORD numGenericArgs, TypeHandle *pPerInstInfo, DictionaryLayout *pDL);
3305
3306 // Setup the IMD as unshared code
3307 void SetupUnsharedMethodInstantiation(DWORD numGenericArgs, TypeHandle *pInst);
3308
3309 // Setup the IMD as the special MethodDesc for a "generic" method
3310 void SetupGenericMethodDefinition(IMDInternalImport *pIMDII, LoaderAllocator* pAllocator, AllocMemTracker *pamTracker,
3311 Module *pModule, mdMethodDef tok);
3312
3313 // Setup the IMD as a wrapper around another method desc
3314 void SetupWrapperStubWithInstantiations(MethodDesc* wrappedMD,DWORD numGenericArgs, TypeHandle *pGenericMethodInst);
3315
3316
3317#ifdef EnC_SUPPORTED
3318 void SetupEnCAddedMethod()
3319 {
3320 LIMITED_METHOD_CONTRACT;
3321 m_wFlags2 = EnCAddedMethod;
3322 }
3323#endif
3324
3325private:
3326 enum
3327 {
3328 KindMask = 0x07,
3329 GenericMethodDefinition = 0x00,
3330 UnsharedMethodInstantiation = 0x01,
3331 SharedMethodInstantiation = 0x02,
3332 WrapperStubWithInstantiations = 0x03,
3333
3334#ifdef EnC_SUPPORTED
3335 // Non-virtual method added through EditAndContinue.
3336 EnCAddedMethod = 0x07,
3337#endif // EnC_SUPPORTED
3338
3339 Unrestored = 0x08,
3340
3341#ifdef FEATURE_COMINTEROP
3342 HasComPlusCallInfo = 0x10, // this IMD contains an optional ComPlusCallInfo
3343#endif // FEATURE_COMINTEROP
3344 };
3345
3346 friend class MethodDesc; // this fields are currently accessed by MethodDesc::Save/Restore etc.
3347 union {
3348 RelativePointer<PTR_DictionaryLayout> m_pDictLayout; //SharedMethodInstantiation
3349
3350 RelativeFixupPointer<PTR_MethodDesc> m_pWrappedMethodDesc; // For WrapperStubWithInstantiations
3351 };
3352
3353public: // <TODO>make private: JITinterface.cpp accesses through this </TODO>
3354 // Note we can't steal bits off m_pPerInstInfo as the JIT generates code to access through it!!
3355
3356 // Type parameters to method (exact)
3357 // For non-unboxing instantiating stubs this is actually
3358 // a dictionary and further slots may hang off the end of the
3359 // instantiation.
3360 //
3361 // For generic method definitions that are not the typical method definition (e.g. C<int>.m<U>)
3362 // this field is null; to obtain the instantiation use LoadMethodInstantiation
3363#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
3364 RelativePointer<PTR_Dictionary> m_pPerInstInfo; //SHARED
3365#else
3366 PlainPointer<PTR_Dictionary> m_pPerInstInfo; //SHARED
3367#endif
3368
3369private:
3370 WORD m_wFlags2;
3371 WORD m_wNumGenericArgs;
3372
3373public:
3374 static InstantiatedMethodDesc *FindOrCreateExactClassMethod(MethodTable *pExactMT,
3375 MethodDesc *pCanonicalMD);
3376
3377 static InstantiatedMethodDesc* FindLoadedInstantiatedMethodDesc(MethodTable *pMT,
3378 mdMethodDef methodDef,
3379 Instantiation methodInst,
3380 BOOL getSharedNotStub);
3381
3382private:
3383
3384 static InstantiatedMethodDesc *NewInstantiatedMethodDesc(MethodTable *pMT,
3385 MethodDesc* pGenericMDescInRepMT,
3386 MethodDesc* pSharedMDescForStub,
3387 Instantiation methodInst,
3388 BOOL getSharedNotStub);
3389
3390};
3391
3392inline PTR_MethodTable MethodDesc::GetMethodTable_NoLogging() const
3393{
3394 LIMITED_METHOD_DAC_CONTRACT;
3395
3396 MethodDescChunk *pChunk = GetMethodDescChunk();
3397 PREFIX_ASSUME(pChunk != NULL);
3398 return pChunk->GetMethodTable();
3399}
3400
3401inline PTR_MethodTable MethodDesc::GetMethodTable() const
3402{
3403 LIMITED_METHOD_DAC_CONTRACT;
3404
3405 g_IBCLogger.LogMethodDescAccess(this);
3406 return GetMethodTable_NoLogging();
3407}
3408
3409inline DPTR(RelativeFixupPointer<PTR_MethodTable>) MethodDesc::GetMethodTablePtr() const
3410{
3411 LIMITED_METHOD_DAC_CONTRACT;
3412
3413 MethodDescChunk *pChunk = GetMethodDescChunk();
3414 PREFIX_ASSUME(pChunk != NULL);
3415 return pChunk->GetMethodTablePtr();
3416}
3417
3418inline MethodTable* MethodDesc::GetCanonicalMethodTable()
3419{
3420 LIMITED_METHOD_DAC_CONTRACT;
3421
3422 return GetMethodTable()->GetCanonicalMethodTable();
3423}
3424
3425inline mdMethodDef MethodDesc::GetMemberDef_NoLogging() const
3426{
3427 LIMITED_METHOD_DAC_CONTRACT;
3428
3429 MethodDescChunk *pChunk = GetMethodDescChunk();
3430 PREFIX_ASSUME(pChunk != NULL);
3431 UINT16 tokrange = pChunk->GetTokRange();
3432
3433 UINT16 tokremainder = m_wFlags3AndTokenRemainder & enum_flag3_TokenRemainderMask;
3434 static_assert_no_msg(enum_flag3_TokenRemainderMask == METHOD_TOKEN_REMAINDER_MASK);
3435
3436 return MergeToken(tokrange, tokremainder);
3437}
3438
3439inline mdMethodDef MethodDesc::GetMemberDef() const
3440{
3441 LIMITED_METHOD_DAC_CONTRACT;
3442 g_IBCLogger.LogMethodDescAccess(this);
3443 return GetMemberDef_NoLogging();
3444}
3445
3446// Set the offset of this method desc in a chunk table (which allows us
3447// to work back to the method table/module pointer stored at the head of
3448// the table.
3449inline void MethodDesc::SetChunkIndex(MethodDescChunk * pChunk)
3450{
3451 WRAPPER_NO_CONTRACT;
3452
3453 // Calculate the offset (mod 8) from the chunk table header.
3454 SIZE_T offset = (BYTE*)this - (BYTE*)pChunk->GetFirstMethodDesc();
3455 _ASSERTE((offset & ALIGNMENT_MASK) == 0);
3456 offset >>= ALIGNMENT_SHIFT;
3457
3458 // Make sure that we did not overflow the BYTE
3459 _ASSERTE(offset == (BYTE)offset);
3460 m_chunkIndex = (BYTE)offset;
3461
3462 // Make sure that the MethodDescChunk is setup correctly
3463 _ASSERTE(GetMethodDescChunk() == pChunk);
3464}
3465
3466inline void MethodDesc::SetMemberDef(mdMethodDef mb)
3467{
3468 WRAPPER_NO_CONTRACT;
3469
3470 UINT16 tokrange;
3471 UINT16 tokremainder;
3472 SplitToken(mb, &tokrange, &tokremainder);
3473
3474 _ASSERTE((tokremainder & ~enum_flag3_TokenRemainderMask) == 0);
3475 m_wFlags3AndTokenRemainder = (m_wFlags3AndTokenRemainder & ~enum_flag3_TokenRemainderMask) | tokremainder;
3476
3477 if (GetMethodDescIndex() == 0)
3478 {
3479 GetMethodDescChunk()->SetTokenRange(tokrange);
3480 }
3481
3482#ifdef _DEBUG
3483 if (mb != 0)
3484 {
3485 _ASSERTE(GetMemberDef_NoLogging() == mb);
3486 }
3487#endif
3488}
3489
3490#ifdef _DEBUG
3491
3492inline BOOL MethodDesc::SanityCheck()
3493{
3494 CONTRACTL
3495 {
3496 NOTHROW;
3497 GC_NOTRIGGER;
3498 SO_TOLERANT;
3499 MODE_ANY;
3500 SUPPORTS_DAC;
3501 }
3502 CONTRACTL_END;
3503
3504
3505 // Do a simple sanity test
3506 if (IsRestored())
3507 {
3508 // If it looks good, do a more intensive sanity test. We don't care about the result,
3509 // we just want it to not AV.
3510 return GetMethodTable() == m_pDebugMethodTable.GetValue() && this->GetModule() != NULL;
3511 }
3512
3513 return TRUE;
3514}
3515
3516#endif // _DEBUG
3517
3518inline BOOL MethodDesc::IsEnCAddedMethod()
3519{
3520 LIMITED_METHOD_DAC_CONTRACT;
3521
3522 return (GetClassification() == mcInstantiated) && AsInstantiatedMethodDesc()->IMD_IsEnCAddedMethod();
3523}
3524
3525inline BOOL MethodDesc::HasNonVtableSlot()
3526{
3527 LIMITED_METHOD_DAC_CONTRACT;
3528
3529 return (m_wFlags & mdcHasNonVtableSlot) != 0;
3530}
3531
3532inline Instantiation MethodDesc::GetMethodInstantiation() const
3533{
3534 LIMITED_METHOD_DAC_CONTRACT;
3535
3536 return
3537 (GetClassification() == mcInstantiated)
3538 ? AsInstantiatedMethodDesc()->IMD_GetMethodInstantiation()
3539 : Instantiation();
3540}
3541
3542inline Instantiation MethodDesc::GetClassInstantiation() const
3543{
3544 LIMITED_METHOD_DAC_CONTRACT;
3545
3546 return GetMethodTable()->GetInstantiation();
3547}
3548
3549inline BOOL MethodDesc::IsGenericMethodDefinition() const
3550{
3551 LIMITED_METHOD_DAC_CONTRACT;
3552
3553 g_IBCLogger.LogMethodDescAccess(this);
3554 return GetClassification() == mcInstantiated && AsInstantiatedMethodDesc()->IMD_IsGenericMethodDefinition();
3555}
3556
3557// True if the method descriptor is an instantiation of a generic method.
3558inline BOOL MethodDesc::HasMethodInstantiation() const
3559{
3560 LIMITED_METHOD_DAC_CONTRACT;
3561
3562 return mcInstantiated == GetClassification() && AsInstantiatedMethodDesc()->IMD_HasMethodInstantiation();
3563}
3564
3565#if defined(FEATURE_GDBJIT)
3566class CalledMethod
3567{
3568private:
3569 MethodDesc * m_pMD;
3570 void * m_CallAddr;
3571 CalledMethod * m_pNext;
3572public:
3573 CalledMethod(MethodDesc *pMD, void * addr, CalledMethod * next) : m_pMD(pMD), m_CallAddr(addr), m_pNext(next) {}
3574 ~CalledMethod() {}
3575 MethodDesc * GetMethodDesc() { return m_pMD; }
3576 void * GetCallAddr() { return m_CallAddr; }
3577 CalledMethod * GetNext() { return m_pNext; }
3578};
3579#endif
3580
3581#include "method.inl"
3582
3583#endif // !_METHOD_H
3584