1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4// ===========================================================================
5// File: JITinterface.CPP
6//
7
8// ===========================================================================
9
10
11#include "common.h"
12#include "jitinterface.h"
13#include "codeman.h"
14#include "method.hpp"
15#include "class.h"
16#include "object.h"
17#include "field.h"
18#include "stublink.h"
19#include "virtualcallstub.h"
20#include "corjit.h"
21#include "eeconfig.h"
22#include "excep.h"
23#include "log.h"
24#include "excep.h"
25#include "float.h" // for isnan
26#include "dbginterface.h"
27#include "dllimport.h"
28#include "gcheaputilities.h"
29#include "comdelegate.h"
30#include "jitperf.h" // to track jit perf
31#include "corprof.h"
32#include "eeprofinterfaces.h"
33#include "perfcounters.h"
34#ifdef PROFILING_SUPPORTED
35#include "proftoeeinterfaceimpl.h"
36#include "eetoprofinterfaceimpl.h"
37#include "eetoprofinterfaceimpl.inl"
38#include "profilepriv.h"
39#endif
40#include "ecall.h"
41#include "generics.h"
42#include "typestring.h"
43#include "stackprobe.h"
44#include "typedesc.h"
45#include "genericdict.h"
46#include "array.h"
47#include "debuginfostore.h"
48#include "safemath.h"
49#include "runtimehandles.h"
50#include "sigbuilder.h"
51#include "openum.h"
52#ifdef HAVE_GCCOVER
53#include "gccover.h"
54#endif // HAVE_GCCOVER
55
56#include "mdaassistants.h"
57
58#ifdef FEATURE_PREJIT
59#include "compile.h"
60#include "corcompile.h"
61#endif // FEATURE_PREJIT
62
63
64#ifdef FEATURE_INTERPRETER
65#include "interpreter.h"
66#endif // FEATURE_INTERPRETER
67
68#ifdef FEATURE_PERFMAP
69#include "perfmap.h"
70#endif
71
72// The Stack Overflow probe takes place in the COOPERATIVE_TRANSITION_BEGIN() macro
73//
74
75#define JIT_TO_EE_TRANSITION() MAKE_CURRENT_THREAD_AVAILABLE_EX(m_pThread); \
76 _ASSERTE(CURRENT_THREAD == GetThread()); \
77 INSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE; \
78 COOPERATIVE_TRANSITION_BEGIN(); \
79 START_NON_JIT_PERF();
80
81#define EE_TO_JIT_TRANSITION() STOP_NON_JIT_PERF(); \
82 COOPERATIVE_TRANSITION_END(); \
83 UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE;
84
85#define JIT_TO_EE_TRANSITION_LEAF()
86#define EE_TO_JIT_TRANSITION_LEAF()
87
88
89#if defined(CROSSGEN_COMPILE)
90static const char *const hlpNameTable[CORINFO_HELP_COUNT] = {
91#define JITHELPER(code, pfnHelper, sig) #code,
92#include "jithelpers.h"
93};
94#endif
95
96#ifdef DACCESS_COMPILE
97
98// The real definitions are in jithelpers.cpp. However, those files are not included in the DAC build.
99// Hence, we add them here.
100GARY_IMPL(VMHELPDEF, hlpFuncTable, CORINFO_HELP_COUNT);
101GARY_IMPL(VMHELPDEF, hlpDynamicFuncTable, DYNAMIC_CORINFO_HELP_COUNT);
102
103#else // DACCESS_COMPILE
104
105/*********************************************************************/
106
107#if defined(ENABLE_PERF_COUNTERS)
108LARGE_INTEGER g_lastTimeInJitCompilation;
109#endif
110
111/*********************************************************************/
112
113inline CORINFO_MODULE_HANDLE GetScopeHandle(MethodDesc* method)
114{
115 LIMITED_METHOD_CONTRACT;
116 if (method->IsDynamicMethod())
117 {
118 return MakeDynamicScope(method->AsDynamicMethodDesc()->GetResolver());
119 }
120 else
121 {
122 return GetScopeHandle(method->GetModule());
123 }
124}
125
126//This is common refactored code from within several of the access check functions.
127BOOL ModifyCheckForDynamicMethod(DynamicResolver *pResolver,
128 TypeHandle *pOwnerTypeForSecurity,
129 AccessCheckOptions::AccessCheckType *pAccessCheckType,
130 DynamicResolver** ppAccessContext)
131{
132 CONTRACTL {
133 STANDARD_VM_CHECK;
134 PRECONDITION(CheckPointer(pResolver));
135 PRECONDITION(CheckPointer(pOwnerTypeForSecurity));
136 PRECONDITION(CheckPointer(pAccessCheckType));
137 PRECONDITION(CheckPointer(ppAccessContext));
138 PRECONDITION(*pAccessCheckType == AccessCheckOptions::kNormalAccessibilityChecks);
139 } CONTRACTL_END;
140
141 BOOL doAccessCheck = TRUE;
142
143 //Do not blindly initialize fields, since they've already got important values.
144 DynamicResolver::SecurityControlFlags dwSecurityFlags = DynamicResolver::Default;
145
146 TypeHandle dynamicOwner;
147 pResolver->GetJitContext(&dwSecurityFlags, &dynamicOwner);
148 if (!dynamicOwner.IsNull())
149 *pOwnerTypeForSecurity = dynamicOwner;
150
151 if (dwSecurityFlags & DynamicResolver::SkipVisibilityChecks)
152 {
153 doAccessCheck = FALSE;
154 }
155 else if (dwSecurityFlags & DynamicResolver::RestrictedSkipVisibilityChecks)
156 {
157 *pAccessCheckType = AccessCheckOptions::kRestrictedMemberAccessNoTransparency;
158 }
159 else
160 {
161 *pAccessCheckType = AccessCheckOptions::kNormalAccessNoTransparency;
162 }
163
164 return doAccessCheck;
165}
166
167/*****************************************************************************/
168
169// Initialize from data we passed across to the JIT
170inline static void GetTypeContext(const CORINFO_SIG_INST *info, SigTypeContext *pTypeContext)
171{
172 LIMITED_METHOD_CONTRACT;
173 SigTypeContext::InitTypeContext(
174 Instantiation((TypeHandle *) info->classInst, info->classInstCount),
175 Instantiation((TypeHandle *) info->methInst, info->methInstCount),
176 pTypeContext);
177}
178
179static MethodDesc* GetMethodFromContext(CORINFO_CONTEXT_HANDLE context)
180{
181 LIMITED_METHOD_CONTRACT;
182 if (((size_t) context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
183 {
184 return NULL;
185 }
186 else
187 {
188 return GetMethod((CORINFO_METHOD_HANDLE)((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK));
189 }
190}
191
192static TypeHandle GetTypeFromContext(CORINFO_CONTEXT_HANDLE context)
193{
194 LIMITED_METHOD_CONTRACT;
195 if (((size_t) context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
196 {
197 return TypeHandle((CORINFO_CLASS_HANDLE) ((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK));
198 }
199 else
200 {
201 MethodTable * pMT = GetMethodFromContext(context)->GetMethodTable();
202 return TypeHandle(pMT);
203 }
204}
205
206// Initialize from a context parameter passed to the JIT and back. This is a parameter
207// that indicates which method is being jitted.
208
209inline static void GetTypeContext(CORINFO_CONTEXT_HANDLE context, SigTypeContext *pTypeContext)
210{
211 CONTRACTL
212 {
213 NOTHROW;
214 GC_NOTRIGGER;
215 SO_TOLERANT;
216 MODE_ANY;
217 PRECONDITION(context != NULL);
218 }
219 CONTRACTL_END;
220 if (GetMethodFromContext(context))
221 {
222 SigTypeContext::InitTypeContext(GetMethodFromContext(context), pTypeContext);
223 }
224 else
225 {
226 SigTypeContext::InitTypeContext(GetTypeFromContext(context), pTypeContext);
227 }
228}
229
230static BOOL ContextIsShared(CORINFO_CONTEXT_HANDLE context)
231{
232 LIMITED_METHOD_CONTRACT;
233 MethodDesc *pContextMD = GetMethodFromContext(context);
234 if (pContextMD != NULL)
235 {
236 return pContextMD->IsSharedByGenericInstantiations();
237 }
238 else
239 {
240 // Type handle contexts are non-shared and are used for inlining of
241 // non-generic methods in generic classes
242 return FALSE;
243 }
244}
245
246// Returns true if context is providing any generic variables
247static BOOL ContextIsInstantiated(CORINFO_CONTEXT_HANDLE context)
248{
249 LIMITED_METHOD_CONTRACT;
250 if (GetMethodFromContext(context))
251 {
252 return GetMethodFromContext(context)->HasClassOrMethodInstantiation();
253 }
254 else
255 {
256 return GetTypeFromContext(context).HasInstantiation();
257 }
258}
259
260/*********************************************************************/
261// This normalizes EE type information into the form expected by the JIT.
262//
263// If typeHnd contains exact type information, then *clsRet will contain
264// the normalized CORINFO_CLASS_HANDLE information on return.
265
266// Static
267CorInfoType CEEInfo::asCorInfoType(CorElementType eeType,
268 TypeHandle typeHnd, /* optional in */
269 CORINFO_CLASS_HANDLE *clsRet/* optional out */ ) {
270 CONTRACT(CorInfoType) {
271 THROWS;
272 GC_TRIGGERS;
273 PRECONDITION((CorTypeInfo::IsGenericVariable(eeType)) ==
274 (!typeHnd.IsNull() && typeHnd.IsGenericVariable()));
275 PRECONDITION(eeType != ELEMENT_TYPE_GENERICINST);
276 } CONTRACT_END;
277
278 TypeHandle typeHndUpdated = typeHnd;
279
280 if (!typeHnd.IsNull())
281 {
282 CorElementType normType = typeHnd.GetInternalCorElementType();
283 // If we have a type handle, then it has the better type
284 // in some cases
285 if (eeType == ELEMENT_TYPE_VALUETYPE && !CorTypeInfo::IsObjRef(normType))
286 eeType = normType;
287
288 // Zap the typeHnd when the type _really_ is a primitive
289 // as far as verification is concerned. Returning a null class
290 // handle means it is is a primitive.
291 //
292 // Enums are exactly like primitives, even from a verification standpoint,
293 // so we zap the type handle in this case.
294 //
295 // However RuntimeTypeHandle etc. are reported as E_T_INT (or something like that)
296 // but don't count as primitives as far as verification is concerned...
297 //
298 // To make things stranger, TypedReference returns true for "IsTruePrimitive".
299 // However the JIT likes us to report the type handle in that case.
300 if (!typeHnd.IsTypeDesc() && (
301 (typeHnd.AsMethodTable()->IsTruePrimitive() && typeHnd != TypeHandle(g_TypedReferenceMT))
302 || typeHnd.AsMethodTable()->IsEnum()) )
303 {
304 typeHndUpdated = TypeHandle();
305 }
306
307 }
308
309 static const BYTE map[] = {
310 CORINFO_TYPE_UNDEF,
311 CORINFO_TYPE_VOID,
312 CORINFO_TYPE_BOOL,
313 CORINFO_TYPE_CHAR,
314 CORINFO_TYPE_BYTE,
315 CORINFO_TYPE_UBYTE,
316 CORINFO_TYPE_SHORT,
317 CORINFO_TYPE_USHORT,
318 CORINFO_TYPE_INT,
319 CORINFO_TYPE_UINT,
320 CORINFO_TYPE_LONG,
321 CORINFO_TYPE_ULONG,
322 CORINFO_TYPE_FLOAT,
323 CORINFO_TYPE_DOUBLE,
324 CORINFO_TYPE_STRING,
325 CORINFO_TYPE_PTR, // PTR
326 CORINFO_TYPE_BYREF,
327 CORINFO_TYPE_VALUECLASS,
328 CORINFO_TYPE_CLASS,
329 CORINFO_TYPE_VAR, // VAR (type variable)
330 CORINFO_TYPE_CLASS, // ARRAY
331 CORINFO_TYPE_CLASS, // WITH
332 CORINFO_TYPE_REFANY,
333 CORINFO_TYPE_UNDEF, // VALUEARRAY_UNSUPPORTED
334 CORINFO_TYPE_NATIVEINT, // I
335 CORINFO_TYPE_NATIVEUINT, // U
336 CORINFO_TYPE_UNDEF, // R_UNSUPPORTED
337
338 // put the correct type when we know our implementation
339 CORINFO_TYPE_PTR, // FNPTR
340 CORINFO_TYPE_CLASS, // OBJECT
341 CORINFO_TYPE_CLASS, // SZARRAY
342 CORINFO_TYPE_VAR, // MVAR
343
344 CORINFO_TYPE_UNDEF, // CMOD_REQD
345 CORINFO_TYPE_UNDEF, // CMOD_OPT
346 CORINFO_TYPE_UNDEF, // INTERNAL
347 };
348
349 _ASSERTE(sizeof(map) == ELEMENT_TYPE_MAX);
350 _ASSERTE(eeType < (CorElementType) sizeof(map));
351 // spot check of the map
352 _ASSERTE((CorInfoType) map[ELEMENT_TYPE_I4] == CORINFO_TYPE_INT);
353 _ASSERTE((CorInfoType) map[ELEMENT_TYPE_PTR] == CORINFO_TYPE_PTR);
354 _ASSERTE((CorInfoType) map[ELEMENT_TYPE_TYPEDBYREF] == CORINFO_TYPE_REFANY);
355
356 CorInfoType res = ((unsigned)eeType < ELEMENT_TYPE_MAX) ? ((CorInfoType) map[(unsigned)eeType]) : CORINFO_TYPE_UNDEF;
357
358 if (clsRet)
359 *clsRet = CORINFO_CLASS_HANDLE(typeHndUpdated.AsPtr());
360
361 RETURN res;
362}
363
364
365inline static CorInfoType toJitType(TypeHandle typeHnd, CORINFO_CLASS_HANDLE *clsRet = NULL)
366{
367 WRAPPER_NO_CONTRACT;
368 return CEEInfo::asCorInfoType(typeHnd.GetInternalCorElementType(), typeHnd, clsRet);
369}
370
371void CheckForEquivalenceAndLoadTypeBeforeCodeIsRun(Module *pModule, mdToken token, Module *pDefModule, mdToken defToken, const SigParser *ptr, SigTypeContext *pTypeContext, void *pData)
372{
373 CONTRACTL
374 {
375 THROWS;
376 GC_TRIGGERS;
377 SO_INTOLERANT;
378 }
379 CONTRACTL_END;
380
381 if (IsTypeDefEquivalent(defToken, pDefModule))
382 {
383 SigPointer sigPtr(*ptr);
384 TypeHandle th = sigPtr.GetTypeHandleThrowing(pModule, pTypeContext);
385 ((ICorDynamicInfo *)pData)->classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_HANDLE(th.AsPtr()));
386 }
387}
388
389inline static void TypeEquivalenceFixupSpecificationHelper(ICorDynamicInfo * pCorInfo, MethodDesc *pMD)
390{
391 STANDARD_VM_CONTRACT;
392
393 // A fixup is necessary to ensure that the parameters to the method are loaded before the method
394 // is called. In these cases we will not perform the appropriate loading when we load parameter
395 // types because with type equivalence, the parameter types at the call site do not necessarily
396 // match that those in the actual function. (They must be equivalent, but not necessarily the same.)
397 // In non-ngen scenarios this code here will force the types to be loaded directly by the call to
398 // HasTypeEquivalentStructParameters.
399 if (!pMD->IsVirtual())
400 {
401 if (pMD->HasTypeEquivalentStructParameters())
402 {
403 if (IsCompilationProcess())
404 pMD->WalkValueTypeParameters(pMD->GetMethodTable(), CheckForEquivalenceAndLoadTypeBeforeCodeIsRun, pCorInfo);
405 }
406 }
407 else
408 {
409 if (pMD->GetMethodTable()->DependsOnEquivalentOrForwardedStructs())
410 {
411 if (pMD->HasTypeEquivalentStructParameters())
412 pCorInfo->classMustBeLoadedBeforeCodeIsRun((CORINFO_CLASS_HANDLE)pMD->GetMethodTable());
413 }
414 }
415}
416
417//---------------------------------------------------------------------------------------
418//
419//@GENERICS:
420// The method handle is used to instantiate method and class type parameters
421// It's also used to determine whether an extra dictionary parameter is required
422//
423// sig - Input metadata signature
424// scopeHnd - The signature is to be interpreted in the context of this scope (module)
425// token - Metadata token used to refer to the signature (may be mdTokenNil for dynamic methods)
426// sigRet - Resulting output signature in a format that is understood by native compilers
427// pContextMD - The method with any instantiation information (may be NULL)
428// localSig - Is it a local variables declaration, or a method signature (with return type, etc).
429// contextType - The type with any instantiaton information
430//
431//static
432void
433CEEInfo::ConvToJitSig(
434 PCCOR_SIGNATURE pSig,
435 DWORD cbSig,
436 CORINFO_MODULE_HANDLE scopeHnd,
437 mdToken token,
438 CORINFO_SIG_INFO * sigRet,
439 MethodDesc * pContextMD,
440 bool localSig,
441 TypeHandle contextType)
442{
443 CONTRACTL {
444 THROWS;
445 GC_TRIGGERS;
446 } CONTRACTL_END;
447
448 SigTypeContext typeContext;
449
450 if (pContextMD)
451 {
452 SigTypeContext::InitTypeContext(pContextMD, contextType, &typeContext);
453 }
454 else
455 {
456 SigTypeContext::InitTypeContext(contextType, &typeContext);
457 }
458
459 _ASSERTE(CORINFO_CALLCONV_DEFAULT == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_DEFAULT);
460 _ASSERTE(CORINFO_CALLCONV_VARARG == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_VARARG);
461 _ASSERTE(CORINFO_CALLCONV_MASK == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_MASK);
462 _ASSERTE(CORINFO_CALLCONV_HASTHIS == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_HASTHIS);
463
464 TypeHandle typeHnd = TypeHandle();
465
466 sigRet->pSig = pSig;
467 sigRet->cbSig = cbSig;
468 sigRet->retTypeClass = 0;
469 sigRet->retTypeSigClass = 0;
470 sigRet->scope = scopeHnd;
471 sigRet->token = token;
472 sigRet->sigInst.classInst = (CORINFO_CLASS_HANDLE *) typeContext.m_classInst.GetRawArgs();
473 sigRet->sigInst.classInstCount = (unsigned) typeContext.m_classInst.GetNumArgs();
474 sigRet->sigInst.methInst = (CORINFO_CLASS_HANDLE *) typeContext.m_methodInst.GetRawArgs();
475 sigRet->sigInst.methInstCount = (unsigned) typeContext.m_methodInst.GetNumArgs();
476
477 SigPointer sig(pSig, cbSig);
478
479 if (!localSig)
480 {
481 // This is a method signature which includes calling convention, return type,
482 // arguments, etc
483
484 _ASSERTE(!sig.IsNull());
485 Module * module = GetModule(scopeHnd);
486 sigRet->flags = 0;
487
488 ULONG data;
489 IfFailThrow(sig.GetCallingConvInfo(&data));
490 sigRet->callConv = (CorInfoCallConv) data;
491
492#ifdef PLATFORM_UNIX
493 if ((isCallConv(sigRet->callConv, IMAGE_CEE_CS_CALLCONV_VARARG)) ||
494 (isCallConv(sigRet->callConv, IMAGE_CEE_CS_CALLCONV_NATIVEVARARG)))
495 {
496 // This signature corresponds to a method that uses varargs, which are not supported.
497 COMPlusThrow(kInvalidProgramException, IDS_EE_VARARG_NOT_SUPPORTED);
498 }
499#endif // PLATFORM_UNIX
500
501 // Skip number of type arguments
502 if (sigRet->callConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
503 IfFailThrow(sig.GetData(NULL));
504
505 ULONG numArgs;
506 IfFailThrow(sig.GetData(&numArgs));
507 if (numArgs != (unsigned short) numArgs)
508 COMPlusThrowHR(COR_E_INVALIDPROGRAM);
509
510 sigRet->numArgs = (unsigned short) numArgs;
511
512 CorElementType type = sig.PeekElemTypeClosed(module, &typeContext);
513
514 if (!CorTypeInfo::IsPrimitiveType(type))
515 {
516 typeHnd = sig.GetTypeHandleThrowing(module, &typeContext);
517 _ASSERTE(!typeHnd.IsNull());
518
519 // I believe it doesn't make any diff. if this is
520 // GetInternalCorElementType or GetSignatureCorElementType
521 type = typeHnd.GetSignatureCorElementType();
522
523 }
524 sigRet->retType = CEEInfo::asCorInfoType(type, typeHnd, &sigRet->retTypeClass);
525 sigRet->retTypeSigClass = CORINFO_CLASS_HANDLE(typeHnd.AsPtr());
526
527 IfFailThrow(sig.SkipExactlyOne()); // must to a skip so we skip any class tokens associated with the return type
528 _ASSERTE(sigRet->retType < CORINFO_TYPE_COUNT);
529
530 sigRet->args = (CORINFO_ARG_LIST_HANDLE)sig.GetPtr();
531 }
532 else
533 {
534 // This is local variables declaration
535
536 sigRet->callConv = CORINFO_CALLCONV_DEFAULT;
537 sigRet->retType = CORINFO_TYPE_VOID;
538 sigRet->flags = CORINFO_SIGFLAG_IS_LOCAL_SIG;
539 sigRet->numArgs = 0;
540 if (!sig.IsNull())
541 {
542 ULONG callConv;
543 IfFailThrow(sig.GetCallingConvInfo(&callConv));
544 if (callConv != IMAGE_CEE_CS_CALLCONV_LOCAL_SIG)
545 {
546 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_CALLCONV_NOT_LOCAL_SIG);
547 }
548
549 ULONG numArgs;
550 IfFailThrow(sig.GetData(&numArgs));
551
552 if (numArgs != (unsigned short) numArgs)
553 COMPlusThrowHR(COR_E_INVALIDPROGRAM);
554
555 sigRet->numArgs = (unsigned short) numArgs;
556 }
557
558 sigRet->args = (CORINFO_ARG_LIST_HANDLE)sig.GetPtr();
559 }
560
561 _ASSERTE(SigInfoFlagsAreValid(sigRet));
562} // CEEInfo::ConvToJitSig
563
564//---------------------------------------------------------------------------------------
565//
566CORINFO_CLASS_HANDLE CEEInfo::getTokenTypeAsHandle (CORINFO_RESOLVED_TOKEN * pResolvedToken)
567{
568 CONTRACTL {
569 SO_TOLERANT;
570 THROWS;
571 GC_TRIGGERS;
572 MODE_PREEMPTIVE;
573 } CONTRACTL_END;
574
575 CORINFO_CLASS_HANDLE tokenType = NULL;
576
577 JIT_TO_EE_TRANSITION();
578
579 _ASSERTE((pResolvedToken->hMethod == NULL) || (pResolvedToken->hField == NULL));
580
581 BinderClassID classID = CLASS__TYPE_HANDLE;
582
583 if (pResolvedToken->hMethod != NULL)
584 {
585 classID = CLASS__METHOD_HANDLE;
586 }
587 else
588 if (pResolvedToken->hField != NULL)
589 {
590 classID = CLASS__FIELD_HANDLE;
591 }
592
593 tokenType = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(classID));
594
595 EE_TO_JIT_TRANSITION();
596
597 return tokenType;
598}
599
600/*********************************************************************/
601size_t CEEInfo::findNameOfToken (
602 CORINFO_MODULE_HANDLE scopeHnd,
603 mdToken metaTOK,
604 __out_ecount (FQNameCapacity) char * szFQName,
605 size_t FQNameCapacity)
606{
607 CONTRACTL {
608 SO_TOLERANT;
609 THROWS;
610 GC_TRIGGERS;
611 MODE_PREEMPTIVE;
612 } CONTRACTL_END;
613
614 size_t NameLen = 0;
615
616 JIT_TO_EE_TRANSITION();
617
618 if (IsDynamicScope(scopeHnd))
619 {
620 strncpy_s (szFQName, FQNameCapacity, "DynamicToken", FQNameCapacity - 1);
621 NameLen = strlen (szFQName);
622 }
623 else
624 {
625 Module* module = (Module *)scopeHnd;
626 NameLen = findNameOfToken(module, metaTOK, szFQName, FQNameCapacity);
627 }
628
629 EE_TO_JIT_TRANSITION();
630
631 return NameLen;
632}
633
634CorInfoCanSkipVerificationResult CEEInfo::canSkipMethodVerification(CORINFO_METHOD_HANDLE ftnHnd)
635{
636 CONTRACTL {
637 SO_TOLERANT;
638 THROWS;
639 GC_TRIGGERS;
640 MODE_PREEMPTIVE;
641 } CONTRACTL_END;
642
643 return CORINFO_VERIFICATION_CAN_SKIP;
644}
645
646/*********************************************************************/
647BOOL CEEInfo::shouldEnforceCallvirtRestriction(
648 CORINFO_MODULE_HANDLE scopeHnd)
649{
650 LIMITED_METHOD_CONTRACT;
651 return TRUE;
652}
653
654#ifdef FEATURE_READYTORUN_COMPILER
655
656// Returns true if assemblies are in the same version bubble
657// Right now each assembly is in its own version bubble.
658// If the need arises (i.e. performance issues) we will define sets of assemblies (e.g. all app assemblies)
659// The main point is that all this logic is concentrated in one place.
660
661// NOTICE: If you change this logic to allow multi-assembly version bubbles you
662// need to consider the impact on diagnostic tools. Currently there is an inlining
663// table which tracks inliner/inlinee relationships in R2R images but it is not
664// yet capable of encoding cross-assembly inlines. The scenario where this
665// may show are instrumenting profilers that want to instrument a given method A
666// using the ReJit APIs. If method A happens to inlined within method B in another
667// assembly then the profiler needs to know that so it can rejit B too.
668// The recommended approach is to upgrade the inlining table (vm\inlinetracking.h\.cpp)
669// now that presumably R2R images have some way to refer to methods in other
670// assemblies in their version bubble. Chat with the diagnostics team if you need more
671// details.
672//
673// There already is a case where cross-assembly inlining occurs in an
674// unreported fashion for methods marked NonVersionable. There is a specific
675// exemption called out for this on ICorProfilerInfo6::EnumNgenModuleMethodsInliningThisMethod
676// and the impact of the cut was vetted with partners. It would not be appropriate
677// to increase that unreported set without additional review.
678
679
680bool IsInSameVersionBubble(Assembly * current, Assembly * target)
681{
682 LIMITED_METHOD_CONTRACT;
683
684 // trivial case: current and target are identical
685 // DO NOT change this without reading the notice above
686 if (current == target)
687 return true;
688
689 return false;
690}
691
692// Returns true if the assemblies defining current and target are in the same version bubble
693static bool IsInSameVersionBubble(MethodDesc* pCurMD, MethodDesc *pTargetMD)
694{
695 LIMITED_METHOD_CONTRACT;
696 // DO NOT change this without reading the notice above
697 if (IsInSameVersionBubble(pCurMD->GetModule()->GetAssembly(),
698 pTargetMD->GetModule()->GetAssembly()))
699 {
700 return true;
701 }
702 if (IsReadyToRunCompilation())
703 {
704 if (pTargetMD->GetModule()->GetMDImport()->GetCustomAttributeByName(pTargetMD->GetMemberDef(),
705 NONVERSIONABLE_TYPE, NULL, NULL) == S_OK)
706 {
707 return true;
708 }
709 }
710 return false;
711
712}
713
714#endif // FEATURE_READYTORUN_COMPILER
715
716static bool CallerAndCalleeInSystemVersionBubble(MethodDesc* pCaller, MethodDesc* pCallee)
717{
718 LIMITED_METHOD_CONTRACT;
719
720#ifdef FEATURE_READYTORUN_COMPILER
721 if (IsReadyToRunCompilation())
722 return pCallee->GetModule()->IsSystem() && IsInSameVersionBubble(pCaller, pCallee);
723#endif
724
725 return false;
726}
727
728
729/*********************************************************************/
730CorInfoCanSkipVerificationResult CEEInfo::canSkipVerification(
731 CORINFO_MODULE_HANDLE moduleHnd)
732{
733 CONTRACTL {
734 SO_TOLERANT;
735 THROWS;
736 GC_TRIGGERS;
737 MODE_PREEMPTIVE;
738 } CONTRACTL_END;
739
740 return CORINFO_VERIFICATION_CAN_SKIP;
741}
742
743/*********************************************************************/
744// Checks if the given metadata token is valid
745BOOL CEEInfo::isValidToken (
746 CORINFO_MODULE_HANDLE module,
747 mdToken metaTOK)
748{
749 CONTRACTL {
750 SO_TOLERANT;
751 NOTHROW;
752 GC_NOTRIGGER;
753 MODE_ANY;
754 } CONTRACTL_END;
755
756 BOOL result = FALSE;
757
758 JIT_TO_EE_TRANSITION_LEAF();
759
760 if (IsDynamicScope(module))
761 {
762 // No explicit token validation for dynamic code. Validation is
763 // side-effect of token resolution.
764 result = TRUE;
765 }
766 else
767 {
768 result = ((Module *)module)->GetMDImport()->IsValidToken(metaTOK);
769 }
770
771 EE_TO_JIT_TRANSITION_LEAF();
772
773 return result;
774}
775
776/*********************************************************************/
777// Checks if the given metadata token is valid StringRef
778BOOL CEEInfo::isValidStringRef (
779 CORINFO_MODULE_HANDLE module,
780 mdToken metaTOK)
781{
782 CONTRACTL {
783 SO_TOLERANT;
784 THROWS;
785 GC_TRIGGERS;
786 MODE_PREEMPTIVE;
787 } CONTRACTL_END;
788
789 BOOL result = FALSE;
790
791 JIT_TO_EE_TRANSITION();
792
793 if (IsDynamicScope(module))
794 {
795 result = GetDynamicResolver(module)->IsValidStringRef(metaTOK);
796 }
797 else
798 {
799 result = ((Module *)module)->CheckStringRef(metaTOK);
800 if (result)
801 {
802 DWORD dwCharCount;
803 LPCWSTR pString;
804 result = (!FAILED(((Module *)module)->GetMDImport()->GetUserString(metaTOK, &dwCharCount, NULL, &pString)) &&
805 pString != NULL);
806 }
807 }
808
809 EE_TO_JIT_TRANSITION();
810
811 return result;
812}
813
814/* static */
815size_t CEEInfo::findNameOfToken (Module* module,
816 mdToken metaTOK,
817 __out_ecount (FQNameCapacity) char * szFQName,
818 size_t FQNameCapacity)
819{
820 CONTRACTL {
821 NOTHROW;
822 GC_TRIGGERS;
823 } CONTRACTL_END;
824
825#ifdef _DEBUG
826 PCCOR_SIGNATURE sig = NULL;
827 DWORD cSig;
828 LPCUTF8 pszNamespace = NULL;
829 LPCUTF8 pszClassName = NULL;
830
831 mdToken tokType = TypeFromToken(metaTOK);
832 switch(tokType)
833 {
834 case mdtTypeRef:
835 {
836 if (FAILED(module->GetMDImport()->GetNameOfTypeRef(metaTOK, &pszNamespace, &pszClassName)))
837 {
838 pszNamespace = pszClassName = "Invalid TypeRef record";
839 }
840 ns::MakePath(szFQName, (int)FQNameCapacity, pszNamespace, pszClassName);
841 break;
842 }
843 case mdtTypeDef:
844 {
845 if (FAILED(module->GetMDImport()->GetNameOfTypeDef(metaTOK, &pszClassName, &pszNamespace)))
846 {
847 pszClassName = pszNamespace = "Invalid TypeDef record";
848 }
849 ns::MakePath(szFQName, (int)FQNameCapacity, pszNamespace, pszClassName);
850 break;
851 }
852 case mdtFieldDef:
853 {
854 LPCSTR szFieldName;
855 if (FAILED(module->GetMDImport()->GetNameOfFieldDef(metaTOK, &szFieldName)))
856 {
857 szFieldName = "Invalid FieldDef record";
858 }
859 strncpy_s(szFQName, FQNameCapacity, (char*)szFieldName, FQNameCapacity - 1);
860 break;
861 }
862 case mdtMethodDef:
863 {
864 LPCSTR szMethodName;
865 if (FAILED(module->GetMDImport()->GetNameOfMethodDef(metaTOK, &szMethodName)))
866 {
867 szMethodName = "Invalid MethodDef record";
868 }
869 strncpy_s(szFQName, FQNameCapacity, (char*)szMethodName, FQNameCapacity - 1);
870 break;
871 }
872 case mdtMemberRef:
873 {
874 LPCSTR szName;
875 if (FAILED(module->GetMDImport()->GetNameAndSigOfMemberRef((mdMemberRef)metaTOK, &sig, &cSig, &szName)))
876 {
877 szName = "Invalid MemberRef record";
878 }
879 strncpy_s(szFQName, FQNameCapacity, (char *)szName, FQNameCapacity - 1);
880 break;
881 }
882 default:
883 sprintf_s(szFQName, FQNameCapacity, "!TK_%x", metaTOK);
884 break;
885 }
886
887#else // !_DEBUG
888 strncpy_s (szFQName, FQNameCapacity, "<UNKNOWN>", FQNameCapacity - 1);
889#endif // _DEBUG
890
891
892 return strlen (szFQName);
893}
894
895CorInfoHelpFunc CEEInfo::getLazyStringLiteralHelper(CORINFO_MODULE_HANDLE handle)
896{
897 CONTRACTL {
898 SO_TOLERANT;
899 NOTHROW;
900 GC_NOTRIGGER;
901 MODE_PREEMPTIVE;
902 } CONTRACTL_END;
903
904 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
905
906 JIT_TO_EE_TRANSITION_LEAF();
907
908 result = IsDynamicScope(handle) ? CORINFO_HELP_UNDEF : CORINFO_HELP_STRCNS;
909
910 EE_TO_JIT_TRANSITION_LEAF();
911
912 return result;
913}
914
915
916CHECK CheckContext(CORINFO_MODULE_HANDLE scopeHnd, CORINFO_CONTEXT_HANDLE context)
917{
918 CHECK_MSG(scopeHnd != NULL, "Illegal null scope");
919 CHECK_MSG(((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK) != NULL, "Illegal null context");
920 if (((size_t) context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
921 {
922 TypeHandle handle((CORINFO_CLASS_HANDLE) ((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK));
923 CHECK_MSG(handle.GetModule() == GetModule(scopeHnd), "Inconsistent scope and context");
924 }
925 else
926 {
927 MethodDesc* handle = (MethodDesc*) ((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK);
928 CHECK_MSG(handle->GetModule() == GetModule(scopeHnd), "Inconsistent scope and context");
929 }
930
931 CHECK_OK;
932}
933
934
935static DECLSPEC_NORETURN void ThrowBadTokenException(CORINFO_RESOLVED_TOKEN * pResolvedToken)
936{
937 switch (pResolvedToken->tokenType & CORINFO_TOKENKIND_Mask)
938 {
939 case CORINFO_TOKENKIND_Class:
940 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_CLASS_TOKEN);
941 case CORINFO_TOKENKIND_Method:
942 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_METHOD_TOKEN);
943 case CORINFO_TOKENKIND_Field:
944 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_FIELD_TOKEN);
945 default:
946 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
947 }
948}
949
950/*********************************************************************/
951void CEEInfo::resolveToken(/* IN, OUT */ CORINFO_RESOLVED_TOKEN * pResolvedToken)
952{
953 CONTRACTL {
954 SO_TOLERANT;
955 THROWS;
956 GC_TRIGGERS;
957 MODE_PREEMPTIVE;
958 } CONTRACTL_END;
959
960 JIT_TO_EE_TRANSITION();
961
962 _ASSERTE(CheckContext(pResolvedToken->tokenScope, pResolvedToken->tokenContext));
963
964 pResolvedToken->pTypeSpec = NULL;
965 pResolvedToken->cbTypeSpec = NULL;
966 pResolvedToken->pMethodSpec = NULL;
967 pResolvedToken->cbMethodSpec = NULL;
968
969 TypeHandle th;
970 MethodDesc * pMD = NULL;
971 FieldDesc * pFD = NULL;
972
973 CorInfoTokenKind tokenType = pResolvedToken->tokenType;
974
975 if (IsDynamicScope(pResolvedToken->tokenScope))
976 {
977 GetDynamicResolver(pResolvedToken->tokenScope)->ResolveToken(pResolvedToken->token, &th, &pMD, &pFD);
978
979 //
980 // Check that we got the expected handles and fill in missing data if necessary
981 //
982
983 CorTokenType tkType = (CorTokenType)TypeFromToken(pResolvedToken->token);
984
985 if (pMD != NULL)
986 {
987 if ((tkType != mdtMethodDef) && (tkType != mdtMemberRef))
988 ThrowBadTokenException(pResolvedToken);
989 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
990 ThrowBadTokenException(pResolvedToken);
991 if (th.IsNull())
992 th = pMD->GetMethodTable();
993
994 // "PermitUninstDefOrRef" check
995 if ((tokenType != CORINFO_TOKENKIND_Ldtoken) && pMD->ContainsGenericVariables())
996 {
997 COMPlusThrow(kInvalidProgramException);
998 }
999
1000 // if this is a BoxedEntryPointStub get the UnboxedEntryPoint one
1001 if (pMD->IsUnboxingStub())
1002 {
1003 pMD = pMD->GetMethodTable()->GetUnboxedEntryPointMD(pMD);
1004 }
1005
1006 // Activate target if required
1007 if (tokenType != CORINFO_TOKENKIND_Ldtoken)
1008 {
1009 ScanTokenForDynamicScope(pResolvedToken, th, pMD);
1010 }
1011 }
1012 else
1013 if (pFD != NULL)
1014 {
1015 if ((tkType != mdtFieldDef) && (tkType != mdtMemberRef))
1016 ThrowBadTokenException(pResolvedToken);
1017 if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1018 ThrowBadTokenException(pResolvedToken);
1019 if (th.IsNull())
1020 th = pFD->GetApproxEnclosingMethodTable();
1021
1022 if (pFD->IsStatic() && (tokenType != CORINFO_TOKENKIND_Ldtoken))
1023 {
1024 ScanTokenForDynamicScope(pResolvedToken, th);
1025 }
1026 }
1027 else
1028 {
1029 if ((tkType != mdtTypeDef) && (tkType != mdtTypeRef))
1030 ThrowBadTokenException(pResolvedToken);
1031 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1032 ThrowBadTokenException(pResolvedToken);
1033 if (th.IsNull())
1034 ThrowBadTokenException(pResolvedToken);
1035
1036 if (tokenType == CORINFO_TOKENKIND_Box || tokenType == CORINFO_TOKENKIND_Constrained)
1037 {
1038 ScanTokenForDynamicScope(pResolvedToken, th);
1039 }
1040 }
1041
1042 _ASSERTE((pMD == NULL) || (pFD == NULL));
1043 _ASSERTE(!th.IsNull());
1044
1045 // "PermitUninstDefOrRef" check
1046 if ((tokenType != CORINFO_TOKENKIND_Ldtoken) && th.ContainsGenericVariables())
1047 {
1048 COMPlusThrow(kInvalidProgramException);
1049 }
1050
1051 // The JIT always wants to see normalized typedescs for arrays
1052 if (!th.IsTypeDesc() && th.AsMethodTable()->IsArray())
1053 {
1054 MethodTable * pMT = th.AsMethodTable();
1055
1056 // Load the TypeDesc for the array type.
1057 DWORD rank = pMT->GetRank();
1058 TypeHandle elemType = pMT->GetApproxArrayElementTypeHandle();
1059 th = ClassLoader::LoadArrayTypeThrowing(elemType, pMT->GetInternalCorElementType(), rank);
1060 }
1061 }
1062 else
1063 {
1064 unsigned metaTOK = pResolvedToken->token;
1065 Module * pModule = (Module *)pResolvedToken->tokenScope;
1066
1067 switch (TypeFromToken(metaTOK))
1068 {
1069 case mdtModuleRef:
1070 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1071 ThrowBadTokenException(pResolvedToken);
1072
1073 {
1074 DomainFile *pTargetModule = pModule->LoadModule(GetAppDomain(), metaTOK, FALSE /* loadResources */);
1075 if (pTargetModule == NULL)
1076 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
1077 th = TypeHandle(pTargetModule->GetModule()->GetGlobalMethodTable());
1078 if (th.IsNull())
1079 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
1080 }
1081 break;
1082
1083 case mdtTypeDef:
1084 case mdtTypeRef:
1085 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1086 ThrowBadTokenException(pResolvedToken);
1087
1088 th = ClassLoader::LoadTypeDefOrRefThrowing(pModule, metaTOK,
1089 ClassLoader::ThrowIfNotFound,
1090 (tokenType == CORINFO_TOKENKIND_Ldtoken) ?
1091 ClassLoader::PermitUninstDefOrRef : ClassLoader::FailIfUninstDefOrRef);
1092 break;
1093
1094 case mdtTypeSpec:
1095 {
1096 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1097 ThrowBadTokenException(pResolvedToken);
1098
1099 IfFailThrow(pModule->GetMDImport()->GetTypeSpecFromToken(metaTOK, &pResolvedToken->pTypeSpec, &pResolvedToken->cbTypeSpec));
1100
1101 SigTypeContext typeContext;
1102 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1103
1104 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
1105 th = sigptr.GetTypeHandleThrowing(pModule, &typeContext);
1106 }
1107 break;
1108
1109 case mdtMethodDef:
1110 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1111 ThrowBadTokenException(pResolvedToken);
1112
1113 pMD = MemberLoader::GetMethodDescFromMethodDef(pModule, metaTOK, (tokenType != CORINFO_TOKENKIND_Ldtoken));
1114
1115 th = pMD->GetMethodTable();
1116 break;
1117
1118 case mdtFieldDef:
1119 if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1120 ThrowBadTokenException(pResolvedToken);
1121
1122 pFD = MemberLoader::GetFieldDescFromFieldDef(pModule, metaTOK, (tokenType != CORINFO_TOKENKIND_Ldtoken));
1123
1124 th = pFD->GetEnclosingMethodTable();
1125 break;
1126
1127 case mdtMemberRef:
1128 {
1129 SigTypeContext typeContext;
1130 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1131
1132 MemberLoader::GetDescFromMemberRef(pModule, metaTOK, &pMD, &pFD, &typeContext, (tokenType != CORINFO_TOKENKIND_Ldtoken),
1133 &th, TRUE, &pResolvedToken->pTypeSpec, &pResolvedToken->cbTypeSpec);
1134
1135 _ASSERTE((pMD != NULL) ^ (pFD != NULL));
1136 _ASSERTE(!th.IsNull());
1137
1138 if (pMD != NULL)
1139 {
1140 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1141 ThrowBadTokenException(pResolvedToken);
1142 }
1143 else
1144 {
1145 if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1146 ThrowBadTokenException(pResolvedToken);
1147 }
1148 }
1149 break;
1150
1151 case mdtMethodSpec:
1152 {
1153 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1154 ThrowBadTokenException(pResolvedToken);
1155
1156 SigTypeContext typeContext;
1157 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1158
1159 // We need the method desc to carry exact instantiation, thus allowInstParam == FALSE.
1160 pMD = MemberLoader::GetMethodDescFromMethodSpec(pModule, metaTOK, &typeContext, (tokenType != CORINFO_TOKENKIND_Ldtoken), FALSE /* allowInstParam */,
1161 &th, TRUE, &pResolvedToken->pTypeSpec, &pResolvedToken->cbTypeSpec, &pResolvedToken->pMethodSpec, &pResolvedToken->cbMethodSpec);
1162 }
1163 break;
1164
1165 default:
1166 ThrowBadTokenException(pResolvedToken);
1167 }
1168
1169 //
1170 // Module dependency tracking
1171 //
1172 if (pMD != NULL)
1173 {
1174 ScanToken(pModule, pResolvedToken, th, pMD);
1175 }
1176 else
1177 if (pFD != NULL)
1178 {
1179 if (pFD->IsStatic())
1180 ScanToken(pModule, pResolvedToken, th);
1181 }
1182 else
1183 {
1184 // It should not be required to trigger the modules cctors for ldtoken, it is done for backward compatibility only.
1185 if (tokenType == CORINFO_TOKENKIND_Box || tokenType == CORINFO_TOKENKIND_Constrained || tokenType == CORINFO_TOKENKIND_Ldtoken)
1186 ScanToken(pModule, pResolvedToken, th);
1187 }
1188 }
1189
1190 //
1191 // tokenType specific verification and transformations
1192 //
1193 CorElementType et = th.GetInternalCorElementType();
1194 switch (tokenType)
1195 {
1196 case CORINFO_TOKENKIND_Ldtoken:
1197 // Allow everything.
1198 break;
1199
1200 case CORINFO_TOKENKIND_Newarr:
1201 // Disallow ELEMENT_TYPE_BYREF and ELEMENT_TYPE_VOID
1202 if (et == ELEMENT_TYPE_BYREF || et == ELEMENT_TYPE_VOID)
1203 COMPlusThrow(kInvalidProgramException);
1204
1205 th = ClassLoader::LoadArrayTypeThrowing(th);
1206 break;
1207
1208 default:
1209 // Disallow ELEMENT_TYPE_BYREF and ELEMENT_TYPE_VOID
1210 if (et == ELEMENT_TYPE_BYREF || et == ELEMENT_TYPE_VOID)
1211 COMPlusThrow(kInvalidProgramException);
1212 break;
1213 }
1214
1215 // The JIT interface should always return fully loaded types
1216 _ASSERTE(th.IsFullyLoaded());
1217
1218 pResolvedToken->hClass = CORINFO_CLASS_HANDLE(th.AsPtr());
1219 pResolvedToken->hMethod = CORINFO_METHOD_HANDLE(pMD);
1220 pResolvedToken->hField = CORINFO_FIELD_HANDLE(pFD);
1221
1222 EE_TO_JIT_TRANSITION();
1223}
1224
1225/*********************************************************************/
1226struct TryResolveTokenFilterParam
1227{
1228 CEEInfo* m_this;
1229 CORINFO_RESOLVED_TOKEN* m_resolvedToken;
1230 EXCEPTION_POINTERS m_exceptionPointers;
1231 bool m_success;
1232};
1233
1234bool isValidTokenForTryResolveToken(CEEInfo* info, CORINFO_RESOLVED_TOKEN* resolvedToken)
1235{
1236 CONTRACTL {
1237 NOTHROW;
1238 GC_NOTRIGGER;
1239 SO_TOLERANT;
1240 MODE_ANY;
1241 } CONTRACTL_END;
1242
1243 if (!info->isValidToken(resolvedToken->tokenScope, resolvedToken->token))
1244 {
1245 return false;
1246 }
1247
1248 CorInfoTokenKind tokenType = resolvedToken->tokenType;
1249 switch (TypeFromToken(resolvedToken->token))
1250 {
1251 case mdtModuleRef:
1252 case mdtTypeDef:
1253 case mdtTypeRef:
1254 case mdtTypeSpec:
1255 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1256 return false;
1257 break;
1258
1259 case mdtMethodDef:
1260 case mdtMethodSpec:
1261 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1262 return false;
1263 break;
1264
1265 case mdtFieldDef:
1266 if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1267 return false;
1268 break;
1269
1270 case mdtMemberRef:
1271 if ((tokenType & (CORINFO_TOKENKIND_Method | CORINFO_TOKENKIND_Field)) == 0)
1272 return false;
1273 break;
1274
1275 default:
1276 return false;
1277 }
1278
1279 return true;
1280}
1281
1282LONG EEFilterException(struct _EXCEPTION_POINTERS* exceptionPointers, void* unused);
1283
1284LONG TryResolveTokenFilter(struct _EXCEPTION_POINTERS* exceptionPointers, void* theParam)
1285{
1286 CONTRACTL {
1287 NOTHROW;
1288 GC_NOTRIGGER;
1289 SO_TOLERANT;
1290 MODE_ANY;
1291 } CONTRACTL_END;
1292
1293 // Backward compatibility: Convert bad image format exceptions thrown while resolving tokens
1294 // to simple true/false successes. This is done for backward compatibility only. Ideally,
1295 // we would always treat bad tokens in the IL stream as fatal errors.
1296 if (exceptionPointers->ExceptionRecord->ExceptionCode == EXCEPTION_COMPLUS)
1297 {
1298 auto* param = reinterpret_cast<TryResolveTokenFilterParam*>(theParam);
1299 if (!isValidTokenForTryResolveToken(param->m_this, param->m_resolvedToken))
1300 {
1301 param->m_exceptionPointers = *exceptionPointers;
1302 return EEFilterException(exceptionPointers, nullptr);
1303 }
1304 }
1305
1306 return EXCEPTION_CONTINUE_SEARCH;
1307}
1308
1309bool CEEInfo::tryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken)
1310{
1311 // No dynamic contract here because SEH is used
1312 STATIC_CONTRACT_SO_TOLERANT;
1313 STATIC_CONTRACT_THROWS;
1314 STATIC_CONTRACT_GC_TRIGGERS;
1315 STATIC_CONTRACT_MODE_PREEMPTIVE;
1316
1317 TryResolveTokenFilterParam param;
1318 param.m_this = this;
1319 param.m_resolvedToken = resolvedToken;
1320 param.m_success = true;
1321
1322 PAL_TRY(TryResolveTokenFilterParam*, pParam, &param)
1323 {
1324 pParam->m_this->resolveToken(pParam->m_resolvedToken);
1325 }
1326 PAL_EXCEPT_FILTER(TryResolveTokenFilter)
1327 {
1328 if (param.m_exceptionPointers.ExceptionRecord->ExceptionCode == EXCEPTION_COMPLUS)
1329 {
1330 HandleException(&param.m_exceptionPointers);
1331 }
1332
1333 param.m_success = false;
1334 }
1335 PAL_ENDTRY
1336
1337 return param.m_success;
1338}
1339
1340/*********************************************************************/
1341// We have a few frequently used constants in mscorlib that are defined as
1342// readonly static fields for historic reasons. Check for them here and
1343// allow them to be treated as actual constants by the JIT.
1344static CORINFO_FIELD_ACCESSOR getFieldIntrinsic(FieldDesc * field)
1345{
1346 STANDARD_VM_CONTRACT;
1347
1348 if (MscorlibBinder::GetField(FIELD__STRING__EMPTY) == field)
1349 {
1350 return CORINFO_FIELD_INTRINSIC_EMPTY_STRING;
1351 }
1352 else
1353 if ((MscorlibBinder::GetField(FIELD__INTPTR__ZERO) == field) ||
1354 (MscorlibBinder::GetField(FIELD__UINTPTR__ZERO) == field))
1355 {
1356 return CORINFO_FIELD_INTRINSIC_ZERO;
1357 }
1358 else
1359 if (MscorlibBinder::GetField(FIELD__BITCONVERTER__ISLITTLEENDIAN) == field)
1360 {
1361 return CORINFO_FIELD_INTRINSIC_ISLITTLEENDIAN;
1362 }
1363
1364 return (CORINFO_FIELD_ACCESSOR)-1;
1365}
1366
1367static CorInfoHelpFunc getGenericStaticsHelper(FieldDesc * pField)
1368{
1369 STANDARD_VM_CONTRACT;
1370
1371 int helper = CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE;
1372
1373 if (pField->GetFieldType() == ELEMENT_TYPE_CLASS ||
1374 pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1375 {
1376 helper = CORINFO_HELP_GETGENERICS_GCSTATIC_BASE;
1377 }
1378
1379 if (pField->IsThreadStatic())
1380 {
1381 const int delta = CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE;
1382
1383 static_assert_no_msg(CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE
1384 == CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE + delta);
1385
1386 helper += (CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE);
1387 }
1388
1389 return (CorInfoHelpFunc)helper;
1390}
1391
1392CorInfoHelpFunc CEEInfo::getSharedStaticsHelper(FieldDesc * pField, MethodTable * pFieldMT)
1393{
1394 STANDARD_VM_CONTRACT;
1395
1396 int helper = CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE;
1397
1398 if (pField->GetFieldType() == ELEMENT_TYPE_CLASS ||
1399 pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1400 {
1401 helper = CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1402 }
1403
1404 if (pFieldMT->IsDynamicStatics())
1405 {
1406 const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1407
1408 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS
1409 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1410
1411 helper += delta;
1412 }
1413 else
1414 if (!pFieldMT->HasClassConstructor() && !pFieldMT->HasBoxedRegularStatics())
1415 {
1416 const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1417
1418 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR
1419 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1420
1421 helper += delta;
1422 }
1423
1424 if (pField->IsThreadStatic())
1425 {
1426 const int delta = CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1427
1428 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE
1429 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1430 static_assert_no_msg(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR
1431 == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR + delta);
1432 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR
1433 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR + delta);
1434 static_assert_no_msg(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS
1435 == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS + delta);
1436 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS
1437 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS + delta);
1438
1439 helper += delta;
1440 }
1441
1442 return (CorInfoHelpFunc)helper;
1443}
1444
1445static CorInfoHelpFunc getInstanceFieldHelper(FieldDesc * pField, CORINFO_ACCESS_FLAGS flags)
1446{
1447 STANDARD_VM_CONTRACT;
1448
1449 int helper;
1450
1451 CorElementType type = pField->GetFieldType();
1452
1453 if (CorTypeInfo::IsObjRef(type))
1454 helper = CORINFO_HELP_GETFIELDOBJ;
1455 else
1456 switch (type)
1457 {
1458 case ELEMENT_TYPE_VALUETYPE:
1459 helper = CORINFO_HELP_GETFIELDSTRUCT;
1460 break;
1461 case ELEMENT_TYPE_I1:
1462 case ELEMENT_TYPE_BOOLEAN:
1463 case ELEMENT_TYPE_U1:
1464 helper = CORINFO_HELP_GETFIELD8;
1465 break;
1466 case ELEMENT_TYPE_I2:
1467 case ELEMENT_TYPE_CHAR:
1468 case ELEMENT_TYPE_U2:
1469 helper = CORINFO_HELP_GETFIELD16;
1470 break;
1471 case ELEMENT_TYPE_I4:
1472 case ELEMENT_TYPE_U4:
1473 IN_TARGET_32BIT(default:)
1474 helper = CORINFO_HELP_GETFIELD32;
1475 break;
1476 case ELEMENT_TYPE_I8:
1477 case ELEMENT_TYPE_U8:
1478 IN_TARGET_64BIT(default:)
1479 helper = CORINFO_HELP_GETFIELD64;
1480 break;
1481 case ELEMENT_TYPE_R4:
1482 helper = CORINFO_HELP_GETFIELDFLOAT;
1483 break;
1484 case ELEMENT_TYPE_R8:
1485 helper = CORINFO_HELP_GETFIELDDOUBLE;
1486 break;
1487 }
1488
1489 if (flags & CORINFO_ACCESS_SET)
1490 {
1491 const int delta = CORINFO_HELP_SETFIELDOBJ - CORINFO_HELP_GETFIELDOBJ;
1492
1493 static_assert_no_msg(CORINFO_HELP_SETFIELD8 == CORINFO_HELP_GETFIELD8 + delta);
1494 static_assert_no_msg(CORINFO_HELP_SETFIELD16 == CORINFO_HELP_GETFIELD16 + delta);
1495 static_assert_no_msg(CORINFO_HELP_SETFIELD32 == CORINFO_HELP_GETFIELD32 + delta);
1496 static_assert_no_msg(CORINFO_HELP_SETFIELD64 == CORINFO_HELP_GETFIELD64 + delta);
1497 static_assert_no_msg(CORINFO_HELP_SETFIELDSTRUCT == CORINFO_HELP_GETFIELDSTRUCT + delta);
1498 static_assert_no_msg(CORINFO_HELP_SETFIELDFLOAT == CORINFO_HELP_GETFIELDFLOAT + delta);
1499 static_assert_no_msg(CORINFO_HELP_SETFIELDDOUBLE == CORINFO_HELP_GETFIELDDOUBLE + delta);
1500
1501 helper += delta;
1502 }
1503
1504 return (CorInfoHelpFunc)helper;
1505}
1506
1507/*********************************************************************/
1508void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken,
1509 CORINFO_METHOD_HANDLE callerHandle,
1510 CORINFO_ACCESS_FLAGS flags,
1511 CORINFO_FIELD_INFO *pResult
1512 )
1513{
1514 CONTRACTL {
1515 SO_TOLERANT;
1516 THROWS;
1517 GC_TRIGGERS;
1518 MODE_PREEMPTIVE;
1519 } CONTRACTL_END;
1520
1521 JIT_TO_EE_TRANSITION();
1522
1523 _ASSERTE((flags & (CORINFO_ACCESS_GET | CORINFO_ACCESS_SET | CORINFO_ACCESS_ADDRESS | CORINFO_ACCESS_INIT_ARRAY)) != 0);
1524
1525 INDEBUG(memset(pResult, 0xCC, sizeof(*pResult)));
1526
1527 FieldDesc * pField = (FieldDesc*)pResolvedToken->hField;
1528 MethodTable * pFieldMT = pField->GetApproxEnclosingMethodTable();
1529
1530 // Helper to use if the field access requires it
1531 CORINFO_FIELD_ACCESSOR fieldAccessor = (CORINFO_FIELD_ACCESSOR)-1;
1532 DWORD fieldFlags = 0;
1533
1534 pResult->offset = pField->GetOffset();
1535 if (pField->IsStatic())
1536 {
1537 fieldFlags |= CORINFO_FLG_FIELD_STATIC;
1538
1539 if (pField->IsRVA())
1540 {
1541 fieldFlags |= CORINFO_FLG_FIELD_UNMANAGED;
1542
1543 Module* module = pFieldMT->GetModule();
1544 if (module->IsRvaFieldTls(pResult->offset))
1545 {
1546 fieldAccessor = CORINFO_FIELD_STATIC_TLS;
1547
1548 // Provide helper to use if the JIT is not able to emit the TLS access
1549 // as intrinsic
1550 pResult->helper = CORINFO_HELP_GETSTATICFIELDADDR_TLS;
1551
1552 pResult->offset = module->GetFieldTlsOffset(pResult->offset);
1553 }
1554 else
1555 {
1556 fieldAccessor = CORINFO_FIELD_STATIC_RVA_ADDRESS;
1557 }
1558
1559 // We are not going through a helper. The constructor has to be triggered explicitly.
1560 if (!pFieldMT->IsClassPreInited())
1561 fieldFlags |= CORINFO_FLG_FIELD_INITCLASS;
1562 }
1563 else
1564 {
1565 // Regular or thread static
1566 CORINFO_FIELD_ACCESSOR intrinsicAccessor;
1567
1568 if (pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1569 fieldFlags |= CORINFO_FLG_FIELD_STATIC_IN_HEAP;
1570
1571 if (pFieldMT->IsSharedByGenericInstantiations())
1572 {
1573 fieldAccessor = CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER;
1574
1575 pResult->helper = getGenericStaticsHelper(pField);
1576 }
1577 else
1578 if (pFieldMT->GetModule()->IsSystem() && (flags & CORINFO_ACCESS_GET) &&
1579 (intrinsicAccessor = getFieldIntrinsic(pField)) != (CORINFO_FIELD_ACCESSOR)-1)
1580 {
1581 // Intrinsics
1582 fieldAccessor = intrinsicAccessor;
1583 }
1584 else
1585 if (m_pMethodBeingCompiled->IsZapped() || IsCompilingForNGen() ||
1586 // Static fields are not pinned in collectible types. We will always access
1587 // them using a helper since the address cannot be embeded into the code.
1588 pFieldMT->Collectible() ||
1589 // We always treat accessing thread statics as if we are in domain neutral code.
1590 pField->IsThreadStatic()
1591 )
1592 {
1593 fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER;
1594
1595 pResult->helper = getSharedStaticsHelper(pField, pFieldMT);
1596 }
1597 else
1598 {
1599 fieldAccessor = CORINFO_FIELD_STATIC_ADDRESS;
1600
1601 // We are not going through a helper. The constructor has to be triggered explicitly.
1602 if (!pFieldMT->IsClassPreInited())
1603 fieldFlags |= CORINFO_FLG_FIELD_INITCLASS;
1604 }
1605 }
1606
1607 //
1608 // Currently, we only this optimization for regular statics, but it
1609 // looks like it may be permissible to do this optimization for
1610 // thread statics as well.
1611 //
1612 if ((flags & CORINFO_ACCESS_ADDRESS) &&
1613 !pField->IsThreadStatic() &&
1614 (fieldAccessor != CORINFO_FIELD_STATIC_TLS))
1615 {
1616 fieldFlags |= CORINFO_FLG_FIELD_SAFESTATIC_BYREF_RETURN;
1617 }
1618 }
1619 else
1620 {
1621 BOOL fInstanceHelper = FALSE;
1622
1623 if (fInstanceHelper)
1624 {
1625 if (flags & CORINFO_ACCESS_ADDRESS)
1626 {
1627 fieldAccessor = CORINFO_FIELD_INSTANCE_ADDR_HELPER;
1628
1629 pResult->helper = CORINFO_HELP_GETFIELDADDR;
1630 }
1631 else
1632 {
1633 fieldAccessor = CORINFO_FIELD_INSTANCE_HELPER;
1634
1635 pResult->helper = getInstanceFieldHelper(pField, flags);
1636 }
1637 }
1638 else
1639 if (pField->IsEnCNew())
1640 {
1641 fieldAccessor = CORINFO_FIELD_INSTANCE_ADDR_HELPER;
1642
1643 pResult->helper = CORINFO_HELP_GETFIELDADDR;
1644 }
1645 else
1646 {
1647 fieldAccessor = CORINFO_FIELD_INSTANCE;
1648 }
1649
1650 // FieldDesc::GetOffset() does not include the size of Object
1651 if (!pFieldMT->IsValueType())
1652 {
1653 pResult->offset += OBJECT_SIZE;
1654 }
1655 }
1656
1657 // TODO: This is touching metadata. Can we avoid it?
1658 DWORD fieldAttribs = pField->GetAttributes();
1659
1660 if (IsFdFamily(fieldAttribs))
1661 fieldFlags |= CORINFO_FLG_FIELD_PROTECTED;
1662
1663 if (IsFdInitOnly(fieldAttribs))
1664 fieldFlags |= CORINFO_FLG_FIELD_FINAL;
1665
1666 pResult->fieldAccessor = fieldAccessor;
1667 pResult->fieldFlags = fieldFlags;
1668
1669 if (!(flags & CORINFO_ACCESS_INLINECHECK))
1670 {
1671 //get the field's type. Grab the class for structs.
1672 pResult->fieldType = getFieldTypeInternal(pResolvedToken->hField, &pResult->structType, pResolvedToken->hClass);
1673
1674
1675 MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle);
1676
1677 //
1678 //Since we can't get the special verify-only instantiated FD like we can with MDs, go back to the parent
1679 //of the memberRef and load that one. That should give us the open instantiation.
1680 //
1681 //If the field we found is owned by a generic type, you have to go back to the signature and reload.
1682 //Otherwise we filled in !0.
1683 TypeHandle fieldTypeForSecurity = TypeHandle(pResolvedToken->hClass);
1684 if (pResolvedToken->pTypeSpec != NULL)
1685 {
1686 SigTypeContext typeContext;
1687 SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
1688
1689 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
1690 fieldTypeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
1691
1692 // typeHnd can be a variable type
1693 if (fieldTypeForSecurity.GetMethodTable() == NULL)
1694 {
1695 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_METHODDEF_PARENT_NO_MEMBERS);
1696 }
1697 }
1698
1699 BOOL doAccessCheck = TRUE;
1700 AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
1701
1702 DynamicResolver * pAccessContext = NULL;
1703
1704 //More in code:CEEInfo::getCallInfo, but the short version is that the caller and callee Descs do
1705 //not completely describe the type.
1706 TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
1707 if (IsDynamicScope(pResolvedToken->tokenScope))
1708 {
1709 doAccessCheck = ModifyCheckForDynamicMethod(GetDynamicResolver(pResolvedToken->tokenScope), &callerTypeForSecurity,
1710 &accessCheckType, &pAccessContext);
1711 }
1712
1713 //Now for some link time checks.
1714 //Um... where are the field link demands?
1715
1716 pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
1717
1718 if (doAccessCheck)
1719 {
1720 //Well, let's check some visibility at least.
1721 AccessCheckOptions accessCheckOptions(accessCheckType,
1722 pAccessContext,
1723 FALSE,
1724 pField);
1725
1726 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
1727 StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
1728
1729 BOOL canAccess = ClassLoader::CanAccess(
1730 &accessContext,
1731 fieldTypeForSecurity.GetMethodTable(),
1732 fieldTypeForSecurity.GetAssembly(),
1733 fieldAttribs,
1734 NULL,
1735 (flags & CORINFO_ACCESS_INIT_ARRAY) ? NULL : pField, // For InitializeArray, we don't need tocheck the type of the field.
1736 accessCheckOptions);
1737
1738 if (!canAccess)
1739 {
1740 //Set up the throw helper
1741 pResult->accessAllowed = CORINFO_ACCESS_ILLEGAL;
1742
1743 pResult->accessCalloutHelper.helperNum = CORINFO_HELP_FIELD_ACCESS_EXCEPTION;
1744 pResult->accessCalloutHelper.numArgs = 2;
1745
1746 pResult->accessCalloutHelper.args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
1747 pResult->accessCalloutHelper.args[1].Set(CORINFO_FIELD_HANDLE(pField));
1748
1749 if (IsCompilingForNGen())
1750 {
1751 //see code:CEEInfo::getCallInfo for more information.
1752 if (pCallerForSecurity->ContainsGenericVariables())
1753 COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic MethodDesc"));
1754 }
1755 }
1756 }
1757 }
1758
1759 EE_TO_JIT_TRANSITION();
1760}
1761
1762//---------------------------------------------------------------------------------------
1763//
1764bool CEEInfo::isFieldStatic(CORINFO_FIELD_HANDLE fldHnd)
1765{
1766 CONTRACTL {
1767 SO_TOLERANT;
1768 THROWS;
1769 GC_TRIGGERS;
1770 MODE_PREEMPTIVE;
1771 } CONTRACTL_END;
1772
1773 bool res = false;
1774 JIT_TO_EE_TRANSITION_LEAF();
1775 FieldDesc* field = (FieldDesc*)fldHnd;
1776 res = (field->IsStatic() != 0);
1777 EE_TO_JIT_TRANSITION_LEAF();
1778 return res;
1779}
1780
1781//---------------------------------------------------------------------------------------
1782//
1783void
1784CEEInfo::findCallSiteSig(
1785 CORINFO_MODULE_HANDLE scopeHnd,
1786 unsigned sigMethTok,
1787 CORINFO_CONTEXT_HANDLE context,
1788 CORINFO_SIG_INFO * sigRet)
1789{
1790 CONTRACTL {
1791 SO_TOLERANT;
1792 THROWS;
1793 GC_TRIGGERS;
1794 MODE_PREEMPTIVE;
1795 } CONTRACTL_END;
1796
1797 JIT_TO_EE_TRANSITION();
1798
1799 PCCOR_SIGNATURE pSig = NULL;
1800 DWORD cbSig = 0;
1801
1802 if (IsDynamicScope(scopeHnd))
1803 {
1804 DynamicResolver * pResolver = GetDynamicResolver(scopeHnd);
1805 SigPointer sig;
1806
1807 if (TypeFromToken(sigMethTok) == mdtMemberRef)
1808 {
1809 sig = pResolver->ResolveSignatureForVarArg(sigMethTok);
1810 }
1811 else
1812 {
1813 _ASSERTE(TypeFromToken(sigMethTok) == mdtMethodDef);
1814
1815 TypeHandle classHandle;
1816 MethodDesc * pMD = NULL;
1817 FieldDesc * pFD = NULL;
1818
1819 // in this case a method is asked for its sig. Resolve the method token and get the sig
1820 pResolver->ResolveToken(sigMethTok, &classHandle, &pMD, &pFD);
1821 if (pMD == NULL)
1822 COMPlusThrow(kInvalidProgramException);
1823
1824 PCCOR_SIGNATURE pSig = NULL;
1825 DWORD cbSig;
1826 pMD->GetSig(&pSig, &cbSig);
1827 sig = SigPointer(pSig, cbSig);
1828
1829 context = MAKE_METHODCONTEXT(pMD);
1830 scopeHnd = GetScopeHandle(pMD->GetModule());
1831 }
1832
1833 sig.GetSignature(&pSig, &cbSig);
1834 sigMethTok = mdTokenNil;
1835 }
1836 else
1837 {
1838 Module * module = (Module *)scopeHnd;
1839 LPCUTF8 szName;
1840
1841 if (TypeFromToken(sigMethTok) == mdtMemberRef)
1842 {
1843 IfFailThrow(module->GetMDImport()->GetNameAndSigOfMemberRef(sigMethTok, &pSig, &cbSig, &szName));
1844 }
1845 else if (TypeFromToken(sigMethTok) == mdtMethodDef)
1846 {
1847 IfFailThrow(module->GetMDImport()->GetSigOfMethodDef(sigMethTok, &cbSig, &pSig));
1848 }
1849 }
1850
1851 CEEInfo::ConvToJitSig(
1852 pSig,
1853 cbSig,
1854 scopeHnd,
1855 sigMethTok,
1856 sigRet,
1857 GetMethodFromContext(context),
1858 false,
1859 GetTypeFromContext(context));
1860 EE_TO_JIT_TRANSITION();
1861} // CEEInfo::findCallSiteSig
1862
1863//---------------------------------------------------------------------------------------
1864//
1865void
1866CEEInfo::findSig(
1867 CORINFO_MODULE_HANDLE scopeHnd,
1868 unsigned sigTok,
1869 CORINFO_CONTEXT_HANDLE context,
1870 CORINFO_SIG_INFO * sigRet)
1871{
1872 CONTRACTL {
1873 SO_TOLERANT;
1874 THROWS;
1875 GC_TRIGGERS;
1876 MODE_PREEMPTIVE;
1877 } CONTRACTL_END;
1878
1879 JIT_TO_EE_TRANSITION();
1880
1881 PCCOR_SIGNATURE pSig = NULL;
1882 DWORD cbSig = 0;
1883
1884 if (IsDynamicScope(scopeHnd))
1885 {
1886 SigPointer sig = GetDynamicResolver(scopeHnd)->ResolveSignature(sigTok);
1887 sig.GetSignature(&pSig, &cbSig);
1888 sigTok = mdTokenNil;
1889 }
1890 else
1891 {
1892 Module * module = (Module *)scopeHnd;
1893
1894 // We need to resolve this stand alone sig
1895 IfFailThrow(module->GetMDImport()->GetSigFromToken(
1896 (mdSignature)sigTok,
1897 &cbSig,
1898 &pSig));
1899 }
1900
1901 CEEInfo::ConvToJitSig(
1902 pSig,
1903 cbSig,
1904 scopeHnd,
1905 sigTok,
1906 sigRet,
1907 GetMethodFromContext(context),
1908 false,
1909 GetTypeFromContext(context));
1910
1911 EE_TO_JIT_TRANSITION();
1912} // CEEInfo::findSig
1913
1914//---------------------------------------------------------------------------------------
1915//
1916unsigned
1917CEEInfo::getClassSize(
1918 CORINFO_CLASS_HANDLE clsHnd)
1919{
1920 CONTRACTL {
1921 SO_TOLERANT;
1922 NOTHROW;
1923 GC_NOTRIGGER;
1924 MODE_PREEMPTIVE;
1925 } CONTRACTL_END;
1926
1927 unsigned result = 0;
1928
1929 JIT_TO_EE_TRANSITION_LEAF();
1930
1931 TypeHandle VMClsHnd(clsHnd);
1932 result = VMClsHnd.GetSize();
1933
1934 EE_TO_JIT_TRANSITION_LEAF();
1935
1936 return result;
1937}
1938
1939//---------------------------------------------------------------------------------------
1940//
1941// Get the size of a reference type as allocated on the heap. This includes the size of the fields
1942// (and any padding between the fields) and the size of a method table pointer but doesn't include
1943// object header size or any padding for minimum size.
1944unsigned
1945CEEInfo::getHeapClassSize(
1946 CORINFO_CLASS_HANDLE clsHnd)
1947{
1948 CONTRACTL{
1949 SO_TOLERANT;
1950 NOTHROW;
1951 GC_NOTRIGGER;
1952 MODE_PREEMPTIVE;
1953 } CONTRACTL_END;
1954
1955 unsigned result = 0;
1956
1957 JIT_TO_EE_TRANSITION_LEAF();
1958
1959 TypeHandle VMClsHnd(clsHnd);
1960 MethodTable* pMT = VMClsHnd.GetMethodTable();
1961 _ASSERTE(pMT);
1962 _ASSERTE(!pMT->IsValueType());
1963 _ASSERTE(!pMT->HasComponentSize());
1964#ifdef FEATURE_READYTORUN_COMPILER
1965 _ASSERTE(!IsReadyToRunCompilation() || pMT->IsInheritanceChainLayoutFixedInCurrentVersionBubble());
1966#endif
1967
1968 // Add OBJECT_SIZE to account for method table pointer.
1969 result = pMT->GetNumInstanceFieldBytes() + OBJECT_SIZE;
1970
1971 EE_TO_JIT_TRANSITION_LEAF();
1972 return result;
1973}
1974
1975//---------------------------------------------------------------------------------------
1976//
1977// Return TRUE if an object of this type can be allocated on the stack.
1978BOOL CEEInfo::canAllocateOnStack(CORINFO_CLASS_HANDLE clsHnd)
1979{
1980 CONTRACTL{
1981 SO_TOLERANT;
1982 NOTHROW;
1983 GC_NOTRIGGER;
1984 MODE_PREEMPTIVE;
1985 } CONTRACTL_END;
1986
1987 BOOL result = FALSE;
1988
1989 JIT_TO_EE_TRANSITION_LEAF();
1990
1991 TypeHandle VMClsHnd(clsHnd);
1992 MethodTable* pMT = VMClsHnd.GetMethodTable();
1993 _ASSERTE(pMT);
1994 _ASSERTE(!pMT->IsValueType());
1995
1996 result = !pMT->HasFinalizer();
1997
1998#ifdef FEATURE_READYTORUN_COMPILER
1999 if (IsReadyToRunCompilation() && !pMT->IsInheritanceChainLayoutFixedInCurrentVersionBubble())
2000 {
2001 result = false;
2002 }
2003#endif
2004
2005 EE_TO_JIT_TRANSITION_LEAF();
2006 return result;
2007}
2008
2009unsigned CEEInfo::getClassAlignmentRequirement(CORINFO_CLASS_HANDLE type, BOOL fDoubleAlignHint)
2010{
2011 CONTRACTL {
2012 SO_TOLERANT;
2013 NOTHROW;
2014 GC_NOTRIGGER;
2015 MODE_PREEMPTIVE;
2016 } CONTRACTL_END;
2017
2018 // Default alignment is sizeof(void*)
2019 unsigned result = TARGET_POINTER_SIZE;
2020
2021 JIT_TO_EE_TRANSITION_LEAF();
2022
2023 TypeHandle clsHnd(type);
2024
2025#ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
2026 if (fDoubleAlignHint)
2027 {
2028 MethodTable* pMT = clsHnd.GetMethodTable();
2029 if (pMT != NULL)
2030 {
2031 // Return the size of the double align hint. Ignore the actual alignment info account
2032 // so that structs with 64-bit integer fields do not trigger double aligned frames on x86.
2033 if (pMT->GetClass()->IsAlign8Candidate())
2034 result = 8;
2035 }
2036 }
2037 else
2038#endif
2039 {
2040 result = getClassAlignmentRequirementStatic(clsHnd);
2041 }
2042
2043 EE_TO_JIT_TRANSITION_LEAF();
2044
2045 return result;
2046}
2047
2048unsigned CEEInfo::getClassAlignmentRequirementStatic(TypeHandle clsHnd)
2049{
2050 LIMITED_METHOD_CONTRACT;
2051
2052 // Default alignment is sizeof(void*)
2053 unsigned result = TARGET_POINTER_SIZE;
2054
2055 MethodTable * pMT = clsHnd.GetMethodTable();
2056 if (pMT == NULL)
2057 return result;
2058
2059 if (pMT->HasLayout())
2060 {
2061 EEClassLayoutInfo* pInfo = pMT->GetLayoutInfo();
2062
2063 if (clsHnd.IsNativeValueType())
2064 {
2065 // if it's the unmanaged view of the managed type, we always use the unmanaged alignment requirement
2066 result = pInfo->m_LargestAlignmentRequirementOfAllMembers;
2067 }
2068 else
2069 if (pInfo->IsManagedSequential())
2070 {
2071 _ASSERTE(!pMT->ContainsPointers());
2072
2073 // if it's managed sequential, we use the managed alignment requirement
2074 result = pInfo->m_ManagedLargestAlignmentRequirementOfAllMembers;
2075 }
2076 else if (pInfo->IsBlittable())
2077 {
2078 _ASSERTE(!pMT->ContainsPointers());
2079
2080 // if it's blittable, we use the unmanaged alignment requirement
2081 result = pInfo->m_LargestAlignmentRequirementOfAllMembers;
2082 }
2083 }
2084
2085#ifdef FEATURE_64BIT_ALIGNMENT
2086 if (result < 8 && pMT->RequiresAlign8())
2087 {
2088 // If the structure contains 64-bit primitive fields and the platform requires 8-byte alignment for
2089 // such fields then make sure we return at least 8-byte alignment. Note that it's technically possible
2090 // to create unmanaged APIs that take unaligned structures containing such fields and this
2091 // unconditional alignment bump would cause us to get the calling convention wrong on platforms such
2092 // as ARM. If we see such cases in the future we'd need to add another control (such as an alignment
2093 // property for the StructLayout attribute or a marshaling directive attribute for p/invoke arguments)
2094 // that allows more precise control. For now we'll go with the likely scenario.
2095 result = 8;
2096 }
2097#endif // FEATURE_64BIT_ALIGNMENT
2098
2099 return result;
2100}
2101
2102CORINFO_FIELD_HANDLE
2103CEEInfo::getFieldInClass(CORINFO_CLASS_HANDLE clsHnd, INT num)
2104{
2105 CONTRACTL {
2106 SO_TOLERANT;
2107 NOTHROW;
2108 GC_NOTRIGGER;
2109 MODE_PREEMPTIVE;
2110 } CONTRACTL_END;
2111
2112 CORINFO_FIELD_HANDLE result = NULL;
2113
2114 JIT_TO_EE_TRANSITION_LEAF();
2115
2116 TypeHandle VMClsHnd(clsHnd);
2117
2118 MethodTable* pMT= VMClsHnd.AsMethodTable();
2119
2120 result = (CORINFO_FIELD_HANDLE) ((pMT->GetApproxFieldDescListRaw()) + num);
2121
2122 EE_TO_JIT_TRANSITION_LEAF();
2123
2124 return result;
2125}
2126
2127mdMethodDef
2128CEEInfo::getMethodDefFromMethod(CORINFO_METHOD_HANDLE hMethod)
2129{
2130 CONTRACTL {
2131 SO_TOLERANT;
2132 NOTHROW;
2133 GC_NOTRIGGER;
2134 MODE_PREEMPTIVE;
2135 } CONTRACTL_END;
2136
2137 mdMethodDef result = 0;
2138
2139 JIT_TO_EE_TRANSITION_LEAF();
2140
2141 MethodDesc* pMD = GetMethod(hMethod);
2142
2143 if (pMD->IsDynamicMethod())
2144 {
2145 // Dynamic methods do not have tokens
2146 result = mdMethodDefNil;
2147 }
2148 else
2149 {
2150 result = pMD->GetMemberDef();
2151 }
2152
2153 EE_TO_JIT_TRANSITION_LEAF();
2154
2155 return result;
2156}
2157
2158BOOL CEEInfo::checkMethodModifier(CORINFO_METHOD_HANDLE hMethod,
2159 LPCSTR modifier,
2160 BOOL fOptional)
2161{
2162 CONTRACTL {
2163 SO_TOLERANT;
2164 THROWS;
2165 GC_TRIGGERS;
2166 MODE_PREEMPTIVE;
2167 } CONTRACTL_END;
2168
2169 BOOL result = FALSE;
2170
2171 JIT_TO_EE_TRANSITION();
2172
2173 MethodDesc* pMD = GetMethod(hMethod);
2174 Module* pModule = pMD->GetModule();
2175 MetaSig sig(pMD);
2176 CorElementType eeType = fOptional ? ELEMENT_TYPE_CMOD_OPT : ELEMENT_TYPE_CMOD_REQD;
2177
2178 // modopts/modreqs for the method are by convention stored on the return type
2179 result = sig.GetReturnProps().HasCustomModifier(pModule, modifier, eeType);
2180
2181 EE_TO_JIT_TRANSITION();
2182
2183 return result;
2184}
2185
2186/*********************************************************************/
2187static unsigned ComputeGCLayout(MethodTable * pMT, BYTE* gcPtrs)
2188{
2189 STANDARD_VM_CONTRACT;
2190
2191 unsigned result = 0;
2192
2193 _ASSERTE(pMT->IsValueType());
2194
2195 // TODO: TypedReference should ideally be implemented as a by-ref-like struct containing a ByReference<T> field, in which
2196 // case the check for g_TypedReferenceMT below would not be necessary
2197 if (pMT == g_TypedReferenceMT || pMT->HasSameTypeDefAs(g_pByReferenceClass))
2198 {
2199 if (gcPtrs[0] == TYPE_GC_NONE)
2200 {
2201 gcPtrs[0] = TYPE_GC_BYREF;
2202 result++;
2203 }
2204 else if (gcPtrs[0] != TYPE_GC_BYREF)
2205 {
2206 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
2207 }
2208 return result;
2209 }
2210
2211 ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
2212 for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
2213 {
2214 int fieldStartIndex = pFD->GetOffset() / TARGET_POINTER_SIZE;
2215
2216 if (pFD->GetFieldType() != ELEMENT_TYPE_VALUETYPE)
2217 {
2218 if (pFD->IsObjRef())
2219 {
2220 if (gcPtrs[fieldStartIndex] == TYPE_GC_NONE)
2221 {
2222 gcPtrs[fieldStartIndex] = TYPE_GC_REF;
2223 result++;
2224 }
2225 else if (gcPtrs[fieldStartIndex] != TYPE_GC_REF)
2226 {
2227 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
2228 }
2229 }
2230 }
2231 else
2232 {
2233 MethodTable * pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
2234 result += ComputeGCLayout(pFieldMT, gcPtrs + fieldStartIndex);
2235 }
2236 }
2237 return result;
2238}
2239
2240unsigned CEEInfo::getClassGClayout (CORINFO_CLASS_HANDLE clsHnd, BYTE* gcPtrs)
2241{
2242 CONTRACTL {
2243 SO_TOLERANT;
2244 THROWS;
2245 GC_TRIGGERS;
2246 MODE_PREEMPTIVE;
2247 } CONTRACTL_END;
2248
2249 unsigned result = 0;
2250
2251 JIT_TO_EE_TRANSITION();
2252
2253 TypeHandle VMClsHnd(clsHnd);
2254
2255 MethodTable* pMT = VMClsHnd.GetMethodTable();
2256
2257 if (VMClsHnd.IsNativeValueType())
2258 {
2259 // native value types have no GC pointers
2260 result = 0;
2261 memset(gcPtrs, TYPE_GC_NONE,
2262 (VMClsHnd.GetSize() + TARGET_POINTER_SIZE - 1) / TARGET_POINTER_SIZE);
2263 }
2264 else if (pMT->IsByRefLike())
2265 {
2266 // TODO: TypedReference should ideally be implemented as a by-ref-like struct containing a ByReference<T> field, in
2267 // which case the check for g_TypedReferenceMT below would not be necessary
2268 if (pMT == g_TypedReferenceMT)
2269 {
2270 gcPtrs[0] = TYPE_GC_BYREF;
2271 gcPtrs[1] = TYPE_GC_NONE;
2272 result = 1;
2273 }
2274 else
2275 {
2276 memset(gcPtrs, TYPE_GC_NONE,
2277 (VMClsHnd.GetSize() + TARGET_POINTER_SIZE - 1) / TARGET_POINTER_SIZE);
2278 // Note: This case is more complicated than the TypedReference case
2279 // due to ByRefLike structs being included as fields in other value
2280 // types (TypedReference can not be.)
2281 result = ComputeGCLayout(VMClsHnd.AsMethodTable(), gcPtrs);
2282 }
2283 }
2284 else
2285 {
2286 _ASSERTE(sizeof(BYTE) == 1);
2287
2288 BOOL isValueClass = pMT->IsValueType();
2289
2290#ifdef FEATURE_READYTORUN_COMPILER
2291 _ASSERTE(isValueClass || !IsReadyToRunCompilation() || pMT->IsInheritanceChainLayoutFixedInCurrentVersionBubble());
2292#endif
2293
2294 unsigned int size = isValueClass ? VMClsHnd.GetSize() : pMT->GetNumInstanceFieldBytes() + OBJECT_SIZE;
2295
2296 // assume no GC pointers at first
2297 result = 0;
2298 memset(gcPtrs, TYPE_GC_NONE,
2299 (size + TARGET_POINTER_SIZE - 1) / TARGET_POINTER_SIZE);
2300
2301 // walk the GC descriptors, turning on the correct bits
2302 if (pMT->ContainsPointers())
2303 {
2304 CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
2305 CGCDescSeries * pByValueSeries = map->GetLowestSeries();
2306
2307 for (SIZE_T i = 0; i < map->GetNumSeries(); i++)
2308 {
2309 // Get offset into the value class of the first pointer field (includes a +Object)
2310 size_t cbSeriesSize = pByValueSeries->GetSeriesSize() + pMT->GetBaseSize();
2311 size_t cbSeriesOffset = pByValueSeries->GetSeriesOffset();
2312 size_t cbOffset = isValueClass ? cbSeriesOffset - OBJECT_SIZE : cbSeriesOffset;
2313
2314 _ASSERTE (cbOffset % TARGET_POINTER_SIZE == 0);
2315 _ASSERTE (cbSeriesSize % TARGET_POINTER_SIZE == 0);
2316
2317 result += (unsigned) (cbSeriesSize / TARGET_POINTER_SIZE);
2318 memset(&gcPtrs[cbOffset / TARGET_POINTER_SIZE], TYPE_GC_REF, cbSeriesSize / TARGET_POINTER_SIZE);
2319
2320 pByValueSeries++;
2321 }
2322 }
2323 }
2324
2325 EE_TO_JIT_TRANSITION();
2326
2327 return result;
2328}
2329
2330// returns the enregister info for a struct based on type of fields, alignment, etc.
2331bool CEEInfo::getSystemVAmd64PassStructInRegisterDescriptor(
2332 /*IN*/ CORINFO_CLASS_HANDLE structHnd,
2333 /*OUT*/ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr)
2334{
2335 CONTRACTL {
2336 SO_TOLERANT;
2337 THROWS;
2338 GC_TRIGGERS;
2339 MODE_PREEMPTIVE;
2340 } CONTRACTL_END;
2341
2342#if defined(UNIX_AMD64_ABI_ITF)
2343 JIT_TO_EE_TRANSITION();
2344
2345 _ASSERTE(structPassInRegDescPtr != nullptr);
2346 TypeHandle th(structHnd);
2347
2348 structPassInRegDescPtr->passedInRegisters = false;
2349
2350 // Make sure this is a value type.
2351 if (th.IsValueType())
2352 {
2353 _ASSERTE((CorInfoType2UnixAmd64Classification(th.GetInternalCorElementType()) == SystemVClassificationTypeStruct) ||
2354 (CorInfoType2UnixAmd64Classification(th.GetInternalCorElementType()) == SystemVClassificationTypeTypedReference));
2355
2356 // The useNativeLayout in this case tracks whether the classification
2357 // is for a native layout of the struct or not.
2358 // If the struct has special marshaling it has a native layout.
2359 // In such cases the classifier needs to use the native layout.
2360 // For structs with no native layout, the managed layout should be used
2361 // even if classified for the purposes of marshaling/PInvoke passing.
2362 bool useNativeLayout = false;
2363 MethodTable* methodTablePtr = nullptr;
2364 if (!th.IsTypeDesc())
2365 {
2366 methodTablePtr = th.AsMethodTable();
2367 }
2368 else
2369 {
2370 _ASSERTE(th.IsNativeValueType());
2371
2372 useNativeLayout = true;
2373 methodTablePtr = th.AsNativeValueType();
2374 }
2375 _ASSERTE(methodTablePtr != nullptr);
2376
2377 // If we have full support for UNIX_AMD64_ABI, and not just the interface,
2378 // then we've cached whether this is a reg passed struct in the MethodTable, computed during
2379 // MethodTable construction. Otherwise, we are just building in the interface, and we haven't
2380 // computed or cached anything, so we need to compute it now.
2381#if defined(UNIX_AMD64_ABI)
2382 bool canPassInRegisters = useNativeLayout ? methodTablePtr->GetLayoutInfo()->IsNativeStructPassedInRegisters()
2383 : methodTablePtr->IsRegPassedStruct();
2384#else // !defined(UNIX_AMD64_ABI)
2385 bool canPassInRegisters = false;
2386 SystemVStructRegisterPassingHelper helper((unsigned int)th.GetSize());
2387 if (th.GetSize() <= CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS)
2388 {
2389 canPassInRegisters = methodTablePtr->ClassifyEightBytes(&helper, 0, 0, useNativeLayout);
2390 }
2391#endif // !defined(UNIX_AMD64_ABI)
2392
2393 if (canPassInRegisters)
2394 {
2395#if defined(UNIX_AMD64_ABI)
2396 SystemVStructRegisterPassingHelper helper((unsigned int)th.GetSize());
2397 bool result = methodTablePtr->ClassifyEightBytes(&helper, 0, 0, useNativeLayout);
2398
2399 // The answer must be true at this point.
2400 _ASSERTE(result);
2401#endif // UNIX_AMD64_ABI
2402
2403 structPassInRegDescPtr->passedInRegisters = true;
2404
2405 structPassInRegDescPtr->eightByteCount = helper.eightByteCount;
2406 _ASSERTE(structPassInRegDescPtr->eightByteCount <= CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS);
2407
2408 for (unsigned int i = 0; i < CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS; i++)
2409 {
2410 structPassInRegDescPtr->eightByteClassifications[i] = helper.eightByteClassifications[i];
2411 structPassInRegDescPtr->eightByteSizes[i] = helper.eightByteSizes[i];
2412 structPassInRegDescPtr->eightByteOffsets[i] = helper.eightByteOffsets[i];
2413 }
2414 }
2415
2416 _ASSERTE(structPassInRegDescPtr->passedInRegisters == canPassInRegisters);
2417 }
2418
2419 EE_TO_JIT_TRANSITION();
2420
2421 return true;
2422#else // !defined(UNIX_AMD64_ABI_ITF)
2423 return false;
2424#endif // !defined(UNIX_AMD64_ABI_ITF)
2425}
2426
2427/*********************************************************************/
2428unsigned CEEInfo::getClassNumInstanceFields (CORINFO_CLASS_HANDLE clsHnd)
2429{
2430 CONTRACTL {
2431 SO_TOLERANT;
2432 NOTHROW;
2433 GC_NOTRIGGER;
2434 MODE_PREEMPTIVE;
2435 } CONTRACTL_END;
2436
2437 unsigned result = 0;
2438
2439 JIT_TO_EE_TRANSITION_LEAF();
2440
2441 TypeHandle th(clsHnd);
2442
2443 if (!th.IsTypeDesc())
2444 {
2445 result = th.AsMethodTable()->GetNumInstanceFields();
2446 }
2447 else
2448 {
2449 // native value types are opaque aggregates with explicit size
2450 result = 0;
2451 }
2452
2453 EE_TO_JIT_TRANSITION_LEAF();
2454
2455 return result;
2456}
2457
2458
2459CorInfoType CEEInfo::asCorInfoType (CORINFO_CLASS_HANDLE clsHnd)
2460{
2461 CONTRACTL {
2462 SO_TOLERANT;
2463 THROWS;
2464 GC_TRIGGERS;
2465 MODE_PREEMPTIVE;
2466 } CONTRACTL_END;
2467
2468 CorInfoType result = CORINFO_TYPE_UNDEF;
2469
2470 JIT_TO_EE_TRANSITION();
2471
2472 TypeHandle VMClsHnd(clsHnd);
2473 result = toJitType(VMClsHnd);
2474
2475 EE_TO_JIT_TRANSITION();
2476
2477 return result;
2478}
2479
2480
2481CORINFO_LOOKUP_KIND CEEInfo::getLocationOfThisType(CORINFO_METHOD_HANDLE context)
2482{
2483 CONTRACTL {
2484 SO_TOLERANT;
2485 THROWS;
2486 GC_TRIGGERS;
2487 MODE_PREEMPTIVE;
2488 } CONTRACTL_END;
2489
2490 CORINFO_LOOKUP_KIND result;
2491
2492 /* Initialize fields of result for debug build warning */
2493 result.needsRuntimeLookup = false;
2494 result.runtimeLookupKind = CORINFO_LOOKUP_THISOBJ;
2495
2496 JIT_TO_EE_TRANSITION();
2497
2498 MethodDesc *pContextMD = GetMethod(context);
2499
2500 // If the method table is not shared, then return CONST
2501 if (!pContextMD->GetMethodTable()->IsSharedByGenericInstantiations())
2502 {
2503 result.needsRuntimeLookup = false;
2504 }
2505 else
2506 {
2507 result.needsRuntimeLookup = true;
2508
2509 // If we've got a vtable extra argument, go through that
2510 if (pContextMD->RequiresInstMethodTableArg())
2511 {
2512 result.runtimeLookupKind = CORINFO_LOOKUP_CLASSPARAM;
2513 }
2514 // If we've got an object, go through its vtable
2515 else if (pContextMD->AcquiresInstMethodTableFromThis())
2516 {
2517 result.runtimeLookupKind = CORINFO_LOOKUP_THISOBJ;
2518 }
2519 // Otherwise go through the method-desc argument
2520 else
2521 {
2522 _ASSERTE(pContextMD->RequiresInstMethodDescArg());
2523 result.runtimeLookupKind = CORINFO_LOOKUP_METHODPARAM;
2524 }
2525 }
2526
2527 EE_TO_JIT_TRANSITION();
2528
2529 return result;
2530}
2531
2532CORINFO_METHOD_HANDLE CEEInfo::GetDelegateCtor(
2533 CORINFO_METHOD_HANDLE methHnd,
2534 CORINFO_CLASS_HANDLE clsHnd,
2535 CORINFO_METHOD_HANDLE targetMethodHnd,
2536 DelegateCtorArgs *pCtorData)
2537{
2538 CONTRACTL {
2539 SO_TOLERANT;
2540 THROWS;
2541 GC_TRIGGERS;
2542 MODE_PREEMPTIVE;
2543 } CONTRACTL_END;
2544
2545 if (isVerifyOnly())
2546 {
2547 // No sense going through the optimized case just for verification and it can cause issues parsing
2548 // uninstantiated generic signatures.
2549 return methHnd;
2550 }
2551
2552 CORINFO_METHOD_HANDLE result = NULL;
2553
2554 JIT_TO_EE_TRANSITION();
2555
2556 MethodDesc *pCurrentCtor = (MethodDesc*)methHnd;
2557 if (!pCurrentCtor->IsFCall())
2558 {
2559 result = methHnd;
2560 }
2561 else
2562 {
2563 MethodDesc *pTargetMethod = (MethodDesc*)targetMethodHnd;
2564 TypeHandle delegateType = (TypeHandle)clsHnd;
2565
2566 MethodDesc *pDelegateCtor = COMDelegate::GetDelegateCtor(delegateType, pTargetMethod, pCtorData);
2567 if (!pDelegateCtor)
2568 pDelegateCtor = pCurrentCtor;
2569 result = (CORINFO_METHOD_HANDLE)pDelegateCtor;
2570 }
2571
2572 EE_TO_JIT_TRANSITION();
2573
2574 return result;
2575}
2576
2577void CEEInfo::MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd)
2578{
2579 CONTRACTL {
2580 SO_TOLERANT;
2581 THROWS;
2582 GC_TRIGGERS;
2583 MODE_PREEMPTIVE;
2584 } CONTRACTL_END;
2585
2586 JIT_TO_EE_TRANSITION();
2587
2588 MethodDesc* pMD = GetMethod(methHnd);
2589
2590 if (pMD->IsDynamicMethod())
2591 {
2592 pMD->AsDynamicMethodDesc()->GetResolver()->FreeCompileTimeState();
2593 }
2594
2595 EE_TO_JIT_TRANSITION();
2596}
2597
2598// Given a module scope (scopeHnd), a method handle (context) and an metadata token,
2599// attempt to load the handle (type, field or method) associated with the token.
2600// If this is not possible at compile-time (because the method code is shared and the token contains type parameters)
2601// then indicate how the handle should be looked up at run-time.
2602//
2603// See corinfo.h for more details
2604//
2605void CEEInfo::embedGenericHandle(
2606 CORINFO_RESOLVED_TOKEN * pResolvedToken,
2607 BOOL fEmbedParent,
2608 CORINFO_GENERICHANDLE_RESULT *pResult)
2609{
2610 CONTRACTL {
2611 SO_TOLERANT;
2612 THROWS;
2613 GC_TRIGGERS;
2614 MODE_PREEMPTIVE;
2615 } CONTRACTL_END;
2616
2617 INDEBUG(memset(pResult, 0xCC, sizeof(*pResult)));
2618
2619 JIT_TO_EE_TRANSITION();
2620
2621 BOOL fRuntimeLookup;
2622 MethodDesc * pTemplateMD = NULL;
2623
2624 if (!fEmbedParent && pResolvedToken->hMethod != NULL)
2625 {
2626 MethodDesc * pMD = (MethodDesc *)pResolvedToken->hMethod;
2627 TypeHandle th(pResolvedToken->hClass);
2628
2629 pResult->handleType = CORINFO_HANDLETYPE_METHOD;
2630
2631 Instantiation methodInst = pMD->GetMethodInstantiation();
2632
2633 pMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, th.GetMethodTable(), FALSE, methodInst, FALSE);
2634
2635 // Normalize the method handle for reflection
2636 if (pResolvedToken->tokenType == CORINFO_TOKENKIND_Ldtoken)
2637 pMD = MethodDesc::FindOrCreateAssociatedMethodDescForReflection(pMD, th, methodInst);
2638
2639 pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)pMD;
2640 pTemplateMD = pMD;
2641
2642 // Runtime lookup is only required for stubs. Regular entrypoints are always the same shared MethodDescs.
2643 fRuntimeLookup = pMD->IsWrapperStub() &&
2644 (pMD->GetMethodTable()->IsSharedByGenericInstantiations() || TypeHandle::IsCanonicalSubtypeInstantiation(methodInst));
2645 }
2646 else
2647 if (!fEmbedParent && pResolvedToken->hField != NULL)
2648 {
2649 FieldDesc * pFD = (FieldDesc *)pResolvedToken->hField;
2650 TypeHandle th(pResolvedToken->hClass);
2651
2652 pResult->handleType = CORINFO_HANDLETYPE_FIELD;
2653
2654 pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)pFD;
2655
2656 fRuntimeLookup = th.IsSharedByGenericInstantiations() && pFD->IsStatic();
2657 }
2658 else
2659 {
2660 TypeHandle th(pResolvedToken->hClass);
2661
2662 pResult->handleType = CORINFO_HANDLETYPE_CLASS;
2663
2664 if (pResolvedToken->tokenType == CORINFO_TOKENKIND_Newarr)
2665 {
2666 pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)th.AsArray()->GetTemplateMethodTable();
2667 }
2668 else
2669 {
2670 pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)th.AsPtr();
2671 }
2672
2673 if (fEmbedParent && pResolvedToken->hMethod != NULL)
2674 {
2675 MethodDesc * pDeclaringMD = (MethodDesc *)pResolvedToken->hMethod;
2676
2677 if (!pDeclaringMD->GetMethodTable()->HasSameTypeDefAs(th.GetMethodTable()))
2678 {
2679 //
2680 // The method type may point to a sub-class of the actual class that declares the method.
2681 // It is important to embed the declaring type in this case.
2682 //
2683
2684 pTemplateMD = pDeclaringMD;
2685
2686 pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)pDeclaringMD->GetMethodTable();
2687 }
2688 }
2689
2690 // IsSharedByGenericInstantiations would not work here. The runtime lookup is required
2691 // even for standalone generic variables that show up as __Canon here.
2692 fRuntimeLookup = th.IsCanonicalSubtype();
2693 }
2694
2695 _ASSERTE(pResult->compileTimeHandle);
2696
2697 if (fRuntimeLookup
2698 // Handle invalid IL - see comment in code:CEEInfo::ComputeRuntimeLookupForSharedGenericToken
2699 && ContextIsShared(pResolvedToken->tokenContext))
2700 {
2701 DictionaryEntryKind entryKind = EmptySlot;
2702 switch (pResult->handleType)
2703 {
2704 case CORINFO_HANDLETYPE_CLASS:
2705 entryKind = (pTemplateMD != NULL) ? DeclaringTypeHandleSlot : TypeHandleSlot;
2706 break;
2707 case CORINFO_HANDLETYPE_METHOD:
2708 entryKind = MethodDescSlot;
2709 break;
2710 case CORINFO_HANDLETYPE_FIELD:
2711 entryKind = FieldDescSlot;
2712 break;
2713 default:
2714 _ASSERTE(false);
2715 }
2716
2717 ComputeRuntimeLookupForSharedGenericToken(entryKind,
2718 pResolvedToken,
2719 NULL,
2720 pTemplateMD,
2721 &pResult->lookup);
2722 }
2723 else
2724 {
2725 // If the target is not shared then we've already got our result and
2726 // can simply do a static look up
2727 pResult->lookup.lookupKind.needsRuntimeLookup = false;
2728
2729 pResult->lookup.constLookup.handle = pResult->compileTimeHandle;
2730 pResult->lookup.constLookup.accessType = IAT_VALUE;
2731 }
2732
2733 EE_TO_JIT_TRANSITION();
2734}
2735
2736void CEEInfo::ScanForModuleDependencies(Module* pModule, SigPointer psig)
2737{
2738 STANDARD_VM_CONTRACT;
2739
2740 _ASSERTE(pModule && !pModule->IsSystem());
2741
2742 CorElementType eType;
2743 IfFailThrow(psig.GetElemType(&eType));
2744
2745 switch (eType)
2746 {
2747 case ELEMENT_TYPE_GENERICINST:
2748 {
2749 ScanForModuleDependencies(pModule,psig);
2750 IfFailThrow(psig.SkipExactlyOne());
2751
2752 ULONG ntypars;
2753 IfFailThrow(psig.GetData(&ntypars));
2754 for (ULONG i = 0; i < ntypars; i++)
2755 {
2756 ScanForModuleDependencies(pModule,psig);
2757 IfFailThrow(psig.SkipExactlyOne());
2758 }
2759 break;
2760 }
2761
2762 case ELEMENT_TYPE_VALUETYPE:
2763 case ELEMENT_TYPE_CLASS:
2764 {
2765 mdToken tk;
2766 IfFailThrow(psig.GetToken(&tk));
2767 if (TypeFromToken(tk) == mdtTypeRef)
2768 {
2769 Module * pTypeDefModule;
2770 mdToken tkTypeDef;
2771
2772 if (ClassLoader::ResolveTokenToTypeDefThrowing(pModule, tk, &pTypeDefModule, &tkTypeDef))
2773 break;
2774
2775 if (!pTypeDefModule->IsSystem() && (pModule != pTypeDefModule))
2776 {
2777 m_pOverride->addActiveDependency((CORINFO_MODULE_HANDLE)pModule, (CORINFO_MODULE_HANDLE)pTypeDefModule);
2778 }
2779 }
2780 break;
2781 }
2782
2783 default:
2784 break;
2785 }
2786}
2787
2788void CEEInfo::ScanMethodSpec(Module * pModule, PCCOR_SIGNATURE pMethodSpec, ULONG cbMethodSpec)
2789{
2790 STANDARD_VM_CONTRACT;
2791
2792 SigPointer sp(pMethodSpec, cbMethodSpec);
2793
2794 BYTE etype;
2795 IfFailThrow(sp.GetByte(&etype));
2796
2797 _ASSERT(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST);
2798
2799 ULONG nGenericMethodArgs;
2800 IfFailThrow(sp.GetData(&nGenericMethodArgs));
2801
2802 for (ULONG i = 0; i < nGenericMethodArgs; i++)
2803 {
2804 ScanForModuleDependencies(pModule,sp);
2805 IfFailThrow(sp.SkipExactlyOne());
2806 }
2807}
2808
2809BOOL CEEInfo::ScanTypeSpec(Module * pModule, PCCOR_SIGNATURE pTypeSpec, ULONG cbTypeSpec)
2810{
2811 STANDARD_VM_CONTRACT;
2812
2813 SigPointer sp(pTypeSpec, cbTypeSpec);
2814
2815 CorElementType eType;
2816 IfFailThrow(sp.GetElemType(&eType));
2817
2818 // Filter out non-instantiated types and typedescs (typevars, arrays, ...)
2819 if (eType != ELEMENT_TYPE_GENERICINST)
2820 {
2821 // Scanning of the parent chain is required for reference types only.
2822 // Note that the parent chain MUST NOT be scanned for instantiated
2823 // generic variables because of they are not a real dependencies.
2824 return (eType == ELEMENT_TYPE_CLASS);
2825 }
2826
2827 IfFailThrow(sp.SkipExactlyOne());
2828
2829 ULONG ntypars;
2830 IfFailThrow(sp.GetData(&ntypars));
2831
2832 for (ULONG i = 0; i < ntypars; i++)
2833 {
2834 ScanForModuleDependencies(pModule,sp);
2835 IfFailThrow(sp.SkipExactlyOne());
2836 }
2837
2838 return TRUE;
2839}
2840
2841void CEEInfo::ScanInstantiation(Module * pModule, Instantiation inst)
2842{
2843 STANDARD_VM_CONTRACT;
2844
2845 for (DWORD i = 0; i < inst.GetNumArgs(); i++)
2846 {
2847 TypeHandle th = inst[i];
2848 if (th.IsTypeDesc())
2849 continue;
2850
2851 MethodTable * pMT = th.AsMethodTable();
2852
2853 Module * pDefModule = pMT->GetModule();
2854
2855 if (!pDefModule->IsSystem() && (pModule != pDefModule))
2856 {
2857 m_pOverride->addActiveDependency((CORINFO_MODULE_HANDLE)pModule, (CORINFO_MODULE_HANDLE)pDefModule);
2858 }
2859
2860 if (pMT->HasInstantiation())
2861 {
2862 ScanInstantiation(pModule, pMT->GetInstantiation());
2863 }
2864 }
2865}
2866
2867//
2868// ScanToken is used to track triggers for creation of per-AppDomain state instead, including allocations required for statics and
2869// triggering of module cctors.
2870//
2871// The basic rule is: There should be no possibility of a shared module that is "active" to have a direct call into a module that
2872// is not "active". And we don't want to intercept every call during runtime, so during compile time we track static calls and
2873// everything that can result in new virtual calls.
2874//
2875// The current algorithm (scan the parent type chain and instantiation variables) is more than enough to maintain this invariant.
2876// One could come up with a more efficient algorithm that still maintains the invariant, but it may introduce backward compatibility
2877// issues.
2878//
2879// For efficiency, the implementation leverages the loaded types as much as possible. Unfortunately, we still have to go back to
2880// metadata when the generic variables could have been substituted via generic context.
2881//
2882void CEEInfo::ScanToken(Module * pModule, CORINFO_RESOLVED_TOKEN * pResolvedToken, TypeHandle th, MethodDesc * pMD)
2883{
2884 STANDARD_VM_CONTRACT;
2885
2886 if (pModule->IsSystem())
2887 return;
2888
2889 if (isVerifyOnly())
2890 return;
2891
2892 //
2893 // Scan method instantiation
2894 //
2895 if (pMD != NULL && pResolvedToken->pMethodSpec != NULL)
2896 {
2897 if (ContextIsInstantiated(pResolvedToken->tokenContext))
2898 {
2899 ScanMethodSpec(pModule, pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
2900 }
2901 else
2902 {
2903 ScanInstantiation(pModule, pMD->GetMethodInstantiation());
2904 }
2905 }
2906
2907 if (th.IsTypeDesc())
2908 return;
2909
2910 MethodTable * pMT = th.AsMethodTable();
2911
2912 //
2913 // Scan type instantiation
2914 //
2915 if (pResolvedToken->pTypeSpec != NULL)
2916 {
2917 if (ContextIsInstantiated(pResolvedToken->tokenContext))
2918 {
2919 if (!ScanTypeSpec(pModule, pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec))
2920 return;
2921 }
2922 else
2923 {
2924 ScanInstantiation(pModule, pMT->GetInstantiation());
2925 }
2926 }
2927
2928 //
2929 // Scan chain of parent types
2930 //
2931 for (;;)
2932 {
2933 Module * pDefModule = pMT->GetModule();
2934 if (pDefModule->IsSystem())
2935 break;
2936
2937 if (pModule != pDefModule)
2938 {
2939 m_pOverride->addActiveDependency((CORINFO_MODULE_HANDLE)pModule, (CORINFO_MODULE_HANDLE)pDefModule);
2940 }
2941
2942 MethodTable * pParentMT = pMT->GetParentMethodTable();
2943 if (pParentMT == NULL)
2944 break;
2945
2946 if (pParentMT->HasInstantiation())
2947 {
2948 IMDInternalImport* pInternalImport = pDefModule->GetMDImport();
2949
2950 mdToken tkParent;
2951 IfFailThrow(pInternalImport->GetTypeDefProps(pMT->GetCl(), NULL, &tkParent));
2952
2953 if (TypeFromToken(tkParent) == mdtTypeSpec)
2954 {
2955 PCCOR_SIGNATURE pTypeSpec;
2956 ULONG cbTypeSpec;
2957 IfFailThrow(pInternalImport->GetTypeSpecFromToken(tkParent, &pTypeSpec, &cbTypeSpec));
2958
2959 ScanTypeSpec(pDefModule, pTypeSpec, cbTypeSpec);
2960 }
2961 }
2962
2963 pMT = pParentMT;
2964 }
2965}
2966
2967void CEEInfo::ScanTokenForDynamicScope(CORINFO_RESOLVED_TOKEN * pResolvedToken, TypeHandle th, MethodDesc * pMD)
2968{
2969 STANDARD_VM_CONTRACT;
2970
2971 if (m_pMethodBeingCompiled->IsLCGMethod())
2972 {
2973 // The dependency tracking for LCG is irrelevant. Perform immediate activation.
2974 if (pMD != NULL && pMD->HasMethodInstantiation())
2975 pMD->EnsureActive();
2976 if (!th.IsTypeDesc())
2977 th.AsMethodTable()->EnsureInstanceActive();
2978 return;
2979 }
2980
2981 // Stubs-as-IL have to do regular dependency tracking because they can be shared cross-domain.
2982 Module * pModule = GetDynamicResolver(pResolvedToken->tokenScope)->GetDynamicMethod()->GetModule();
2983 ScanToken(pModule, pResolvedToken, th, pMD);
2984}
2985
2986MethodDesc * CEEInfo::GetMethodForSecurity(CORINFO_METHOD_HANDLE callerHandle)
2987{
2988 STANDARD_VM_CONTRACT;
2989
2990 // Cache the cast lookup
2991 if (callerHandle == m_hMethodForSecurity_Key)
2992 {
2993 return m_pMethodForSecurity_Value;
2994 }
2995
2996 MethodDesc * pCallerMethod = (MethodDesc *)callerHandle;
2997
2998 //If the caller is generic, load the open type and then load the field again, This allows us to
2999 //differentiate between BadGeneric<T> containing a memberRef for a field of type InaccessibleClass and
3000 //GoodGeneric<T> containing a memberRef for a field of type T instantiated over InaccessibleClass.
3001 MethodDesc * pMethodForSecurity = pCallerMethod->IsILStub() ?
3002 pCallerMethod : pCallerMethod->LoadTypicalMethodDefinition();
3003
3004 m_hMethodForSecurity_Key = callerHandle;
3005 m_pMethodForSecurity_Value = pMethodForSecurity;
3006
3007 return pMethodForSecurity;
3008}
3009
3010// Check that the instantation is <!/!!0, ..., !/!!(n-1)>
3011static BOOL IsSignatureForTypicalInstantiation(SigPointer sigptr, CorElementType varType, ULONG ntypars)
3012{
3013 STANDARD_VM_CONTRACT;
3014
3015 for (ULONG i = 0; i < ntypars; i++)
3016 {
3017 CorElementType type;
3018 IfFailThrow(sigptr.GetElemType(&type));
3019 if (type != varType)
3020 return FALSE;
3021
3022 ULONG data;
3023 IfFailThrow(sigptr.GetData(&data));
3024
3025 if (data != i)
3026 return FALSE;
3027 }
3028
3029 return TRUE;
3030}
3031
3032// Check that methodSpec instantiation is <!!0, ..., !!(n-1)>
3033static BOOL IsMethodSpecForTypicalInstantation(SigPointer sigptr)
3034{
3035 STANDARD_VM_CONTRACT;
3036
3037 BYTE etype;
3038 IfFailThrow(sigptr.GetByte(&etype));
3039 _ASSERTE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST);
3040
3041 ULONG ntypars;
3042 IfFailThrow(sigptr.GetData(&ntypars));
3043
3044 return IsSignatureForTypicalInstantiation(sigptr, ELEMENT_TYPE_MVAR, ntypars);
3045}
3046
3047// Check that typeSpec instantiation is <!0, ..., !(n-1)>
3048static BOOL IsTypeSpecForTypicalInstantiation(SigPointer sigptr)
3049{
3050 STANDARD_VM_CONTRACT;
3051
3052 CorElementType type;
3053 IfFailThrow(sigptr.GetElemType(&type));
3054 if (type != ELEMENT_TYPE_GENERICINST)
3055 return FALSE;
3056
3057 IfFailThrow(sigptr.SkipExactlyOne());
3058
3059 ULONG ntypars;
3060 IfFailThrow(sigptr.GetData(&ntypars));
3061
3062 return IsSignatureForTypicalInstantiation(sigptr, ELEMENT_TYPE_VAR, ntypars);
3063}
3064
3065void CEEInfo::ComputeRuntimeLookupForSharedGenericToken(DictionaryEntryKind entryKind,
3066 CORINFO_RESOLVED_TOKEN * pResolvedToken,
3067 CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken,
3068 MethodDesc * pTemplateMD /* for method-based slots */,
3069 CORINFO_LOOKUP *pResultLookup)
3070{
3071 CONTRACTL{
3072 STANDARD_VM_CHECK;
3073 PRECONDITION(CheckPointer(pResultLookup));
3074 } CONTRACTL_END;
3075
3076
3077 // We should never get here when we are only verifying
3078 _ASSERTE(!isVerifyOnly());
3079
3080 pResultLookup->lookupKind.needsRuntimeLookup = true;
3081 pResultLookup->lookupKind.runtimeLookupFlags = 0;
3082
3083 CORINFO_RUNTIME_LOOKUP *pResult = &pResultLookup->runtimeLookup;
3084 pResult->signature = NULL;
3085
3086 pResult->indirectFirstOffset = 0;
3087 pResult->indirectSecondOffset = 0;
3088
3089 // Unless we decide otherwise, just do the lookup via a helper function
3090 pResult->indirections = CORINFO_USEHELPER;
3091
3092 MethodDesc *pContextMD = GetMethodFromContext(pResolvedToken->tokenContext);
3093 MethodTable *pContextMT = pContextMD->GetMethodTable();
3094
3095 // Do not bother computing the runtime lookup if we are inlining. The JIT is going
3096 // to abort the inlining attempt anyway.
3097 if (pContextMD != m_pMethodBeingCompiled)
3098 {
3099 return;
3100 }
3101
3102 // There is a pathological case where invalid IL refereces __Canon type directly, but there is no dictionary availabled to store the lookup.
3103 // All callers of ComputeRuntimeLookupForSharedGenericToken have to filter out this case. We can't do much about it here.
3104 _ASSERTE(pContextMD->IsSharedByGenericInstantiations());
3105
3106 BOOL fInstrument = FALSE;
3107
3108#ifdef FEATURE_NATIVE_IMAGE_GENERATION
3109 // This will make sure that when IBC logging is turned on we will go through a version
3110 // of JIT_GenericHandle which logs the access. Note that we still want the dictionaries
3111 // to be populated to prepopulate the types at NGen time.
3112 if (IsCompilingForNGen() &&
3113 GetAppDomain()->ToCompilationDomain()->m_fForceInstrument)
3114 {
3115 fInstrument = TRUE;
3116 }
3117#endif // FEATURE_NATIVE_IMAGE_GENERATION
3118
3119 if (pContextMD->RequiresInstMethodDescArg())
3120 {
3121 pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_METHODPARAM;
3122 }
3123 else
3124 {
3125 if (pContextMD->RequiresInstMethodTableArg())
3126 pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_CLASSPARAM;
3127 else
3128 pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_THISOBJ;
3129 }
3130
3131#ifdef FEATURE_READYTORUN_COMPILER
3132 if (IsReadyToRunCompilation())
3133 {
3134 pResultLookup->lookupKind.runtimeLookupArgs = NULL;
3135
3136 switch (entryKind)
3137 {
3138 case DeclaringTypeHandleSlot:
3139 _ASSERTE(pTemplateMD != NULL);
3140 pResultLookup->lookupKind.runtimeLookupArgs = pTemplateMD->GetMethodTable();
3141 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_DeclaringTypeHandle;
3142 break;
3143
3144 case TypeHandleSlot:
3145 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_TypeHandle;
3146 break;
3147
3148 case MethodDescSlot:
3149 case MethodEntrySlot:
3150 case ConstrainedMethodEntrySlot:
3151 case DispatchStubAddrSlot:
3152 {
3153 if (pTemplateMD != (MethodDesc*)pResolvedToken->hMethod)
3154 ThrowHR(E_NOTIMPL);
3155
3156 if (entryKind == MethodDescSlot)
3157 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_MethodHandle;
3158 else if (entryKind == MethodEntrySlot || entryKind == ConstrainedMethodEntrySlot)
3159 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_MethodEntry;
3160 else
3161 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_VirtualEntry;
3162
3163 pResultLookup->lookupKind.runtimeLookupArgs = pConstrainedResolvedToken;
3164
3165 break;
3166 }
3167
3168 case FieldDescSlot:
3169 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_FieldHandle;
3170 break;
3171
3172 default:
3173 _ASSERTE(!"Unknown dictionary entry kind!");
3174 IfFailThrow(E_FAIL);
3175 }
3176
3177 // For R2R compilations, we don't generate the dictionary lookup signatures (dictionary lookups are done in a
3178 // different way that is more version resilient... plus we can't have pointers to existing MTs/MDs in the sigs)
3179 return;
3180 }
3181#endif
3182 // If we've got a method type parameter of any kind then we must look in the method desc arg
3183 if (pContextMD->RequiresInstMethodDescArg())
3184 {
3185 pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_METHOD_LOG : CORINFO_HELP_RUNTIMEHANDLE_METHOD;
3186
3187 if (fInstrument)
3188 goto NoSpecialCase;
3189
3190 // Special cases:
3191 // (1) Naked method type variable: look up directly in instantiation hanging off runtime md
3192 // (2) Reference to method-spec of current method (e.g. a recursive call) i.e. currentmeth<!0,...,!(n-1)>
3193 if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr))
3194 {
3195 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3196 CorElementType type;
3197 IfFailThrow(sigptr.GetElemType(&type));
3198 if (type == ELEMENT_TYPE_MVAR)
3199 {
3200 pResult->indirections = 2;
3201 pResult->testForNull = 0;
3202#ifdef FEATURE_PREJIT
3203 pResult->testForFixup = 1;
3204#else
3205 pResult->testForFixup = 0;
3206#endif
3207 pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
3208
3209 if (decltype(InstantiatedMethodDesc::m_pPerInstInfo)::isRelative)
3210 {
3211 pResult->indirectFirstOffset = 1;
3212 }
3213
3214 ULONG data;
3215 IfFailThrow(sigptr.GetData(&data));
3216 pResult->offsets[1] = sizeof(TypeHandle) * data;
3217
3218 return;
3219 }
3220 }
3221 else if (entryKind == MethodDescSlot)
3222 {
3223 // It's the context itself (i.e. a recursive call)
3224 if (!pTemplateMD->HasSameMethodDefAs(pContextMD))
3225 goto NoSpecialCase;
3226
3227 // Now just check that the instantiation is (!!0, ..., !!(n-1))
3228 if (!IsMethodSpecForTypicalInstantation(SigPointer(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec)))
3229 goto NoSpecialCase;
3230
3231 // Type instantiation has to match too if there is one
3232 if (pContextMT->HasInstantiation())
3233 {
3234 TypeHandle thTemplate(pResolvedToken->hClass);
3235
3236 if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT))
3237 goto NoSpecialCase;
3238
3239 // This check filters out method instantiation on generic type definition, like G::M<!!0>()
3240 // We may not ever get it here. Filter it out just to be sure...
3241 if (pResolvedToken->pTypeSpec == NULL)
3242 goto NoSpecialCase;
3243
3244 if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)))
3245 goto NoSpecialCase;
3246 }
3247
3248 // Just use the method descriptor that was passed in!
3249 pResult->indirections = 0;
3250 pResult->testForNull = 0;
3251 pResult->testForFixup = 0;
3252
3253 return;
3254 }
3255 }
3256 // Otherwise we must just have class type variables
3257 else
3258 {
3259 _ASSERTE(pContextMT->GetNumGenericArgs() > 0);
3260
3261 if (pContextMD->RequiresInstMethodTableArg())
3262 {
3263 // If we've got a vtable extra argument, go through that
3264 pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG : CORINFO_HELP_RUNTIMEHANDLE_CLASS;
3265 }
3266 // If we've got an object, go through its vtable
3267 else
3268 {
3269 _ASSERTE(pContextMD->AcquiresInstMethodTableFromThis());
3270 pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG : CORINFO_HELP_RUNTIMEHANDLE_CLASS;
3271 }
3272
3273 if (fInstrument)
3274 goto NoSpecialCase;
3275
3276 // Special cases:
3277 // (1) Naked class type variable: look up directly in instantiation hanging off vtable
3278 // (2) C<!0,...,!(n-1)> where C is the context's class and C is sealed: just return vtable ptr
3279 if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr))
3280 {
3281 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3282 CorElementType type;
3283 IfFailThrow(sigptr.GetElemType(&type));
3284 if (type == ELEMENT_TYPE_VAR)
3285 {
3286 pResult->indirections = 3;
3287 pResult->testForNull = 0;
3288#ifdef FEATURE_PREJIT
3289 pResult->testForFixup = 1;
3290#else
3291 pResult->testForFixup = 0;
3292#endif
3293 pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo();
3294 pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1);
3295 ULONG data;
3296 IfFailThrow(sigptr.GetData(&data));
3297 pResult->offsets[2] = sizeof(TypeHandle) * data;
3298
3299 if (MethodTable::IsPerInstInfoRelative())
3300 {
3301 pResult->indirectFirstOffset = 1;
3302 pResult->indirectSecondOffset = 1;
3303 }
3304
3305 return;
3306 }
3307 else if (type == ELEMENT_TYPE_GENERICINST &&
3308 (pContextMT->IsSealed() || pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_CLASSPARAM))
3309 {
3310 TypeHandle thTemplate(pResolvedToken->hClass);
3311
3312 if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT))
3313 goto NoSpecialCase;
3314
3315 if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)))
3316 goto NoSpecialCase;
3317
3318 // Just use the vtable pointer itself!
3319 pResult->indirections = 0;
3320 pResult->testForNull = 0;
3321 pResult->testForFixup = 0;
3322
3323 return;
3324 }
3325 }
3326 }
3327
3328NoSpecialCase:
3329
3330 SigBuilder sigBuilder;
3331
3332 sigBuilder.AppendData(entryKind);
3333
3334 if (pResultLookup->lookupKind.runtimeLookupKind != CORINFO_LOOKUP_METHODPARAM)
3335 {
3336 _ASSERTE(pContextMT->GetNumDicts() > 0);
3337 sigBuilder.AppendData(pContextMT->GetNumDicts() - 1);
3338 }
3339
3340 Module * pModule = (Module *)pResolvedToken->tokenScope;
3341
3342 switch (entryKind)
3343 {
3344 case DeclaringTypeHandleSlot:
3345 _ASSERTE(pTemplateMD != NULL);
3346 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3347 sigBuilder.AppendPointer(pTemplateMD->GetMethodTable());
3348 // fall through
3349
3350 case TypeHandleSlot:
3351 {
3352 if (pResolvedToken->tokenType == CORINFO_TOKENKIND_Newarr)
3353 {
3354 if (!IsReadyToRunCompilation())
3355 {
3356 sigBuilder.AppendElementType((CorElementType)ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG);
3357 }
3358
3359 sigBuilder.AppendElementType(ELEMENT_TYPE_SZARRAY);
3360 }
3361
3362 // Note that we can come here with pResolvedToken->pTypeSpec == NULL for invalid IL that
3363 // directly references __Canon
3364 if (pResolvedToken->pTypeSpec != NULL)
3365 {
3366 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3367 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3368 }
3369 else
3370 {
3371 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3372 sigBuilder.AppendPointer(pResolvedToken->hClass);
3373 }
3374 }
3375 break;
3376
3377 case ConstrainedMethodEntrySlot:
3378 // Encode constrained type token
3379 if (pConstrainedResolvedToken->pTypeSpec != NULL)
3380 {
3381 SigPointer sigptr(pConstrainedResolvedToken->pTypeSpec, pConstrainedResolvedToken->cbTypeSpec);
3382 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3383 }
3384 else
3385 {
3386 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3387 sigBuilder.AppendPointer(pConstrainedResolvedToken->hClass);
3388 }
3389 // fall through
3390
3391 case MethodDescSlot:
3392 case MethodEntrySlot:
3393 case DispatchStubAddrSlot:
3394 {
3395 // Encode containing type
3396 if (pResolvedToken->pTypeSpec != NULL)
3397 {
3398 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3399 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3400 }
3401 else
3402 {
3403 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3404 sigBuilder.AppendPointer(pResolvedToken->hClass);
3405 }
3406
3407 // Encode method
3408 _ASSERTE(pTemplateMD != NULL);
3409
3410 mdMethodDef methodToken = pTemplateMD->GetMemberDef_NoLogging();
3411 DWORD methodFlags = 0;
3412
3413 // Check for non-NULL method spec first. We can encode the method instantiation only if we have one in method spec to start with. Note that there are weird cases
3414 // like instantiating stub for generic method definition that do not have method spec but that won't be caught by the later conditions either.
3415 BOOL fMethodNeedsInstantiation = (pResolvedToken->pMethodSpec != NULL) && pTemplateMD->HasMethodInstantiation() && !pTemplateMD->IsGenericMethodDefinition();
3416
3417 if (pTemplateMD->IsUnboxingStub())
3418 methodFlags |= ENCODE_METHOD_SIG_UnboxingStub;
3419 // Always create instantiating stub for method entry points even if the template does not ask for it. It saves caller
3420 // from creating throw-away instantiating stub.
3421 if (pTemplateMD->IsInstantiatingStub() || (entryKind == MethodEntrySlot))
3422 methodFlags |= ENCODE_METHOD_SIG_InstantiatingStub;
3423 if (fMethodNeedsInstantiation)
3424 methodFlags |= ENCODE_METHOD_SIG_MethodInstantiation;
3425 if (IsNilToken(methodToken))
3426 {
3427 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
3428 }
3429 else
3430 if (entryKind == DispatchStubAddrSlot && pTemplateMD->IsVtableMethod())
3431 {
3432 // Encode the method for dispatch stub using slot to avoid touching the interface method MethodDesc at runtime
3433
3434 // There should be no other flags set if we are encoding the method using slot for virtual stub dispatch
3435 _ASSERTE(methodFlags == 0);
3436
3437 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
3438 }
3439 else
3440 if (!pTemplateMD->GetModule()->IsInCurrentVersionBubble())
3441 {
3442 // Using a method defined in another version bubble. We can assume the slot number is stable only for real interface methods.
3443 if (!pTemplateMD->GetMethodTable()->IsInterface() || pTemplateMD->IsStatic() || pTemplateMD->HasMethodInstantiation())
3444 {
3445 _ASSERTE(!"References to non-interface methods not yet supported in version resilient images");
3446 IfFailThrow(E_FAIL);
3447 }
3448 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
3449 }
3450
3451 sigBuilder.AppendData(methodFlags);
3452
3453 if ((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0)
3454 {
3455 // Encode method token and its module context (as method's type)
3456 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3457 sigBuilder.AppendPointer(pTemplateMD->GetMethodTable());
3458
3459 sigBuilder.AppendData(RidFromToken(methodToken));
3460 }
3461 else
3462 {
3463 sigBuilder.AppendData(pTemplateMD->GetSlot());
3464 }
3465
3466 if (fMethodNeedsInstantiation)
3467 {
3468 SigPointer sigptr(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
3469
3470 BYTE etype;
3471 IfFailThrow(sigptr.GetByte(&etype));
3472
3473 // Load the generic method instantiation
3474 THROW_BAD_FORMAT_MAYBE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST, 0, pModule);
3475
3476 DWORD nGenericMethodArgs;
3477 IfFailThrow(sigptr.GetData(&nGenericMethodArgs));
3478 sigBuilder.AppendData(nGenericMethodArgs);
3479
3480 _ASSERTE(nGenericMethodArgs == pTemplateMD->GetNumGenericMethodArgs());
3481
3482 for (DWORD i = 0; i < nGenericMethodArgs; i++)
3483 {
3484 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3485 }
3486 }
3487 }
3488 break;
3489
3490 case FieldDescSlot:
3491 {
3492 if (pResolvedToken->pTypeSpec != NULL)
3493 {
3494 // Encode containing type
3495 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3496 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3497 }
3498 else
3499 {
3500 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3501 sigBuilder.AppendPointer(pResolvedToken->hClass);
3502 }
3503
3504 FieldDesc * pField = (FieldDesc *)pResolvedToken->hField;
3505 _ASSERTE(pField != NULL);
3506
3507 DWORD fieldIndex = pField->GetApproxEnclosingMethodTable()->GetIndexForFieldDesc(pField);
3508 sigBuilder.AppendData(fieldIndex);
3509 }
3510 break;
3511
3512 default:
3513 _ASSERTE(false);
3514 }
3515
3516 DictionaryEntrySignatureSource signatureSource = (IsCompilationProcess() ? FromZapImage : FromJIT);
3517
3518 // It's a method dictionary lookup
3519 if (pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_METHODPARAM)
3520 {
3521 _ASSERTE(pContextMD != NULL);
3522 _ASSERTE(pContextMD->HasMethodInstantiation());
3523
3524 if (DictionaryLayout::FindToken(pContextMD->GetLoaderAllocator(), pContextMD->GetNumGenericMethodArgs(), pContextMD->GetDictionaryLayout(), pResult, &sigBuilder, 1, signatureSource))
3525 {
3526 pResult->testForNull = 1;
3527 pResult->testForFixup = 0;
3528
3529 // Indirect through dictionary table pointer in InstantiatedMethodDesc
3530 pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
3531
3532 if (decltype(InstantiatedMethodDesc::m_pPerInstInfo)::isRelative)
3533 {
3534 pResult->indirectFirstOffset = 1;
3535 }
3536 }
3537 }
3538
3539 // It's a class dictionary lookup (CORINFO_LOOKUP_CLASSPARAM or CORINFO_LOOKUP_THISOBJ)
3540 else
3541 {
3542 if (DictionaryLayout::FindToken(pContextMT->GetLoaderAllocator(), pContextMT->GetNumGenericArgs(), pContextMT->GetClass()->GetDictionaryLayout(), pResult, &sigBuilder, 2, signatureSource))
3543 {
3544 pResult->testForNull = 1;
3545 pResult->testForFixup = 0;
3546
3547 // Indirect through dictionary table pointer in vtable
3548 pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo();
3549
3550 // Next indirect through the dictionary appropriate to this instantiated type
3551 pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1);
3552
3553 if (MethodTable::IsPerInstInfoRelative())
3554 {
3555 pResult->indirectFirstOffset = 1;
3556 pResult->indirectSecondOffset = 1;
3557 }
3558 }
3559 }
3560}
3561
3562
3563
3564/*********************************************************************/
3565const char* CEEInfo::getClassName (CORINFO_CLASS_HANDLE clsHnd)
3566{
3567 CONTRACTL {
3568 SO_TOLERANT;
3569 THROWS;
3570 GC_TRIGGERS;
3571 MODE_PREEMPTIVE;
3572 } CONTRACTL_END;
3573
3574 const char* result = NULL;
3575
3576 JIT_TO_EE_TRANSITION();
3577
3578 TypeHandle VMClsHnd(clsHnd);
3579 MethodTable* pMT = VMClsHnd.GetMethodTable();
3580 if (pMT == NULL)
3581 {
3582 result = "";
3583 }
3584 else
3585 {
3586#ifdef _DEBUG
3587 result = pMT->GetDebugClassName();
3588#else // !_DEBUG
3589 // since this is for diagnostic purposes only,
3590 // give up on the namespace, as we don't have a buffer to concat it
3591 // also note this won't show array class names.
3592 LPCUTF8 nameSpace;
3593 result = pMT->GetFullyQualifiedNameInfo(&nameSpace);
3594#endif
3595 }
3596
3597 EE_TO_JIT_TRANSITION();
3598
3599 return result;
3600}
3601
3602/***********************************************************************/
3603const char* CEEInfo::getHelperName (CorInfoHelpFunc ftnNum)
3604{
3605 CONTRACTL {
3606 SO_TOLERANT;
3607 NOTHROW;
3608 GC_NOTRIGGER;
3609 MODE_PREEMPTIVE;
3610 PRECONDITION(ftnNum >= 0 && ftnNum < CORINFO_HELP_COUNT);
3611 } CONTRACTL_END;
3612
3613 const char* result = NULL;
3614
3615 JIT_TO_EE_TRANSITION_LEAF();
3616
3617#ifdef CROSSGEN_COMPILE
3618 result = hlpNameTable[ftnNum];
3619#else
3620#ifdef _DEBUG
3621 result = hlpFuncTable[ftnNum].name;
3622#else
3623 result = "AnyJITHelper";
3624#endif
3625#endif
3626
3627 EE_TO_JIT_TRANSITION_LEAF();
3628
3629 return result;
3630}
3631
3632
3633/*********************************************************************/
3634int CEEInfo::appendClassName(__deref_inout_ecount(*pnBufLen) WCHAR** ppBuf,
3635 int* pnBufLen,
3636 CORINFO_CLASS_HANDLE clsHnd,
3637 BOOL fNamespace,
3638 BOOL fFullInst,
3639 BOOL fAssembly)
3640{
3641 CONTRACTL {
3642 SO_TOLERANT;
3643 MODE_PREEMPTIVE;
3644 THROWS;
3645 GC_TRIGGERS;
3646 } CONTRACTL_END;
3647
3648 int nLen = 0;
3649
3650 JIT_TO_EE_TRANSITION();
3651
3652 TypeHandle th(clsHnd);
3653 StackSString ss;
3654 TypeString::AppendType(ss,th,
3655 (fNamespace ? TypeString::FormatNamespace : 0) |
3656 (fFullInst ? TypeString::FormatFullInst : 0) |
3657 (fAssembly ? TypeString::FormatAssembly : 0));
3658 const WCHAR* szString = ss.GetUnicode();
3659 nLen = (int)wcslen(szString);
3660 if (*pnBufLen > 0)
3661 {
3662 wcscpy_s(*ppBuf, *pnBufLen, szString );
3663 (*ppBuf)[(*pnBufLen) - 1] = W('\0');
3664 (*ppBuf) += nLen;
3665 (*pnBufLen) -= nLen;
3666 }
3667
3668 EE_TO_JIT_TRANSITION();
3669
3670 return nLen;
3671}
3672
3673/*********************************************************************/
3674CORINFO_MODULE_HANDLE CEEInfo::getClassModule(CORINFO_CLASS_HANDLE clsHnd)
3675{
3676 CONTRACTL {
3677 SO_TOLERANT;
3678 NOTHROW;
3679 GC_NOTRIGGER;
3680 MODE_PREEMPTIVE;
3681 } CONTRACTL_END;
3682
3683 CORINFO_MODULE_HANDLE result = NULL;
3684
3685 JIT_TO_EE_TRANSITION_LEAF();
3686
3687 TypeHandle VMClsHnd(clsHnd);
3688
3689 result = CORINFO_MODULE_HANDLE(VMClsHnd.GetModule());
3690
3691 EE_TO_JIT_TRANSITION_LEAF();
3692
3693 return result;
3694}
3695
3696/*********************************************************************/
3697CORINFO_ASSEMBLY_HANDLE CEEInfo::getModuleAssembly(CORINFO_MODULE_HANDLE modHnd)
3698{
3699 CONTRACTL {
3700 SO_TOLERANT;
3701 NOTHROW;
3702 GC_NOTRIGGER;
3703 MODE_PREEMPTIVE;
3704 } CONTRACTL_END;
3705
3706 CORINFO_ASSEMBLY_HANDLE result = NULL;
3707
3708 JIT_TO_EE_TRANSITION_LEAF();
3709
3710 result = CORINFO_ASSEMBLY_HANDLE(GetModule(modHnd)->GetAssembly());
3711
3712 EE_TO_JIT_TRANSITION_LEAF();
3713
3714 return result;
3715}
3716
3717/*********************************************************************/
3718const char* CEEInfo::getAssemblyName(CORINFO_ASSEMBLY_HANDLE asmHnd)
3719{
3720 CONTRACTL {
3721 SO_TOLERANT;
3722 THROWS;
3723 GC_TRIGGERS;
3724 MODE_PREEMPTIVE;
3725 } CONTRACTL_END;
3726
3727 const char* result = NULL;
3728
3729 JIT_TO_EE_TRANSITION();
3730 result = ((Assembly*)asmHnd)->GetSimpleName();
3731 EE_TO_JIT_TRANSITION();
3732
3733 return result;
3734}
3735
3736/*********************************************************************/
3737void* CEEInfo::LongLifetimeMalloc(size_t sz)
3738{
3739 CONTRACTL {
3740 SO_TOLERANT;
3741 NOTHROW;
3742 GC_NOTRIGGER;
3743 MODE_PREEMPTIVE;
3744 } CONTRACTL_END;
3745
3746 void* result = NULL;
3747
3748 JIT_TO_EE_TRANSITION_LEAF();
3749 result = new (nothrow) char[sz];
3750 EE_TO_JIT_TRANSITION_LEAF();
3751
3752 return result;
3753}
3754
3755/*********************************************************************/
3756void CEEInfo::LongLifetimeFree(void* obj)
3757{
3758 CONTRACTL {
3759 SO_TOLERANT;
3760 NOTHROW;
3761 GC_NOTRIGGER;
3762 MODE_PREEMPTIVE;
3763 } CONTRACTL_END;
3764
3765 JIT_TO_EE_TRANSITION_LEAF();
3766 (operator delete)(obj);
3767 EE_TO_JIT_TRANSITION_LEAF();
3768}
3769
3770/*********************************************************************/
3771size_t CEEInfo::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE clsHnd, CORINFO_MODULE_HANDLE *pModuleHandle, void **ppIndirection)
3772{
3773 CONTRACTL {
3774 SO_TOLERANT;
3775 NOTHROW;
3776 GC_NOTRIGGER;
3777 MODE_PREEMPTIVE;
3778 } CONTRACTL_END;
3779
3780 size_t result = 0;
3781
3782 JIT_TO_EE_TRANSITION_LEAF();
3783
3784 TypeHandle VMClsHnd(clsHnd);
3785 Module *pModule = VMClsHnd.AsMethodTable()->GetModuleForStatics();
3786
3787 if (ppIndirection != NULL)
3788 *ppIndirection = NULL;
3789
3790 // The zapper needs the module handle. The jit should not use it at all.
3791 if (pModuleHandle)
3792 *pModuleHandle = CORINFO_MODULE_HANDLE(pModule);
3793
3794 result = pModule->GetModuleID();
3795
3796 _ASSERTE(result);
3797
3798 EE_TO_JIT_TRANSITION_LEAF();
3799
3800 return result;
3801}
3802
3803/*********************************************************************/
3804BOOL CEEInfo::isValueClass(CORINFO_CLASS_HANDLE clsHnd)
3805{
3806 CONTRACTL {
3807 SO_TOLERANT;
3808 NOTHROW;
3809 GC_NOTRIGGER;
3810 MODE_PREEMPTIVE;
3811 } CONTRACTL_END;
3812
3813 BOOL ret = FALSE;
3814
3815 JIT_TO_EE_TRANSITION_LEAF();
3816
3817 _ASSERTE(clsHnd);
3818
3819 // Note that clsHnd.IsValueType() would not return what the JIT expects
3820 // for corner cases like ELEMENT_TYPE_FNPTR
3821 TypeHandle VMClsHnd(clsHnd);
3822 MethodTable * pMT = VMClsHnd.GetMethodTable();
3823 ret = (pMT != NULL) ? pMT->IsValueType() : 0;
3824
3825 EE_TO_JIT_TRANSITION_LEAF();
3826
3827 return ret;
3828}
3829
3830/*********************************************************************/
3831// Decides how the JIT should do the optimization to inline the check for
3832// GetTypeFromHandle(handle) == obj.GetType() (for CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE)
3833// GetTypeFromHandle(X) == GetTypeFromHandle(Y) (for CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN)
3834//
3835// This will enable to use directly the typehandle instead of going through getClassByHandle
3836CorInfoInlineTypeCheck CEEInfo::canInlineTypeCheck(CORINFO_CLASS_HANDLE clsHnd, CorInfoInlineTypeCheckSource source)
3837{
3838 CONTRACTL {
3839 SO_TOLERANT;
3840 NOTHROW;
3841 GC_NOTRIGGER;
3842 MODE_PREEMPTIVE;
3843 } CONTRACTL_END;
3844
3845 CorInfoInlineTypeCheck ret;
3846
3847 JIT_TO_EE_TRANSITION_LEAF();
3848
3849 if (source == CORINFO_INLINE_TYPECHECK_SOURCE_TOKEN)
3850 {
3851 // It's always okay to compare type handles coming from IL tokens
3852 ret = CORINFO_INLINE_TYPECHECK_PASS;
3853 }
3854 else
3855 {
3856 _ASSERTE(source == CORINFO_INLINE_TYPECHECK_SOURCE_VTABLE);
3857 ret = canInlineTypeCheckWithObjectVTable(clsHnd) ?
3858 CORINFO_INLINE_TYPECHECK_PASS : CORINFO_INLINE_TYPECHECK_NONE;
3859 }
3860
3861 EE_TO_JIT_TRANSITION_LEAF();
3862
3863 return(ret);
3864}
3865
3866/*********************************************************************/
3867// If this method returns true, JIT will do optimization to inline the check for
3868// GetTypeFromHandle(handle) == obj.GetType()
3869//
3870// This will enable to use directly the typehandle instead of going through getClassByHandle
3871BOOL CEEInfo::canInlineTypeCheckWithObjectVTable (CORINFO_CLASS_HANDLE clsHnd)
3872{
3873 CONTRACTL {
3874 SO_TOLERANT;
3875 NOTHROW;
3876 GC_NOTRIGGER;
3877 MODE_PREEMPTIVE;
3878 } CONTRACTL_END;
3879
3880 BOOL ret = FALSE;
3881
3882 JIT_TO_EE_TRANSITION_LEAF();
3883
3884 _ASSERTE(clsHnd);
3885
3886 TypeHandle VMClsHnd(clsHnd);
3887
3888 if (VMClsHnd.IsTypeDesc())
3889 {
3890 // We can't do this optimization for arrays because of the object methodtable is template methodtable
3891 ret = FALSE;
3892 }
3893 else
3894 if (VMClsHnd.AsMethodTable()->IsMarshaledByRef())
3895 {
3896 // We can't do this optimization for marshalbyrefs because of the object methodtable can be transparent proxy
3897 ret = FALSE;
3898 }
3899 else
3900 if (VMClsHnd.AsMethodTable()->IsInterface())
3901 {
3902 // Object.GetType() should not ever return interface. However, WCF custom remoting proxy does it. Disable this
3903 // optimization for interfaces so that (autogenerated) code that compares Object.GetType() with interface type works
3904 // as expected for WCF custom remoting proxy. Note that this optimization is still not going to work well for custom
3905 // remoting proxies that are even more broken than the WCF one, e.g. returning random non-marshalbyref types
3906 // from Object.GetType().
3907 ret = FALSE;
3908 }
3909 else
3910 if (VMClsHnd == TypeHandle(g_pCanonMethodTableClass))
3911 {
3912 // We can't do this optimization in shared generics code because of we do not know what the actual type is going to be.
3913 // (It can be array, marshalbyref, etc.)
3914 ret = FALSE;
3915 }
3916 else
3917 {
3918 // It is safe to perform this optimization
3919 ret = TRUE;
3920 }
3921
3922 EE_TO_JIT_TRANSITION_LEAF();
3923
3924 return(ret);
3925}
3926
3927/*********************************************************************/
3928DWORD CEEInfo::getClassAttribs (CORINFO_CLASS_HANDLE clsHnd)
3929{
3930 CONTRACTL {
3931 SO_TOLERANT;
3932 THROWS;
3933 GC_TRIGGERS;
3934 MODE_PREEMPTIVE;
3935 } CONTRACTL_END;
3936
3937 // <REVISIT_TODO>@todo FIX need to really fetch the class atributes. at present
3938 // we don't need to because the JIT only cares in the case of COM classes</REVISIT_TODO>
3939 DWORD ret = 0;
3940
3941 JIT_TO_EE_TRANSITION();
3942
3943 ret = getClassAttribsInternal(clsHnd);
3944
3945 EE_TO_JIT_TRANSITION();
3946
3947 return ret;
3948}
3949
3950
3951/*********************************************************************/
3952BOOL CEEInfo::isStructRequiringStackAllocRetBuf(CORINFO_CLASS_HANDLE clsHnd)
3953{
3954 CONTRACTL {
3955 SO_TOLERANT;
3956 THROWS;
3957 GC_TRIGGERS;
3958 MODE_PREEMPTIVE;
3959 } CONTRACTL_END;
3960
3961 BOOL ret = 0;
3962
3963 JIT_TO_EE_TRANSITION_LEAF();
3964
3965 TypeHandle VMClsHnd(clsHnd);
3966 MethodTable * pMT = VMClsHnd.GetMethodTable();
3967 ret = (pMT != NULL && pMT->IsStructRequiringStackAllocRetBuf());
3968
3969 EE_TO_JIT_TRANSITION_LEAF();
3970
3971 return ret;
3972}
3973
3974/*********************************************************************/
3975DWORD CEEInfo::getClassAttribsInternal (CORINFO_CLASS_HANDLE clsHnd)
3976{
3977 STANDARD_VM_CONTRACT;
3978
3979 DWORD ret = 0;
3980
3981 _ASSERTE(clsHnd);
3982
3983 TypeHandle VMClsHnd(clsHnd);
3984
3985 // Byrefs should only occur in method and local signatures, which are accessed
3986 // using ICorClassInfo and ICorClassInfo.getChildType.
3987 // So getClassAttribs() should not be called for byrefs
3988
3989 if (VMClsHnd.IsByRef())
3990 {
3991 _ASSERTE(!"Did findClass() return a Byref?");
3992 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
3993 }
3994 else if (VMClsHnd.IsGenericVariable())
3995 {
3996 //@GENERICSVER: for now, type variables simply report "variable".
3997 ret |= CORINFO_FLG_GENERIC_TYPE_VARIABLE;
3998 }
3999 else
4000 {
4001 MethodTable *pMT = VMClsHnd.GetMethodTable();
4002
4003 if (!pMT)
4004 {
4005 _ASSERTE(!"Did findClass() return a Byref?");
4006 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
4007 }
4008
4009 EEClass * pClass = pMT->GetClass();
4010
4011 // The array flag is used to identify the faked-up methods on
4012 // array types, i.e. .ctor, Get, Set and Address
4013 if (pMT->IsArray())
4014 ret |= CORINFO_FLG_ARRAY;
4015
4016 if (pMT->IsInterface())
4017 ret |= CORINFO_FLG_INTERFACE;
4018
4019 if (pMT->HasComponentSize())
4020 ret |= CORINFO_FLG_VAROBJSIZE;
4021
4022 if (pMT->IsValueType())
4023 {
4024 ret |= CORINFO_FLG_VALUECLASS;
4025
4026 if (pMT->IsByRefLike())
4027 ret |= CORINFO_FLG_CONTAINS_STACK_PTR;
4028
4029 if ((pClass->IsNotTightlyPacked() && (!pClass->IsManagedSequential() || pClass->HasExplicitSize())) ||
4030 pMT == g_TypedReferenceMT ||
4031 VMClsHnd.IsNativeValueType())
4032 {
4033 ret |= CORINFO_FLG_CUSTOMLAYOUT;
4034 }
4035
4036 if (pClass->IsUnsafeValueClass())
4037 ret |= CORINFO_FLG_UNSAFE_VALUECLASS;
4038 }
4039 if (pClass->HasExplicitFieldOffsetLayout() && pClass->HasOverLayedField())
4040 ret |= CORINFO_FLG_OVERLAPPING_FIELDS;
4041 if (VMClsHnd.IsCanonicalSubtype())
4042 ret |= CORINFO_FLG_SHAREDINST;
4043
4044 if (pMT->HasVariance())
4045 ret |= CORINFO_FLG_VARIANCE;
4046
4047 if (pMT->IsContextful())
4048 ret |= CORINFO_FLG_CONTEXTFUL;
4049
4050 if (pMT->IsMarshaledByRef())
4051 ret |= CORINFO_FLG_MARSHAL_BYREF;
4052
4053 if (pMT->ContainsPointers() || pMT == g_TypedReferenceMT)
4054 ret |= CORINFO_FLG_CONTAINS_GC_PTR;
4055
4056 if (pMT->IsDelegate())
4057 ret |= CORINFO_FLG_DELEGATE;
4058
4059 if (pClass->IsBeforeFieldInit())
4060 {
4061 if (IsReadyToRunCompilation() && !pMT->GetModule()->IsInCurrentVersionBubble())
4062 {
4063 // For version resiliency do not allow hoisting static constructors out of loops
4064 }
4065 else
4066 {
4067 ret |= CORINFO_FLG_BEFOREFIELDINIT;
4068 }
4069 }
4070
4071 if (pClass->IsAbstract())
4072 ret |= CORINFO_FLG_ABSTRACT;
4073
4074 if (pClass->IsSealed())
4075 ret |= CORINFO_FLG_FINAL;
4076
4077 if (pMT->IsIntrinsicType())
4078 ret |= CORINFO_FLG_INTRINSIC_TYPE;
4079 }
4080
4081 return ret;
4082}
4083
4084/*********************************************************************/
4085//
4086// See code:CorInfoFlag#ClassConstructionFlags for details.
4087//
4088CorInfoInitClassResult CEEInfo::initClass(
4089 CORINFO_FIELD_HANDLE field,
4090 CORINFO_METHOD_HANDLE method,
4091 CORINFO_CONTEXT_HANDLE context,
4092 BOOL speculative)
4093{
4094 CONTRACTL {
4095 SO_TOLERANT;
4096 THROWS;
4097 GC_TRIGGERS;
4098 MODE_PREEMPTIVE;
4099 } CONTRACTL_END;
4100
4101 DWORD result = CORINFO_INITCLASS_NOT_REQUIRED;
4102
4103 JIT_TO_EE_TRANSITION();
4104 {
4105
4106 // Do not bother figuring out the initialization if we are only verifying the method.
4107 if (isVerifyOnly())
4108 {
4109 result = CORINFO_INITCLASS_NOT_REQUIRED;
4110 goto exit;
4111 }
4112
4113 FieldDesc * pFD = (FieldDesc *)field;
4114 _ASSERTE(pFD == NULL || pFD->IsStatic());
4115
4116 MethodDesc * pMD = (MethodDesc *)method;
4117
4118 TypeHandle typeToInitTH = (pFD != NULL) ? pFD->GetEnclosingMethodTable() : GetTypeFromContext(context);
4119
4120 MethodDesc *methodBeingCompiled = m_pMethodBeingCompiled;
4121
4122 BOOL fMethodZappedOrNGen = methodBeingCompiled->IsZapped() || IsCompilingForNGen();
4123
4124 MethodTable *pTypeToInitMT = typeToInitTH.AsMethodTable();
4125
4126 // This should be the most common early-out case.
4127 if (fMethodZappedOrNGen)
4128 {
4129 if (pTypeToInitMT->IsClassPreInited())
4130 {
4131 result = CORINFO_INITCLASS_NOT_REQUIRED;
4132 goto exit;
4133 }
4134 }
4135 else
4136 {
4137#ifdef CROSSGEN_COMPILE
4138 _ASSERTE(FALSE);
4139#else // CROSSGEN_COMPILE
4140 if (pTypeToInitMT->IsClassInited())
4141 {
4142 // If the type is initialized there really is nothing to do.
4143 result = CORINFO_INITCLASS_INITIALIZED;
4144 goto exit;
4145 }
4146#endif // CROSSGEN_COMPILE
4147 }
4148
4149 if (pTypeToInitMT->IsGlobalClass())
4150 {
4151 // For both jitted and ngen code the global class is always considered initialized
4152 result = CORINFO_INITCLASS_NOT_REQUIRED;
4153 goto exit;
4154 }
4155
4156 bool fIgnoreBeforeFieldInit = false;
4157
4158 if (pFD == NULL)
4159 {
4160 if (!fIgnoreBeforeFieldInit && pTypeToInitMT->GetClass()->IsBeforeFieldInit())
4161 {
4162 // We can wait for field accesses to run .cctor
4163 result = CORINFO_INITCLASS_NOT_REQUIRED;
4164 goto exit;
4165 }
4166
4167 // Run .cctor on statics & constructors
4168 if (pMD->IsStatic())
4169 {
4170 // Except don't class construct on .cctor - it would be circular
4171 if (pMD->IsClassConstructor())
4172 {
4173 result = CORINFO_INITCLASS_NOT_REQUIRED;
4174 goto exit;
4175 }
4176 }
4177 else
4178 // According to the spec, we should be able to do this optimization for both reference and valuetypes.
4179 // To maintain backward compatibility, we are doing it for reference types only.
4180 // We don't do this for interfaces though, as those don't have instance constructors.
4181 if (!pMD->IsCtor() && !pTypeToInitMT->IsValueType() && !pTypeToInitMT->IsInterface())
4182 {
4183 // For instance methods of types with precise-initialization
4184 // semantics, we can assume that the .ctor triggerred the
4185 // type initialization.
4186 // This does not hold for NULL "this" object. However, the spec does
4187 // not require that case to work.
4188 result = CORINFO_INITCLASS_NOT_REQUIRED;
4189 goto exit;
4190 }
4191 }
4192
4193 if (pTypeToInitMT->IsSharedByGenericInstantiations())
4194 {
4195 // Shared generic code has to use helper. Moreover, tell JIT not to inline since
4196 // inlining of generic dictionary lookups is not supported.
4197 result = CORINFO_INITCLASS_USE_HELPER | CORINFO_INITCLASS_DONT_INLINE;
4198 goto exit;
4199 }
4200
4201 //
4202 // Try to prove that the initialization is not necessary because of nesting
4203 //
4204
4205 if (pFD == NULL)
4206 {
4207 // Handled above
4208 _ASSERTE(fIgnoreBeforeFieldInit || !pTypeToInitMT->GetClass()->IsBeforeFieldInit());
4209
4210 // Note that jit has both methods the same if asking whether to emit cctor
4211 // for a given method's code (as opposed to inlining codegen).
4212 if (context != MAKE_METHODCONTEXT(methodBeingCompiled) && pTypeToInitMT == methodBeingCompiled->GetMethodTable())
4213 {
4214 // If we're inling a call to a method in our own type, then we should already
4215 // have triggered the .cctor when caller was itself called.
4216 result = CORINFO_INITCLASS_NOT_REQUIRED;
4217 goto exit;
4218 }
4219 }
4220 else
4221 {
4222 // This optimization may cause static fields in reference types to be accessed without cctor being triggered
4223 // for NULL "this" object. It does not conform with what the spec says. However, we have been historically
4224 // doing it for perf reasons.
4225 if (!pTypeToInitMT->IsValueType() && !pTypeToInitMT->IsInterface() && !pTypeToInitMT->GetClass()->IsBeforeFieldInit())
4226 {
4227 if (pTypeToInitMT == GetTypeFromContext(context).AsMethodTable() || pTypeToInitMT == methodBeingCompiled->GetMethodTable())
4228 {
4229 // The class will be initialized by the time we access the field.
4230 result = CORINFO_INITCLASS_NOT_REQUIRED;
4231 goto exit;
4232 }
4233 }
4234
4235 // If we are currently compiling the class constructor for this static field access then we can skip the initClass
4236 if (methodBeingCompiled->GetMethodTable() == pTypeToInitMT && methodBeingCompiled->IsStatic() && methodBeingCompiled->IsClassConstructor())
4237 {
4238 // The class will be initialized by the time we access the field.
4239 result = CORINFO_INITCLASS_NOT_REQUIRED;
4240 goto exit;
4241 }
4242 }
4243
4244 if (fMethodZappedOrNGen)
4245 {
4246 // Well, because of code sharing we can't do anything at coge generation time.
4247 // We have to do it at runtime.
4248 result = CORINFO_INITCLASS_USE_HELPER;
4249 goto exit;
4250 }
4251
4252#ifndef CROSSGEN_COMPILE
4253 //
4254 // Optimizations for domain specific code
4255 //
4256
4257 // Allocate space for the local class if necessary, but don't trigger
4258 // class construction.
4259 DomainLocalModule *pModule = pTypeToInitMT->GetDomainLocalModule();
4260 pModule->PopulateClass(pTypeToInitMT);
4261
4262 if (pTypeToInitMT->IsClassInited())
4263 {
4264 result = CORINFO_INITCLASS_INITIALIZED;
4265 goto exit;
4266 }
4267#endif // CROSSGEN_COMPILE
4268
4269 result = CORINFO_INITCLASS_USE_HELPER;
4270 }
4271exit: ;
4272 EE_TO_JIT_TRANSITION();
4273
4274 return (CorInfoInitClassResult)result;
4275}
4276
4277
4278
4279void CEEInfo::classMustBeLoadedBeforeCodeIsRun (CORINFO_CLASS_HANDLE typeToLoadHnd)
4280{
4281 CONTRACTL {
4282 SO_TOLERANT;
4283 NOTHROW;
4284 GC_NOTRIGGER;
4285 MODE_PREEMPTIVE;
4286 } CONTRACTL_END;
4287
4288 JIT_TO_EE_TRANSITION_LEAF();
4289
4290 TypeHandle th = TypeHandle(typeToLoadHnd);
4291
4292 // Type handles returned to JIT at runtime are always fully loaded. Verify that it is the case.
4293 _ASSERTE(th.IsFullyLoaded());
4294
4295 EE_TO_JIT_TRANSITION_LEAF();
4296}
4297
4298/*********************************************************************/
4299void CEEInfo::methodMustBeLoadedBeforeCodeIsRun (CORINFO_METHOD_HANDLE methHnd)
4300{
4301 CONTRACTL {
4302 SO_TOLERANT;
4303 NOTHROW;
4304 GC_NOTRIGGER;
4305 MODE_PREEMPTIVE;
4306 } CONTRACTL_END;
4307
4308 JIT_TO_EE_TRANSITION_LEAF();
4309
4310 MethodDesc *pMD = (MethodDesc*) methHnd;
4311
4312 // MethodDescs returned to JIT at runtime are always fully loaded. Verify that it is the case.
4313 _ASSERTE(pMD->IsRestored() && pMD->GetMethodTable()->IsFullyLoaded());
4314
4315 EE_TO_JIT_TRANSITION_LEAF();
4316}
4317
4318/*********************************************************************/
4319CORINFO_METHOD_HANDLE CEEInfo::mapMethodDeclToMethodImpl(CORINFO_METHOD_HANDLE methHnd)
4320{
4321 CONTRACTL {
4322 SO_TOLERANT;
4323 THROWS;
4324 GC_TRIGGERS;
4325 MODE_PREEMPTIVE;
4326 } CONTRACTL_END;
4327
4328 CORINFO_METHOD_HANDLE result = NULL;
4329
4330 JIT_TO_EE_TRANSITION();
4331
4332 MethodDesc *pMD = GetMethod(methHnd);
4333 pMD = MethodTable::MapMethodDeclToMethodImpl(pMD);
4334 result = (CORINFO_METHOD_HANDLE) pMD;
4335
4336 EE_TO_JIT_TRANSITION();
4337
4338 return result;
4339}
4340
4341/*********************************************************************/
4342CORINFO_CLASS_HANDLE CEEInfo::getBuiltinClass(CorInfoClassId classId)
4343{
4344 CONTRACTL {
4345 SO_TOLERANT;
4346 THROWS;
4347 GC_TRIGGERS;
4348 MODE_PREEMPTIVE;
4349 } CONTRACTL_END;
4350
4351 CORINFO_CLASS_HANDLE result = (CORINFO_CLASS_HANDLE) 0;
4352
4353 JIT_TO_EE_TRANSITION();
4354
4355 switch (classId)
4356 {
4357 case CLASSID_SYSTEM_OBJECT:
4358 result = CORINFO_CLASS_HANDLE(g_pObjectClass);
4359 break;
4360 case CLASSID_TYPED_BYREF:
4361 result = CORINFO_CLASS_HANDLE(g_TypedReferenceMT);
4362 break;
4363 case CLASSID_TYPE_HANDLE:
4364 result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__TYPE_HANDLE));
4365 break;
4366 case CLASSID_FIELD_HANDLE:
4367 result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__FIELD_HANDLE));
4368 break;
4369 case CLASSID_METHOD_HANDLE:
4370 result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__METHOD_HANDLE));
4371 break;
4372 case CLASSID_ARGUMENT_HANDLE:
4373 result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__ARGUMENT_HANDLE));
4374 break;
4375 case CLASSID_STRING:
4376 result = CORINFO_CLASS_HANDLE(g_pStringClass);
4377 break;
4378 case CLASSID_RUNTIME_TYPE:
4379 result = CORINFO_CLASS_HANDLE(g_pRuntimeTypeClass);
4380 break;
4381 default:
4382 _ASSERTE(!"NYI: unknown classId");
4383 break;
4384 }
4385
4386 EE_TO_JIT_TRANSITION();
4387
4388 return result;
4389}
4390
4391
4392
4393/*********************************************************************/
4394CorInfoType CEEInfo::getTypeForPrimitiveValueClass(
4395 CORINFO_CLASS_HANDLE clsHnd)
4396{
4397 CONTRACTL {
4398 SO_TOLERANT;
4399 THROWS;
4400 GC_TRIGGERS;
4401 MODE_PREEMPTIVE;
4402 } CONTRACTL_END;
4403
4404 CorInfoType result = CORINFO_TYPE_UNDEF;
4405
4406 JIT_TO_EE_TRANSITION();
4407
4408 TypeHandle th(clsHnd);
4409 _ASSERTE (!th.IsGenericVariable());
4410
4411 MethodTable *pMT = th.GetMethodTable();
4412 PREFIX_ASSUME(pMT != NULL);
4413
4414 // Is it a non primitive struct such as
4415 // RuntimeTypeHandle, RuntimeMethodHandle, RuntimeArgHandle?
4416 if (pMT->IsValueType() &&
4417 !pMT->IsTruePrimitive() &&
4418 !pMT->IsEnum())
4419 {
4420 // default value CORINFO_TYPE_UNDEF is what we want
4421 }
4422 else
4423 {
4424 switch (th.GetInternalCorElementType())
4425 {
4426 case ELEMENT_TYPE_I1:
4427 case ELEMENT_TYPE_U1:
4428 case ELEMENT_TYPE_BOOLEAN:
4429 result = asCorInfoType(ELEMENT_TYPE_I1);
4430 break;
4431
4432 case ELEMENT_TYPE_I2:
4433 case ELEMENT_TYPE_U2:
4434 case ELEMENT_TYPE_CHAR:
4435 result = asCorInfoType(ELEMENT_TYPE_I2);
4436 break;
4437
4438 case ELEMENT_TYPE_I4:
4439 case ELEMENT_TYPE_U4:
4440 result = asCorInfoType(ELEMENT_TYPE_I4);
4441 break;
4442
4443 case ELEMENT_TYPE_I8:
4444 case ELEMENT_TYPE_U8:
4445 result = asCorInfoType(ELEMENT_TYPE_I8);
4446 break;
4447
4448 case ELEMENT_TYPE_I:
4449 case ELEMENT_TYPE_U:
4450 result = asCorInfoType(ELEMENT_TYPE_I);
4451 break;
4452
4453 case ELEMENT_TYPE_R4:
4454 result = asCorInfoType(ELEMENT_TYPE_R4);
4455 break;
4456
4457 case ELEMENT_TYPE_R8:
4458 result = asCorInfoType(ELEMENT_TYPE_R8);
4459 break;
4460
4461 case ELEMENT_TYPE_VOID:
4462 result = asCorInfoType(ELEMENT_TYPE_VOID);
4463 break;
4464
4465 case ELEMENT_TYPE_PTR:
4466 case ELEMENT_TYPE_FNPTR:
4467 result = asCorInfoType(ELEMENT_TYPE_PTR);
4468 break;
4469
4470 default:
4471 break;
4472 }
4473 }
4474
4475 EE_TO_JIT_TRANSITION();
4476
4477 return result;
4478}
4479
4480/*********************************************************************/
4481CorInfoType CEEInfo::getTypeForPrimitiveNumericClass(
4482 CORINFO_CLASS_HANDLE clsHnd)
4483{
4484 CONTRACTL{
4485 SO_TOLERANT;
4486 NOTHROW;
4487 GC_NOTRIGGER;
4488 MODE_PREEMPTIVE;
4489 } CONTRACTL_END;
4490
4491 CorInfoType result = CORINFO_TYPE_UNDEF;
4492
4493 JIT_TO_EE_TRANSITION_LEAF();
4494
4495 TypeHandle th(clsHnd);
4496 _ASSERTE (!th.IsGenericVariable());
4497
4498 CorElementType ty = th.GetSignatureCorElementType();
4499 switch (ty)
4500 {
4501 case ELEMENT_TYPE_I1:
4502 result = CORINFO_TYPE_BYTE;
4503 break;
4504 case ELEMENT_TYPE_U1:
4505 result = CORINFO_TYPE_UBYTE;
4506 break;
4507 case ELEMENT_TYPE_I2:
4508 result = CORINFO_TYPE_SHORT;
4509 break;
4510 case ELEMENT_TYPE_U2:
4511 result = CORINFO_TYPE_USHORT;
4512 break;
4513 case ELEMENT_TYPE_I4:
4514 result = CORINFO_TYPE_INT;
4515 break;
4516 case ELEMENT_TYPE_U4:
4517 result = CORINFO_TYPE_UINT;
4518 break;
4519 case ELEMENT_TYPE_I8:
4520 result = CORINFO_TYPE_LONG;
4521 break;
4522 case ELEMENT_TYPE_U8:
4523 result = CORINFO_TYPE_ULONG;
4524 break;
4525 case ELEMENT_TYPE_R4:
4526 result = CORINFO_TYPE_FLOAT;
4527 break;
4528 case ELEMENT_TYPE_R8:
4529 result = CORINFO_TYPE_DOUBLE;
4530 break;
4531
4532 default:
4533 // Error case, we will return CORINFO_TYPE_UNDEF
4534 break;
4535 }
4536
4537 JIT_TO_EE_TRANSITION_LEAF();
4538
4539 return result;
4540}
4541
4542
4543void CEEInfo::getGSCookie(GSCookie * pCookieVal, GSCookie ** ppCookieVal)
4544{
4545 CONTRACTL {
4546 SO_TOLERANT;
4547 THROWS;
4548 GC_TRIGGERS;
4549 MODE_PREEMPTIVE;
4550 } CONTRACTL_END;
4551
4552 JIT_TO_EE_TRANSITION();
4553
4554 if (pCookieVal)
4555 {
4556 *pCookieVal = GetProcessGSCookie();
4557 *ppCookieVal = NULL;
4558 }
4559 else
4560 {
4561 *ppCookieVal = GetProcessGSCookiePtr();
4562 }
4563
4564 EE_TO_JIT_TRANSITION();
4565}
4566
4567
4568/*********************************************************************/
4569// TRUE if child is a subtype of parent
4570// if parent is an interface, then does child implement / extend parent
4571BOOL CEEInfo::canCast(
4572 CORINFO_CLASS_HANDLE child,
4573 CORINFO_CLASS_HANDLE parent)
4574{
4575 CONTRACTL {
4576 SO_TOLERANT;
4577 THROWS;
4578 GC_TRIGGERS;
4579 MODE_PREEMPTIVE;
4580 } CONTRACTL_END;
4581
4582 BOOL result = FALSE;
4583
4584 JIT_TO_EE_TRANSITION();
4585
4586 result = ((TypeHandle)child).CanCastTo((TypeHandle)parent);
4587
4588 EE_TO_JIT_TRANSITION();
4589
4590 return result;
4591}
4592
4593/*********************************************************************/
4594// TRUE if cls1 and cls2 are considered equivalent types.
4595BOOL CEEInfo::areTypesEquivalent(
4596 CORINFO_CLASS_HANDLE cls1,
4597 CORINFO_CLASS_HANDLE cls2)
4598{
4599 CONTRACTL {
4600 SO_TOLERANT;
4601 THROWS;
4602 GC_TRIGGERS;
4603 MODE_PREEMPTIVE;
4604 } CONTRACTL_END;
4605
4606 BOOL result = FALSE;
4607
4608 JIT_TO_EE_TRANSITION();
4609
4610 result = ((TypeHandle)cls1).IsEquivalentTo((TypeHandle)cls2);
4611
4612 EE_TO_JIT_TRANSITION();
4613
4614 return result;
4615}
4616
4617/*********************************************************************/
4618// See if a cast from fromClass to toClass will succeed, fail, or needs
4619// to be resolved at runtime.
4620TypeCompareState CEEInfo::compareTypesForCast(
4621 CORINFO_CLASS_HANDLE fromClass,
4622 CORINFO_CLASS_HANDLE toClass)
4623{
4624 CONTRACTL {
4625 SO_TOLERANT;
4626 THROWS;
4627 GC_TRIGGERS;
4628 MODE_PREEMPTIVE;
4629 } CONTRACTL_END;
4630
4631 TypeCompareState result = TypeCompareState::May;
4632
4633 JIT_TO_EE_TRANSITION();
4634
4635 TypeHandle fromHnd = (TypeHandle) fromClass;
4636 TypeHandle toHnd = (TypeHandle) toClass;
4637
4638#ifdef FEATURE_COMINTEROP
4639 // If casting from a com object class, don't try to optimize.
4640 if (fromHnd.IsComObjectType())
4641 {
4642 result = TypeCompareState::May;
4643 }
4644 else
4645#endif // FEATURE_COMINTEROP
4646
4647 // If casting from ICastable, don't try to optimize
4648 if (fromHnd.GetMethodTable()->IsICastable())
4649 {
4650 result = TypeCompareState::May;
4651 }
4652 // If casting to Nullable<T>, don't try to optimize
4653 else if (Nullable::IsNullableType(toHnd))
4654 {
4655 result = TypeCompareState::May;
4656 }
4657 // If the types are not shared, we can check directly.
4658 else if (!fromHnd.IsCanonicalSubtype() && !toHnd.IsCanonicalSubtype())
4659 {
4660 result = fromHnd.CanCastTo(toHnd) ? TypeCompareState::Must : TypeCompareState::MustNot;
4661 }
4662 // Casting from a shared type to an unshared type.
4663 else if (fromHnd.IsCanonicalSubtype() && !toHnd.IsCanonicalSubtype())
4664 {
4665 // Only handle casts to interface types for now
4666 if (toHnd.IsInterface())
4667 {
4668 // Do a preliminary check.
4669 BOOL canCast = fromHnd.CanCastTo(toHnd);
4670
4671 // Pass back positive results unfiltered. The unknown type
4672 // parameters in fromClass did not come into play.
4673 if (canCast)
4674 {
4675 result = TypeCompareState::Must;
4676 }
4677 // For negative results, the unknown type parameter in
4678 // fromClass might match some instantiated interface,
4679 // either directly or via variance.
4680 //
4681 // However, CanCastTo will report failure in such cases since
4682 // __Canon won't match the instantiated type on the
4683 // interface (which can't be __Canon since we screened out
4684 // canonical subtypes for toClass above). So only report
4685 // failure if the interface is not instantiated.
4686 else if (!toHnd.HasInstantiation())
4687 {
4688 result = TypeCompareState::MustNot;
4689 }
4690 }
4691 }
4692
4693#ifdef FEATURE_READYTORUN_COMPILER
4694 // In R2R it is a breaking change for a previously positive
4695 // cast to become negative, but not for a previously negative
4696 // cast to become positive. So in R2R a negative result is
4697 // always reported back as May.
4698 if (IsReadyToRunCompilation() && (result == TypeCompareState::MustNot))
4699 {
4700 result = TypeCompareState::May;
4701 }
4702#endif // FEATURE_READYTORUN_COMPILER
4703
4704 EE_TO_JIT_TRANSITION();
4705
4706 return result;
4707}
4708
4709/*********************************************************************/
4710// See if types represented by cls1 and cls2 compare equal, not
4711// equal, or the comparison needs to be resolved at runtime.
4712TypeCompareState CEEInfo::compareTypesForEquality(
4713 CORINFO_CLASS_HANDLE cls1,
4714 CORINFO_CLASS_HANDLE cls2)
4715{
4716 CONTRACTL {
4717 SO_TOLERANT;
4718 THROWS;
4719 GC_TRIGGERS;
4720 MODE_PREEMPTIVE;
4721 } CONTRACTL_END;
4722
4723 TypeCompareState result = TypeCompareState::May;
4724
4725 JIT_TO_EE_TRANSITION();
4726
4727 TypeHandle hnd1 = (TypeHandle) cls1;
4728 TypeHandle hnd2 = (TypeHandle) cls2;
4729
4730 // If neither type is a canonical subtype, type handle comparison suffices
4731 if (!hnd1.IsCanonicalSubtype() && !hnd2.IsCanonicalSubtype())
4732 {
4733 result = (hnd1 == hnd2 ? TypeCompareState::Must : TypeCompareState::MustNot);
4734 }
4735 // If either or both types are canonical subtypes, we can sometimes prove inequality.
4736 else
4737 {
4738 // If either is a value type then the types cannot
4739 // be equal unless the type defs are the same.
4740 if (hnd1.IsValueType() || hnd2.IsValueType())
4741 {
4742 if (!hnd1.GetMethodTable()->HasSameTypeDefAs(hnd2.GetMethodTable()))
4743 {
4744 result = TypeCompareState::MustNot;
4745 }
4746 }
4747 // If we have two ref types that are not __Canon, then the
4748 // types cannot be equal unless the type defs are the same.
4749 else
4750 {
4751 TypeHandle canonHnd = TypeHandle(g_pCanonMethodTableClass);
4752 if ((hnd1 != canonHnd) && (hnd2 != canonHnd))
4753 {
4754 if (!hnd1.GetMethodTable()->HasSameTypeDefAs(hnd2.GetMethodTable()))
4755 {
4756 result = TypeCompareState::MustNot;
4757 }
4758 }
4759 }
4760 }
4761
4762 EE_TO_JIT_TRANSITION();
4763
4764 return result;
4765}
4766
4767/*********************************************************************/
4768// returns is the intersection of cls1 and cls2.
4769CORINFO_CLASS_HANDLE CEEInfo::mergeClasses(
4770 CORINFO_CLASS_HANDLE cls1,
4771 CORINFO_CLASS_HANDLE cls2)
4772{
4773 CONTRACTL {
4774 SO_TOLERANT;
4775 THROWS;
4776 GC_TRIGGERS;
4777 MODE_PREEMPTIVE;
4778 } CONTRACTL_END;
4779
4780 CORINFO_CLASS_HANDLE result = NULL;
4781
4782 JIT_TO_EE_TRANSITION();
4783
4784 TypeHandle merged = TypeHandle::MergeTypeHandlesToCommonParent(TypeHandle(cls1), TypeHandle(cls2));
4785#ifdef _DEBUG
4786 {
4787 //Make sure the merge is reflexive in the cases we "support".
4788 TypeHandle hnd1 = TypeHandle(cls1);
4789 TypeHandle hnd2 = TypeHandle(cls2);
4790 TypeHandle reflexive = TypeHandle::MergeTypeHandlesToCommonParent(hnd2, hnd1);
4791
4792 //If both sides are classes than either they have a common non-interface parent (in which case it is
4793 //reflexive)
4794 //OR they share a common interface, and it can be order dependent (if they share multiple interfaces
4795 //in common)
4796 if (!hnd1.IsInterface() && !hnd2.IsInterface())
4797 {
4798 if (merged.IsInterface())
4799 {
4800 _ASSERTE(reflexive.IsInterface());
4801 }
4802 else
4803 {
4804 _ASSERTE(merged == reflexive);
4805 }
4806 }
4807 //Both results must either be interfaces or classes. They cannot be mixed.
4808 _ASSERTE((!!merged.IsInterface()) == (!!reflexive.IsInterface()));
4809
4810 //If the result of the merge was a class, then the result of the reflexive merge was the same class.
4811 if (!merged.IsInterface())
4812 {
4813 _ASSERTE(merged == reflexive);
4814 }
4815
4816 //If both sides are arrays, then the result is either an array or g_pArrayClass. The above is
4817 //actually true about the element type for references types, but I think that that is a little
4818 //excessive for sanity.
4819 if (hnd1.IsArray() && hnd2.IsArray())
4820 {
4821 _ASSERTE((merged.IsArray() && reflexive.IsArray())
4822 || ((merged == g_pArrayClass) && (reflexive == g_pArrayClass)));
4823 }
4824
4825 //Can I assert anything about generic variables?
4826
4827 //The results must always be assignable
4828 _ASSERTE(hnd1.CanCastTo(merged) && hnd2.CanCastTo(merged) && hnd1.CanCastTo(reflexive)
4829 && hnd2.CanCastTo(reflexive));
4830 }
4831#endif
4832 result = CORINFO_CLASS_HANDLE(merged.AsPtr());
4833
4834 EE_TO_JIT_TRANSITION();
4835 return result;
4836}
4837
4838/*********************************************************************/
4839// Given a class handle, returns the Parent type.
4840// For COMObjectType, it returns Class Handle of System.Object.
4841// Returns 0 if System.Object is passed in.
4842CORINFO_CLASS_HANDLE CEEInfo::getParentType(
4843 CORINFO_CLASS_HANDLE cls)
4844{
4845 CONTRACTL {
4846 SO_TOLERANT;
4847 THROWS;
4848 GC_TRIGGERS;
4849 MODE_PREEMPTIVE;
4850 } CONTRACTL_END;
4851
4852 CORINFO_CLASS_HANDLE result = NULL;
4853
4854 JIT_TO_EE_TRANSITION();
4855
4856 TypeHandle th(cls);
4857
4858 _ASSERTE(!th.IsNull());
4859 _ASSERTE(!th.IsGenericVariable());
4860
4861 TypeHandle thParent = th.GetParent();
4862
4863#ifdef FEATURE_COMINTEROP
4864 // If we encounter __ComObject in the hierarchy, we need to skip it
4865 // since this hierarchy is introduced by the EE, but won't be present
4866 // in the metadata.
4867 if (!thParent.IsNull() && IsComObjectClass(thParent))
4868 {
4869 result = (CORINFO_CLASS_HANDLE) g_pObjectClass;
4870 }
4871 else
4872#endif // FEATURE_COMINTEROP
4873 {
4874 result = CORINFO_CLASS_HANDLE(thParent.AsPtr());
4875 }
4876
4877 EE_TO_JIT_TRANSITION();
4878
4879 return result;
4880}
4881
4882
4883/*********************************************************************/
4884// Returns the CorInfoType of the "child type". If the child type is
4885// not a primitive type, *clsRet will be set.
4886// Given an Array of Type Foo, returns Foo.
4887// Given BYREF Foo, returns Foo
4888CorInfoType CEEInfo::getChildType (
4889 CORINFO_CLASS_HANDLE clsHnd,
4890 CORINFO_CLASS_HANDLE *clsRet
4891 )
4892{
4893 CONTRACTL {
4894 SO_TOLERANT;
4895 THROWS;
4896 GC_TRIGGERS;
4897 MODE_PREEMPTIVE;
4898 } CONTRACTL_END;
4899
4900 CorInfoType ret = CORINFO_TYPE_UNDEF;
4901 *clsRet = 0;
4902 TypeHandle retType = TypeHandle();
4903
4904 JIT_TO_EE_TRANSITION();
4905
4906 TypeHandle th(clsHnd);
4907
4908 _ASSERTE(!th.IsNull());
4909
4910 // BYREF, ARRAY types
4911 if (th.IsTypeDesc())
4912 {
4913 retType = th.AsTypeDesc()->GetTypeParam();
4914 }
4915 else
4916 {
4917 // <REVISIT_TODO> we really should not have this case. arrays type handles
4918 // used in the JIT interface should never be ordinary method tables,
4919 // indeed array type handles should really never be ordinary MTs
4920 // at all. Perhaps we should assert !th.IsTypeDesc() && th.AsMethodTable().IsArray()? </REVISIT_TODO>
4921 MethodTable* pMT= th.AsMethodTable();
4922 if (pMT->IsArray())
4923 retType = pMT->GetApproxArrayElementTypeHandle();
4924 }
4925
4926 if (!retType.IsNull()) {
4927 CorElementType type = retType.GetInternalCorElementType();
4928 ret = CEEInfo::asCorInfoType(type,retType, clsRet);
4929
4930 // <REVISIT_TODO>What if this one is a value array ?</REVISIT_TODO>
4931 }
4932
4933 EE_TO_JIT_TRANSITION();
4934
4935 return ret;
4936}
4937
4938/*********************************************************************/
4939// Check any constraints on class type arguments
4940BOOL CEEInfo::satisfiesClassConstraints(CORINFO_CLASS_HANDLE cls)
4941{
4942 CONTRACTL {
4943 SO_TOLERANT;
4944 THROWS;
4945 GC_TRIGGERS;
4946 MODE_PREEMPTIVE;
4947 } CONTRACTL_END;
4948
4949 BOOL result = FALSE;
4950
4951 JIT_TO_EE_TRANSITION();
4952
4953 _ASSERTE(cls != NULL);
4954 result = TypeHandle(cls).SatisfiesClassConstraints();
4955
4956 EE_TO_JIT_TRANSITION();
4957
4958 return result;
4959}
4960
4961/*********************************************************************/
4962// Check if this is a single dimensional array type
4963BOOL CEEInfo::isSDArray(CORINFO_CLASS_HANDLE cls)
4964{
4965 CONTRACTL {
4966 SO_TOLERANT;
4967 THROWS;
4968 GC_TRIGGERS;
4969 MODE_PREEMPTIVE;
4970 } CONTRACTL_END;
4971
4972 BOOL result = FALSE;
4973
4974 JIT_TO_EE_TRANSITION();
4975
4976 TypeHandle th(cls);
4977
4978 _ASSERTE(!th.IsNull());
4979
4980 if (th.IsArrayType())
4981 {
4982 // Lots of code used to think that System.Array's methodtable returns TRUE for IsArray(). It doesn't.
4983 _ASSERTE(th != TypeHandle(g_pArrayClass));
4984
4985 result = (th.GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY);
4986 }
4987
4988 EE_TO_JIT_TRANSITION();
4989
4990 return result;
4991}
4992
4993/*********************************************************************/
4994// Get the number of dimensions in an array
4995unsigned CEEInfo::getArrayRank(CORINFO_CLASS_HANDLE cls)
4996{
4997 CONTRACTL {
4998 SO_TOLERANT;
4999 THROWS;
5000 GC_TRIGGERS;
5001 MODE_PREEMPTIVE;
5002 } CONTRACTL_END;
5003
5004 unsigned result = 0;
5005
5006 JIT_TO_EE_TRANSITION();
5007
5008 TypeHandle th(cls);
5009
5010 _ASSERTE(!th.IsNull());
5011
5012 if (th.IsArrayType())
5013 {
5014 // Lots of code used to think that System.Array's methodtable returns TRUE for IsArray(). It doesn't.
5015 _ASSERTE(th != TypeHandle(g_pArrayClass));
5016
5017 result = th.GetPossiblySharedArrayMethodTable()->GetRank();
5018 }
5019
5020 EE_TO_JIT_TRANSITION();
5021
5022 return result;
5023}
5024
5025/*********************************************************************/
5026// Get static field data for an array
5027// Note that it's OK to return NULL from this method. This will cause
5028// the JIT to make a runtime call to InitializeArray instead of doing
5029// the inline optimization (thus preserving the original behavior).
5030void * CEEInfo::getArrayInitializationData(
5031 CORINFO_FIELD_HANDLE field,
5032 DWORD size
5033 )
5034{
5035 CONTRACTL {
5036 SO_TOLERANT;
5037 THROWS;
5038 GC_TRIGGERS;
5039 MODE_PREEMPTIVE;
5040 } CONTRACTL_END;
5041
5042 void * result = NULL;
5043
5044 JIT_TO_EE_TRANSITION();
5045
5046 FieldDesc* pField = (FieldDesc*) field;
5047
5048 if (!pField ||
5049 !pField->IsRVA() ||
5050 (pField->LoadSize() < size)
5051#ifdef FEATURE_NATIVE_IMAGE_GENERATION
5052 // This will make sure that when IBC logging is on, the array initialization happens thru
5053 // COMArrayInfo::InitializeArray. This gives a place to put the IBC probe that can help
5054 // separate hold and cold RVA blobs.
5055 || (IsCompilingForNGen() &&
5056 GetAppDomain()->ToCompilationDomain()->m_fForceInstrument)
5057#endif // FEATURE_NATIVE_IMAGE_GENERATION
5058 )
5059 {
5060 result = NULL;
5061 }
5062 else
5063 {
5064 result = pField->GetStaticAddressHandle(NULL);
5065 }
5066
5067 EE_TO_JIT_TRANSITION();
5068
5069 return result;
5070}
5071
5072CorInfoIsAccessAllowedResult CEEInfo::canAccessClass(
5073 CORINFO_RESOLVED_TOKEN * pResolvedToken,
5074 CORINFO_METHOD_HANDLE callerHandle,
5075 CORINFO_HELPER_DESC *pAccessHelper
5076 )
5077{
5078 CONTRACTL {
5079 SO_TOLERANT;
5080 THROWS;
5081 GC_TRIGGERS;
5082 MODE_PREEMPTIVE;
5083 } CONTRACTL_END;
5084
5085 CorInfoIsAccessAllowedResult isAccessAllowed = CORINFO_ACCESS_ALLOWED;
5086
5087 JIT_TO_EE_TRANSITION();
5088
5089 INDEBUG(memset(pAccessHelper, 0xCC, sizeof(*pAccessHelper)));
5090
5091 BOOL doAccessCheck = TRUE;
5092 AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
5093 DynamicResolver * pAccessContext = NULL;
5094
5095 //All access checks must be done on the open instantiation.
5096 MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle);
5097 TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
5098
5099 TypeHandle pCalleeForSecurity = TypeHandle(pResolvedToken->hClass);
5100 if (pResolvedToken->pTypeSpec != NULL)
5101 {
5102 SigTypeContext typeContext;
5103 SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
5104
5105 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
5106 pCalleeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
5107 }
5108
5109 while (pCalleeForSecurity.HasTypeParam())
5110 {
5111 pCalleeForSecurity = pCalleeForSecurity.GetTypeParam();
5112 }
5113
5114 if (IsDynamicScope(pResolvedToken->tokenScope))
5115 {
5116 doAccessCheck = ModifyCheckForDynamicMethod(GetDynamicResolver(pResolvedToken->tokenScope),
5117 &callerTypeForSecurity, &accessCheckType,
5118 &pAccessContext);
5119 }
5120
5121 //Since this is a check against a TypeHandle, there are some things we can stick in a TypeHandle that
5122 //don't require access checks.
5123 if (pCalleeForSecurity.IsGenericVariable())
5124 {
5125 //I don't need to check for access against !!0.
5126 doAccessCheck = FALSE;
5127 }
5128
5129 //Now do the visibility checks
5130 if (doAccessCheck)
5131 {
5132 AccessCheckOptions accessCheckOptions(accessCheckType,
5133 pAccessContext,
5134 FALSE /*throw on error*/,
5135 pCalleeForSecurity.GetMethodTable());
5136
5137 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
5138 StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
5139
5140 BOOL canAccessType = ClassLoader::CanAccessClass(&accessContext,
5141 pCalleeForSecurity.GetMethodTable(),
5142 pCalleeForSecurity.GetAssembly(),
5143 accessCheckOptions);
5144
5145 isAccessAllowed = canAccessType ? CORINFO_ACCESS_ALLOWED : CORINFO_ACCESS_ILLEGAL;
5146 }
5147
5148
5149 if (isAccessAllowed != CORINFO_ACCESS_ALLOWED)
5150 {
5151 //These all get the throw helper
5152 pAccessHelper->helperNum = CORINFO_HELP_CLASS_ACCESS_EXCEPTION;
5153 pAccessHelper->numArgs = 2;
5154
5155 pAccessHelper->args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
5156 pAccessHelper->args[1].Set(CORINFO_CLASS_HANDLE(pCalleeForSecurity.AsPtr()));
5157
5158 if (IsCompilingForNGen())
5159 {
5160 //see code:CEEInfo::getCallInfo for more information.
5161 if (pCallerForSecurity->ContainsGenericVariables() || pCalleeForSecurity.ContainsGenericVariables())
5162 COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic TypeHandle"));
5163 }
5164 }
5165
5166 EE_TO_JIT_TRANSITION();
5167 return isAccessAllowed;
5168}
5169
5170/***********************************************************************/
5171// return the address of a pointer to a callable stub that will do the
5172// virtual or interface call
5173void CEEInfo::getCallInfo(
5174 CORINFO_RESOLVED_TOKEN * pResolvedToken,
5175 CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken,
5176 CORINFO_METHOD_HANDLE callerHandle,
5177 CORINFO_CALLINFO_FLAGS flags,
5178 CORINFO_CALL_INFO *pResult /*out */)
5179{
5180 CONTRACTL {
5181 SO_TOLERANT;
5182 THROWS;
5183 GC_TRIGGERS;
5184 MODE_PREEMPTIVE;
5185 } CONTRACTL_END;
5186
5187 JIT_TO_EE_TRANSITION();
5188
5189 _ASSERTE(CheckPointer(pResult));
5190
5191 INDEBUG(memset(pResult, 0xCC, sizeof(*pResult)));
5192
5193 pResult->stubLookup.lookupKind.needsRuntimeLookup = false;
5194
5195 MethodDesc* pMD = (MethodDesc *)pResolvedToken->hMethod;
5196 TypeHandle th(pResolvedToken->hClass);
5197
5198 _ASSERTE(pMD);
5199 _ASSERTE((size_t(pMD) & 0x1) == 0);
5200
5201 // Spec says that a callvirt lookup ignores static methods. Since static methods
5202 // can't have the exact same signature as instance methods, a lookup that found
5203 // a static method would have never found an instance method.
5204 if (pMD->IsStatic() && (flags & CORINFO_CALLINFO_CALLVIRT))
5205 {
5206 EX_THROW(EEMessageException, (kMissingMethodException, IDS_EE_MISSING_METHOD, W("?")));
5207 }
5208
5209 TypeHandle exactType = TypeHandle(pResolvedToken->hClass);
5210
5211 TypeHandle constrainedType;
5212 if ((flags & CORINFO_CALLINFO_CALLVIRT) && (pConstrainedResolvedToken != NULL))
5213 {
5214 constrainedType = TypeHandle(pConstrainedResolvedToken->hClass);
5215 }
5216
5217 BOOL fResolvedConstraint = FALSE;
5218 BOOL fForceUseRuntimeLookup = FALSE;
5219
5220 MethodDesc * pMDAfterConstraintResolution = pMD;
5221 if (constrainedType.IsNull())
5222 {
5223 pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
5224 }
5225 // <NICE> Things go wrong when this code path is used when verifying generic code.
5226 // It would be nice if we didn't go down this sort of code path when verifying but
5227 // not generating code. </NICE>
5228 else if (constrainedType.ContainsGenericVariables() || exactType.ContainsGenericVariables())
5229 {
5230 // <NICE> It shouldn't really matter what we do here - but the x86 JIT is annoyingly sensitive
5231 // about what we do, since it pretend generic variables are reference types and generates
5232 // an internal JIT tree even when just verifying generic code. </NICE>
5233 if (constrainedType.IsGenericVariable())
5234 {
5235 pResult->thisTransform = CORINFO_DEREF_THIS; // convert 'this' of type &T --> T
5236 }
5237 else if (constrainedType.IsValueType())
5238 {
5239 pResult->thisTransform = CORINFO_BOX_THIS; // convert 'this' of type &VC<T> --> boxed(VC<T>)
5240 }
5241 else
5242 {
5243 pResult->thisTransform = CORINFO_DEREF_THIS; // convert 'this' of type &C<T> --> C<T>
5244 }
5245 }
5246 else
5247 {
5248 // We have a "constrained." call. Try a partial resolve of the constraint call. Note that this
5249 // will not necessarily resolve the call exactly, since we might be compiling
5250 // shared generic code - it may just resolve it to a candidate suitable for
5251 // JIT compilation, and require a runtime lookup for the actual code pointer
5252 // to call.
5253 if (constrainedType.IsEnum())
5254 {
5255 // Optimize constrained calls to enum's GetHashCode method. TryResolveConstraintMethodApprox would return
5256 // null since the virtual method resolves to System.Enum's implementation and that's a reference type.
5257 // We can't do this for any other method since ToString and Equals have different semantics for enums
5258 // and their underlying type.
5259 if (pMD->GetSlot() == MscorlibBinder::GetMethod(METHOD__OBJECT__GET_HASH_CODE)->GetSlot())
5260 {
5261 // Pretend this was a "constrained. UnderlyingType" instruction prefix
5262 constrainedType = TypeHandle(MscorlibBinder::GetElementType(constrainedType.GetVerifierCorElementType()));
5263
5264 // Native image signature encoder will use this field. It needs to match that pretended type, a bogus signature
5265 // would be produced otherwise.
5266 pConstrainedResolvedToken->hClass = (CORINFO_CLASS_HANDLE)constrainedType.AsPtr();
5267
5268 // Clear the token and typespec because of they do not match hClass anymore.
5269 pConstrainedResolvedToken->token = mdTokenNil;
5270 pConstrainedResolvedToken->pTypeSpec = NULL;
5271 }
5272 }
5273
5274 MethodDesc * directMethod = constrainedType.GetMethodTable()->TryResolveConstraintMethodApprox(
5275 exactType,
5276 pMD,
5277 &fForceUseRuntimeLookup);
5278 if (directMethod)
5279 {
5280 // Either
5281 // 1. no constraint resolution at compile time (!directMethod)
5282 // OR 2. no code sharing lookup in call
5283 // OR 3. we have have resolved to an instantiating stub
5284
5285 pMDAfterConstraintResolution = directMethod;
5286 _ASSERTE(!pMDAfterConstraintResolution->IsInterface());
5287 fResolvedConstraint = TRUE;
5288 pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
5289
5290 exactType = constrainedType;
5291 }
5292 else if (constrainedType.IsValueType())
5293 {
5294 pResult->thisTransform = CORINFO_BOX_THIS;
5295 }
5296 else
5297 {
5298 pResult->thisTransform = CORINFO_DEREF_THIS;
5299 }
5300 }
5301
5302 //
5303 // Initialize callee context used for inlining and instantiation arguments
5304 //
5305
5306 MethodDesc * pTargetMD = pMDAfterConstraintResolution;
5307
5308 if (pTargetMD->HasMethodInstantiation())
5309 {
5310 pResult->contextHandle = MAKE_METHODCONTEXT(pTargetMD);
5311 pResult->exactContextNeedsRuntimeLookup = pTargetMD->GetMethodTable()->IsSharedByGenericInstantiations() || TypeHandle::IsCanonicalSubtypeInstantiation(pTargetMD->GetMethodInstantiation());
5312 }
5313 else
5314 {
5315 if (!exactType.IsTypeDesc())
5316 {
5317 // Because of .NET's notion of base calls, exactType may point to a sub-class
5318 // of the actual class that defines pTargetMD. If the JIT decides to inline, it is
5319 // important that they 'match', so we fix exactType here.
5320#ifdef FEATURE_READYTORUN_COMPILER
5321 if (IsReadyToRunCompilation() &&
5322 !isVerifyOnly() &&
5323 !IsInSameVersionBubble((MethodDesc*)callerHandle, pTargetMD))
5324 {
5325 // For version resilient code we can only inline within the same version bubble;
5326 // we "repair" the precise types only for those callees.
5327 // The above condition needs to stay in sync with CEEInfo::canInline
5328 }
5329 else
5330#endif
5331 {
5332
5333 exactType = pTargetMD->GetExactDeclaringType(exactType.AsMethodTable());
5334 _ASSERTE(!exactType.IsNull());
5335 }
5336 }
5337
5338 pResult->contextHandle = MAKE_CLASSCONTEXT(exactType.AsPtr());
5339 pResult->exactContextNeedsRuntimeLookup = exactType.IsSharedByGenericInstantiations();
5340 }
5341
5342 //
5343 // Determine whether to perform direct call
5344 //
5345
5346 bool directCall = false;
5347 bool resolvedCallVirt = false;
5348 bool callVirtCrossingVersionBubble = false;
5349
5350 // Delegate targets are always treated as direct calls here. (It would be nice to clean it up...).
5351 if (flags & CORINFO_CALLINFO_LDFTN)
5352 {
5353 if (m_pOverride != NULL)
5354 TypeEquivalenceFixupSpecificationHelper(m_pOverride, pTargetMD);
5355 directCall = true;
5356 }
5357 else
5358 // Static methods are always direct calls
5359 if (pTargetMD->IsStatic())
5360 {
5361 directCall = true;
5362 }
5363 else
5364 // Backwards compat: calls to abstract interface methods are treated as callvirt
5365 if (pTargetMD->GetMethodTable()->IsInterface() && pTargetMD->IsAbstract())
5366 {
5367 directCall = false;
5368 }
5369 else
5370 if (!(flags & CORINFO_CALLINFO_CALLVIRT) || fResolvedConstraint)
5371 {
5372 directCall = true;
5373 }
5374 else
5375 {
5376 bool devirt;
5377
5378#ifdef FEATURE_READYTORUN_COMPILER
5379
5380 // if we are generating version resilient code
5381 // AND
5382 // caller/callee are in different version bubbles
5383 // we have to apply more restrictive rules
5384 // These rules are related to the "inlining rules" as far as the
5385 // boundaries of a version bubble are concerned.
5386
5387 if (IsReadyToRunCompilation() &&
5388 !isVerifyOnly() &&
5389 !IsInSameVersionBubble((MethodDesc*)callerHandle, pTargetMD)
5390 )
5391 {
5392 // For version resiliency we won't de-virtualize all final/sealed method calls. Because during a
5393 // servicing event it is legal to unseal a method or type.
5394 //
5395 // Note that it is safe to devirtualize in the following cases, since a servicing event cannot later modify it
5396 // 1) Callvirt on a virtual final method of a value type - since value types are sealed types as per ECMA spec
5397 // 2) Delegate.Invoke() - since a Delegate is a sealed class as per ECMA spec
5398 // 3) JIT intrinsics - since they have pre-defined behavior
5399 devirt = pTargetMD->GetMethodTable()->IsValueType() ||
5400 (pTargetMD->GetMethodTable()->IsDelegate() && ((DelegateEEClass*)(pTargetMD->GetMethodTable()->GetClass()))->GetInvokeMethod() == pMD) ||
5401 (pTargetMD->IsFCall() && ECall::GetIntrinsicID(pTargetMD) != CORINFO_INTRINSIC_Illegal);
5402
5403 callVirtCrossingVersionBubble = true;
5404 }
5405 else
5406#endif
5407 if (pTargetMD->GetMethodTable()->IsInterface())
5408 {
5409 // Handle interface methods specially because the Sealed bit has no meaning on interfaces.
5410 devirt = !IsMdVirtual(pTargetMD->GetAttrs());
5411 }
5412 else
5413 {
5414 DWORD dwMethodAttrs = pTargetMD->GetAttrs();
5415 devirt = !IsMdVirtual(dwMethodAttrs) || IsMdFinal(dwMethodAttrs) || pTargetMD->GetMethodTable()->IsSealed();
5416 }
5417
5418 if (devirt)
5419 {
5420 resolvedCallVirt = true;
5421 directCall = true;
5422 }
5423 }
5424
5425 if (directCall)
5426 {
5427 bool allowInstParam = (flags & CORINFO_CALLINFO_ALLOWINSTPARAM);
5428
5429 // Create instantiating stub if necesary
5430 if (!allowInstParam && pTargetMD->RequiresInstArg())
5431 {
5432 pTargetMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pTargetMD,
5433 exactType.AsMethodTable(),
5434 FALSE /* forceBoxedEntryPoint */,
5435 pTargetMD->GetMethodInstantiation(),
5436 FALSE /* allowInstParam */);
5437 }
5438
5439 // We don't allow a JIT to call the code directly if a runtime lookup is
5440 // needed. This is the case if
5441 // 1. the scan of the call token indicated that it involves code sharing
5442 // AND 2. the method is an instantiating stub
5443 //
5444 // In these cases the correct instantiating stub is only found via a runtime lookup.
5445 //
5446 // Note that most JITs don't call instantiating stubs directly if they can help it -
5447 // they call the underlying shared code and provide the type context parameter
5448 // explicitly. However
5449 // (a) some JITs may call instantiating stubs (it makes the JIT simpler) and
5450 // (b) if the method is a remote stub then the EE will force the
5451 // call through an instantiating stub and
5452 // (c) constraint calls that require runtime context lookup are never resolved
5453 // to underlying shared generic code
5454
5455 if (((pResult->exactContextNeedsRuntimeLookup && pTargetMD->IsInstantiatingStub() && (!allowInstParam || fResolvedConstraint)) || fForceUseRuntimeLookup)
5456 // Handle invalid IL - see comment in code:CEEInfo::ComputeRuntimeLookupForSharedGenericToken
5457 && ContextIsShared(pResolvedToken->tokenContext))
5458 {
5459 _ASSERTE(!m_pMethodBeingCompiled->IsDynamicMethod());
5460 pResult->kind = CORINFO_CALL_CODE_POINTER;
5461
5462 // For reference types, the constrained type does not affect method resolution
5463 DictionaryEntryKind entryKind = (!constrainedType.IsNull() && constrainedType.IsValueType()) ? ConstrainedMethodEntrySlot : MethodEntrySlot;
5464
5465 ComputeRuntimeLookupForSharedGenericToken(entryKind,
5466 pResolvedToken,
5467 pConstrainedResolvedToken,
5468 pMD,
5469 &pResult->codePointerLookup);
5470 }
5471 else
5472 {
5473 if (allowInstParam && pTargetMD->IsInstantiatingStub())
5474 {
5475 pTargetMD = pTargetMD->GetWrappedMethodDesc();
5476 }
5477
5478 pResult->kind = CORINFO_CALL;
5479
5480 if (IsReadyToRunCompilation())
5481 {
5482 // Compensate for always treating delegates as direct calls above
5483 if ((flags & CORINFO_CALLINFO_LDFTN) && (flags & CORINFO_CALLINFO_CALLVIRT) && !resolvedCallVirt)
5484 {
5485 pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN;
5486 }
5487 }
5488 }
5489 pResult->nullInstanceCheck = resolvedCallVirt;
5490 }
5491 // All virtual calls which take method instantiations must
5492 // currently be implemented by an indirect call via a runtime-lookup
5493 // function pointer
5494 else if (pTargetMD->HasMethodInstantiation())
5495 {
5496 pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN; // stub dispatch can't handle generic method calls yet
5497 pResult->nullInstanceCheck = TRUE;
5498 }
5499 // Non-interface dispatches go through the vtable.
5500 else if (!pTargetMD->IsInterface())
5501 {
5502 pResult->kind = CORINFO_VIRTUALCALL_VTABLE;
5503 pResult->nullInstanceCheck = TRUE;
5504
5505 // We'll special virtual calls to target methods in the corelib assembly when compiling in R2R mode, and generate fragile-NI-like callsites for improved performance. We
5506 // can do that because today we'll always service the corelib assembly and the runtime in one bundle. Any caller in the corelib version bubble can benefit from this
5507 // performance optimization.
5508 if (IsReadyToRunCompilation() && !CallerAndCalleeInSystemVersionBubble((MethodDesc*)callerHandle, pTargetMD))
5509 {
5510 pResult->kind = CORINFO_VIRTUALCALL_STUB;
5511 }
5512 }
5513 else
5514 {
5515 if (IsReadyToRunCompilation())
5516 {
5517 // Insert explicit null checks for cross-version bubble non-interface calls.
5518 // It is required to handle null checks properly for non-virtual <-> virtual change between versions
5519 pResult->nullInstanceCheck = !!(callVirtCrossingVersionBubble && !pTargetMD->IsInterface());
5520 }
5521 else
5522 {
5523 // No need to null check - the dispatch code will deal with null this.
5524 pResult->nullInstanceCheck = FALSE;
5525 }
5526#ifdef STUB_DISPATCH_PORTABLE
5527 pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN;
5528#else // STUB_DISPATCH_PORTABLE
5529 pResult->kind = CORINFO_VIRTUALCALL_STUB;
5530
5531 // We can't make stub calls when we need exact information
5532 // for interface calls from shared code.
5533
5534 if (// If the token is not shared then we don't need a runtime lookup
5535 pResult->exactContextNeedsRuntimeLookup
5536 // Handle invalid IL - see comment in code:CEEInfo::ComputeRuntimeLookupForSharedGenericToken
5537 && ContextIsShared(pResolvedToken->tokenContext))
5538 {
5539 _ASSERTE(!m_pMethodBeingCompiled->IsDynamicMethod());
5540
5541 ComputeRuntimeLookupForSharedGenericToken(DispatchStubAddrSlot,
5542 pResolvedToken,
5543 NULL,
5544 pMD,
5545 &pResult->stubLookup);
5546 }
5547 else
5548 {
5549 BYTE * indcell = NULL;
5550
5551 if (!(flags & CORINFO_CALLINFO_KINDONLY) && !isVerifyOnly())
5552 {
5553#ifndef CROSSGEN_COMPILE
5554 // We shouldn't be using GetLoaderAllocator here because for LCG, we need to get the
5555 // VirtualCallStubManager from where the stub will be used.
5556 // For normal methods there is no difference.
5557 LoaderAllocator *pLoaderAllocator = m_pMethodBeingCompiled->GetLoaderAllocatorForCode();
5558 VirtualCallStubManager *pMgr = pLoaderAllocator->GetVirtualCallStubManager();
5559
5560 PCODE addr = pMgr->GetCallStub(exactType, pTargetMD);
5561 _ASSERTE(pMgr->isStub(addr));
5562
5563 // Now we want to indirect through a cell so that updates can take place atomically.
5564 if (m_pMethodBeingCompiled->IsLCGMethod())
5565 {
5566 // LCG methods should use recycled indcells to prevent leaks.
5567 indcell = pMgr->GenerateStubIndirection(addr, TRUE);
5568
5569 // Add it to the per DM list so that we can recycle them when the resolver is finalized
5570 LCGMethodResolver *pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetLCGMethodResolver();
5571 pResolver->AddToUsedIndCellList(indcell);
5572 }
5573 else
5574 {
5575 // Normal methods should avoid recycled cells to preserve the locality of all indcells
5576 // used by one method.
5577 indcell = pMgr->GenerateStubIndirection(addr, FALSE);
5578 }
5579#else // CROSSGEN_COMPILE
5580 // This path should be unreachable during crossgen
5581 _ASSERTE(false);
5582#endif // CROSSGEN_COMPILE
5583 }
5584
5585 // We use an indirect call
5586 pResult->stubLookup.constLookup.accessType = IAT_PVALUE;
5587 pResult->stubLookup.constLookup.addr = indcell;
5588 }
5589#endif // STUB_DISPATCH_PORTABLE
5590 }
5591
5592 pResult->hMethod = CORINFO_METHOD_HANDLE(pTargetMD);
5593
5594 pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
5595 if ((flags & CORINFO_CALLINFO_SECURITYCHECKS) &&
5596 !((MethodDesc *)callerHandle)->IsILStub()) // IL stubs can access everything, don't bother doing access checks
5597 {
5598 //Our type system doesn't always represent the target exactly with the MethodDesc. In all cases,
5599 //carry around the parent MethodTable for both Caller and Callee.
5600 TypeHandle calleeTypeForSecurity = TypeHandle(pResolvedToken->hClass);
5601 MethodDesc * pCalleeForSecurity = pMD;
5602
5603 MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle); //Should this be the open MD?
5604
5605 if (pCallerForSecurity->HasClassOrMethodInstantiation())
5606 {
5607 _ASSERTE(!IsDynamicScope(pResolvedToken->tokenScope));
5608
5609 SigTypeContext typeContext;
5610 SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
5611 _ASSERTE(!typeContext.IsEmpty());
5612
5613 //If the caller is generic, load the open type and resolve the token again. Use that for the access
5614 //checks. If we don't do this then we can't tell the difference between:
5615 //
5616 //BadGeneric<T> containing a methodspec for InaccessibleType::member (illegal)
5617 //and
5618 //BadGeneric<T> containing a methodspec for !!0::member instantiated over InaccessibleType (legal)
5619
5620 if (pResolvedToken->pTypeSpec != NULL)
5621 {
5622 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
5623 calleeTypeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
5624
5625 // typeHnd can be a variable type
5626 if (calleeTypeForSecurity.GetMethodTable() == NULL)
5627 {
5628 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_METHODDEF_PARENT_NO_MEMBERS);
5629 }
5630 }
5631
5632 if (pCalleeForSecurity->IsArray())
5633 {
5634 // FindOrCreateAssociatedMethodDesc won't remap array method desc because of array base type
5635 // is not part of instantiation. We have to special case it.
5636 pCalleeForSecurity = calleeTypeForSecurity.GetMethodTable()->GetParallelMethodDesc(pCalleeForSecurity);
5637 }
5638 else
5639 if (pResolvedToken->pMethodSpec != NULL)
5640 {
5641 DWORD nGenericMethodArgs = 0;
5642 CQuickBytes qbGenericMethodArgs;
5643 TypeHandle *genericMethodArgs = NULL;
5644
5645 SigPointer sp(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
5646
5647 BYTE etype;
5648 IfFailThrow(sp.GetByte(&etype));
5649
5650 // Load the generic method instantiation
5651 THROW_BAD_FORMAT_MAYBE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST, 0, (Module *)pResolvedToken->tokenScope);
5652
5653 IfFailThrow(sp.GetData(&nGenericMethodArgs));
5654
5655 DWORD cbAllocSize = 0;
5656 if (!ClrSafeInt<DWORD>::multiply(nGenericMethodArgs, sizeof(TypeHandle), cbAllocSize))
5657 {
5658 COMPlusThrowHR(COR_E_OVERFLOW);
5659 }
5660
5661 genericMethodArgs = reinterpret_cast<TypeHandle *>(qbGenericMethodArgs.AllocThrows(cbAllocSize));
5662
5663 for (DWORD i = 0; i < nGenericMethodArgs; i++)
5664 {
5665 genericMethodArgs[i] = sp.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
5666 _ASSERTE (!genericMethodArgs[i].IsNull());
5667 IfFailThrow(sp.SkipExactlyOne());
5668 }
5669
5670 pCalleeForSecurity = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, calleeTypeForSecurity.GetMethodTable(), FALSE, Instantiation(genericMethodArgs, nGenericMethodArgs), FALSE);
5671 }
5672 else
5673 if (pResolvedToken->pTypeSpec != NULL)
5674 {
5675 pCalleeForSecurity = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, calleeTypeForSecurity.GetMethodTable(), FALSE, Instantiation(), TRUE);
5676 }
5677 }
5678
5679 TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
5680
5681 //Passed various link-time checks. Now do access checks.
5682
5683 BOOL doAccessCheck = TRUE;
5684 BOOL canAccessMethod = TRUE;
5685 AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
5686 DynamicResolver * pAccessContext = NULL;
5687
5688 callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
5689 if (pCallerForSecurity->IsDynamicMethod())
5690 {
5691 doAccessCheck = ModifyCheckForDynamicMethod(pCallerForSecurity->AsDynamicMethodDesc()->GetResolver(),
5692 &callerTypeForSecurity,
5693 &accessCheckType, &pAccessContext);
5694 }
5695
5696 pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
5697
5698 if (doAccessCheck)
5699 {
5700 AccessCheckOptions accessCheckOptions(accessCheckType,
5701 pAccessContext,
5702 FALSE,
5703 pCalleeForSecurity);
5704
5705 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
5706 StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
5707
5708 canAccessMethod = ClassLoader::CanAccess(&accessContext,
5709 calleeTypeForSecurity.GetMethodTable(),
5710 calleeTypeForSecurity.GetAssembly(),
5711 pCalleeForSecurity->GetAttrs(),
5712 pCalleeForSecurity,
5713 NULL,
5714 accessCheckOptions
5715 );
5716
5717 // If we were allowed access to the exact method, but it is on a type that has a type parameter
5718 // (for instance an array), we need to ensure that we also have access to the type parameter.
5719 if (canAccessMethod && calleeTypeForSecurity.HasTypeParam())
5720 {
5721 TypeHandle typeParam = calleeTypeForSecurity.GetTypeParam();
5722 while (typeParam.HasTypeParam())
5723 {
5724 typeParam = typeParam.GetTypeParam();
5725 }
5726
5727 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
5728 StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
5729
5730 MethodTable* pTypeParamMT = typeParam.GetMethodTable();
5731
5732 // No access check is need for Var, MVar, or FnPtr.
5733 if (pTypeParamMT != NULL)
5734 canAccessMethod = ClassLoader::CanAccessClass(&accessContext,
5735 pTypeParamMT,
5736 typeParam.GetAssembly(),
5737 accessCheckOptions);
5738 }
5739
5740 pResult->accessAllowed = canAccessMethod ? CORINFO_ACCESS_ALLOWED : CORINFO_ACCESS_ILLEGAL;
5741 if (!canAccessMethod)
5742 {
5743 //Check failed, fill in the throw exception helper.
5744 pResult->callsiteCalloutHelper.helperNum = CORINFO_HELP_METHOD_ACCESS_EXCEPTION;
5745 pResult->callsiteCalloutHelper.numArgs = 2;
5746
5747 pResult->callsiteCalloutHelper.args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
5748 pResult->callsiteCalloutHelper.args[1].Set(CORINFO_METHOD_HANDLE(pCalleeForSecurity));
5749
5750 //We now embed open instantiations in a few places for security callouts (since you can only
5751 //do the security check on the open instantiation). We throw these methods out in
5752 //TriageMethodForZap. In addition, NGen has problems referencing them properly. Just throw out the whole
5753 //method and rejit at runtime.
5754 if (IsCompilingForNGen())
5755 {
5756 if (pCallerForSecurity->ContainsGenericVariables()
5757 || pCalleeForSecurity->ContainsGenericVariables())
5758 {
5759 COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic MethodDesc"));
5760 }
5761 }
5762 }
5763 }
5764 }
5765
5766 //We're pretty much done at this point. Let's grab the rest of the information that the jit is going to
5767 //need.
5768 pResult->classFlags = getClassAttribsInternal(pResolvedToken->hClass);
5769
5770 pResult->methodFlags = getMethodAttribsInternal(pResult->hMethod);
5771
5772 SignatureKind signatureKind = flags & CORINFO_CALLINFO_CALLVIRT ? SK_VIRTUAL_CALLSITE : SK_CALLSITE;
5773 getMethodSigInternal(pResult->hMethod, &pResult->sig, (pResult->hMethod == pResolvedToken->hMethod) ? pResolvedToken->hClass : NULL, signatureKind);
5774
5775 if (flags & CORINFO_CALLINFO_VERIFICATION)
5776 {
5777 if (pResult->hMethod != pResolvedToken->hMethod)
5778 {
5779 pResult->verMethodFlags = getMethodAttribsInternal(pResolvedToken->hMethod);
5780 getMethodSigInternal(pResolvedToken->hMethod, &pResult->verSig, pResolvedToken->hClass);
5781 }
5782 else
5783 {
5784 pResult->verMethodFlags = pResult->methodFlags;
5785 pResult->verSig = pResult->sig;
5786 }
5787 }
5788
5789 pResult->secureDelegateInvoke = FALSE;
5790
5791#ifdef FEATURE_STUBS_AS_IL
5792 if (m_pMethodBeingCompiled->IsDynamicMethod())
5793 {
5794 auto pMD = m_pMethodBeingCompiled->AsDynamicMethodDesc();
5795 if (pMD->IsILStub() && pMD->IsSecureDelegateStub())
5796 {
5797 pResult->secureDelegateInvoke = TRUE;
5798 }
5799 }
5800#endif
5801
5802 EE_TO_JIT_TRANSITION();
5803}
5804
5805BOOL CEEInfo::canAccessFamily(CORINFO_METHOD_HANDLE hCaller,
5806 CORINFO_CLASS_HANDLE hInstanceType)
5807{
5808 WRAPPER_NO_CONTRACT;
5809
5810 BOOL ret = FALSE;
5811
5812 //Since this is only for verification, I don't need to do the demand.
5813 JIT_TO_EE_TRANSITION();
5814
5815 TypeHandle targetType = TypeHandle(hInstanceType);
5816 TypeHandle accessingType = TypeHandle(GetMethod(hCaller)->GetMethodTable());
5817 AccessCheckOptions::AccessCheckType accessCheckOptions = AccessCheckOptions::kNormalAccessibilityChecks;
5818 DynamicResolver* pIgnored;
5819 BOOL doCheck = TRUE;
5820 if (GetMethod(hCaller)->IsDynamicMethod())
5821 {
5822 //If this is a DynamicMethod, perform the check from the type to which the DynamicMethod was
5823 //attached.
5824 //
5825 //If this is a dynamic method, don't do this check. If they specified SkipVisibilityChecks
5826 //(ModifyCheckForDynamicMethod returned false), we should obviously skip the check for the C++
5827 //protected rule (since we skipped all the other visibility checks). If they specified
5828 //RestrictedSkipVisibilityChecks, then they're a "free" DynamicMethod. This check is meaningless
5829 //(i.e. it would always fail). We've already done a demand for access to the member. Let that be
5830 //enough.
5831 doCheck = ModifyCheckForDynamicMethod(GetMethod(hCaller)->AsDynamicMethodDesc()->GetResolver(),
5832 &accessingType, &accessCheckOptions, &pIgnored);
5833 if (accessCheckOptions == AccessCheckOptions::kRestrictedMemberAccess
5834 || accessCheckOptions == AccessCheckOptions::kRestrictedMemberAccessNoTransparency
5835 )
5836 doCheck = FALSE;
5837 }
5838
5839 if (doCheck)
5840 {
5841 ret = ClassLoader::CanAccessFamilyVerification(accessingType, targetType);
5842 }
5843 else
5844 {
5845 ret = TRUE;
5846 }
5847
5848 EE_TO_JIT_TRANSITION();
5849 return ret;
5850}
5851void CEEInfo::ThrowExceptionForHelper(const CORINFO_HELPER_DESC * throwHelper)
5852{
5853 CONTRACTL {
5854 SO_TOLERANT;
5855 THROWS;
5856 GC_TRIGGERS;
5857 MODE_PREEMPTIVE;
5858 } CONTRACTL_END;
5859
5860 JIT_TO_EE_TRANSITION();
5861
5862 _ASSERTE(throwHelper->args[0].argType == CORINFO_HELPER_ARG_TYPE_Method);
5863 MethodDesc *pCallerMD = GetMethod(throwHelper->args[0].methodHandle);
5864
5865 StaticAccessCheckContext accessContext(pCallerMD);
5866
5867 switch (throwHelper->helperNum)
5868 {
5869 case CORINFO_HELP_METHOD_ACCESS_EXCEPTION:
5870 {
5871 _ASSERTE(throwHelper->args[1].argType == CORINFO_HELPER_ARG_TYPE_Method);
5872 ThrowMethodAccessException(&accessContext, GetMethod(throwHelper->args[1].methodHandle));
5873 }
5874 break;
5875 case CORINFO_HELP_FIELD_ACCESS_EXCEPTION:
5876 {
5877 _ASSERTE(throwHelper->args[1].argType == CORINFO_HELPER_ARG_TYPE_Field);
5878 ThrowFieldAccessException(&accessContext, reinterpret_cast<FieldDesc *>(throwHelper->args[1].fieldHandle));
5879 }
5880 break;
5881 case CORINFO_HELP_CLASS_ACCESS_EXCEPTION:
5882 {
5883 _ASSERTE(throwHelper->args[1].argType == CORINFO_HELPER_ARG_TYPE_Class);
5884 TypeHandle typeHnd(throwHelper->args[1].classHandle);
5885 ThrowTypeAccessException(&accessContext, typeHnd.GetMethodTable());
5886 }
5887 break;
5888
5889 default:
5890 _ASSERTE(!"Unknown access exception type");
5891 }
5892 EE_TO_JIT_TRANSITION();
5893}
5894
5895
5896BOOL CEEInfo::isRIDClassDomainID(CORINFO_CLASS_HANDLE cls)
5897{
5898 CONTRACTL {
5899 SO_TOLERANT;
5900 THROWS;
5901 GC_TRIGGERS;
5902 MODE_PREEMPTIVE;
5903 } CONTRACTL_END;
5904
5905 BOOL result = FALSE;
5906
5907 JIT_TO_EE_TRANSITION();
5908
5909 TypeHandle VMClsHnd(cls);
5910
5911 result = !VMClsHnd.AsMethodTable()->IsDynamicStatics();
5912
5913 EE_TO_JIT_TRANSITION();
5914
5915 return result;
5916}
5917
5918
5919/***********************************************************************/
5920unsigned CEEInfo::getClassDomainID (CORINFO_CLASS_HANDLE clsHnd,
5921 void **ppIndirection)
5922{
5923 CONTRACTL {
5924 SO_TOLERANT;
5925 THROWS;
5926 GC_TRIGGERS;
5927 MODE_PREEMPTIVE;
5928 } CONTRACTL_END;
5929
5930 unsigned result = 0;
5931
5932 if (ppIndirection != NULL)
5933 *ppIndirection = NULL;
5934
5935 JIT_TO_EE_TRANSITION();
5936
5937 TypeHandle VMClsHnd(clsHnd);
5938
5939 if (VMClsHnd.AsMethodTable()->IsDynamicStatics())
5940 {
5941 result = (unsigned)VMClsHnd.AsMethodTable()->GetModuleDynamicEntryID();
5942 }
5943 else
5944 {
5945 result = (unsigned)VMClsHnd.AsMethodTable()->GetClassIndex();
5946 }
5947
5948 EE_TO_JIT_TRANSITION();
5949
5950 return result;
5951}
5952
5953//---------------------------------------------------------------------------------------
5954//
5955// Used by the JIT to determine whether the profiler or IBC is tracking object
5956// allocations
5957//
5958// Return Value:
5959// bool indicating whether the profiler or IBC is tracking object allocations
5960//
5961// Notes:
5962// Normally, a profiler would just directly call the inline helper to determine
5963// whether the profiler set the relevant event flag (e.g.,
5964// CORProfilerTrackAllocationsEnabled). However, this wrapper also asks whether we're
5965// running for IBC instrumentation or enabling the object allocated ETW event. If so,
5966// we treat that the same as if the profiler requested allocation information, so that
5967// the JIT will still use the profiling-friendly object allocation jit helper, so the
5968// allocations can be tracked.
5969//
5970
5971bool __stdcall TrackAllocationsEnabled()
5972{
5973 CONTRACTL
5974 {
5975 NOTHROW;
5976 GC_NOTRIGGER;
5977 MODE_ANY;
5978 }
5979 CONTRACTL_END;
5980
5981 return (
5982 (g_IBCLogger.InstrEnabled() != FALSE)
5983#ifdef PROFILING_SUPPORTED
5984 || CORProfilerTrackAllocationsEnabled()
5985#endif // PROFILING_SUPPORTED
5986#ifdef FEATURE_EVENT_TRACE
5987 || ETW::TypeSystemLog::IsHeapAllocEventEnabled()
5988#endif // FEATURE_EVENT_TRACE
5989 );
5990}
5991
5992/***********************************************************************/
5993CorInfoHelpFunc CEEInfo::getNewHelper(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, bool * pHasSideEffects)
5994{
5995 CONTRACTL {
5996 SO_TOLERANT;
5997 THROWS;
5998 GC_TRIGGERS;
5999 MODE_PREEMPTIVE;
6000 } CONTRACTL_END;
6001
6002 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6003
6004 JIT_TO_EE_TRANSITION();
6005
6006 TypeHandle VMClsHnd(pResolvedToken->hClass);
6007
6008 if(VMClsHnd.IsTypeDesc())
6009 {
6010 COMPlusThrow(kInvalidOperationException,W("InvalidOperation_CantInstantiateFunctionPointer"));
6011 }
6012
6013 if(VMClsHnd.IsAbstract())
6014 {
6015 COMPlusThrow(kInvalidOperationException,W("InvalidOperation_CantInstantiateAbstractClass"));
6016 }
6017
6018 MethodTable* pMT = VMClsHnd.AsMethodTable();
6019 result = getNewHelperStatic(pMT, pHasSideEffects);
6020
6021 _ASSERTE(result != CORINFO_HELP_UNDEF);
6022
6023 EE_TO_JIT_TRANSITION();
6024
6025 return result;
6026}
6027
6028/***********************************************************************/
6029CorInfoHelpFunc CEEInfo::getNewHelperStatic(MethodTable * pMT, bool * pHasSideEffects)
6030{
6031 STANDARD_VM_CONTRACT;
6032
6033
6034 // Slow helper is the default
6035 CorInfoHelpFunc helper = CORINFO_HELP_NEWFAST;
6036 BOOL hasFinalizer = pMT->HasFinalizer();
6037 BOOL isComObjectType = pMT->IsComObjectType();
6038
6039 if (pHasSideEffects != nullptr)
6040 {
6041 if (isComObjectType)
6042 {
6043 *pHasSideEffects = true;
6044 }
6045 else
6046#ifdef FEATURE_READYTORUN_COMPILER
6047 if (IsReadyToRunCompilation())
6048 {
6049 *pHasSideEffects = hasFinalizer || !pMT->IsInheritanceChainFixedInCurrentVersionBubble();
6050 }
6051 else
6052#endif
6053 {
6054 *pHasSideEffects = !!hasFinalizer;
6055 }
6056 }
6057
6058 if (isComObjectType)
6059 {
6060 // Use slow helper
6061 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
6062 }
6063 else
6064 if ((pMT->GetBaseSize() >= LARGE_OBJECT_SIZE) ||
6065 hasFinalizer)
6066 {
6067 // Use slow helper
6068 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
6069 }
6070 else
6071 // don't call the super-optimized one since that does not check
6072 // for GCStress
6073 if (GCStress<cfg_alloc>::IsEnabled())
6074 {
6075 // Use slow helper
6076 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
6077 }
6078 else
6079#ifdef _LOGALLOC
6080#ifdef LOGGING
6081 // Super fast version doesn't do logging
6082 if (LoggingOn(LF_GCALLOC, LL_INFO10))
6083 {
6084 // Use slow helper
6085 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
6086 }
6087 else
6088#endif // LOGGING
6089#endif // _LOGALLOC
6090 // Don't use the SFAST allocator when tracking object allocations,
6091 // so we don't have to instrument it.
6092 if (TrackAllocationsEnabled())
6093 {
6094 // Use slow helper
6095 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
6096 }
6097 else
6098#ifdef FEATURE_64BIT_ALIGNMENT
6099 // @ARMTODO: Force all 8-byte alignment requiring allocations down one slow path. As performance
6100 // measurements dictate we can spread these out to faster, more specialized helpers later.
6101 if (pMT->RequiresAlign8())
6102 {
6103 // Use slow helper
6104 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
6105 }
6106 else
6107#endif
6108 {
6109 // Use the fast helper when all conditions are met
6110 helper = CORINFO_HELP_NEWSFAST;
6111 }
6112
6113#ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
6114 // If we are use the the fast allocator we also may need the
6115 // specialized varion for align8
6116 if (pMT->GetClass()->IsAlign8Candidate() &&
6117 (helper == CORINFO_HELP_NEWSFAST))
6118 {
6119 helper = CORINFO_HELP_NEWSFAST_ALIGN8;
6120 }
6121#endif // FEATURE_DOUBLE_ALIGNMENT_HINT
6122
6123 return helper;
6124}
6125
6126/***********************************************************************/
6127// <REVIEW> this only works for shared generic code because all the
6128// helpers are actually the same. If they were different then things might
6129// break because the same helper would end up getting used for different but
6130// representation-compatible arrays (e.g. one with a default constructor
6131// and one without) </REVIEW>
6132CorInfoHelpFunc CEEInfo::getNewArrHelper (CORINFO_CLASS_HANDLE arrayClsHnd)
6133{
6134 CONTRACTL {
6135 SO_TOLERANT;
6136 THROWS;
6137 GC_TRIGGERS;
6138 MODE_PREEMPTIVE;
6139 } CONTRACTL_END;
6140
6141 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6142
6143 JIT_TO_EE_TRANSITION();
6144
6145 TypeHandle arrayType(arrayClsHnd);
6146
6147 result = getNewArrHelperStatic(arrayType);
6148
6149 _ASSERTE(result != CORINFO_HELP_UNDEF);
6150
6151 EE_TO_JIT_TRANSITION();
6152
6153 return result;
6154}
6155
6156/***********************************************************************/
6157CorInfoHelpFunc CEEInfo::getNewArrHelperStatic(TypeHandle clsHnd)
6158{
6159 STANDARD_VM_CONTRACT;
6160
6161 ArrayTypeDesc* arrayTypeDesc = clsHnd.AsArray();
6162 _ASSERTE(arrayTypeDesc->GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY);
6163
6164 if (GCStress<cfg_alloc>::IsEnabled())
6165 {
6166 return CORINFO_HELP_NEWARR_1_DIRECT;
6167 }
6168
6169 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6170
6171 TypeHandle thElemType = arrayTypeDesc->GetTypeParam();
6172 CorElementType elemType = thElemType.GetInternalCorElementType();
6173
6174 // This is if we're asked for newarr !0 when verifying generic code
6175 // Of course ideally you wouldn't even be generating code when
6176 // simply doing verification (we run the JIT importer in import-only
6177 // mode), but importing does more than one would like so we try to be
6178 // tolerant when asked for non-sensical helpers.
6179 if (CorTypeInfo::IsGenericVariable(elemType))
6180 {
6181 result = CORINFO_HELP_NEWARR_1_OBJ;
6182 }
6183 else if (CorTypeInfo::IsObjRef(elemType))
6184 {
6185 // It is an array of object refs
6186 result = CORINFO_HELP_NEWARR_1_OBJ;
6187 }
6188 else
6189 {
6190 // These cases always must use the slow helper
6191 if (
6192#ifdef FEATURE_64BIT_ALIGNMENT
6193 thElemType.RequiresAlign8() ||
6194#endif
6195 (elemType == ELEMENT_TYPE_VOID) ||
6196 LoggingOn(LF_GCALLOC, LL_INFO10) ||
6197 TrackAllocationsEnabled())
6198 {
6199 // Use the slow helper
6200 result = CORINFO_HELP_NEWARR_1_DIRECT;
6201 }
6202#ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
6203 else if (elemType == ELEMENT_TYPE_R8)
6204 {
6205 // Use the Align8 fast helper
6206 result = CORINFO_HELP_NEWARR_1_ALIGN8;
6207 }
6208#endif
6209 else
6210 {
6211 // Yea, we can do it the fast way!
6212 result = CORINFO_HELP_NEWARR_1_VC;
6213 }
6214 }
6215
6216 return result;
6217}
6218
6219/***********************************************************************/
6220CorInfoHelpFunc CEEInfo::getCastingHelper(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fThrowing)
6221{
6222 CONTRACTL {
6223 SO_TOLERANT;
6224 THROWS;
6225 GC_TRIGGERS;
6226 MODE_PREEMPTIVE;
6227 } CONTRACTL_END;
6228
6229 if (isVerifyOnly())
6230 return fThrowing ? CORINFO_HELP_CHKCASTANY : CORINFO_HELP_ISINSTANCEOFANY;
6231
6232 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6233
6234 JIT_TO_EE_TRANSITION();
6235
6236 bool fClassMustBeRestored;
6237 result = getCastingHelperStatic(TypeHandle(pResolvedToken->hClass), fThrowing, &fClassMustBeRestored);
6238 if (fClassMustBeRestored && m_pOverride != NULL)
6239 m_pOverride->classMustBeLoadedBeforeCodeIsRun(pResolvedToken->hClass);
6240
6241 EE_TO_JIT_TRANSITION();
6242
6243 return result;
6244}
6245
6246/***********************************************************************/
6247CorInfoHelpFunc CEEInfo::getCastingHelperStatic(TypeHandle clsHnd, bool fThrowing, bool * pfClassMustBeRestored)
6248{
6249 STANDARD_VM_CONTRACT;
6250
6251 // Slow helper is the default
6252 int helper = CORINFO_HELP_ISINSTANCEOFANY;
6253
6254 *pfClassMustBeRestored = false;
6255
6256 if (clsHnd == TypeHandle(g_pCanonMethodTableClass))
6257 {
6258 // In shared code just use the catch-all helper for type variables, as the same
6259 // code may be used for interface/array/class instantiations
6260 //
6261 // We may be able to take advantage of constraints to select a specialized helper.
6262 // This optimizations does not seem to be warranted at the moment.
6263 _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6264 }
6265 else
6266 if (!clsHnd.IsTypeDesc() && clsHnd.AsMethodTable()->HasVariance())
6267 {
6268 // Casting to variant type requires the type to be fully loaded
6269 *pfClassMustBeRestored = true;
6270
6271 _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6272 }
6273 else
6274 if (!clsHnd.IsTypeDesc() && clsHnd.AsMethodTable()->HasTypeEquivalence())
6275 {
6276 // If the type can be equivalent with something, use the slow helper
6277 // Note: if the type of the instance is the one marked as equivalent, it will be
6278 // caught by the fast helpers in the same way as they catch transparent proxies.
6279 _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6280 }
6281 else
6282 if (clsHnd.IsInterface())
6283 {
6284 // If it is a non-variant interface, use the fast interface helper
6285 helper = CORINFO_HELP_ISINSTANCEOFINTERFACE;
6286 }
6287 else
6288 if (clsHnd.IsArray())
6289 {
6290 if (clsHnd.AsArray()->GetInternalCorElementType() != ELEMENT_TYPE_SZARRAY)
6291 {
6292 // Casting to multidimensional array type requires restored pointer to EEClass to fetch rank
6293 *pfClassMustBeRestored = true;
6294 }
6295
6296 // If it is an array, use the fast array helper
6297 helper = CORINFO_HELP_ISINSTANCEOFARRAY;
6298 }
6299 else
6300 if (!clsHnd.IsTypeDesc() && !Nullable::IsNullableType(clsHnd))
6301 {
6302 // If it is a non-variant class, use the fast class helper
6303 helper = CORINFO_HELP_ISINSTANCEOFCLASS;
6304 }
6305 else
6306 {
6307 // Otherwise, use the slow helper
6308 _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6309 }
6310
6311#ifdef FEATURE_PREJIT
6312 BOOL t1, t2, forceInstr;
6313 SystemDomain::GetCompilationOverrides(&t1, &t2, &forceInstr);
6314 if (forceInstr)
6315 {
6316 // If we're compiling for instrumentation, use the slowest but instrumented cast helper
6317 helper = CORINFO_HELP_ISINSTANCEOFANY;
6318 }
6319#endif
6320
6321 if (fThrowing)
6322 {
6323 const int delta = CORINFO_HELP_CHKCASTANY - CORINFO_HELP_ISINSTANCEOFANY;
6324
6325 static_assert_no_msg(CORINFO_HELP_CHKCASTINTERFACE
6326 == CORINFO_HELP_ISINSTANCEOFINTERFACE + delta);
6327 static_assert_no_msg(CORINFO_HELP_CHKCASTARRAY
6328 == CORINFO_HELP_ISINSTANCEOFARRAY + delta);
6329 static_assert_no_msg(CORINFO_HELP_CHKCASTCLASS
6330 == CORINFO_HELP_ISINSTANCEOFCLASS + delta);
6331
6332 helper += delta;
6333 }
6334
6335 return (CorInfoHelpFunc)helper;
6336}
6337
6338/***********************************************************************/
6339CorInfoHelpFunc CEEInfo::getSharedCCtorHelper(CORINFO_CLASS_HANDLE clsHnd)
6340{
6341 CONTRACTL {
6342 SO_TOLERANT;
6343 NOTHROW;
6344 GC_NOTRIGGER;
6345 MODE_PREEMPTIVE;
6346 } CONTRACTL_END;
6347
6348 CorInfoHelpFunc result = CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE;
6349
6350 JIT_TO_EE_TRANSITION_LEAF();
6351
6352 TypeHandle cls(clsHnd);
6353 MethodTable* pMT = cls.AsMethodTable();
6354
6355 if (pMT->IsDynamicStatics())
6356 {
6357 _ASSERTE(!cls.ContainsGenericVariables());
6358 _ASSERTE(pMT->GetModuleDynamicEntryID() != (unsigned) -1);
6359
6360 result = CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS;
6361 }
6362
6363 EE_TO_JIT_TRANSITION_LEAF();
6364
6365 return result;
6366}
6367
6368/***********************************************************************/
6369CorInfoHelpFunc CEEInfo::getUnBoxHelper(CORINFO_CLASS_HANDLE clsHnd)
6370{
6371 LIMITED_METHOD_CONTRACT;
6372
6373 if (m_pOverride != NULL)
6374 m_pOverride->classMustBeLoadedBeforeCodeIsRun(clsHnd);
6375
6376 TypeHandle VMClsHnd(clsHnd);
6377 if (Nullable::IsNullableType(VMClsHnd))
6378 return CORINFO_HELP_UNBOX_NULLABLE;
6379
6380 return CORINFO_HELP_UNBOX;
6381}
6382
6383/***********************************************************************/
6384bool CEEInfo::getReadyToRunHelper(
6385 CORINFO_RESOLVED_TOKEN * pResolvedToken,
6386 CORINFO_LOOKUP_KIND * pGenericLookupKind,
6387 CorInfoHelpFunc id,
6388 CORINFO_CONST_LOOKUP * pLookup
6389 )
6390{
6391 LIMITED_METHOD_CONTRACT;
6392 UNREACHABLE(); // only called during NGen
6393}
6394
6395/***********************************************************************/
6396void CEEInfo::getReadyToRunDelegateCtorHelper(
6397 CORINFO_RESOLVED_TOKEN * pTargetMethod,
6398 CORINFO_CLASS_HANDLE delegateType,
6399 CORINFO_LOOKUP * pLookup
6400 )
6401{
6402 LIMITED_METHOD_CONTRACT;
6403 UNREACHABLE(); // only called during NGen
6404}
6405
6406/***********************************************************************/
6407// see code:Nullable#NullableVerification
6408
6409CORINFO_CLASS_HANDLE CEEInfo::getTypeForBox(CORINFO_CLASS_HANDLE cls)
6410{
6411 LIMITED_METHOD_CONTRACT;
6412
6413 TypeHandle VMClsHnd(cls);
6414 if (Nullable::IsNullableType(VMClsHnd)) {
6415 VMClsHnd = VMClsHnd.AsMethodTable()->GetInstantiation()[0];
6416 }
6417 return static_cast<CORINFO_CLASS_HANDLE>(VMClsHnd.AsPtr());
6418}
6419
6420/***********************************************************************/
6421// see code:Nullable#NullableVerification
6422CorInfoHelpFunc CEEInfo::getBoxHelper(CORINFO_CLASS_HANDLE clsHnd)
6423{
6424 CONTRACTL {
6425 SO_TOLERANT;
6426 THROWS;
6427 GC_TRIGGERS;
6428 MODE_PREEMPTIVE;
6429 } CONTRACTL_END;
6430
6431 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6432
6433 JIT_TO_EE_TRANSITION();
6434
6435 TypeHandle VMClsHnd(clsHnd);
6436 if (Nullable::IsNullableType(VMClsHnd))
6437 {
6438 result = CORINFO_HELP_BOX_NULLABLE;
6439 }
6440 else
6441 {
6442 if(VMClsHnd.IsTypeDesc())
6443 COMPlusThrow(kInvalidOperationException,W("InvalidOperation_TypeCannotBeBoxed"));
6444
6445 // we shouldn't allow boxing of types that contains stack pointers
6446 // csc and vbc already disallow it.
6447 if (VMClsHnd.AsMethodTable()->IsByRefLike())
6448 COMPlusThrow(kInvalidProgramException,W("NotSupported_ByRefLike"));
6449
6450 result = CORINFO_HELP_BOX;
6451 }
6452
6453 EE_TO_JIT_TRANSITION();
6454
6455 return result;
6456}
6457
6458/***********************************************************************/
6459CorInfoHelpFunc CEEInfo::getSecurityPrologHelper(CORINFO_METHOD_HANDLE ftn)
6460{
6461 CONTRACTL {
6462 SO_TOLERANT;
6463 THROWS;
6464 GC_TRIGGERS;
6465 MODE_PREEMPTIVE;
6466 } CONTRACTL_END;
6467
6468 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6469
6470 JIT_TO_EE_TRANSITION();
6471
6472#ifdef FEATURE_NATIVE_IMAGE_GENERATION
6473 // This will make sure that when IBC logging is on, we call the slow helper with IBC probe
6474 if (IsCompilingForNGen() &&
6475 GetAppDomain()->ToCompilationDomain()->m_fForceInstrument)
6476 {
6477 result = CORINFO_HELP_SECURITY_PROLOG_FRAMED;
6478 }
6479#endif // FEATURE_NATIVE_IMAGE_GENERATION
6480
6481 if (result == CORINFO_HELP_UNDEF)
6482 {
6483 result = CORINFO_HELP_SECURITY_PROLOG;
6484 }
6485
6486 EE_TO_JIT_TRANSITION();
6487
6488 return result;
6489}
6490
6491/***********************************************************************/
6492// registers a vararg sig & returns a class-specific cookie for it.
6493
6494CORINFO_VARARGS_HANDLE CEEInfo::getVarArgsHandle(CORINFO_SIG_INFO *sig,
6495 void **ppIndirection)
6496{
6497 CONTRACTL {
6498 SO_TOLERANT;
6499 THROWS;
6500 GC_TRIGGERS;
6501 MODE_PREEMPTIVE;
6502 } CONTRACTL_END;
6503
6504 CORINFO_VARARGS_HANDLE result = NULL;
6505
6506 if (ppIndirection != NULL)
6507 *ppIndirection = NULL;
6508
6509 JIT_TO_EE_TRANSITION();
6510
6511 Module* module = GetModule(sig->scope);
6512
6513 result = CORINFO_VARARGS_HANDLE(module->GetVASigCookie(Signature(sig->pSig, sig->cbSig)));
6514
6515 EE_TO_JIT_TRANSITION();
6516
6517 return result;
6518}
6519
6520bool CEEInfo::canGetVarArgsHandle(CORINFO_SIG_INFO *sig)
6521{
6522 LIMITED_METHOD_CONTRACT;
6523 return true;
6524}
6525
6526/***********************************************************************/
6527unsigned CEEInfo::getMethodHash (CORINFO_METHOD_HANDLE ftnHnd)
6528{
6529 CONTRACTL {
6530 SO_TOLERANT;
6531 THROWS;
6532 GC_TRIGGERS;
6533 MODE_PREEMPTIVE;
6534 } CONTRACTL_END;
6535
6536 unsigned result = 0;
6537
6538 JIT_TO_EE_TRANSITION();
6539
6540 MethodDesc* ftn = GetMethod(ftnHnd);
6541
6542 result = (unsigned) ftn->GetStableHash();
6543
6544 EE_TO_JIT_TRANSITION();
6545
6546 return result;
6547}
6548
6549/***********************************************************************/
6550const char* CEEInfo::getMethodName (CORINFO_METHOD_HANDLE ftnHnd, const char** scopeName)
6551{
6552 CONTRACTL {
6553 SO_TOLERANT;
6554 THROWS;
6555 GC_TRIGGERS;
6556 MODE_PREEMPTIVE;
6557 } CONTRACTL_END;
6558
6559 const char* result = NULL;
6560
6561 JIT_TO_EE_TRANSITION();
6562
6563 MethodDesc *ftn;
6564
6565 ftn = GetMethod(ftnHnd);
6566
6567 if (scopeName != 0)
6568 {
6569 if (ftn->IsLCGMethod())
6570 {
6571 *scopeName = "DynamicClass";
6572 }
6573 else if (ftn->IsILStub())
6574 {
6575 *scopeName = ILStubResolver::GetStubClassName(ftn);
6576 }
6577 else
6578 {
6579 MethodTable * pMT = ftn->GetMethodTable();
6580#if defined(_DEBUG)
6581#ifdef FEATURE_SYMDIFF
6582 if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_SymDiffDump))
6583 {
6584 if (pMT->IsArray())
6585 {
6586 ssClsNameBuff.Clear();
6587 ssClsNameBuff.SetUTF8(pMT->GetDebugClassName());
6588 }
6589 else
6590 pMT->_GetFullyQualifiedNameForClassNestedAware(ssClsNameBuff);
6591 }
6592 else
6593 {
6594#endif
6595 // Calling _GetFullyQualifiedNameForClass in chk build is very expensive
6596 // since it construct the class name everytime we call this method. In chk
6597 // builds we already have a cheaper way to get the class name -
6598 // GetDebugClassName - which doesn't calculate the class name everytime.
6599 // This results in huge saving in Ngen time for checked builds.
6600 ssClsNameBuff.Clear();
6601 ssClsNameBuff.SetUTF8(pMT->GetDebugClassName());
6602
6603#ifdef FEATURE_SYMDIFF
6604 }
6605#endif
6606 // Append generic instantiation at the end
6607 Instantiation inst = pMT->GetInstantiation();
6608 if (!inst.IsEmpty())
6609 TypeString::AppendInst(ssClsNameBuff, inst);
6610
6611 *scopeName = ssClsNameBuff.GetUTF8(ssClsNameBuffScratch);
6612#else // !_DEBUG
6613 // since this is for diagnostic purposes only,
6614 // give up on the namespace, as we don't have a buffer to concat it
6615 // also note this won't show array class names.
6616 LPCUTF8 nameSpace;
6617 *scopeName= pMT->GetFullyQualifiedNameInfo(&nameSpace);
6618#endif // !_DEBUG
6619 }
6620 }
6621
6622 result = ftn->GetName();
6623
6624 EE_TO_JIT_TRANSITION();
6625
6626 return result;
6627}
6628
6629const char* CEEInfo::getMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftnHnd, const char** className, const char** namespaceName, const char **enclosingClassName)
6630{
6631 CONTRACTL {
6632 SO_TOLERANT;
6633 THROWS;
6634 GC_TRIGGERS;
6635 MODE_PREEMPTIVE;
6636 } CONTRACTL_END;
6637
6638 const char* result = NULL;
6639 const char* classResult = NULL;
6640 const char* namespaceResult = NULL;
6641 const char* enclosingResult = NULL;
6642
6643 JIT_TO_EE_TRANSITION();
6644
6645 MethodDesc *ftn = GetMethod(ftnHnd);
6646 mdMethodDef token = ftn->GetMemberDef();
6647
6648 if (!IsNilToken(token))
6649 {
6650 MethodTable* pMT = ftn->GetMethodTable();
6651 IMDInternalImport* pMDImport = pMT->GetMDImport();
6652
6653 IfFailThrow(pMDImport->GetNameOfMethodDef(token, &result));
6654 IfFailThrow(pMDImport->GetNameOfTypeDef(pMT->GetCl(), &classResult, &namespaceResult));
6655 // Query enclosingClassName when the method is in a nested class
6656 // and get the namespace of enclosing classes (nested class's namespace is empty)
6657 if (pMT->GetClass()->IsNested())
6658 {
6659 IfFailThrow(pMDImport->GetNameOfTypeDef(pMT->GetEnclosingCl(), &enclosingResult, &namespaceResult));
6660 }
6661 }
6662
6663 if (className != NULL)
6664 {
6665 *className = classResult;
6666 }
6667
6668 if (namespaceName != NULL)
6669 {
6670 *namespaceName = namespaceResult;
6671 }
6672
6673 if (enclosingClassName != NULL)
6674 {
6675 *enclosingClassName = enclosingResult;
6676 }
6677
6678 EE_TO_JIT_TRANSITION();
6679
6680 return result;
6681}
6682
6683/*********************************************************************/
6684const char* CEEInfo::getClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, const char** namespaceName)
6685{
6686 CONTRACTL {
6687 SO_TOLERANT;
6688 THROWS;
6689 GC_TRIGGERS;
6690 MODE_PREEMPTIVE;
6691 } CONTRACTL_END;
6692
6693 const char* result = NULL;
6694 const char* namespaceResult = NULL;
6695
6696 JIT_TO_EE_TRANSITION();
6697 TypeHandle VMClsHnd(cls);
6698
6699 if (!VMClsHnd.IsTypeDesc())
6700 {
6701 result = VMClsHnd.AsMethodTable()->GetFullyQualifiedNameInfo(&namespaceResult);
6702 }
6703
6704 if (namespaceName != NULL)
6705 {
6706 *namespaceName = namespaceResult;
6707 }
6708
6709 EE_TO_JIT_TRANSITION();
6710
6711 return result;
6712}
6713
6714/*********************************************************************/
6715CORINFO_CLASS_HANDLE CEEInfo::getTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, unsigned index)
6716{
6717 CONTRACTL {
6718 SO_TOLERANT;
6719 THROWS;
6720 GC_TRIGGERS;
6721 MODE_PREEMPTIVE;
6722 } CONTRACTL_END;
6723
6724 CORINFO_CLASS_HANDLE result = NULL;
6725
6726 JIT_TO_EE_TRANSITION_LEAF();
6727
6728 TypeHandle VMClsHnd(cls);
6729 Instantiation inst = VMClsHnd.GetInstantiation();
6730 TypeHandle typeArg = index < inst.GetNumArgs() ? inst[index] : NULL;
6731 result = CORINFO_CLASS_HANDLE(typeArg.AsPtr());
6732
6733 EE_TO_JIT_TRANSITION_LEAF();
6734
6735 return result;
6736}
6737
6738/*********************************************************************/
6739DWORD CEEInfo::getMethodAttribs (CORINFO_METHOD_HANDLE ftn)
6740{
6741 CONTRACTL {
6742 SO_TOLERANT;
6743 THROWS;
6744 GC_TRIGGERS;
6745 MODE_PREEMPTIVE;
6746 } CONTRACTL_END;
6747
6748 DWORD result = 0;
6749
6750 JIT_TO_EE_TRANSITION();
6751
6752 result = getMethodAttribsInternal(ftn);
6753
6754 EE_TO_JIT_TRANSITION();
6755
6756 return result;
6757}
6758
6759/*********************************************************************/
6760DWORD CEEInfo::getMethodAttribsInternal (CORINFO_METHOD_HANDLE ftn)
6761{
6762 STANDARD_VM_CONTRACT;
6763
6764/*
6765 returns method attribute flags (defined in corhdr.h)
6766
6767 NOTE: This doesn't return certain method flags
6768 (mdAssem, mdFamANDAssem, mdFamORAssem, mdPrivateScope)
6769*/
6770
6771 MethodDesc* pMD = GetMethod(ftn);
6772
6773 if (pMD->IsLCGMethod())
6774 {
6775 return CORINFO_FLG_STATIC | CORINFO_FLG_DONT_INLINE | CORINFO_FLG_NOSECURITYWRAP;
6776 }
6777
6778 DWORD result = CORINFO_FLG_NOSECURITYWRAP;
6779
6780 // <REVISIT_TODO>@todo: can we git rid of CORINFO_FLG_ stuff and just include cor.h?</REVISIT_TODO>
6781
6782 DWORD attribs = pMD->GetAttrs();
6783
6784 if (IsMdFamily(attribs))
6785 result |= CORINFO_FLG_PROTECTED;
6786 if (IsMdStatic(attribs))
6787 result |= CORINFO_FLG_STATIC;
6788 if (pMD->IsSynchronized())
6789 result |= CORINFO_FLG_SYNCH;
6790 if (pMD->IsFCallOrIntrinsic())
6791 result |= CORINFO_FLG_NOGCCHECK | CORINFO_FLG_INTRINSIC;
6792 if (pMD->IsJitIntrinsic())
6793 result |= CORINFO_FLG_JIT_INTRINSIC;
6794 if (IsMdVirtual(attribs))
6795 result |= CORINFO_FLG_VIRTUAL;
6796 if (IsMdAbstract(attribs))
6797 result |= CORINFO_FLG_ABSTRACT;
6798 if (IsMdRTSpecialName(attribs))
6799 {
6800 LPCUTF8 pName = pMD->GetName();
6801 if (IsMdInstanceInitializer(attribs, pName) ||
6802 IsMdClassConstructor(attribs, pName))
6803 result |= CORINFO_FLG_CONSTRUCTOR;
6804 }
6805
6806 //
6807 // See if we need to embed a .cctor call at the head of the
6808 // method body.
6809 //
6810
6811 MethodTable* pMT = pMD->GetMethodTable();
6812
6813 // method or class might have the final bit
6814 if (IsMdFinal(attribs) || pMT->IsSealed())
6815 {
6816 result |= CORINFO_FLG_FINAL;
6817 }
6818
6819 if (pMD->IsEnCAddedMethod())
6820 {
6821 result |= CORINFO_FLG_EnC;
6822 }
6823
6824 if (pMD->IsSharedByGenericInstantiations())
6825 {
6826 result |= CORINFO_FLG_SHAREDINST;
6827 }
6828
6829 if (pMD->IsNDirect())
6830 {
6831 result |= CORINFO_FLG_PINVOKE;
6832 }
6833
6834 if (IsMdRequireSecObject(attribs))
6835 {
6836 // Assume all methods marked as DynamicSecurity are
6837 // marked that way because they use StackCrawlMark to identify
6838 // the caller.
6839 // See comments in canInline or canTailCall
6840 result |= CORINFO_FLG_DONT_INLINE_CALLER;
6841 }
6842
6843 // Check for the aggressive optimization directive. AggressiveOptimization only makes sense for IL methods.
6844 DWORD ilMethodImplAttribs = 0;
6845 if (pMD->IsIL())
6846 {
6847 ilMethodImplAttribs = pMD->GetImplAttrs();
6848 if (IsMiAggressiveOptimization(ilMethodImplAttribs))
6849 {
6850 result |= CORINFO_FLG_AGGRESSIVE_OPT;
6851 }
6852 }
6853
6854 // Check for an inlining directive.
6855 if (pMD->IsNotInline())
6856 {
6857 /* Function marked as not inlineable */
6858 result |= CORINFO_FLG_DONT_INLINE;
6859 }
6860 // AggressiveInlining only makes sense for IL methods.
6861 else if (pMD->IsIL() && IsMiAggressiveInlining(ilMethodImplAttribs))
6862 {
6863 result |= CORINFO_FLG_FORCEINLINE;
6864 }
6865
6866 if (pMT->IsDelegate() && ((DelegateEEClass*)(pMT->GetClass()))->GetInvokeMethod() == pMD)
6867 {
6868 // This is now used to emit efficient invoke code for any delegate invoke,
6869 // including multicast.
6870 result |= CORINFO_FLG_DELEGATE_INVOKE;
6871 }
6872
6873 return result;
6874}
6875
6876/*********************************************************************/
6877void CEEInfo::setMethodAttribs (
6878 CORINFO_METHOD_HANDLE ftnHnd,
6879 CorInfoMethodRuntimeFlags attribs)
6880{
6881 CONTRACTL {
6882 SO_TOLERANT;
6883 THROWS;
6884 GC_TRIGGERS;
6885 MODE_PREEMPTIVE;
6886 } CONTRACTL_END;
6887
6888 JIT_TO_EE_TRANSITION();
6889
6890 MethodDesc* ftn = GetMethod(ftnHnd);
6891
6892 if (attribs & CORINFO_FLG_BAD_INLINEE)
6893 {
6894 BOOL fCacheInliningHint = TRUE;
6895
6896#ifdef FEATURE_NATIVE_IMAGE_GENERATION
6897 if (IsCompilationProcess())
6898 {
6899 // Since we are running managed code during NGen the inlining hint may be
6900 // changing underneeth us as the code is JITed. We need to prevent the inlining
6901 // hints from changing once we start to use them to place IL in the image.
6902 if (!g_pCEECompileInfo->IsCachingOfInliningHintsEnabled())
6903 {
6904 fCacheInliningHint = FALSE;
6905 }
6906 else
6907 {
6908 // Don't cache inlining hints inside mscorlib during NGen of other assemblies,
6909 // since mscorlib is loaded domain neutral and will survive worker process recycling,
6910 // causing determinism problems.
6911 Module * pModule = ftn->GetModule();
6912 if (pModule->IsSystem() && pModule->HasNativeImage())
6913 {
6914 fCacheInliningHint = FALSE;
6915 }
6916 }
6917 }
6918#endif
6919
6920 if (fCacheInliningHint)
6921 {
6922 ftn->SetNotInline(true);
6923 }
6924 }
6925
6926 EE_TO_JIT_TRANSITION();
6927}
6928
6929/*********************************************************************/
6930
6931void getMethodInfoILMethodHeaderHelper(
6932 COR_ILMETHOD_DECODER* header,
6933 CORINFO_METHOD_INFO* methInfo
6934 )
6935{
6936 LIMITED_METHOD_CONTRACT;
6937
6938 methInfo->ILCode = const_cast<BYTE*>(header->Code);
6939 methInfo->ILCodeSize = header->GetCodeSize();
6940 methInfo->maxStack = static_cast<unsigned short>(header->GetMaxStack());
6941 methInfo->EHcount = static_cast<unsigned short>(header->EHCount());
6942
6943 methInfo->options =
6944 (CorInfoOptions)((header->GetFlags() & CorILMethod_InitLocals) ? CORINFO_OPT_INIT_LOCALS : 0) ;
6945}
6946
6947mdToken FindGenericMethodArgTypeSpec(IMDInternalImport* pInternalImport)
6948{
6949 STANDARD_VM_CONTRACT;
6950
6951 HENUMInternalHolder hEnumTypeSpecs(pInternalImport);
6952 mdToken token;
6953
6954 static const BYTE signature[] = { ELEMENT_TYPE_MVAR, 0 };
6955
6956 hEnumTypeSpecs.EnumAllInit(mdtTypeSpec);
6957 while (hEnumTypeSpecs.EnumNext(&token))
6958 {
6959 PCCOR_SIGNATURE pSig;
6960 ULONG cbSig;
6961 IfFailThrow(pInternalImport->GetTypeSpecFromToken(token, &pSig, &cbSig));
6962 if (cbSig == sizeof(signature) && memcmp(pSig, signature, cbSig) == 0)
6963 return token;
6964 }
6965
6966 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
6967}
6968
6969/*********************************************************************
6970
6971IL is the most efficient and portable way to implement certain low level methods
6972in mscorlib.dll. Unfortunately, there is no good way to link IL into mscorlib.dll today.
6973Until we find a good way to link IL into mscorlib.dll, we will provide the IL implementation here.
6974
6975- All IL intrinsincs are members of System.Runtime.CompilerServices.JitHelpers class
6976- All IL intrinsincs should be kept very simple. Implement the minimal reusable version of
6977unsafe construct and depend on inlining to do the rest.
6978- The C# implementation of the IL intrinsic should be good enough for functionalily. Everything should work
6979correctly (but slower) if the IL intrinsics are removed.
6980
6981*********************************************************************/
6982
6983bool getILIntrinsicImplementation(MethodDesc * ftn,
6984 CORINFO_METHOD_INFO * methInfo)
6985{
6986 STANDARD_VM_CONTRACT;
6987
6988 // Precondition: ftn is a method in mscorlib
6989 _ASSERTE(ftn->GetModule()->IsSystem());
6990
6991 mdMethodDef tk = ftn->GetMemberDef();
6992
6993 // Compare tokens to cover all generic instantiations
6994 // The body of the first method is simply ret Arg0. The second one first casts the arg to I4.
6995
6996 if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__ENUM_EQUALS)->GetMemberDef())
6997 {
6998 // Normally we would follow the above pattern and unconditionally replace the IL,
6999 // relying on generic type constraints to guarantee that it will only ever be instantiated
7000 // on the type/size of argument we expect.
7001 //
7002 // However C#/CLR does not support restricting a generic type to be an Enum, so the best
7003 // we can do is constrain it to be a value type. This is fine for run time, since we only
7004 // ever create instantiations on 4 byte or less Enums. But during NGen we may compile instantiations
7005 // on other value types (to be specific, every value type instatiation of EqualityComparer
7006 // because of its TypeDependencyAttribute; here again we would like to restrict this to
7007 // 4 byte or less Enums but cannot).
7008 //
7009 // This IL is invalid for those instantiations, and replacing it would lead to all sorts of
7010 // errors at NGen time. So we only replace it for instantiations where it would be valid,
7011 // leaving the others, which we should never execute, with the C# implementation of throwing.
7012
7013 _ASSERTE(ftn->HasMethodInstantiation());
7014 Instantiation inst = ftn->GetMethodInstantiation();
7015
7016 _ASSERTE(inst.GetNumArgs() == 1);
7017 CorElementType et = inst[0].GetVerifierCorElementType();
7018 if (et == ELEMENT_TYPE_I4 ||
7019 et == ELEMENT_TYPE_U4 ||
7020 et == ELEMENT_TYPE_I2 ||
7021 et == ELEMENT_TYPE_U2 ||
7022 et == ELEMENT_TYPE_I1 ||
7023 et == ELEMENT_TYPE_U1 ||
7024 et == ELEMENT_TYPE_I8 ||
7025 et == ELEMENT_TYPE_U8)
7026 {
7027 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (CEE_CEQ & 0xFF), CEE_RET };
7028 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7029 methInfo->ILCodeSize = sizeof(ilcode);
7030 methInfo->maxStack = 2;
7031 methInfo->EHcount = 0;
7032 methInfo->options = (CorInfoOptions)0;
7033 return true;
7034 }
7035 }
7036 else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__ENUM_COMPARE_TO)->GetMemberDef())
7037 {
7038 // The the comment above on why this is is not an unconditional replacement. This case handles
7039 // Enums backed by 8 byte values.
7040
7041 _ASSERTE(ftn->HasMethodInstantiation());
7042 Instantiation inst = ftn->GetMethodInstantiation();
7043
7044 _ASSERTE(inst.GetNumArgs() == 1);
7045 CorElementType et = inst[0].GetVerifierCorElementType();
7046 if (et == ELEMENT_TYPE_I4 ||
7047 et == ELEMENT_TYPE_U4 ||
7048 et == ELEMENT_TYPE_I2 ||
7049 et == ELEMENT_TYPE_U2 ||
7050 et == ELEMENT_TYPE_I1 ||
7051 et == ELEMENT_TYPE_U1 ||
7052 et == ELEMENT_TYPE_I8 ||
7053 et == ELEMENT_TYPE_U8)
7054 {
7055 static BYTE ilcode[8][9];
7056
7057 TypeHandle thUnderlyingType = MscorlibBinder::GetElementType(et);
7058
7059 TypeHandle thIComparable = TypeHandle(MscorlibBinder::GetClass(CLASS__ICOMPARABLEGENERIC)).Instantiate(Instantiation(&thUnderlyingType, 1));
7060
7061 MethodDesc * pCompareToMD = thUnderlyingType.AsMethodTable()->GetMethodDescForInterfaceMethod(
7062 thIComparable, MscorlibBinder::GetMethod(METHOD__ICOMPARABLEGENERIC__COMPARE_TO), TRUE /* throwOnConflict */);
7063
7064 // Call CompareTo method on the primitive type
7065 int tokCompareTo = pCompareToMD->GetMemberDef();
7066
7067 int index = (et - ELEMENT_TYPE_I1);
7068 _ASSERTE(index < _countof(ilcode));
7069
7070 ilcode[index][0] = CEE_LDARGA_S;
7071 ilcode[index][1] = 0;
7072 ilcode[index][2] = CEE_LDARG_1;
7073 ilcode[index][3] = CEE_CALL;
7074 ilcode[index][4] = (BYTE)(tokCompareTo);
7075 ilcode[index][5] = (BYTE)(tokCompareTo >> 8);
7076 ilcode[index][6] = (BYTE)(tokCompareTo >> 16);
7077 ilcode[index][7] = (BYTE)(tokCompareTo >> 24);
7078 ilcode[index][8] = CEE_RET;
7079
7080 methInfo->ILCode = const_cast<BYTE*>(ilcode[index]);
7081 methInfo->ILCodeSize = sizeof(ilcode[index]);
7082 methInfo->maxStack = 2;
7083 methInfo->EHcount = 0;
7084 methInfo->options = (CorInfoOptions)0;
7085 return true;
7086 }
7087 }
7088 else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__GET_RAW_SZ_ARRAY_DATA)->GetMemberDef())
7089 {
7090 mdToken tokRawSzArrayData = MscorlibBinder::GetField(FIELD__RAW_SZARRAY_DATA__DATA)->GetMemberDef();
7091
7092 static BYTE ilcode[] = { CEE_LDARG_0,
7093 CEE_LDFLDA,0,0,0,0,
7094 CEE_RET };
7095
7096 ilcode[2] = (BYTE)(tokRawSzArrayData);
7097 ilcode[3] = (BYTE)(tokRawSzArrayData >> 8);
7098 ilcode[4] = (BYTE)(tokRawSzArrayData >> 16);
7099 ilcode[5] = (BYTE)(tokRawSzArrayData >> 24);
7100
7101 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7102 methInfo->ILCodeSize = sizeof(ilcode);
7103 methInfo->maxStack = 1;
7104 methInfo->EHcount = 0;
7105 methInfo->options = (CorInfoOptions)0;
7106 return true;
7107 }
7108
7109 return false;
7110}
7111
7112bool getILIntrinsicImplementationForUnsafe(MethodDesc * ftn,
7113 CORINFO_METHOD_INFO * methInfo)
7114{
7115 STANDARD_VM_CONTRACT;
7116
7117 // Precondition: ftn is a method in mscorlib
7118 _ASSERTE(ftn->GetModule()->IsSystem());
7119
7120 mdMethodDef tk = ftn->GetMemberDef();
7121
7122 if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__AS_POINTER)->GetMemberDef())
7123 {
7124 // Return the argument that was passed in.
7125 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_U, CEE_RET };
7126 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7127 methInfo->ILCodeSize = sizeof(ilcode);
7128 methInfo->maxStack = 1;
7129 methInfo->EHcount = 0;
7130 methInfo->options = (CorInfoOptions)0;
7131 return true;
7132 }
7133 if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__SIZEOF)->GetMemberDef())
7134 {
7135 _ASSERTE(ftn->HasMethodInstantiation());
7136 Instantiation inst = ftn->GetMethodInstantiation();
7137
7138 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7139 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
7140
7141 static BYTE ilcode[] = { CEE_PREFIX1, (CEE_SIZEOF & 0xFF), 0,0,0,0, CEE_RET };
7142
7143 ilcode[2] = (BYTE)(tokGenericArg);
7144 ilcode[3] = (BYTE)(tokGenericArg >> 8);
7145 ilcode[4] = (BYTE)(tokGenericArg >> 16);
7146 ilcode[5] = (BYTE)(tokGenericArg >> 24);
7147
7148 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7149 methInfo->ILCodeSize = sizeof(ilcode);
7150 methInfo->maxStack = 1;
7151 methInfo->EHcount = 0;
7152 methInfo->options = (CorInfoOptions)0;
7153 return true;
7154 }
7155 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_AS)->GetMemberDef() ||
7156 tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__OBJECT_AS)->GetMemberDef() ||
7157 tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__AS_REF_POINTER)->GetMemberDef() ||
7158 tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__AS_REF_IN)->GetMemberDef())
7159 {
7160 // Return the argument that was passed in.
7161 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_RET };
7162 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7163 methInfo->ILCodeSize = sizeof(ilcode);
7164 methInfo->maxStack = 1;
7165 methInfo->EHcount = 0;
7166 methInfo->options = (CorInfoOptions)0;
7167 return true;
7168 }
7169 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ADD)->GetMemberDef() ||
7170 tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__PTR_ADD)->GetMemberDef())
7171 {
7172 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
7173
7174 static BYTE ilcode[] = { CEE_LDARG_1,
7175 CEE_PREFIX1, (CEE_SIZEOF & 0xFF), 0,0,0,0,
7176 CEE_CONV_I,
7177 CEE_MUL,
7178 CEE_LDARG_0,
7179 CEE_ADD,
7180 CEE_RET };
7181
7182 ilcode[3] = (BYTE)(tokGenericArg);
7183 ilcode[4] = (BYTE)(tokGenericArg >> 8);
7184 ilcode[5] = (BYTE)(tokGenericArg >> 16);
7185 ilcode[6] = (BYTE)(tokGenericArg >> 24);
7186
7187 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7188 methInfo->ILCodeSize = sizeof(ilcode);
7189 methInfo->maxStack = 2;
7190 methInfo->EHcount = 0;
7191 methInfo->options = (CorInfoOptions)0;
7192 return true;
7193 }
7194 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_INTPTR_ADD)->GetMemberDef())
7195 {
7196 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
7197
7198 static BYTE ilcode[] = { CEE_LDARG_1,
7199 CEE_PREFIX1, (CEE_SIZEOF & 0xFF), 0,0,0,0,
7200 CEE_MUL,
7201 CEE_LDARG_0,
7202 CEE_ADD,
7203 CEE_RET };
7204
7205 ilcode[3] = (BYTE)(tokGenericArg);
7206 ilcode[4] = (BYTE)(tokGenericArg >> 8);
7207 ilcode[5] = (BYTE)(tokGenericArg >> 16);
7208 ilcode[6] = (BYTE)(tokGenericArg >> 24);
7209
7210 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7211 methInfo->ILCodeSize = sizeof(ilcode);
7212 methInfo->maxStack = 2;
7213 methInfo->EHcount = 0;
7214 methInfo->options = (CorInfoOptions)0;
7215 return true;
7216 }
7217 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ADD_BYTE_OFFSET)->GetMemberDef())
7218 {
7219 static BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_ADD, CEE_RET };
7220
7221 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7222 methInfo->ILCodeSize = sizeof(ilcode);
7223 methInfo->maxStack = 2;
7224 methInfo->EHcount = 0;
7225 methInfo->options = (CorInfoOptions)0;
7226 return true;
7227 }
7228 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ARE_SAME)->GetMemberDef())
7229 {
7230 // Compare the two arguments
7231 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (CEE_CEQ & 0xFF), CEE_RET };
7232 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7233 methInfo->ILCodeSize = sizeof(ilcode);
7234 methInfo->maxStack = 2;
7235 methInfo->EHcount = 0;
7236 methInfo->options = (CorInfoOptions)0;
7237 return true;
7238 }
7239 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_IS_ADDRESS_GREATER_THAN)->GetMemberDef())
7240 {
7241 // Compare the two arguments
7242 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (CEE_CGT_UN & 0xFF), CEE_RET };
7243 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7244 methInfo->ILCodeSize = sizeof(ilcode);
7245 methInfo->maxStack = 2;
7246 methInfo->EHcount = 0;
7247 methInfo->options = (CorInfoOptions)0;
7248 return true;
7249 }
7250 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_IS_ADDRESS_LESS_THAN)->GetMemberDef())
7251 {
7252 // Compare the two arguments
7253 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (CEE_CLT_UN & 0xFF), CEE_RET };
7254 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7255 methInfo->ILCodeSize = sizeof(ilcode);
7256 methInfo->maxStack = 2;
7257 methInfo->EHcount = 0;
7258 methInfo->options = (CorInfoOptions)0;
7259 return true;
7260 }
7261 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_INIT_BLOCK_UNALIGNED)->GetMemberDef())
7262 {
7263 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_LDARG_2, CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 0x01, CEE_PREFIX1, (CEE_INITBLK & 0xFF), CEE_RET };
7264 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7265 methInfo->ILCodeSize = sizeof(ilcode);
7266 methInfo->maxStack = 3;
7267 methInfo->EHcount = 0;
7268 methInfo->options = (CorInfoOptions)0;
7269 return true;
7270 }
7271 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_BYTE_OFFSET)->GetMemberDef())
7272 {
7273 static const BYTE ilcode[] =
7274 {
7275 CEE_LDARG_1,
7276 CEE_LDARG_0,
7277 CEE_SUB,
7278 CEE_RET
7279 };
7280
7281 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7282 methInfo->ILCodeSize = sizeof(ilcode);
7283 methInfo->maxStack = 2;
7284 methInfo->EHcount = 0;
7285 methInfo->options = (CorInfoOptions)0;
7286 return true;
7287 }
7288 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_READ_UNALIGNED)->GetMemberDef() ||
7289 tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__PTR_READ_UNALIGNED)->GetMemberDef())
7290 {
7291 _ASSERTE(ftn->HasMethodInstantiation());
7292 Instantiation inst = ftn->GetMethodInstantiation();
7293 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7294 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
7295
7296 static const BYTE ilcode[]
7297 {
7298 CEE_LDARG_0,
7299 CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 1,
7300 CEE_LDOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
7301 CEE_RET
7302 };
7303
7304 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7305 methInfo->ILCodeSize = sizeof(ilcode);
7306 methInfo->maxStack = 2;
7307 methInfo->EHcount = 0;
7308 methInfo->options = (CorInfoOptions)0;
7309 return true;
7310 }
7311 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_WRITE_UNALIGNED)->GetMemberDef() ||
7312 tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__PTR_WRITE_UNALIGNED)->GetMemberDef())
7313 {
7314 _ASSERTE(ftn->HasMethodInstantiation());
7315 Instantiation inst = ftn->GetMethodInstantiation();
7316 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7317 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
7318
7319 static const BYTE ilcode[]
7320 {
7321 CEE_LDARG_0,
7322 CEE_LDARG_1,
7323 CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 1,
7324 CEE_STOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
7325 CEE_RET
7326 };
7327
7328 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7329 methInfo->ILCodeSize = sizeof(ilcode);
7330 methInfo->maxStack = 2;
7331 methInfo->EHcount = 0;
7332 methInfo->options = (CorInfoOptions)0;
7333 return true;
7334 }
7335
7336 return false;
7337}
7338
7339bool getILIntrinsicImplementationForVolatile(MethodDesc * ftn,
7340 CORINFO_METHOD_INFO * methInfo)
7341{
7342 STANDARD_VM_CONTRACT;
7343
7344 //
7345 // This replaces the implementations of Volatile.* in mscorlib with more efficient ones.
7346 // We do this because we cannot otherwise express these in C#. What we *want* to do is
7347 // to treat the byref args to these methods as "volatile." In pseudo-C#, this would look
7348 // like:
7349 //
7350 // int Read(ref volatile int location)
7351 // {
7352 // return location;
7353 // }
7354 //
7355 // However, C# does not yet provide a way to declare a byref as "volatile." So instead,
7356 // we substitute raw IL bodies for these methods that use the correct volatile instructions.
7357 //
7358
7359 // Precondition: ftn is a method in mscorlib in the System.Threading.Volatile class
7360 _ASSERTE(ftn->GetModule()->IsSystem());
7361 _ASSERTE(MscorlibBinder::IsClass(ftn->GetMethodTable(), CLASS__VOLATILE));
7362 _ASSERTE(strcmp(ftn->GetMethodTable()->GetClass()->GetDebugClassName(), "System.Threading.Volatile") == 0);
7363
7364 const size_t VolatileMethodBodySize = 6;
7365
7366 struct VolatileMethodImpl
7367 {
7368 BinderMethodID methodId;
7369 BYTE body[VolatileMethodBodySize];
7370 };
7371
7372#define VOLATILE_IMPL(type, loadinst, storeinst) \
7373 { \
7374 METHOD__VOLATILE__READ_##type, \
7375 { \
7376 CEE_LDARG_0, \
7377 CEE_PREFIX1, (CEE_VOLATILE & 0xFF), \
7378 loadinst, \
7379 CEE_NOP, /*pad to VolatileMethodBodySize bytes*/ \
7380 CEE_RET \
7381 } \
7382 }, \
7383 { \
7384 METHOD__VOLATILE__WRITE_##type, \
7385 { \
7386 CEE_LDARG_0, \
7387 CEE_LDARG_1, \
7388 CEE_PREFIX1, (CEE_VOLATILE & 0xFF), \
7389 storeinst, \
7390 CEE_RET \
7391 } \
7392 },
7393
7394 static const VolatileMethodImpl volatileImpls[] =
7395 {
7396 VOLATILE_IMPL(T, CEE_LDIND_REF, CEE_STIND_REF)
7397 VOLATILE_IMPL(Bool, CEE_LDIND_I1, CEE_STIND_I1)
7398 VOLATILE_IMPL(Int, CEE_LDIND_I4, CEE_STIND_I4)
7399 VOLATILE_IMPL(IntPtr, CEE_LDIND_I, CEE_STIND_I)
7400 VOLATILE_IMPL(UInt, CEE_LDIND_U4, CEE_STIND_I4)
7401 VOLATILE_IMPL(UIntPtr, CEE_LDIND_I, CEE_STIND_I)
7402 VOLATILE_IMPL(SByt, CEE_LDIND_I1, CEE_STIND_I1)
7403 VOLATILE_IMPL(Byte, CEE_LDIND_U1, CEE_STIND_I1)
7404 VOLATILE_IMPL(Shrt, CEE_LDIND_I2, CEE_STIND_I2)
7405 VOLATILE_IMPL(UShrt, CEE_LDIND_U2, CEE_STIND_I2)
7406 VOLATILE_IMPL(Flt, CEE_LDIND_R4, CEE_STIND_R4)
7407
7408 //
7409 // Ordinary volatile loads and stores only guarantee atomicity for pointer-sized (or smaller) data.
7410 // So, on 32-bit platforms we must use Interlocked operations instead for the 64-bit types.
7411 // The implementation in mscorlib already does this, so we will only substitute a new
7412 // IL body if we're running on a 64-bit platform.
7413 //
7414 IN_TARGET_64BIT(VOLATILE_IMPL(Long, CEE_LDIND_I8, CEE_STIND_I8))
7415 IN_TARGET_64BIT(VOLATILE_IMPL(ULong, CEE_LDIND_I8, CEE_STIND_I8))
7416 IN_TARGET_64BIT(VOLATILE_IMPL(Dbl, CEE_LDIND_R8, CEE_STIND_R8))
7417 };
7418
7419 mdMethodDef md = ftn->GetMemberDef();
7420 for (unsigned i = 0; i < NumItems(volatileImpls); i++)
7421 {
7422 if (md == MscorlibBinder::GetMethod(volatileImpls[i].methodId)->GetMemberDef())
7423 {
7424 methInfo->ILCode = const_cast<BYTE*>(volatileImpls[i].body);
7425 methInfo->ILCodeSize = VolatileMethodBodySize;
7426 methInfo->maxStack = 2;
7427 methInfo->EHcount = 0;
7428 methInfo->options = (CorInfoOptions)0;
7429 return true;
7430 }
7431 }
7432
7433 return false;
7434}
7435
7436bool getILIntrinsicImplementationForInterlocked(MethodDesc * ftn,
7437 CORINFO_METHOD_INFO * methInfo)
7438{
7439 STANDARD_VM_CONTRACT;
7440
7441 // Precondition: ftn is a method in mscorlib in the System.Threading.Interlocked class
7442 _ASSERTE(ftn->GetModule()->IsSystem());
7443 _ASSERTE(MscorlibBinder::IsClass(ftn->GetMethodTable(), CLASS__INTERLOCKED));
7444
7445 // We are only interested if ftn's token and CompareExchange<T> token match
7446 if (ftn->GetMemberDef() != MscorlibBinder::GetMethod(METHOD__INTERLOCKED__COMPARE_EXCHANGE_T)->GetMemberDef())
7447 return false;
7448
7449 // Get MethodDesc for System.Threading.Interlocked.CompareExchangeFast()
7450 MethodDesc* cmpxchgFast = MscorlibBinder::GetMethod(METHOD__INTERLOCKED__COMPARE_EXCHANGE_OBJECT);
7451
7452 // The MethodDesc lookup must not fail, and it should have the name "CompareExchangeFast"
7453 _ASSERTE(cmpxchgFast != NULL);
7454 _ASSERTE(strcmp(cmpxchgFast->GetName(), "CompareExchange") == 0);
7455
7456 // Setup up the body of the method
7457 static BYTE il[] = {
7458 CEE_LDARG_0,
7459 CEE_LDARG_1,
7460 CEE_LDARG_2,
7461 CEE_CALL,0,0,0,0,
7462 CEE_RET
7463 };
7464
7465 // Get the token for System.Threading.Interlocked.CompareExchangeFast(), and patch [target]
7466 mdMethodDef cmpxchgFastToken = cmpxchgFast->GetMemberDef();
7467 il[4] = (BYTE)((int)cmpxchgFastToken >> 0);
7468 il[5] = (BYTE)((int)cmpxchgFastToken >> 8);
7469 il[6] = (BYTE)((int)cmpxchgFastToken >> 16);
7470 il[7] = (BYTE)((int)cmpxchgFastToken >> 24);
7471
7472 // Initialize methInfo
7473 methInfo->ILCode = const_cast<BYTE*>(il);
7474 methInfo->ILCodeSize = sizeof(il);
7475 methInfo->maxStack = 3;
7476 methInfo->EHcount = 0;
7477 methInfo->options = (CorInfoOptions)0;
7478
7479 return true;
7480}
7481
7482bool getILIntrinsicImplementationForRuntimeHelpers(MethodDesc * ftn,
7483 CORINFO_METHOD_INFO * methInfo)
7484{
7485 STANDARD_VM_CONTRACT;
7486
7487 // Precondition: ftn is a method in mscorlib
7488 _ASSERTE(ftn->GetModule()->IsSystem());
7489
7490 mdMethodDef tk = ftn->GetMemberDef();
7491
7492 if (tk == MscorlibBinder::GetMethod(METHOD__RUNTIME_HELPERS__IS_REFERENCE_OR_CONTAINS_REFERENCES)->GetMemberDef())
7493 {
7494 _ASSERTE(ftn->HasMethodInstantiation());
7495 Instantiation inst = ftn->GetMethodInstantiation();
7496
7497 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7498 TypeHandle typeHandle = inst[0];
7499 MethodTable * methodTable = typeHandle.GetMethodTable();
7500
7501 static const BYTE returnTrue[] = { CEE_LDC_I4_1, CEE_RET };
7502 static const BYTE returnFalse[] = { CEE_LDC_I4_0, CEE_RET };
7503
7504 if (!methodTable->IsValueType() || methodTable->ContainsPointers())
7505 {
7506 methInfo->ILCode = const_cast<BYTE*>(returnTrue);
7507 }
7508 else
7509 {
7510 methInfo->ILCode = const_cast<BYTE*>(returnFalse);
7511 }
7512
7513 methInfo->ILCodeSize = sizeof(returnTrue);
7514 methInfo->maxStack = 1;
7515 methInfo->EHcount = 0;
7516 methInfo->options = (CorInfoOptions)0;
7517 return true;
7518 }
7519
7520 return false;
7521}
7522
7523//---------------------------------------------------------------------------------------
7524//
7525//static
7526void
7527getMethodInfoHelper(
7528 MethodDesc * ftn,
7529 CORINFO_METHOD_HANDLE ftnHnd,
7530 COR_ILMETHOD_DECODER * header,
7531 CORINFO_METHOD_INFO * methInfo)
7532{
7533 STANDARD_VM_CONTRACT;
7534
7535 _ASSERTE(ftn == GetMethod(ftnHnd));
7536
7537 methInfo->ftn = ftnHnd;
7538 methInfo->scope = GetScopeHandle(ftn);
7539 methInfo->regionKind = CORINFO_REGION_JIT;
7540 //
7541 // For Jitted code the regionKind is JIT;
7542 // For Ngen-ed code the zapper will set this to HOT or COLD, if we
7543 // are using IBC data to partition methods into Hot/Cold regions
7544
7545 /* Grab information from the IL header */
7546
7547 PCCOR_SIGNATURE pLocalSig = NULL;
7548 DWORD cbLocalSig = 0;
7549
7550 if (NULL != header)
7551 {
7552 bool fILIntrinsic = false;
7553
7554 MethodTable * pMT = ftn->GetMethodTable();
7555
7556 if (pMT->GetModule()->IsSystem())
7557 {
7558 if (MscorlibBinder::IsClass(pMT, CLASS__JIT_HELPERS))
7559 {
7560 fILIntrinsic = getILIntrinsicImplementation(ftn, methInfo);
7561 }
7562 else if (MscorlibBinder::IsClass(pMT, CLASS__UNSAFE))
7563 {
7564 fILIntrinsic = getILIntrinsicImplementationForUnsafe(ftn, methInfo);
7565 }
7566 else if (MscorlibBinder::IsClass(pMT, CLASS__INTERLOCKED))
7567 {
7568 fILIntrinsic = getILIntrinsicImplementationForInterlocked(ftn, methInfo);
7569 }
7570 else if (MscorlibBinder::IsClass(pMT, CLASS__VOLATILE))
7571 {
7572 fILIntrinsic = getILIntrinsicImplementationForVolatile(ftn, methInfo);
7573 }
7574 else if (MscorlibBinder::IsClass(pMT, CLASS__RUNTIME_HELPERS))
7575 {
7576 fILIntrinsic = getILIntrinsicImplementationForRuntimeHelpers(ftn, methInfo);
7577 }
7578 }
7579
7580 if (!fILIntrinsic)
7581 {
7582 getMethodInfoILMethodHeaderHelper(header, methInfo);
7583 pLocalSig = header->LocalVarSig;
7584 cbLocalSig = header->cbLocalVarSig;
7585 }
7586 }
7587 else
7588 {
7589 _ASSERTE(ftn->IsDynamicMethod());
7590
7591 DynamicResolver * pResolver = ftn->AsDynamicMethodDesc()->GetResolver();
7592 unsigned int EHCount;
7593 methInfo->ILCode = pResolver->GetCodeInfo(&methInfo->ILCodeSize,
7594 &methInfo->maxStack,
7595 &methInfo->options,
7596 &EHCount);
7597 methInfo->EHcount = (unsigned short)EHCount;
7598 SigPointer localSig = pResolver->GetLocalSig();
7599 localSig.GetSignature(&pLocalSig, &cbLocalSig);
7600 }
7601
7602 methInfo->options = (CorInfoOptions)(((UINT32)methInfo->options) |
7603 ((ftn->AcquiresInstMethodTableFromThis() ? CORINFO_GENERICS_CTXT_FROM_THIS : 0) |
7604 (ftn->RequiresInstMethodTableArg() ? CORINFO_GENERICS_CTXT_FROM_METHODTABLE : 0) |
7605 (ftn->RequiresInstMethodDescArg() ? CORINFO_GENERICS_CTXT_FROM_METHODDESC : 0)));
7606
7607 // EEJitManager::ResolveEHClause and CrawlFrame::GetExactGenericInstantiations
7608 // need to be able to get to CORINFO_GENERICS_CTXT_MASK if there are any
7609 // catch clauses like "try {} catch(MyException<T> e) {}".
7610 // Such constructs are rare, and having to extend the lifetime of variable
7611 // for such cases is reasonable
7612
7613 if (methInfo->options & CORINFO_GENERICS_CTXT_MASK)
7614 {
7615#if defined(PROFILING_SUPPORTED)
7616 BOOL fProfilerRequiresGenericsContextForEnterLeave = FALSE;
7617 {
7618 BEGIN_PIN_PROFILER(CORProfilerPresent());
7619 if (g_profControlBlock.pProfInterface->RequiresGenericsContextForEnterLeave())
7620 {
7621 fProfilerRequiresGenericsContextForEnterLeave = TRUE;
7622 }
7623 END_PIN_PROFILER();
7624 }
7625 if (fProfilerRequiresGenericsContextForEnterLeave)
7626 {
7627 methInfo->options = CorInfoOptions(methInfo->options|CORINFO_GENERICS_CTXT_KEEP_ALIVE);
7628 }
7629 else
7630#endif // defined(PROFILING_SUPPORTED)
7631 {
7632 // Check all the exception clauses
7633
7634 if (ftn->IsDynamicMethod())
7635 {
7636 // @TODO: how do we detect the need to mark this flag?
7637 }
7638 else
7639 {
7640 COR_ILMETHOD_SECT_EH_CLAUSE_FAT ehClause;
7641
7642 for (unsigned i = 0; i < methInfo->EHcount; i++)
7643 {
7644 const COR_ILMETHOD_SECT_EH_CLAUSE_FAT* ehInfo =
7645 (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)header->EH->EHClause(i, &ehClause);
7646
7647 // Is it a typed catch clause?
7648 if (ehInfo->GetFlags() != COR_ILEXCEPTION_CLAUSE_NONE)
7649 continue;
7650
7651 // Check if we catch "C<T>" ?
7652
7653 DWORD catchTypeToken = ehInfo->GetClassToken();
7654 if (TypeFromToken(catchTypeToken) != mdtTypeSpec)
7655 continue;
7656
7657 PCCOR_SIGNATURE pSig;
7658 ULONG cSig;
7659 IfFailThrow(ftn->GetMDImport()->GetTypeSpecFromToken(catchTypeToken, &pSig, &cSig));
7660
7661 SigPointer psig(pSig, cSig);
7662
7663 SigTypeContext sigTypeContext(ftn);
7664 if (psig.IsPolyType(&sigTypeContext) & hasSharableVarsMask)
7665 {
7666 methInfo->options = CorInfoOptions(methInfo->options|CORINFO_GENERICS_CTXT_KEEP_ALIVE);
7667 break;
7668 }
7669 }
7670 }
7671 }
7672 }
7673
7674 PCCOR_SIGNATURE pSig = NULL;
7675 DWORD cbSig = 0;
7676 ftn->GetSig(&pSig, &cbSig);
7677
7678 /* Fetch the method signature */
7679 // Type parameters in the signature should be instantiated according to the
7680 // class/method/array instantiation of ftnHnd
7681 CEEInfo::ConvToJitSig(
7682 pSig,
7683 cbSig,
7684 GetScopeHandle(ftn),
7685 mdTokenNil,
7686 &methInfo->args,
7687 ftn,
7688 false);
7689
7690 // Shared generic or static per-inst methods and shared methods on generic structs
7691 // take an extra argument representing their instantiation
7692 if (ftn->RequiresInstArg())
7693 methInfo->args.callConv = (CorInfoCallConv)(methInfo->args.callConv | CORINFO_CALLCONV_PARAMTYPE);
7694
7695 _ASSERTE((IsMdStatic(ftn->GetAttrs()) == 0) == ((methInfo->args.callConv & CORINFO_CALLCONV_HASTHIS) != 0));
7696
7697 /* And its local variables */
7698 // Type parameters in the signature should be instantiated according to the
7699 // class/method/array instantiation of ftnHnd
7700 CEEInfo::ConvToJitSig(
7701 pLocalSig,
7702 cbLocalSig,
7703 GetScopeHandle(ftn),
7704 mdTokenNil,
7705 &methInfo->locals,
7706 ftn,
7707 true);
7708} // getMethodInfoHelper
7709
7710//---------------------------------------------------------------------------------------
7711//
7712bool
7713CEEInfo::getMethodInfo(
7714 CORINFO_METHOD_HANDLE ftnHnd,
7715 CORINFO_METHOD_INFO * methInfo)
7716{
7717 CONTRACTL {
7718 SO_TOLERANT;
7719 THROWS;
7720 GC_TRIGGERS;
7721 MODE_PREEMPTIVE;
7722 } CONTRACTL_END;
7723
7724 bool result = false;
7725
7726 JIT_TO_EE_TRANSITION();
7727
7728 MethodDesc * ftn = GetMethod(ftnHnd);
7729
7730 if (!ftn->IsDynamicMethod() && (!ftn->IsIL() || !ftn->GetRVA() || ftn->IsWrapperStub()))
7731 {
7732 /* Return false if not IL or has no code */
7733 result = false;
7734 }
7735 else
7736 {
7737 /* Get the IL header */
7738
7739 if (ftn->IsDynamicMethod())
7740 {
7741 getMethodInfoHelper(ftn, ftnHnd, NULL, methInfo);
7742 }
7743 else
7744 {
7745 COR_ILMETHOD_DECODER header(ftn->GetILHeader(TRUE), ftn->GetMDImport(), NULL);
7746
7747 getMethodInfoHelper(ftn, ftnHnd, &header, methInfo);
7748 }
7749
7750 LOG((LF_JIT, LL_INFO100000, "Getting method info (possible inline) %s::%s%s\n",
7751 ftn->m_pszDebugClassName, ftn->m_pszDebugMethodName, ftn->m_pszDebugMethodSignature));
7752
7753 result = true;
7754 }
7755
7756 EE_TO_JIT_TRANSITION();
7757
7758 return result;
7759}
7760
7761#ifdef _DEBUG
7762
7763/************************************************************************
7764 Return true when ftn contains a local of type CLASS__STACKCRAWMARK
7765*/
7766
7767bool containsStackCrawlMarkLocal(MethodDesc* ftn)
7768{
7769 STANDARD_VM_CONTRACT;
7770
7771 COR_ILMETHOD* ilHeader = ftn->GetILHeader();
7772 _ASSERTE(ilHeader);
7773
7774 COR_ILMETHOD_DECODER header(ilHeader, ftn->GetMDImport(), NULL);
7775
7776 if (header.LocalVarSig == NULL)
7777 return NULL;
7778
7779 SigPointer ptr(header.LocalVarSig, header.cbLocalVarSig);
7780
7781 IfFailThrow(ptr.GetData(NULL)); // IMAGE_CEE_CS_CALLCONV_LOCAL_SIG
7782
7783 ULONG numLocals;
7784 IfFailThrow(ptr.GetData(&numLocals));
7785
7786 for(ULONG i = 0; i < numLocals; i++)
7787 {
7788 CorElementType eType;
7789 IfFailThrow(ptr.PeekElemType(&eType));
7790 if (eType != ELEMENT_TYPE_VALUETYPE)
7791 {
7792 IfFailThrow(ptr.SkipExactlyOne());
7793 continue;
7794 }
7795
7796 IfFailThrow(ptr.GetElemType(NULL));
7797
7798 mdToken token;
7799 IfFailThrow(ptr.GetToken(&token));
7800
7801 // We are inside mscorlib - simple token match is sufficient
7802 if (token == MscorlibBinder::GetClass(CLASS__STACKCRAWMARK)->GetCl())
7803 return TRUE;
7804 }
7805
7806 return FALSE;
7807}
7808
7809#endif
7810
7811/*************************************************************
7812 * Check if the caller and calle are in the same assembly
7813 * i.e. do not inline across assemblies
7814 *************************************************************/
7815
7816CorInfoInline CEEInfo::canInline (CORINFO_METHOD_HANDLE hCaller,
7817 CORINFO_METHOD_HANDLE hCallee,
7818 DWORD* pRestrictions)
7819{
7820 CONTRACTL {
7821 SO_TOLERANT;
7822 THROWS;
7823 GC_TRIGGERS;
7824 MODE_PREEMPTIVE;
7825 } CONTRACTL_END;
7826
7827 CorInfoInline result = INLINE_PASS; // By default we pass.
7828 // Do not set pass in the rest of the method.
7829 DWORD dwRestrictions = 0; // By default, no restrictions
7830 const char * szFailReason = NULL; // for reportInlineDecision
7831
7832 JIT_TO_EE_TRANSITION();
7833
7834 // This does not work in the multi-threaded case
7835#if 0
7836 // Caller should check this condition first
7837 _ASSERTE(!(CORINFO_FLG_DONT_INLINE & getMethodAttribsInternal(hCallee)));
7838#endif
7839
7840 MethodDesc* pCaller = GetMethod(hCaller);
7841 MethodDesc* pCallee = GetMethod(hCallee);
7842
7843 if (pCallee->IsNoMetadata())
7844 {
7845 result = INLINE_FAIL;
7846 szFailReason = "Inlinee is NoMetadata";
7847 goto exit;
7848 }
7849
7850#ifdef DEBUGGING_SUPPORTED
7851
7852 // If the callee wants debuggable code, don't allow it to be inlined
7853
7854 {
7855 // Combining the next two lines, and eliminating jitDebuggerFlags, leads to bad codegen in x86 Release builds using Visual C++ 19.00.24215.1.
7856 CORJIT_FLAGS jitDebuggerFlags = GetDebuggerCompileFlags(pCallee->GetModule(), CORJIT_FLAGS());
7857 if (jitDebuggerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE))
7858 {
7859 result = INLINE_NEVER;
7860 szFailReason = "Inlinee is debuggable";
7861 goto exit;
7862 }
7863 }
7864#endif
7865
7866 // The orginal caller is the current method
7867 MethodDesc * pOrigCaller;
7868 pOrigCaller = m_pMethodBeingCompiled;
7869 Module * pOrigCallerModule;
7870 pOrigCallerModule = pOrigCaller->GetLoaderModule();
7871
7872 if (pCallee->IsNotInline())
7873 {
7874 result = INLINE_NEVER;
7875 szFailReason = "Inlinee is marked as no inline";
7876 goto exit;
7877 }
7878
7879 // Also check to see if the method requires a security object. This means they call demand and
7880 // shouldn't be inlined.
7881 if (IsMdRequireSecObject(pCallee->GetAttrs()))
7882 {
7883 result = INLINE_NEVER;
7884 szFailReason = "Inlinee requires a security object (or contains StackCrawlMark)";
7885 goto exit;
7886 }
7887
7888 // If the method is MethodImpl'd by another method within the same type, then we have
7889 // an issue that the importer will import the wrong body. In this case, we'll just
7890 // disallow inlining because getFunctionEntryPoint will do the right thing.
7891 {
7892 MethodDesc *pMDDecl = pCallee;
7893 MethodTable *pMT = pMDDecl->GetMethodTable();
7894 MethodDesc *pMDImpl = pMT->MapMethodDeclToMethodImpl(pMDDecl);
7895
7896 if (pMDDecl != pMDImpl)
7897 {
7898 result = INLINE_NEVER;
7899 szFailReason = "Inlinee is MethodImpl'd by another method within the same type";
7900 goto exit;
7901 }
7902 }
7903
7904 //
7905 // Perform the Cross-Assembly inlining checks
7906 //
7907 {
7908 Module * pCalleeModule = pCallee->GetModule();
7909
7910#ifdef FEATURE_PREJIT
7911 Assembly * pCalleeAssembly = pCalleeModule->GetAssembly();
7912
7913#ifdef _DEBUG
7914 //
7915 // Make sure that all methods with StackCrawlMark are marked as IsMdRequireSecObject
7916 //
7917 if (pCalleeAssembly->IsSystem())
7918 {
7919 _ASSERTE(!containsStackCrawlMarkLocal(pCallee));
7920 }
7921#endif
7922
7923 // To allow for servicing of Ngen images we want to disable most
7924 // Cross-Assembly inlining except for the cases that we explicitly allow.
7925 //
7926 if (IsCompilingForNGen())
7927 {
7928 // This is an canInline call at Ngen time
7929 //
7930 //
7931 Assembly * pOrigCallerAssembly = pOrigCallerModule->GetAssembly();
7932
7933 if (pCalleeAssembly == pOrigCallerAssembly)
7934 {
7935 // Within the same assembly
7936 // we can freely inline with no restrictions
7937 }
7938 else
7939 {
7940#ifdef FEATURE_READYTORUN_COMPILER
7941 // No inlinining for version resilient code except if in the same version bubble
7942 // If this condition changes, please make the corresponding change
7943 // in getCallInfo, too.
7944 if (IsReadyToRunCompilation() &&
7945 !isVerifyOnly() &&
7946 !IsInSameVersionBubble(pCaller, pCallee)
7947 )
7948 {
7949 result = INLINE_NEVER;
7950 szFailReason = "Cross-module inlining in version resilient code";
7951 goto exit;
7952 }
7953#endif
7954 }
7955 }
7956#endif // FEATURE_PREJIT
7957
7958 // TODO: We can probably be smarter here if the caller is jitted, as we will
7959 // know for sure if the inlinee has really no string interning active (currently
7960 // it's only on in the ngen case (besides requiring the attribute)), but this is getting
7961 // too subtle. Will only do if somebody screams about it, as bugs here are going to
7962 // be tough to find
7963 if ((pOrigCallerModule != pCalleeModule) && pCalleeModule->IsNoStringInterning())
7964 {
7965 dwRestrictions |= INLINE_NO_CALLEE_LDSTR;
7966 }
7967 }
7968
7969#ifdef PROFILING_SUPPORTED
7970 if (CORProfilerPresent())
7971 {
7972 // #rejit
7973 //
7974 // Currently the rejit path is the only path which sets this.
7975 // If we get more reasons to set this then we may need to change
7976 // the failure reason message or disambiguate them.
7977 if (!m_allowInlining)
7978 {
7979 result = INLINE_FAIL;
7980 szFailReason = "ReJIT request disabled inlining from caller";
7981 goto exit;
7982 }
7983
7984 // If the profiler has set a mask preventing inlining, always return
7985 // false to the jit.
7986 if (CORProfilerDisableInlining())
7987 {
7988 result = INLINE_FAIL;
7989 szFailReason = "Profiler disabled inlining globally";
7990 goto exit;
7991 }
7992
7993 // If the profiler wishes to be notified of JIT events and the result from
7994 // the above tests will cause a function to be inlined, we need to tell the
7995 // profiler that this inlining is going to take place, and give them a
7996 // chance to prevent it.
7997 {
7998 BEGIN_PIN_PROFILER(CORProfilerTrackJITInfo());
7999 if (pCaller->IsILStub() || pCallee->IsILStub())
8000 {
8001 // do nothing
8002 }
8003 else
8004 {
8005 BOOL fShouldInline;
8006
8007 HRESULT hr = g_profControlBlock.pProfInterface->JITInlining(
8008 (FunctionID)pCaller,
8009 (FunctionID)pCallee,
8010 &fShouldInline);
8011
8012 if (SUCCEEDED(hr) && !fShouldInline)
8013 {
8014 result = INLINE_FAIL;
8015 szFailReason = "Profiler disabled inlining locally";
8016 goto exit;
8017 }
8018 }
8019 END_PIN_PROFILER();
8020 }
8021 }
8022#endif // PROFILING_SUPPORTED
8023
8024exit: ;
8025
8026 EE_TO_JIT_TRANSITION();
8027
8028 if (result == INLINE_PASS && dwRestrictions)
8029 {
8030 if (pRestrictions)
8031 {
8032 *pRestrictions = dwRestrictions;
8033 }
8034 else
8035 {
8036 // If the jitter didn't want to know about restrictions, it shouldn't be inlining
8037 result = INLINE_FAIL;
8038 szFailReason = "Inlinee has restrictions the JIT doesn't want";
8039 }
8040 }
8041 else
8042 {
8043 if (pRestrictions)
8044 {
8045 // Denied inlining, makes no sense to pass out restrictions,
8046 *pRestrictions = 0;
8047 }
8048 }
8049
8050 if (dontInline(result))
8051 {
8052 // If you hit this assert, it means you added a new way to prevent inlining
8053 // without documenting it for ETW!
8054 _ASSERTE(szFailReason != NULL);
8055 reportInliningDecision(hCaller, hCallee, result, szFailReason);
8056 }
8057
8058 return result;
8059}
8060
8061void CEEInfo::reportInliningDecision (CORINFO_METHOD_HANDLE inlinerHnd,
8062 CORINFO_METHOD_HANDLE inlineeHnd,
8063 CorInfoInline inlineResult,
8064 const char * reason)
8065{
8066 STATIC_CONTRACT_THROWS;
8067 STATIC_CONTRACT_GC_TRIGGERS;
8068 STATIC_CONTRACT_SO_TOLERANT;
8069
8070 JIT_TO_EE_TRANSITION();
8071
8072#ifdef _DEBUG
8073 if (LoggingOn(LF_JIT, LL_INFO100000))
8074 {
8075 SString currentMethodName;
8076 currentMethodName.AppendUTF8(m_pMethodBeingCompiled->GetModule_NoLogging()->GetFile()->GetSimpleName());
8077 currentMethodName.Append(L'/');
8078 TypeString::AppendMethodInternal(currentMethodName, m_pMethodBeingCompiled, TypeString::FormatBasic);
8079
8080 SString inlineeMethodName;
8081 if (GetMethod(inlineeHnd))
8082 {
8083 inlineeMethodName.AppendUTF8(GetMethod(inlineeHnd)->GetModule_NoLogging()->GetFile()->GetSimpleName());
8084 inlineeMethodName.Append(L'/');
8085 TypeString::AppendMethodInternal(inlineeMethodName, GetMethod(inlineeHnd), TypeString::FormatBasic);
8086 }
8087 else
8088 {
8089 inlineeMethodName.AppendASCII( "<null>" );
8090 }
8091
8092 SString inlinerMethodName;
8093 if (GetMethod(inlinerHnd))
8094 {
8095 inlinerMethodName.AppendUTF8(GetMethod(inlinerHnd)->GetModule_NoLogging()->GetFile()->GetSimpleName());
8096 inlinerMethodName.Append(L'/');
8097 TypeString::AppendMethodInternal(inlinerMethodName, GetMethod(inlinerHnd), TypeString::FormatBasic);
8098 }
8099 else
8100 {
8101 inlinerMethodName.AppendASCII("<null>");
8102 }
8103
8104 if (dontInline(inlineResult))
8105 {
8106 LOG((LF_JIT, LL_INFO100000,
8107 "While compiling '%S', inline of '%S' into '%S' failed because: '%s'.\n",
8108 currentMethodName.GetUnicode(), inlineeMethodName.GetUnicode(),
8109 inlinerMethodName.GetUnicode(), reason));
8110 }
8111 else
8112 {
8113 LOG((LF_JIT, LL_INFO100000, "While compiling '%S', inline of '%S' into '%S' succeeded.\n",
8114 currentMethodName.GetUnicode(), inlineeMethodName.GetUnicode(),
8115 inlinerMethodName.GetUnicode()));
8116
8117 }
8118 }
8119#endif //_DEBUG
8120
8121 //I'm gonna duplicate this code because the format is slightly different. And LoggingOn is debug only.
8122 if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context,
8123 TRACE_LEVEL_VERBOSE,
8124 CLR_JITTRACING_KEYWORD))
8125 {
8126 SString methodBeingCompiledNames[3];
8127 SString inlinerNames[3];
8128 SString inlineeNames[3];
8129 MethodDesc * methodBeingCompiled = m_pMethodBeingCompiled;
8130#define GMI(pMD, strArray) \
8131 do { \
8132 if (pMD) { \
8133 (pMD)->GetMethodInfo((strArray)[0], (strArray)[1], (strArray)[2]); \
8134 } else { \
8135 (strArray)[0].Set(W("<null>")); \
8136 (strArray)[1].Set(W("<null>")); \
8137 (strArray)[2].Set(W("<null>")); \
8138 } } while (0)
8139
8140 GMI(methodBeingCompiled, methodBeingCompiledNames);
8141 GMI(GetMethod(inlinerHnd), inlinerNames);
8142 GMI(GetMethod(inlineeHnd), inlineeNames);
8143#undef GMI
8144 if (dontInline(inlineResult))
8145 {
8146 const char * str = (reason ? reason : "");
8147 SString strReason;
8148 strReason.SetANSI(str);
8149
8150
8151 FireEtwMethodJitInliningFailed(methodBeingCompiledNames[0].GetUnicode(),
8152 methodBeingCompiledNames[1].GetUnicode(),
8153 methodBeingCompiledNames[2].GetUnicode(),
8154 inlinerNames[0].GetUnicode(),
8155 inlinerNames[1].GetUnicode(),
8156 inlinerNames[2].GetUnicode(),
8157 inlineeNames[0].GetUnicode(),
8158 inlineeNames[1].GetUnicode(),
8159 inlineeNames[2].GetUnicode(),
8160 inlineResult == INLINE_NEVER,
8161 strReason.GetUnicode(),
8162 GetClrInstanceId());
8163 }
8164 else
8165 {
8166 FireEtwMethodJitInliningSucceeded(methodBeingCompiledNames[0].GetUnicode(),
8167 methodBeingCompiledNames[1].GetUnicode(),
8168 methodBeingCompiledNames[2].GetUnicode(),
8169 inlinerNames[0].GetUnicode(),
8170 inlinerNames[1].GetUnicode(),
8171 inlinerNames[2].GetUnicode(),
8172 inlineeNames[0].GetUnicode(),
8173 inlineeNames[1].GetUnicode(),
8174 inlineeNames[2].GetUnicode(),
8175 GetClrInstanceId());
8176 }
8177
8178 }
8179
8180 EE_TO_JIT_TRANSITION();
8181}
8182
8183
8184/*************************************************************
8185This loads the (formal) declared constraints on the class and method type parameters,
8186and detects (but does not itself reject) circularities among the class type parameters
8187and (separately) method type parameters.
8188
8189It must be called whenever we verify a typical method, ie any method (generic or
8190nongeneric) in a typical class. It must be called for non-generic methods too,
8191because their bodies may still mention class type parameters which will need to
8192have their formal constraints loaded in order to perform type compatibility tests.
8193
8194We have to rule out cycles like "C<U,T> where T:U, U:T" only to avoid looping
8195in the verifier (ie the T.CanCast(A) would loop calling U.CanCast(A) then
8196T.CanCastTo(A) etc.). Since the JIT only tries to walk the hierarchy from a type
8197a parameter when verifying, it should be safe to JIT unverified, but trusted,
8198instantiations even in the presence of cycle constraints.
8199@TODO: It should be possible (and easy) to detect cycles much earlier on by
8200directly inspecting the metadata. All you have to do is check that, for each
8201of the n type parameters to a class or method there is no path of length n
8202obtained by following naked type parameter constraints of the same kind.
8203This can be detected by looking directly at metadata, without actually loading
8204the typehandles for the naked type parameters.
8205 *************************************************************/
8206
8207void CEEInfo::initConstraintsForVerification(CORINFO_METHOD_HANDLE hMethod,
8208 BOOL *pfHasCircularClassConstraints,
8209 BOOL *pfHasCircularMethodConstraints)
8210{
8211 CONTRACTL {
8212 SO_TOLERANT;
8213 THROWS;
8214 GC_TRIGGERS;
8215 MODE_PREEMPTIVE;
8216 PRECONDITION(CheckPointer(pfHasCircularClassConstraints));
8217 PRECONDITION(CheckPointer(pfHasCircularMethodConstraints));
8218 } CONTRACTL_END;
8219
8220 *pfHasCircularClassConstraints = FALSE;
8221 *pfHasCircularMethodConstraints = FALSE;
8222
8223 JIT_TO_EE_TRANSITION();
8224
8225 MethodDesc* pMethod = GetMethod(hMethod);
8226 if (pMethod->IsTypicalMethodDefinition())
8227 {
8228 // Force a load of the constraints on the type parameters, detecting cyclic bounds
8229 pMethod->LoadConstraintsForTypicalMethodDefinition(pfHasCircularClassConstraints,pfHasCircularMethodConstraints);
8230 }
8231
8232 EE_TO_JIT_TRANSITION();
8233}
8234
8235/*************************************************************
8236 * Check if a method to be compiled is an instantiation
8237 * of generic code that has already been verified.
8238 * Three possible return values (see corinfo.h)
8239 *************************************************************/
8240
8241CorInfoInstantiationVerification
8242 CEEInfo::isInstantiationOfVerifiedGeneric(CORINFO_METHOD_HANDLE hMethod)
8243{
8244 CONTRACTL {
8245 SO_TOLERANT;
8246 THROWS;
8247 GC_TRIGGERS;
8248 MODE_PREEMPTIVE;
8249 } CONTRACTL_END;
8250
8251 CorInfoInstantiationVerification result = INSTVER_NOT_INSTANTIATION;
8252
8253 JIT_TO_EE_TRANSITION();
8254
8255 MethodDesc * pMethod = GetMethod(hMethod);
8256
8257 if (!(pMethod->HasClassOrMethodInstantiation()))
8258 {
8259 result = INSTVER_NOT_INSTANTIATION;
8260 goto exit;
8261 }
8262
8263 if (pMethod->IsTypicalMethodDefinition())
8264 {
8265 result = INSTVER_NOT_INSTANTIATION;
8266 goto exit;
8267 }
8268
8269 result = INSTVER_GENERIC_PASSED_VERIFICATION;
8270
8271 exit: ;
8272
8273 EE_TO_JIT_TRANSITION();
8274
8275 return result;
8276}
8277
8278/*************************************************************
8279 * Similar to above, but perform check for tail call
8280 * eligibility. The callee can be passed as NULL if not known
8281 * (calli and callvirt).
8282 *************************************************************/
8283
8284bool CEEInfo::canTailCall (CORINFO_METHOD_HANDLE hCaller,
8285 CORINFO_METHOD_HANDLE hDeclaredCallee,
8286 CORINFO_METHOD_HANDLE hExactCallee,
8287 bool fIsTailPrefix)
8288{
8289 CONTRACTL {
8290 SO_TOLERANT;
8291 THROWS;
8292 GC_TRIGGERS;
8293 MODE_PREEMPTIVE;
8294 } CONTRACTL_END;
8295
8296 bool result = false;
8297 const char * szFailReason = NULL;
8298
8299 JIT_TO_EE_TRANSITION();
8300
8301 // See comments in canInline above.
8302
8303 MethodDesc* pCaller = GetMethod(hCaller);
8304 MethodDesc* pDeclaredCallee = GetMethod(hDeclaredCallee);
8305 MethodDesc* pExactCallee = GetMethod(hExactCallee);
8306
8307 _ASSERTE(pCaller->GetModule());
8308 _ASSERTE(pCaller->GetModule()->GetClassLoader());
8309
8310 _ASSERTE((pExactCallee == NULL) || pExactCallee->GetModule());
8311 _ASSERTE((pExactCallee == NULL) || pExactCallee->GetModule()->GetClassLoader());
8312
8313 // If the caller is the static constructor (.cctor) of a class which has a ComImport base class
8314 // somewhere up the class hierarchy, then we cannot make the call into a tailcall. See
8315 // RegisterObjectCreationCallback() in ExtensibleClassFactory.cpp for more information.
8316 if (pCaller->IsClassConstructor() &&
8317 pCaller->GetMethodTable()->IsComObjectType())
8318 {
8319 result = false;
8320 szFailReason = "Caller is ComImport .cctor";
8321 goto exit;
8322 }
8323
8324 if (!fIsTailPrefix)
8325 {
8326 mdMethodDef callerToken = pCaller->GetMemberDef();
8327
8328 // We don't want to tailcall the entrypoint for an application; JIT64 will sometimes
8329 // do this for simple entrypoints and it results in a rather confusing debugging
8330 // experience.
8331 if (callerToken == pCaller->GetModule()->GetEntryPointToken())
8332 {
8333 result = false;
8334 szFailReason = "Caller is the entry point";
8335 goto exit;
8336 }
8337
8338 if (!pCaller->IsNoMetadata())
8339 {
8340 // Do not tailcall from methods that are marked as noinline (people often use no-inline
8341 // to mean "I want to always see this method in stacktrace")
8342 DWORD dwImplFlags = 0;
8343 IfFailThrow(pCaller->GetMDImport()->GetMethodImplProps(callerToken, NULL, &dwImplFlags));
8344
8345 if (IsMiNoInlining(dwImplFlags))
8346 {
8347 result = false;
8348 szFailReason = "Caller is marked as no inline";
8349 goto exit;
8350 }
8351 }
8352
8353 // Methods with StackCrawlMark depend on finding their caller on the stack.
8354 // If we tail call one of these guys, they get confused. For lack of
8355 // a better way of identifying them, we use DynamicSecurity attribute to identify
8356 // them. We have an assert in canInline that ensures all StackCrawlMark
8357 // methods are appropriately marked.
8358 //
8359 if ((pExactCallee != NULL) && IsMdRequireSecObject(pExactCallee->GetAttrs()))
8360 {
8361 result = false;
8362 szFailReason = "Callee might have a StackCrawlMark.LookForMyCaller";
8363 goto exit;
8364 }
8365 }
8366
8367
8368 result = true;
8369
8370exit: ;
8371
8372 EE_TO_JIT_TRANSITION();
8373
8374 if (!result)
8375 {
8376 // If you hit this assert, it means you added a new way to prevent tail calls
8377 // without documenting it for ETW!
8378 _ASSERTE(szFailReason != NULL);
8379 reportTailCallDecision(hCaller, hExactCallee, fIsTailPrefix, TAILCALL_FAIL, szFailReason);
8380 }
8381
8382 return result;
8383}
8384
8385void CEEInfo::reportTailCallDecision (CORINFO_METHOD_HANDLE callerHnd,
8386 CORINFO_METHOD_HANDLE calleeHnd,
8387 bool fIsTailPrefix,
8388 CorInfoTailCall tailCallResult,
8389 const char * reason)
8390{
8391 STATIC_CONTRACT_THROWS;
8392 STATIC_CONTRACT_GC_TRIGGERS;
8393 STATIC_CONTRACT_SO_TOLERANT;
8394
8395 JIT_TO_EE_TRANSITION();
8396
8397 //put code here. Make sure to report the method being compiled in addition to inliner and inlinee.
8398#ifdef _DEBUG
8399 if (LoggingOn(LF_JIT, LL_INFO100000))
8400 {
8401 SString currentMethodName;
8402 TypeString::AppendMethodInternal(currentMethodName, m_pMethodBeingCompiled,
8403 TypeString::FormatBasic);
8404
8405 SString calleeMethodName;
8406 if (GetMethod(calleeHnd))
8407 {
8408 TypeString::AppendMethodInternal(calleeMethodName, GetMethod(calleeHnd),
8409 TypeString::FormatBasic);
8410 }
8411 else
8412 {
8413 calleeMethodName.AppendASCII( "<null>" );
8414 }
8415
8416 SString callerMethodName;
8417 if (GetMethod(callerHnd))
8418 {
8419 TypeString::AppendMethodInternal(callerMethodName, GetMethod(callerHnd),
8420 TypeString::FormatBasic);
8421 }
8422 else
8423 {
8424 callerMethodName.AppendASCII( "<null>" );
8425 }
8426 if (tailCallResult == TAILCALL_FAIL)
8427 {
8428 LOG((LF_JIT, LL_INFO100000,
8429 "While compiling '%S', %Splicit tail call from '%S' to '%S' failed because: '%s'.\n",
8430 currentMethodName.GetUnicode(), fIsTailPrefix ? W("ex") : W("im"),
8431 callerMethodName.GetUnicode(), calleeMethodName.GetUnicode(), reason));
8432 }
8433 else
8434 {
8435 static const char * const tailCallType[] = {
8436 "optimized tail call", "recursive loop", "helper assisted tailcall"
8437 };
8438 _ASSERTE(tailCallResult >= 0 && (size_t)tailCallResult < _countof(tailCallType));
8439 LOG((LF_JIT, LL_INFO100000,
8440 "While compiling '%S', %Splicit tail call from '%S' to '%S' generated as a %s.\n",
8441 currentMethodName.GetUnicode(), fIsTailPrefix ? W("ex") : W("im"),
8442 callerMethodName.GetUnicode(), calleeMethodName.GetUnicode(), tailCallType[tailCallResult]));
8443
8444 }
8445 }
8446#endif //_DEBUG
8447
8448 // I'm gonna duplicate this code because the format is slightly different. And LoggingOn is debug only.
8449 if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context,
8450 TRACE_LEVEL_VERBOSE,
8451 CLR_JITTRACING_KEYWORD))
8452 {
8453 SString methodBeingCompiledNames[3];
8454 SString callerNames[3];
8455 SString calleeNames[3];
8456 MethodDesc * methodBeingCompiled = m_pMethodBeingCompiled;
8457#define GMI(pMD, strArray) \
8458 do { \
8459 if (pMD) { \
8460 (pMD)->GetMethodInfo((strArray)[0], (strArray)[1], (strArray)[2]); \
8461 } else { \
8462 (strArray)[0].Set(W("<null>")); \
8463 (strArray)[1].Set(W("<null>")); \
8464 (strArray)[2].Set(W("<null>")); \
8465 } } while (0)
8466
8467 GMI(methodBeingCompiled, methodBeingCompiledNames);
8468 GMI(GetMethod(callerHnd), callerNames);
8469 GMI(GetMethod(calleeHnd), calleeNames);
8470#undef GMI
8471 if (tailCallResult == TAILCALL_FAIL)
8472 {
8473 const char * str = (reason ? reason : "");
8474 SString strReason;
8475 strReason.SetANSI(str);
8476
8477 FireEtwMethodJitTailCallFailed(methodBeingCompiledNames[0].GetUnicode(),
8478 methodBeingCompiledNames[1].GetUnicode(),
8479 methodBeingCompiledNames[2].GetUnicode(),
8480 callerNames[0].GetUnicode(),
8481 callerNames[1].GetUnicode(),
8482 callerNames[2].GetUnicode(),
8483 calleeNames[0].GetUnicode(),
8484 calleeNames[1].GetUnicode(),
8485 calleeNames[2].GetUnicode(),
8486 fIsTailPrefix,
8487 strReason.GetUnicode(),
8488 GetClrInstanceId());
8489 }
8490 else
8491 {
8492 FireEtwMethodJitTailCallSucceeded(methodBeingCompiledNames[0].GetUnicode(),
8493 methodBeingCompiledNames[1].GetUnicode(),
8494 methodBeingCompiledNames[2].GetUnicode(),
8495 callerNames[0].GetUnicode(),
8496 callerNames[1].GetUnicode(),
8497 callerNames[2].GetUnicode(),
8498 calleeNames[0].GetUnicode(),
8499 calleeNames[1].GetUnicode(),
8500 calleeNames[2].GetUnicode(),
8501 fIsTailPrefix,
8502 tailCallResult,
8503 GetClrInstanceId());
8504 }
8505
8506 }
8507
8508
8509 EE_TO_JIT_TRANSITION();
8510}
8511
8512void CEEInfo::getEHinfoHelper(
8513 CORINFO_METHOD_HANDLE ftnHnd,
8514 unsigned EHnumber,
8515 CORINFO_EH_CLAUSE* clause,
8516 COR_ILMETHOD_DECODER* pILHeader)
8517{
8518 STANDARD_VM_CONTRACT;
8519
8520 _ASSERTE(CheckPointer(pILHeader->EH));
8521 _ASSERTE(EHnumber < pILHeader->EH->EHCount());
8522
8523 COR_ILMETHOD_SECT_EH_CLAUSE_FAT ehClause;
8524 const COR_ILMETHOD_SECT_EH_CLAUSE_FAT* ehInfo;
8525 ehInfo = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)pILHeader->EH->EHClause(EHnumber, &ehClause);
8526
8527 clause->Flags = (CORINFO_EH_CLAUSE_FLAGS)ehInfo->GetFlags();
8528 clause->TryOffset = ehInfo->GetTryOffset();
8529 clause->TryLength = ehInfo->GetTryLength();
8530 clause->HandlerOffset = ehInfo->GetHandlerOffset();
8531 clause->HandlerLength = ehInfo->GetHandlerLength();
8532 if ((clause->Flags & CORINFO_EH_CLAUSE_FILTER) == 0)
8533 clause->ClassToken = ehInfo->GetClassToken();
8534 else
8535 clause->FilterOffset = ehInfo->GetFilterOffset();
8536}
8537
8538/*********************************************************************/
8539// get individual exception handler
8540void CEEInfo::getEHinfo(
8541 CORINFO_METHOD_HANDLE ftnHnd,
8542 unsigned EHnumber,
8543 CORINFO_EH_CLAUSE* clause)
8544{
8545 CONTRACTL {
8546 SO_TOLERANT;
8547 THROWS;
8548 GC_TRIGGERS;
8549 MODE_PREEMPTIVE;
8550 } CONTRACTL_END;
8551
8552 JIT_TO_EE_TRANSITION();
8553
8554 MethodDesc * ftn = GetMethod(ftnHnd);
8555
8556 if (IsDynamicMethodHandle(ftnHnd))
8557 {
8558 GetMethod(ftnHnd)->AsDynamicMethodDesc()->GetResolver()->GetEHInfo(EHnumber, clause);
8559 }
8560 else
8561 {
8562 COR_ILMETHOD_DECODER header(ftn->GetILHeader(TRUE), ftn->GetMDImport(), NULL);
8563 getEHinfoHelper(ftnHnd, EHnumber, clause, &header);
8564 }
8565
8566 EE_TO_JIT_TRANSITION();
8567}
8568
8569//---------------------------------------------------------------------------------------
8570//
8571void
8572CEEInfo::getMethodSig(
8573 CORINFO_METHOD_HANDLE ftnHnd,
8574 CORINFO_SIG_INFO * sigRet,
8575 CORINFO_CLASS_HANDLE owner)
8576{
8577 CONTRACTL {
8578 SO_TOLERANT;
8579 THROWS;
8580 GC_TRIGGERS;
8581 MODE_PREEMPTIVE;
8582 } CONTRACTL_END;
8583
8584 JIT_TO_EE_TRANSITION();
8585
8586 getMethodSigInternal(ftnHnd, sigRet, owner);
8587
8588 EE_TO_JIT_TRANSITION();
8589}
8590
8591//---------------------------------------------------------------------------------------
8592//
8593void
8594CEEInfo::getMethodSigInternal(
8595 CORINFO_METHOD_HANDLE ftnHnd,
8596 CORINFO_SIG_INFO * sigRet,
8597 CORINFO_CLASS_HANDLE owner,
8598 SignatureKind signatureKind)
8599{
8600 STANDARD_VM_CONTRACT;
8601
8602 MethodDesc * ftn = GetMethod(ftnHnd);
8603
8604 PCCOR_SIGNATURE pSig = NULL;
8605 DWORD cbSig = 0;
8606 ftn->GetSig(&pSig, &cbSig);
8607
8608 // Type parameters in the signature are instantiated
8609 // according to the class/method/array instantiation of ftnHnd and owner
8610 CEEInfo::ConvToJitSig(
8611 pSig,
8612 cbSig,
8613 GetScopeHandle(ftn),
8614 mdTokenNil,
8615 sigRet,
8616 ftn,
8617 false,
8618 (TypeHandle)owner);
8619
8620 //@GENERICS:
8621 // Shared generic methods and shared methods on generic structs take an extra argument representing their instantiation
8622 if (ftn->RequiresInstArg())
8623 {
8624 //
8625 // If we are making a virtual call to an instance method on an interface, we need to lie to the JIT.
8626 // The reason being that we already made sure target is always directly callable (through instantiation stubs),
8627 // JIT should not generate shared generics aware call code and insert the secret argument again at the callsite.
8628 // Otherwise we would end up with two secret generic dictionary arguments (since the stub also provides one).
8629 //
8630 BOOL isCallSiteThatGoesThroughInstantiatingStub =
8631 signatureKind == SK_VIRTUAL_CALLSITE &&
8632 !ftn->IsStatic() &&
8633 ftn->GetMethodTable()->IsInterface();
8634 if (!isCallSiteThatGoesThroughInstantiatingStub)
8635 sigRet->callConv = (CorInfoCallConv) (sigRet->callConv | CORINFO_CALLCONV_PARAMTYPE);
8636 }
8637
8638 // We want the calling convention bit to be consistant with the method attribute bit
8639 _ASSERTE( (IsMdStatic(ftn->GetAttrs()) == 0) == ((sigRet->callConv & CORINFO_CALLCONV_HASTHIS) != 0) );
8640}
8641
8642//---------------------------------------------------------------------------------------
8643//
8644//@GENERICSVER: for a method desc in a typical instantiation of a generic class,
8645// this will return the typical instantiation of the generic class,
8646// but only provided type variables are never shared.
8647// The JIT verifier relies on this behaviour to extract the typical class from an instantiated method's typical method handle.
8648//
8649CORINFO_CLASS_HANDLE
8650CEEInfo::getMethodClass(
8651 CORINFO_METHOD_HANDLE methodHnd)
8652{
8653 CONTRACTL {
8654 SO_TOLERANT;
8655 THROWS;
8656 GC_TRIGGERS;
8657 MODE_PREEMPTIVE;
8658 } CONTRACTL_END;
8659
8660 CORINFO_CLASS_HANDLE result = NULL;
8661
8662 JIT_TO_EE_TRANSITION();
8663
8664 MethodDesc* method = GetMethod(methodHnd);
8665
8666 if (method->IsDynamicMethod())
8667 {
8668 DynamicResolver::SecurityControlFlags securityControlFlags = DynamicResolver::Default;
8669 TypeHandle typeOwner;
8670
8671 DynamicResolver* pResolver = method->AsDynamicMethodDesc()->GetResolver();
8672 pResolver->GetJitContext(&securityControlFlags, &typeOwner);
8673
8674 if (!typeOwner.IsNull() && (method == pResolver->GetDynamicMethod()))
8675 {
8676 result = CORINFO_CLASS_HANDLE(typeOwner.AsPtr());
8677 }
8678 }
8679
8680 if (result == NULL)
8681 {
8682 TypeHandle th = TypeHandle(method->GetMethodTable());
8683
8684 result = CORINFO_CLASS_HANDLE(th.AsPtr());
8685 }
8686
8687 EE_TO_JIT_TRANSITION();
8688
8689 return result;
8690}
8691
8692/***********************************************************************/
8693CORINFO_MODULE_HANDLE CEEInfo::getMethodModule (CORINFO_METHOD_HANDLE methodHnd)
8694{
8695 CONTRACTL {
8696 SO_TOLERANT;
8697 NOTHROW;
8698 GC_NOTRIGGER;
8699 MODE_PREEMPTIVE;
8700 } CONTRACTL_END;
8701
8702 CORINFO_MODULE_HANDLE result = NULL;
8703
8704 JIT_TO_EE_TRANSITION_LEAF();
8705
8706 MethodDesc* method = GetMethod(methodHnd);
8707
8708 if (method->IsDynamicMethod())
8709 {
8710 // this should never be called, thus the assert, I don't know if the (non existent) caller
8711 // expects the Module or the scope
8712 UNREACHABLE();
8713 }
8714 else
8715 {
8716 result = (CORINFO_MODULE_HANDLE) method->GetModule();
8717 }
8718
8719 EE_TO_JIT_TRANSITION_LEAF();
8720
8721 return result;
8722}
8723
8724/*********************************************************************/
8725CorInfoIntrinsics CEEInfo::getIntrinsicID(CORINFO_METHOD_HANDLE methodHnd,
8726 bool * pMustExpand)
8727{
8728 CONTRACTL {
8729 SO_TOLERANT;
8730 THROWS;
8731 GC_TRIGGERS;
8732 MODE_PREEMPTIVE;
8733 } CONTRACTL_END;
8734
8735 CorInfoIntrinsics result = CORINFO_INTRINSIC_Illegal;
8736
8737 JIT_TO_EE_TRANSITION();
8738
8739 if (pMustExpand != NULL)
8740 {
8741 *pMustExpand = false;
8742 }
8743
8744 MethodDesc* method = GetMethod(methodHnd);
8745
8746 if (method->IsArray())
8747 {
8748 ArrayMethodDesc * arrMethod = (ArrayMethodDesc *)method;
8749 result = arrMethod->GetIntrinsicID();
8750 }
8751 else
8752 if (method->IsFCall())
8753 {
8754 result = ECall::GetIntrinsicID(method);
8755 }
8756 else
8757 {
8758 MethodTable * pMT = method->GetMethodTable();
8759 if (pMT->GetModule()->IsSystem() && pMT->IsByRefLike())
8760 {
8761 if (pMT->HasSameTypeDefAs(g_pByReferenceClass))
8762 {
8763 // ByReference<T> has just two methods: constructor and Value property
8764 if (method->IsCtor())
8765 {
8766 result = CORINFO_INTRINSIC_ByReference_Ctor;
8767 }
8768 else
8769 {
8770 _ASSERTE(strcmp(method->GetName(), "get_Value") == 0);
8771 result = CORINFO_INTRINSIC_ByReference_Value;
8772 }
8773 if (pMustExpand != nullptr)
8774 {
8775 *pMustExpand = true;
8776 }
8777 }
8778 else if (pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__SPAN)))
8779 {
8780 if (method->HasSameMethodDefAs(MscorlibBinder::GetMethod(METHOD__SPAN__GET_ITEM)))
8781 {
8782 result = CORINFO_INTRINSIC_Span_GetItem;
8783 }
8784 }
8785 else if (pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__READONLY_SPAN)))
8786 {
8787 if (method->HasSameMethodDefAs(MscorlibBinder::GetMethod(METHOD__READONLY_SPAN__GET_ITEM)))
8788 {
8789 result = CORINFO_INTRINSIC_ReadOnlySpan_GetItem;
8790 }
8791 }
8792 }
8793 }
8794
8795 EE_TO_JIT_TRANSITION();
8796
8797 return result;
8798}
8799
8800/*********************************************************************/
8801// TODO: This method should probably be renamed to something like "isSIMDType"
8802bool CEEInfo::isInSIMDModule(CORINFO_CLASS_HANDLE classHnd)
8803{
8804CONTRACTL {
8805 SO_TOLERANT;
8806 NOTHROW;
8807 GC_NOTRIGGER;
8808 MODE_PREEMPTIVE;
8809 } CONTRACTL_END;
8810
8811 bool result = false;
8812 JIT_TO_EE_TRANSITION_LEAF();
8813
8814 TypeHandle VMClsHnd(classHnd);
8815 PTR_MethodTable methodTable = VMClsHnd.GetMethodTable();
8816 if (methodTable->GetAssembly()->IsSIMDVectorAssembly())
8817 {
8818 result = true;
8819 }
8820 else if (methodTable->IsIntrinsicType())
8821 {
8822 LPCUTF8 namespaceName;
8823 LPCUTF8 className = methodTable->GetFullyQualifiedNameInfo(&namespaceName);
8824
8825 if (strcmp(className, "Vector`1") == 0 || strcmp(className, "Vector") == 0)
8826 {
8827 assert(strcmp(namespaceName, "System.Numerics") == 0);
8828
8829 result = true;
8830 }
8831 }
8832 EE_TO_JIT_TRANSITION_LEAF();
8833
8834 return result;
8835}
8836
8837/*********************************************************************/
8838void CEEInfo::getMethodVTableOffset (CORINFO_METHOD_HANDLE methodHnd,
8839 unsigned * pOffsetOfIndirection,
8840 unsigned * pOffsetAfterIndirection,
8841 bool * isRelative)
8842{
8843 CONTRACTL {
8844 SO_TOLERANT;
8845 NOTHROW;
8846 GC_NOTRIGGER;
8847 MODE_PREEMPTIVE;
8848 } CONTRACTL_END;
8849
8850 JIT_TO_EE_TRANSITION_LEAF();
8851
8852 MethodDesc* method = GetMethod(methodHnd);
8853
8854 //@GENERICS: shouldn't be doing this for instantiated methods as they live elsewhere
8855 _ASSERTE(!method->HasMethodInstantiation());
8856
8857 _ASSERTE(MethodTable::GetVtableOffset() < 256); // a rough sanity check
8858
8859 // better be in the vtable
8860 _ASSERTE(method->GetSlot() < method->GetMethodTable()->GetNumVirtuals());
8861
8862 *pOffsetOfIndirection = MethodTable::GetVtableOffset() + MethodTable::GetIndexOfVtableIndirection(method->GetSlot()) * TARGET_POINTER_SIZE /* sizeof(MethodTable::VTableIndir_t) */;
8863 *pOffsetAfterIndirection = MethodTable::GetIndexAfterVtableIndirection(method->GetSlot()) * TARGET_POINTER_SIZE /* sizeof(MethodTable::VTableIndir2_t) */;
8864 *isRelative = MethodTable::VTableIndir_t::isRelative ? 1 : 0;
8865 _ASSERTE(MethodTable::VTableIndir_t::isRelative == MethodTable::VTableIndir2_t::isRelative);
8866
8867 EE_TO_JIT_TRANSITION_LEAF();
8868}
8869
8870/*********************************************************************/
8871CORINFO_METHOD_HANDLE CEEInfo::resolveVirtualMethodHelper(CORINFO_METHOD_HANDLE baseMethod,
8872 CORINFO_CLASS_HANDLE derivedClass,
8873 CORINFO_CONTEXT_HANDLE ownerType)
8874{
8875 CONTRACTL {
8876 THROWS;
8877 GC_TRIGGERS;
8878 MODE_PREEMPTIVE;
8879 } CONTRACTL_END;
8880
8881 MethodDesc* pBaseMD = GetMethod(baseMethod);
8882 MethodTable* pBaseMT = pBaseMD->GetMethodTable();
8883
8884 // Method better be from a fully loaded class
8885 _ASSERTE(pBaseMD->IsRestored() && pBaseMT->IsFullyLoaded());
8886
8887 //@GENERICS: shouldn't be doing this for instantiated methods as they live elsewhere
8888 _ASSERTE(!pBaseMD->HasMethodInstantiation());
8889
8890 // Method better be virtual
8891 _ASSERTE(pBaseMD->IsVirtual());
8892
8893 MethodDesc* pDevirtMD = nullptr;
8894
8895 TypeHandle DerivedClsHnd(derivedClass);
8896 MethodTable* pDerivedMT = DerivedClsHnd.GetMethodTable();
8897 _ASSERTE(pDerivedMT->IsRestored() && pDerivedMT->IsFullyLoaded());
8898
8899 // Can't devirtualize from __Canon.
8900 if (DerivedClsHnd == TypeHandle(g_pCanonMethodTableClass))
8901 {
8902 return nullptr;
8903 }
8904
8905 if (pBaseMT->IsInterface())
8906 {
8907
8908#ifdef FEATURE_COMINTEROP
8909 // Don't try and devirtualize com interface calls.
8910 if (pDerivedMT->IsComObjectType())
8911 {
8912 return nullptr;
8913 }
8914#endif // FEATURE_COMINTEROP
8915
8916 // Interface call devirtualization.
8917 //
8918 // We must ensure that pDerivedMT actually implements the
8919 // interface corresponding to pBaseMD.
8920 if (!pDerivedMT->CanCastToInterface(pBaseMT))
8921 {
8922 return nullptr;
8923 }
8924
8925 // For generic interface methods we must have an ownerType to
8926 // safely devirtualize.
8927 if (ownerType != nullptr)
8928 {
8929 TypeHandle OwnerClsHnd = GetTypeFromContext(ownerType);
8930 MethodTable* pOwnerMT = OwnerClsHnd.GetMethodTable();
8931
8932 // If the derived class is a shared class, make sure the
8933 // owner class is too.
8934 if (pDerivedMT->IsSharedByGenericInstantiations())
8935 {
8936 pOwnerMT = pOwnerMT->GetCanonicalMethodTable();
8937 }
8938
8939 pDevirtMD = pDerivedMT->GetMethodDescForInterfaceMethod(TypeHandle(pOwnerMT), pBaseMD, FALSE /* throwOnConflict */);
8940 }
8941 else if (!pBaseMD->HasClassOrMethodInstantiation())
8942 {
8943 pDevirtMD = pDerivedMT->GetMethodDescForInterfaceMethod(pBaseMD, FALSE /* throwOnConflict */);
8944 }
8945
8946 if (pDevirtMD == nullptr)
8947 {
8948 return nullptr;
8949 }
8950
8951 // If we devirtualized into a default interface method on a generic type, we should actually return an
8952 // instantiating stub but this is not happening.
8953 // Making this work is tracked by https://github.com/dotnet/coreclr/issues/15977
8954 if (pDevirtMD->GetMethodTable()->IsInterface() && pDevirtMD->HasClassInstantiation())
8955 {
8956 return nullptr;
8957 }
8958 }
8959 else
8960 {
8961 // Virtual call devirtualization.
8962 //
8963 // The derived class should be a subclass of the the base class.
8964 MethodTable* pCheckMT = pDerivedMT;
8965
8966 while (pCheckMT != nullptr)
8967 {
8968 if (pCheckMT->HasSameTypeDefAs(pBaseMT))
8969 {
8970 break;
8971 }
8972
8973 pCheckMT = pCheckMT->GetParentMethodTable();
8974 }
8975
8976 if (pCheckMT == nullptr)
8977 {
8978 return nullptr;
8979 }
8980
8981 // The base method should be in the base vtable
8982 WORD slot = pBaseMD->GetSlot();
8983 _ASSERTE(slot < pBaseMT->GetNumVirtuals());
8984
8985 // Fetch the method that would be invoked if the class were
8986 // exactly derived class. It is up to the jit to determine whether
8987 // directly calling this method is correct.
8988 pDevirtMD = pDerivedMT->GetMethodDescForSlot(slot);
8989
8990 // If the derived method's slot does not match the vtable slot,
8991 // bail on devirtualization, as the method was installed into
8992 // the vtable slot via an explicit override and even if the
8993 // method is final, the slot may not be.
8994 //
8995 // Note the jit could still safely devirtualize if it had an exact
8996 // class, but such cases are likely rare.
8997 WORD dslot = pDevirtMD->GetSlot();
8998
8999 if (dslot != slot)
9000 {
9001 return nullptr;
9002 }
9003 }
9004
9005 _ASSERTE(pDevirtMD->IsRestored());
9006
9007#ifdef FEATURE_READYTORUN_COMPILER
9008 // Check if devirtualization is dependent upon cross-version
9009 // bubble information and if so, disallow it.
9010 if (IsReadyToRunCompilation())
9011 {
9012 MethodDesc* callerMethod = m_pMethodBeingCompiled;
9013 Assembly* pCallerAssembly = callerMethod->GetModule()->GetAssembly();
9014 bool allowDevirt =
9015 IsInSameVersionBubble(pCallerAssembly , pDevirtMD->GetModule()->GetAssembly())
9016 && IsInSameVersionBubble(pCallerAssembly , pDerivedMT->GetAssembly());
9017
9018 if (!allowDevirt)
9019 {
9020 return nullptr;
9021 }
9022 }
9023#endif
9024
9025 return (CORINFO_METHOD_HANDLE) pDevirtMD;
9026}
9027
9028CORINFO_METHOD_HANDLE CEEInfo::resolveVirtualMethod(CORINFO_METHOD_HANDLE methodHnd,
9029 CORINFO_CLASS_HANDLE derivedClass,
9030 CORINFO_CONTEXT_HANDLE ownerType)
9031{
9032 CONTRACTL {
9033 SO_TOLERANT;
9034 THROWS;
9035 GC_TRIGGERS;
9036 MODE_PREEMPTIVE;
9037 } CONTRACTL_END;
9038
9039 CORINFO_METHOD_HANDLE result = nullptr;
9040
9041 JIT_TO_EE_TRANSITION();
9042
9043 result = resolveVirtualMethodHelper(methodHnd, derivedClass, ownerType);
9044
9045 EE_TO_JIT_TRANSITION();
9046
9047 return result;
9048}
9049
9050/*********************************************************************/
9051CORINFO_METHOD_HANDLE CEEInfo::getUnboxedEntry(
9052 CORINFO_METHOD_HANDLE ftn,
9053 bool* requiresInstMethodTableArg)
9054{
9055 CONTRACTL {
9056 SO_TOLERANT;
9057 THROWS;
9058 GC_TRIGGERS;
9059 MODE_PREEMPTIVE;
9060 } CONTRACTL_END;
9061
9062 CORINFO_METHOD_HANDLE result = NULL;
9063
9064 JIT_TO_EE_TRANSITION();
9065
9066 MethodDesc* pMD = GetMethod(ftn);
9067 bool requiresInstMTArg = false;
9068
9069 if (pMD->IsUnboxingStub())
9070 {
9071 MethodTable* pMT = pMD->GetMethodTable();
9072 MethodDesc* pUnboxedMD = pMT->GetUnboxedEntryPointMD(pMD);
9073
9074 result = (CORINFO_METHOD_HANDLE)pUnboxedMD;
9075 requiresInstMTArg = !!pUnboxedMD->RequiresInstMethodTableArg();
9076 }
9077
9078 if (requiresInstMethodTableArg != NULL)
9079 {
9080 *requiresInstMethodTableArg = requiresInstMTArg;
9081 }
9082
9083 EE_TO_JIT_TRANSITION();
9084
9085 return result;
9086}
9087
9088/*********************************************************************/
9089void CEEInfo::expandRawHandleIntrinsic(
9090 CORINFO_RESOLVED_TOKEN * pResolvedToken,
9091 CORINFO_GENERICHANDLE_RESULT * pResult)
9092{
9093 LIMITED_METHOD_CONTRACT;
9094 UNREACHABLE(); // only called with CoreRT.
9095}
9096
9097/*********************************************************************/
9098CORINFO_CLASS_HANDLE CEEInfo::getDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE elemType)
9099{
9100 CONTRACTL {
9101 SO_TOLERANT;
9102 THROWS;
9103 GC_TRIGGERS;
9104 MODE_PREEMPTIVE;
9105 } CONTRACTL_END;
9106
9107 CORINFO_CLASS_HANDLE result = NULL;
9108
9109 JIT_TO_EE_TRANSITION();
9110
9111 result = getDefaultEqualityComparerClassHelper(elemType);
9112
9113 EE_TO_JIT_TRANSITION();
9114
9115 return result;
9116}
9117
9118CORINFO_CLASS_HANDLE CEEInfo::getDefaultEqualityComparerClassHelper(CORINFO_CLASS_HANDLE elemType)
9119{
9120 CONTRACTL {
9121 SO_TOLERANT;
9122 THROWS;
9123 GC_TRIGGERS;
9124 MODE_PREEMPTIVE;
9125 } CONTRACTL_END;
9126
9127 // Mirrors the logic in BCL's CompareHelpers.CreateDefaultEqualityComparer
9128 // And in compile.cpp's SpecializeEqualityComparer
9129 TypeHandle elemTypeHnd(elemType);
9130
9131 // Special case for byte
9132 if (elemTypeHnd.AsMethodTable()->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__ELEMENT_TYPE_U1)))
9133 {
9134 return CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__BYTE_EQUALITYCOMPARER));
9135 }
9136
9137 // Else we'll need to find the appropriate instantation
9138 Instantiation inst(&elemTypeHnd, 1);
9139
9140 // If T implements IEquatable<T>
9141 if (elemTypeHnd.CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__IEQUATABLEGENERIC)).Instantiate(inst)))
9142 {
9143 TypeHandle resultTh = ((TypeHandle)MscorlibBinder::GetClass(CLASS__GENERIC_EQUALITYCOMPARER)).Instantiate(inst);
9144 return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
9145 }
9146
9147 // Nullable<T>
9148 if (Nullable::IsNullableType(elemTypeHnd))
9149 {
9150 Instantiation nullableInst = elemTypeHnd.AsMethodTable()->GetInstantiation();
9151 TypeHandle nullableComparer = TypeHandle(MscorlibBinder::GetClass(CLASS__IEQUATABLEGENERIC)).Instantiate(nullableInst);
9152 if (nullableInst[0].CanCastTo(nullableComparer))
9153 {
9154 return CORINFO_CLASS_HANDLE(nullableComparer.GetMethodTable());
9155 }
9156 }
9157
9158 // Enum
9159 //
9160 // We need to special case the Enum comparers based on their underlying type,
9161 // to avoid boxing and call the correct versions of GetHashCode.
9162 if (elemTypeHnd.IsEnum())
9163 {
9164 MethodTable* targetClass = NULL;
9165 CorElementType normType = elemTypeHnd.GetVerifierCorElementType();
9166
9167 switch(normType)
9168 {
9169 case ELEMENT_TYPE_I1:
9170 case ELEMENT_TYPE_I2:
9171 case ELEMENT_TYPE_U1:
9172 case ELEMENT_TYPE_U2:
9173 case ELEMENT_TYPE_I4:
9174 case ELEMENT_TYPE_U4:
9175 case ELEMENT_TYPE_I8:
9176 case ELEMENT_TYPE_U8:
9177 {
9178 targetClass = MscorlibBinder::GetClass(CLASS__ENUM_EQUALITYCOMPARER);
9179 break;
9180 }
9181
9182 default:
9183 break;
9184 }
9185
9186 if (targetClass != NULL)
9187 {
9188 TypeHandle resultTh = ((TypeHandle)targetClass->GetCanonicalMethodTable()).Instantiate(inst);
9189 return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
9190 }
9191 }
9192
9193 // Default case
9194 TypeHandle resultTh = ((TypeHandle)MscorlibBinder::GetClass(CLASS__OBJECT_EQUALITYCOMPARER)).Instantiate(inst);
9195
9196 return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
9197}
9198
9199/*********************************************************************/
9200void CEEInfo::getFunctionEntryPoint(CORINFO_METHOD_HANDLE ftnHnd,
9201 CORINFO_CONST_LOOKUP * pResult,
9202 CORINFO_ACCESS_FLAGS accessFlags)
9203{
9204 CONTRACTL {
9205 SO_TOLERANT;
9206 THROWS;
9207 GC_TRIGGERS;
9208 MODE_PREEMPTIVE;
9209 } CONTRACTL_END;
9210
9211 void* ret = NULL;
9212 InfoAccessType accessType = IAT_VALUE;
9213
9214 JIT_TO_EE_TRANSITION();
9215
9216 MethodDesc * ftn = GetMethod(ftnHnd);
9217#if defined(FEATURE_GDBJIT)
9218 MethodDesc * orig_ftn = ftn;
9219#endif
9220
9221 // Resolve methodImpl.
9222 ftn = ftn->GetMethodTable()->MapMethodDeclToMethodImpl(ftn);
9223
9224 ret = (void *)ftn->TryGetMultiCallableAddrOfCode(accessFlags);
9225
9226 // TryGetMultiCallableAddrOfCode returns NULL if indirect access is desired
9227 if (ret == NULL)
9228 {
9229 // should never get here for EnC methods or if interception via remoting stub is required
9230 _ASSERTE(!ftn->IsEnCMethod());
9231
9232 ret = (void *)ftn->GetAddrOfSlot();
9233
9234 if (MethodTable::VTableIndir2_t::isRelative
9235 && ftn->IsVtableSlot())
9236 {
9237 accessType = IAT_RELPVALUE;
9238 }
9239 else
9240 {
9241 accessType = IAT_PVALUE;
9242 }
9243 }
9244
9245
9246#if defined(FEATURE_GDBJIT)
9247 CalledMethod * pCM = new CalledMethod(orig_ftn, ret, m_pCalledMethods);
9248 m_pCalledMethods = pCM;
9249#endif
9250
9251 EE_TO_JIT_TRANSITION();
9252
9253 _ASSERTE(ret != NULL);
9254
9255 pResult->accessType = accessType;
9256 pResult->addr = ret;
9257}
9258
9259/*********************************************************************/
9260void CEEInfo::getFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE ftn,
9261 CORINFO_CONST_LOOKUP * pResult)
9262{
9263 CONTRACTL {
9264 SO_TOLERANT;
9265 THROWS;
9266 GC_TRIGGERS;
9267 MODE_PREEMPTIVE;
9268 } CONTRACTL_END;
9269
9270 JIT_TO_EE_TRANSITION();
9271
9272 MethodDesc * pMD = GetMethod(ftn);
9273
9274 pResult->accessType = IAT_VALUE;
9275
9276
9277#ifndef CROSSGEN_COMPILE
9278 // If LDFTN target has [NativeCallable] attribute , then create a UMEntryThunk.
9279 if (pMD->HasNativeCallableAttribute())
9280 {
9281 pResult->addr = (void*)COMDelegate::ConvertToCallback(pMD);
9282 }
9283 else
9284#endif //CROSSGEN_COMPILE
9285 {
9286 pResult->addr = (void *)pMD->GetMultiCallableAddrOfCode();
9287 }
9288 EE_TO_JIT_TRANSITION();
9289}
9290
9291/*********************************************************************/
9292const char* CEEInfo::getFieldName (CORINFO_FIELD_HANDLE fieldHnd, const char** scopeName)
9293{
9294 CONTRACTL {
9295 SO_TOLERANT;
9296 THROWS;
9297 GC_TRIGGERS;
9298 MODE_PREEMPTIVE;
9299 } CONTRACTL_END;
9300
9301 const char* result = NULL;
9302
9303 JIT_TO_EE_TRANSITION();
9304
9305 FieldDesc* field = (FieldDesc*) fieldHnd;
9306 if (scopeName != 0)
9307 {
9308 TypeHandle t = TypeHandle(field->GetApproxEnclosingMethodTable());
9309 *scopeName = "";
9310 if (!t.IsNull())
9311 {
9312#ifdef _DEBUG
9313 t.GetName(ssClsNameBuff);
9314 *scopeName = ssClsNameBuff.GetUTF8(ssClsNameBuffScratch);
9315#else // !_DEBUG
9316 // since this is for diagnostic purposes only,
9317 // give up on the namespace, as we don't have a buffer to concat it
9318 // also note this won't show array class names.
9319 LPCUTF8 nameSpace;
9320 *scopeName= t.GetMethodTable()->GetFullyQualifiedNameInfo(&nameSpace);
9321#endif // !_DEBUG
9322 }
9323 }
9324
9325 result = field->GetName();
9326
9327 EE_TO_JIT_TRANSITION();
9328
9329 return result;
9330}
9331
9332/*********************************************************************/
9333// Get the type that declares the field
9334CORINFO_CLASS_HANDLE CEEInfo::getFieldClass (CORINFO_FIELD_HANDLE fieldHnd)
9335{
9336 CONTRACTL {
9337 SO_TOLERANT;
9338 NOTHROW;
9339 GC_NOTRIGGER;
9340 MODE_PREEMPTIVE;
9341 } CONTRACTL_END;
9342
9343 CORINFO_CLASS_HANDLE result = NULL;
9344
9345 JIT_TO_EE_TRANSITION_LEAF();
9346
9347 FieldDesc* field = (FieldDesc*) fieldHnd;
9348 result = CORINFO_CLASS_HANDLE(field->GetApproxEnclosingMethodTable());
9349
9350 EE_TO_JIT_TRANSITION_LEAF();
9351
9352 return result;
9353}
9354
9355/*********************************************************************/
9356// Returns the basic type of the field (not the the type that declares the field)
9357//
9358// pTypeHnd - Optional. If not null then on return, for reference and value types,
9359// *pTypeHnd will contain the normalized type of the field.
9360// owner - Optional. For resolving in a generic context
9361
9362CorInfoType CEEInfo::getFieldType (CORINFO_FIELD_HANDLE fieldHnd,
9363 CORINFO_CLASS_HANDLE* pTypeHnd,
9364 CORINFO_CLASS_HANDLE owner)
9365{
9366 CONTRACTL {
9367 SO_TOLERANT;
9368 THROWS;
9369 GC_TRIGGERS;
9370 MODE_PREEMPTIVE;
9371 } CONTRACTL_END;
9372
9373 CorInfoType result = CORINFO_TYPE_UNDEF;
9374
9375 JIT_TO_EE_TRANSITION();
9376
9377 result = getFieldTypeInternal(fieldHnd, pTypeHnd, owner);
9378
9379 EE_TO_JIT_TRANSITION();
9380
9381 return result;
9382}
9383
9384/*********************************************************************/
9385CorInfoType CEEInfo::getFieldTypeInternal (CORINFO_FIELD_HANDLE fieldHnd,
9386 CORINFO_CLASS_HANDLE* pTypeHnd,
9387 CORINFO_CLASS_HANDLE owner)
9388{
9389 STANDARD_VM_CONTRACT;
9390
9391 if (pTypeHnd != nullptr)
9392 {
9393 *pTypeHnd = 0;
9394 }
9395
9396 TypeHandle clsHnd = TypeHandle();
9397 FieldDesc* field = (FieldDesc*) fieldHnd;
9398 CorElementType type = field->GetFieldType();
9399
9400 // <REVISIT_TODO>TODO should not burn the time to do this for anything but Value Classes</REVISIT_TODO>
9401 _ASSERTE(type != ELEMENT_TYPE_BYREF);
9402
9403 if (type == ELEMENT_TYPE_I)
9404 {
9405 PTR_MethodTable enclosingMethodTable = field->GetApproxEnclosingMethodTable();
9406 if (enclosingMethodTable->IsByRefLike() && enclosingMethodTable->HasSameTypeDefAs(g_pByReferenceClass))
9407 {
9408 _ASSERTE(field->GetOffset() == 0);
9409 return CORINFO_TYPE_BYREF;
9410 }
9411 }
9412
9413 if (!CorTypeInfo::IsPrimitiveType(type))
9414 {
9415 PCCOR_SIGNATURE sig;
9416 DWORD sigCount;
9417 CorCallingConvention conv;
9418
9419 field->GetSig(&sig, &sigCount);
9420
9421 conv = (CorCallingConvention)CorSigUncompressCallingConv(sig);
9422 _ASSERTE(isCallConv(conv, IMAGE_CEE_CS_CALLCONV_FIELD));
9423
9424 SigPointer ptr(sig, sigCount);
9425
9426 // For verifying code involving generics, use the class instantiation
9427 // of the optional owner (to provide exact, not representative,
9428 // type information)
9429 SigTypeContext typeContext(field, (TypeHandle)owner);
9430
9431 clsHnd = ptr.GetTypeHandleThrowing(field->GetModule(), &typeContext);
9432 _ASSERTE(!clsHnd.IsNull());
9433
9434 // I believe it doesn't make any diff. if this is GetInternalCorElementType
9435 // or GetSignatureCorElementType.
9436 type = clsHnd.GetSignatureCorElementType();
9437 }
9438
9439 return CEEInfo::asCorInfoType(type, clsHnd, pTypeHnd);
9440}
9441
9442/*********************************************************************/
9443unsigned CEEInfo::getFieldOffset (CORINFO_FIELD_HANDLE fieldHnd)
9444{
9445 CONTRACTL {
9446 SO_TOLERANT;
9447 THROWS;
9448 GC_TRIGGERS;
9449 MODE_PREEMPTIVE;
9450 } CONTRACTL_END;
9451
9452 unsigned result = (unsigned) -1;
9453
9454 JIT_TO_EE_TRANSITION();
9455
9456 FieldDesc* field = (FieldDesc*) fieldHnd;
9457
9458 // GetOffset() does not include the size of Object
9459 result = field->GetOffset();
9460
9461 // So if it is not a value class, add the Object into it
9462 if (field->IsStatic())
9463 {
9464 Module* pModule = field->GetModule();
9465 if (field->IsRVA() && pModule->IsRvaFieldTls(field->GetOffset()))
9466 {
9467 result = pModule->GetFieldTlsOffset(field->GetOffset());
9468 }
9469 }
9470 else if (!field->GetApproxEnclosingMethodTable()->IsValueType())
9471 {
9472 result += OBJECT_SIZE;
9473 }
9474
9475 EE_TO_JIT_TRANSITION();
9476
9477 return result;
9478}
9479
9480/*********************************************************************/
9481bool CEEInfo::isWriteBarrierHelperRequired(CORINFO_FIELD_HANDLE field)
9482{
9483 CONTRACTL {
9484 SO_TOLERANT;
9485 THROWS;
9486 GC_TRIGGERS;
9487 MODE_PREEMPTIVE;
9488 } CONTRACTL_END;
9489
9490 bool fHelperRequired = false;
9491
9492 JIT_TO_EE_TRANSITION();
9493
9494 FieldDesc * pField = (FieldDesc *)field;
9495
9496 // TODO: jit64 should be switched to the same plan as the i386 jits - use
9497 // getClassGClayout to figure out the need for writebarrier helper, and inline the copying.
9498 // Once this happens, USE_WRITE_BARRIER_HELPERS and CORINFO_FLG_WRITE_BARRIER_HELPER can be removed.
9499 CorElementType type = pField->GetFieldType();
9500
9501 if(CorTypeInfo::IsObjRef(type))
9502 fHelperRequired = true;
9503 else if (type == ELEMENT_TYPE_VALUETYPE)
9504 {
9505 TypeHandle th = pField->GetFieldTypeHandleThrowing();
9506 _ASSERTE(!th.IsNull());
9507 if(th.GetMethodTable()->ContainsPointers())
9508 fHelperRequired = true;
9509 }
9510
9511 EE_TO_JIT_TRANSITION();
9512
9513 return fHelperRequired;
9514}
9515
9516/*********************************************************************/
9517DWORD CEEInfo::getFieldThreadLocalStoreID(CORINFO_FIELD_HANDLE fieldHnd, void **ppIndirection)
9518{
9519 CONTRACTL {
9520 SO_TOLERANT;
9521 THROWS;
9522 GC_TRIGGERS;
9523 MODE_PREEMPTIVE;
9524 } CONTRACTL_END;
9525
9526 DWORD result = 0;
9527
9528 if (ppIndirection != NULL)
9529 *ppIndirection = NULL;
9530
9531 JIT_TO_EE_TRANSITION();
9532
9533 FieldDesc* field = (FieldDesc*) fieldHnd;
9534 Module* module = field->GetModule();
9535
9536 _ASSERTE(field->IsRVA()); // Only RVA statics can be thread local
9537 _ASSERTE(module->IsRvaFieldTls(field->GetOffset()));
9538
9539 result = module->GetTlsIndex();
9540
9541 EE_TO_JIT_TRANSITION();
9542
9543 return result;
9544}
9545
9546void *CEEInfo::allocateArray(ULONG cBytes)
9547{
9548 CONTRACTL {
9549 SO_TOLERANT;
9550 THROWS;
9551 GC_TRIGGERS;
9552 MODE_PREEMPTIVE;
9553 } CONTRACTL_END;
9554
9555 void * result = NULL;
9556
9557 JIT_TO_EE_TRANSITION();
9558
9559 result = new BYTE [cBytes];
9560
9561 EE_TO_JIT_TRANSITION();
9562
9563 return result;
9564}
9565
9566void CEEInfo::freeArray(void *array)
9567{
9568 CONTRACTL {
9569 SO_TOLERANT;
9570 THROWS;
9571 GC_TRIGGERS;
9572 MODE_PREEMPTIVE;
9573 } CONTRACTL_END;
9574
9575 JIT_TO_EE_TRANSITION();
9576
9577 delete [] ((BYTE*) array);
9578
9579 EE_TO_JIT_TRANSITION();
9580}
9581
9582void CEEInfo::getBoundaries(CORINFO_METHOD_HANDLE ftn,
9583 unsigned int *cILOffsets, DWORD **pILOffsets,
9584 ICorDebugInfo::BoundaryTypes *implicitBoundaries)
9585{
9586 CONTRACTL {
9587 SO_TOLERANT;
9588 THROWS;
9589 GC_TRIGGERS;
9590 MODE_PREEMPTIVE;
9591 } CONTRACTL_END;
9592
9593 JIT_TO_EE_TRANSITION();
9594
9595#ifdef DEBUGGING_SUPPORTED
9596 if (g_pDebugInterface && !IsCompilationProcess())
9597 {
9598 g_pDebugInterface->getBoundaries(GetMethod(ftn), cILOffsets, pILOffsets,
9599 implicitBoundaries);
9600 }
9601 else
9602 {
9603 *cILOffsets = 0;
9604 *pILOffsets = NULL;
9605 *implicitBoundaries = ICorDebugInfo::DEFAULT_BOUNDARIES;
9606 }
9607#endif // DEBUGGING_SUPPORTED
9608
9609 EE_TO_JIT_TRANSITION();
9610}
9611
9612void CEEInfo::getVars(CORINFO_METHOD_HANDLE ftn, ULONG32 *cVars, ICorDebugInfo::ILVarInfo **vars,
9613 bool *extendOthers)
9614{
9615 CONTRACTL {
9616 SO_TOLERANT;
9617 THROWS;
9618 GC_TRIGGERS;
9619 MODE_PREEMPTIVE;
9620 } CONTRACTL_END;
9621
9622 JIT_TO_EE_TRANSITION();
9623
9624#ifdef DEBUGGING_SUPPORTED
9625 if (g_pDebugInterface && !IsCompilationProcess())
9626 {
9627 g_pDebugInterface->getVars(GetMethod(ftn), cVars, vars, extendOthers);
9628 }
9629 else
9630 {
9631 *cVars = 0;
9632 *vars = NULL;
9633
9634 // Just tell the JIT to extend everything.
9635 *extendOthers = true;
9636 }
9637#endif // DEBUGGING_SUPPORTED
9638
9639 EE_TO_JIT_TRANSITION();
9640}
9641
9642/*********************************************************************/
9643CORINFO_ARG_LIST_HANDLE CEEInfo::getArgNext(CORINFO_ARG_LIST_HANDLE args)
9644{
9645 CONTRACTL {
9646 SO_TOLERANT;
9647 THROWS;
9648 GC_TRIGGERS;
9649 MODE_PREEMPTIVE;
9650 } CONTRACTL_END;
9651
9652 CORINFO_ARG_LIST_HANDLE result = NULL;
9653
9654 JIT_TO_EE_TRANSITION();
9655
9656 SigPointer ptr((unsigned __int8*) args);
9657 IfFailThrow(ptr.SkipExactlyOne());
9658
9659 result = (CORINFO_ARG_LIST_HANDLE) ptr.GetPtr();
9660
9661 EE_TO_JIT_TRANSITION();
9662
9663 return result;
9664}
9665
9666
9667/*********************************************************************/
9668
9669CorInfoTypeWithMod CEEInfo::getArgType (
9670 CORINFO_SIG_INFO* sig,
9671 CORINFO_ARG_LIST_HANDLE args,
9672 CORINFO_CLASS_HANDLE* vcTypeRet
9673 )
9674{
9675 CONTRACTL {
9676 SO_TOLERANT;
9677 THROWS;
9678 GC_TRIGGERS;
9679 MODE_PREEMPTIVE;
9680 } CONTRACTL_END;
9681
9682 CorInfoTypeWithMod result = CorInfoTypeWithMod(CORINFO_TYPE_UNDEF);
9683
9684 JIT_TO_EE_TRANSITION();
9685
9686 _ASSERTE((BYTE*) sig->pSig <= (BYTE*) sig->args && (BYTE*) args < (BYTE*) sig->pSig + sig->cbSig);
9687 _ASSERTE((BYTE*) sig->args <= (BYTE*) args);
9688 INDEBUG(*vcTypeRet = CORINFO_CLASS_HANDLE((size_t)INVALID_POINTER_CC));
9689
9690 SigPointer ptr((unsigned __int8*) args);
9691 CorElementType eType;
9692 IfFailThrow(ptr.PeekElemType(&eType));
9693 while (eType == ELEMENT_TYPE_PINNED)
9694 {
9695 result = CORINFO_TYPE_MOD_PINNED;
9696 IfFailThrow(ptr.GetElemType(NULL));
9697 IfFailThrow(ptr.PeekElemType(&eType));
9698 }
9699
9700 // Now read off the "real" element type after taking any instantiations into consideration
9701 SigTypeContext typeContext;
9702 GetTypeContext(&sig->sigInst,&typeContext);
9703
9704 Module* pModule = GetModule(sig->scope);
9705
9706 CorElementType type = ptr.PeekElemTypeClosed(pModule, &typeContext);
9707
9708 TypeHandle typeHnd = TypeHandle();
9709 switch (type) {
9710 case ELEMENT_TYPE_VAR :
9711 case ELEMENT_TYPE_MVAR :
9712 case ELEMENT_TYPE_VALUETYPE :
9713 case ELEMENT_TYPE_TYPEDBYREF :
9714 case ELEMENT_TYPE_INTERNAL :
9715 {
9716 typeHnd = ptr.GetTypeHandleThrowing(pModule, &typeContext);
9717 _ASSERTE(!typeHnd.IsNull());
9718
9719 CorElementType normType = typeHnd.GetInternalCorElementType();
9720
9721 // if we are looking up a value class, don't morph it to a refernece type
9722 // (This can only happen in illegal IL)
9723 if (!CorTypeInfo::IsObjRef(normType) || type != ELEMENT_TYPE_VALUETYPE)
9724 {
9725 type = normType;
9726 }
9727 }
9728 break;
9729
9730 case ELEMENT_TYPE_PTR:
9731 // Load the type eagerly under debugger to make the eval work
9732 if (!isVerifyOnly() && CORDisableJITOptimizations(pModule->GetDebuggerInfoBits()))
9733 {
9734 // NOTE: in some IJW cases, when the type pointed at is unmanaged,
9735 // the GetTypeHandle may fail, because there is no TypeDef for such type.
9736 // Usage of GetTypeHandleThrowing would lead to class load exception
9737 TypeHandle thPtr = ptr.GetTypeHandleNT(pModule, &typeContext);
9738 if(!thPtr.IsNull())
9739 {
9740 m_pOverride->classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_HANDLE(thPtr.AsPtr()));
9741 }
9742 }
9743 break;
9744
9745 case ELEMENT_TYPE_VOID:
9746 // void is not valid in local sigs
9747 if (sig->flags & CORINFO_SIGFLAG_IS_LOCAL_SIG)
9748 COMPlusThrowHR(COR_E_INVALIDPROGRAM);
9749 break;
9750
9751 case ELEMENT_TYPE_END:
9752 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
9753 break;
9754
9755 default:
9756 break;
9757 }
9758
9759 result = CorInfoTypeWithMod(result | CEEInfo::asCorInfoType(type, typeHnd, vcTypeRet));
9760 EE_TO_JIT_TRANSITION();
9761
9762 return result;
9763}
9764
9765/*********************************************************************/
9766
9767CORINFO_CLASS_HANDLE CEEInfo::getArgClass (
9768 CORINFO_SIG_INFO* sig,
9769 CORINFO_ARG_LIST_HANDLE args
9770 )
9771{
9772 CONTRACTL {
9773 SO_TOLERANT;
9774 THROWS;
9775 GC_TRIGGERS;
9776 MODE_PREEMPTIVE;
9777 } CONTRACTL_END;
9778
9779 CORINFO_CLASS_HANDLE result = NULL;
9780
9781 JIT_TO_EE_TRANSITION();
9782
9783 // make certain we dont have a completely wacked out sig pointer
9784 _ASSERTE((BYTE*) sig->pSig <= (BYTE*) sig->args);
9785 _ASSERTE((BYTE*) sig->args <= (BYTE*) args && (BYTE*) args < &((BYTE*) sig->args)[0x10000*5]);
9786
9787 Module* pModule = GetModule(sig->scope);
9788
9789 SigPointer ptr((unsigned __int8*) args);
9790
9791 CorElementType eType;
9792 IfFailThrow(ptr.PeekElemType(&eType));
9793
9794 while (eType == ELEMENT_TYPE_PINNED)
9795 {
9796 IfFailThrow(ptr.GetElemType(NULL));
9797 IfFailThrow(ptr.PeekElemType(&eType));
9798 }
9799 // Now read off the "real" element type after taking any instantiations into consideration
9800 SigTypeContext typeContext;
9801 GetTypeContext(&sig->sigInst, &typeContext);
9802 CorElementType type = ptr.PeekElemTypeClosed(pModule, &typeContext);
9803
9804 if (!CorTypeInfo::IsPrimitiveType(type)) {
9805 TypeHandle th = ptr.GetTypeHandleThrowing(pModule, &typeContext);
9806 result = CORINFO_CLASS_HANDLE(th.AsPtr());
9807 }
9808
9809 EE_TO_JIT_TRANSITION();
9810
9811 return result;
9812}
9813
9814/*********************************************************************/
9815
9816CorInfoType CEEInfo::getHFAType(CORINFO_CLASS_HANDLE hClass)
9817{
9818 CONTRACTL {
9819 SO_TOLERANT;
9820 THROWS;
9821 GC_TRIGGERS;
9822 MODE_PREEMPTIVE;
9823 } CONTRACTL_END;
9824
9825 CorInfoType result = CORINFO_TYPE_UNDEF;
9826
9827 JIT_TO_EE_TRANSITION();
9828
9829 TypeHandle VMClsHnd(hClass);
9830
9831 result = asCorInfoType(VMClsHnd.GetHFAType());
9832
9833 EE_TO_JIT_TRANSITION();
9834
9835 return result;
9836}
9837
9838/*********************************************************************/
9839
9840 // return the unmanaged calling convention for a PInvoke
9841CorInfoUnmanagedCallConv CEEInfo::getUnmanagedCallConv(CORINFO_METHOD_HANDLE method)
9842{
9843 CONTRACTL {
9844 SO_TOLERANT;
9845 THROWS;
9846 GC_TRIGGERS;
9847 MODE_PREEMPTIVE;
9848 } CONTRACTL_END;
9849
9850 CorInfoUnmanagedCallConv result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9851
9852 JIT_TO_EE_TRANSITION();
9853
9854 MethodDesc* pMD = NULL;
9855 pMD = GetMethod(method);
9856 _ASSERTE(pMD->IsNDirect());
9857
9858#ifdef _TARGET_X86_
9859 EX_TRY
9860 {
9861 PInvokeStaticSigInfo sigInfo(pMD, PInvokeStaticSigInfo::NO_THROW_ON_ERROR);
9862
9863 switch (sigInfo.GetCallConv()) {
9864 case pmCallConvCdecl:
9865 result = CORINFO_UNMANAGED_CALLCONV_C;
9866 break;
9867 case pmCallConvStdcall:
9868 result = CORINFO_UNMANAGED_CALLCONV_STDCALL;
9869 break;
9870 case pmCallConvThiscall:
9871 result = CORINFO_UNMANAGED_CALLCONV_THISCALL;
9872 break;
9873 default:
9874 result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9875 }
9876 }
9877 EX_CATCH
9878 {
9879 result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9880 }
9881 EX_END_CATCH(SwallowAllExceptions)
9882#else // !_TARGET_X86_
9883 //
9884 // we have only one calling convention
9885 //
9886 result = CORINFO_UNMANAGED_CALLCONV_STDCALL;
9887#endif // !_TARGET_X86_
9888
9889 EE_TO_JIT_TRANSITION();
9890
9891 return result;
9892}
9893
9894/*********************************************************************/
9895BOOL NDirectMethodDesc::ComputeMarshalingRequired()
9896{
9897 WRAPPER_NO_CONTRACT;
9898
9899 return NDirect::MarshalingRequired(this);
9900}
9901
9902/*********************************************************************/
9903BOOL CEEInfo::pInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig)
9904{
9905 CONTRACTL {
9906 SO_TOLERANT;
9907 THROWS;
9908 GC_TRIGGERS;
9909 MODE_PREEMPTIVE;
9910 } CONTRACTL_END;
9911
9912 BOOL result = FALSE;
9913
9914 JIT_TO_EE_TRANSITION();
9915
9916 if (method != 0)
9917 {
9918 MethodDesc* ftn = GetMethod(method);
9919 _ASSERTE(ftn->IsNDirect());
9920 NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
9921
9922#if defined(HAS_NDIRECT_IMPORT_PRECODE)
9923 if (pMD->IsVarArg())
9924 {
9925 // Varag P/Invoke must not be inlined because its NDirectMethodDesc
9926 // does not contain a meaningful stack size (it is call site specific).
9927 // See code:InlinedCallFrame.UpdateRegDisplay where this is needed.
9928 result = TRUE;
9929 }
9930 else if (pMD->MarshalingRequired())
9931 {
9932 // This is not a no-marshal signature.
9933 result = TRUE;
9934 }
9935 else
9936 {
9937 // This is a no-marshal non-vararg signature.
9938 result = FALSE;
9939 }
9940#else
9941 // Marshalling is required to lazy initialize the indirection cell
9942 // without NDirectImportPrecode.
9943 result = TRUE;
9944#endif
9945 }
9946 else
9947 {
9948 // check the call site signature
9949 result = NDirect::MarshalingRequired(
9950 GetMethod(method),
9951 callSiteSig->pSig,
9952 GetModule(callSiteSig->scope));
9953 }
9954
9955 EE_TO_JIT_TRANSITION();
9956
9957 return result;
9958}
9959
9960/*********************************************************************/
9961// Generate a cookie based on the signature that would needs to be passed
9962// to CORINFO_HELP_PINVOKE_CALLI
9963LPVOID CEEInfo::GetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig,
9964 void **ppIndirection)
9965{
9966 WRAPPER_NO_CONTRACT;
9967
9968 return getVarArgsHandle(szMetaSig, ppIndirection);
9969}
9970
9971bool CEEInfo::canGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig)
9972{
9973 LIMITED_METHOD_CONTRACT;
9974 return true;
9975}
9976
9977
9978// Check any constraints on method type arguments
9979BOOL CEEInfo::satisfiesMethodConstraints(
9980 CORINFO_CLASS_HANDLE parent,
9981 CORINFO_METHOD_HANDLE method)
9982{
9983 CONTRACTL {
9984 SO_TOLERANT;
9985 THROWS;
9986 GC_TRIGGERS;
9987 MODE_PREEMPTIVE;
9988 } CONTRACTL_END;
9989
9990 BOOL result = FALSE;
9991
9992 JIT_TO_EE_TRANSITION();
9993
9994 _ASSERTE(parent != NULL);
9995 _ASSERTE(method != NULL);
9996 result = GetMethod(method)->SatisfiesMethodConstraints(TypeHandle(parent));
9997
9998 EE_TO_JIT_TRANSITION();
9999
10000 return result;
10001}
10002
10003
10004
10005/*********************************************************************/
10006// Given a delegate target class, a target method parent class, a target method,
10007// a delegate class, check if the method signature is compatible with the Invoke method of the delegate
10008// (under the typical instantiation of any free type variables in the memberref signatures).
10009//
10010// objCls should be NULL if the target object is NULL
10011//@GENERICSVER: new (suitable for generics)
10012BOOL CEEInfo::isCompatibleDelegate(
10013 CORINFO_CLASS_HANDLE objCls,
10014 CORINFO_CLASS_HANDLE methodParentCls,
10015 CORINFO_METHOD_HANDLE method,
10016 CORINFO_CLASS_HANDLE delegateCls,
10017 BOOL* pfIsOpenDelegate)
10018{
10019 CONTRACTL {
10020 SO_TOLERANT;
10021 THROWS;
10022 GC_TRIGGERS;
10023 MODE_PREEMPTIVE;
10024 } CONTRACTL_END;
10025
10026 BOOL result = FALSE;
10027
10028 JIT_TO_EE_TRANSITION();
10029
10030 _ASSERTE(method != NULL);
10031 _ASSERTE(delegateCls != NULL);
10032
10033 TypeHandle delegateClsHnd = (TypeHandle) delegateCls;
10034
10035 _ASSERTE(delegateClsHnd.GetMethodTable()->IsDelegate());
10036
10037 TypeHandle methodParentHnd = (TypeHandle) (methodParentCls);
10038 MethodDesc* pMDFtn = GetMethod(method);
10039 TypeHandle objClsHnd(objCls);
10040
10041 EX_TRY
10042 {
10043 result = COMDelegate::ValidateCtor(objClsHnd, methodParentHnd, pMDFtn, delegateClsHnd, pfIsOpenDelegate);
10044 }
10045 EX_CATCH
10046 {
10047 }
10048 EX_END_CATCH(SwallowAllExceptions)
10049
10050 EE_TO_JIT_TRANSITION();
10051
10052 return result;
10053}
10054
10055/*********************************************************************/
10056 // return the unmanaged target *if method has already been prelinked.*
10057void* CEEInfo::getPInvokeUnmanagedTarget(CORINFO_METHOD_HANDLE method,
10058 void **ppIndirection)
10059{
10060 CONTRACTL {
10061 SO_TOLERANT;
10062 THROWS;
10063 GC_TRIGGERS;
10064 MODE_PREEMPTIVE;
10065 } CONTRACTL_END;
10066
10067 // Not expected to work due to multicore and tiered JIT potentially needing
10068 // to call managed cctors
10069 _ASSERTE(FALSE);
10070
10071 if (ppIndirection != NULL)
10072 {
10073 *ppIndirection = NULL;
10074 }
10075
10076 return NULL;
10077}
10078
10079/*********************************************************************/
10080 // return address of fixup area for late-bound N/Direct calls.
10081void* CEEInfo::getAddressOfPInvokeFixup(CORINFO_METHOD_HANDLE method,
10082 void **ppIndirection)
10083{
10084 CONTRACTL {
10085 SO_TOLERANT;
10086 NOTHROW;
10087 GC_NOTRIGGER;
10088 MODE_PREEMPTIVE;
10089 } CONTRACTL_END;
10090
10091 void * result = NULL;
10092
10093 if (ppIndirection != NULL)
10094 *ppIndirection = NULL;
10095
10096 JIT_TO_EE_TRANSITION_LEAF();
10097
10098 MethodDesc* ftn = GetMethod(method);
10099 _ASSERTE(ftn->IsNDirect());
10100 NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
10101
10102 result = (LPVOID)&(pMD->GetWriteableData()->m_pNDirectTarget);
10103
10104 EE_TO_JIT_TRANSITION_LEAF();
10105
10106 return result;
10107}
10108
10109/*********************************************************************/
10110 // return address of fixup area for late-bound N/Direct calls.
10111void CEEInfo::getAddressOfPInvokeTarget(CORINFO_METHOD_HANDLE method,
10112 CORINFO_CONST_LOOKUP *pLookup)
10113{
10114 WRAPPER_NO_CONTRACT;
10115
10116 void *pIndirection;
10117 pLookup->accessType = IAT_PVALUE;
10118 pLookup->addr = getAddressOfPInvokeFixup(method, &pIndirection);
10119 _ASSERTE(pIndirection == NULL);
10120}
10121
10122/*********************************************************************/
10123CORINFO_JUST_MY_CODE_HANDLE CEEInfo::getJustMyCodeHandle(
10124 CORINFO_METHOD_HANDLE method,
10125 CORINFO_JUST_MY_CODE_HANDLE**ppIndirection)
10126{
10127 CONTRACTL {
10128 SO_TOLERANT;
10129 NOTHROW;
10130 GC_NOTRIGGER;
10131 MODE_PREEMPTIVE;
10132 } CONTRACTL_END;
10133
10134 CORINFO_JUST_MY_CODE_HANDLE result = NULL;
10135
10136 if (ppIndirection)
10137 *ppIndirection = NULL;
10138
10139 JIT_TO_EE_TRANSITION_LEAF();
10140
10141 // Get the flag from the debugger.
10142 MethodDesc* ftn = GetMethod(method);
10143 DWORD * pFlagAddr = NULL;
10144
10145 if (g_pDebugInterface)
10146 {
10147 pFlagAddr = g_pDebugInterface->GetJMCFlagAddr(ftn->GetModule());
10148 }
10149
10150 result = (CORINFO_JUST_MY_CODE_HANDLE) pFlagAddr;
10151
10152 EE_TO_JIT_TRANSITION_LEAF();
10153
10154 return result;
10155}
10156
10157/*********************************************************************/
10158void InlinedCallFrame::GetEEInfo(CORINFO_EE_INFO::InlinedCallFrameInfo *pInfo)
10159{
10160 LIMITED_METHOD_CONTRACT;
10161
10162 pInfo->size = sizeof(GSCookie) + sizeof(InlinedCallFrame);
10163
10164 pInfo->offsetOfGSCookie = 0;
10165 pInfo->offsetOfFrameVptr = sizeof(GSCookie);
10166 pInfo->offsetOfFrameLink = sizeof(GSCookie) + Frame::GetOffsetOfNextLink();
10167 pInfo->offsetOfCallSiteSP = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCallSiteSP);
10168 pInfo->offsetOfCalleeSavedFP = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCalleeSavedFP);
10169 pInfo->offsetOfCallTarget = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_Datum);
10170 pInfo->offsetOfReturnAddress = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCallerReturnAddress);
10171}
10172
10173/*********************************************************************/
10174// Return details about EE internal data structures
10175void CEEInfo::getEEInfo(CORINFO_EE_INFO *pEEInfoOut)
10176{
10177 CONTRACTL {
10178 SO_TOLERANT;
10179 THROWS;
10180 GC_TRIGGERS;
10181 MODE_PREEMPTIVE;
10182 } CONTRACTL_END;
10183
10184 INDEBUG(memset(pEEInfoOut, 0xCC, sizeof(*pEEInfoOut)));
10185
10186 JIT_TO_EE_TRANSITION();
10187
10188 if (!IsReadyToRunCompilation())
10189 {
10190 InlinedCallFrame::GetEEInfo(&pEEInfoOut->inlinedCallFrameInfo);
10191
10192 // Offsets into the Thread structure
10193 pEEInfoOut->offsetOfThreadFrame = Thread::GetOffsetOfCurrentFrame();
10194 pEEInfoOut->offsetOfGCState = Thread::GetOffsetOfGCFlag();
10195 }
10196 else
10197 {
10198 // inlinedCallFrameInfo is not used for R2R compilation
10199 ZeroMemory(&pEEInfoOut->inlinedCallFrameInfo, sizeof(pEEInfoOut->inlinedCallFrameInfo));
10200
10201 pEEInfoOut->offsetOfThreadFrame = (DWORD)-1;
10202 pEEInfoOut->offsetOfGCState = (DWORD)-1;
10203 }
10204
10205#ifndef CROSSBITNESS_COMPILE
10206 // The assertions must hold in every non-crossbitness scenario
10207 _ASSERTE(OFFSETOF__DelegateObject__target == DelegateObject::GetOffsetOfTarget());
10208 _ASSERTE(OFFSETOF__DelegateObject__methodPtr == DelegateObject::GetOffsetOfMethodPtr());
10209 _ASSERTE(OFFSETOF__DelegateObject__methodPtrAux == DelegateObject::GetOffsetOfMethodPtrAux());
10210 _ASSERTE(OFFSETOF__PtrArray__m_Array_ == PtrArray::GetDataOffset());
10211#endif
10212
10213 // Delegate offsets
10214 pEEInfoOut->offsetOfDelegateInstance = OFFSETOF__DelegateObject__target;
10215 pEEInfoOut->offsetOfDelegateFirstTarget = OFFSETOF__DelegateObject__methodPtr;
10216
10217 // Secure delegate offsets
10218 pEEInfoOut->offsetOfSecureDelegateIndirectCell = OFFSETOF__DelegateObject__methodPtrAux;
10219
10220 // Remoting offsets
10221 pEEInfoOut->offsetOfTransparentProxyRP = (DWORD)-1;
10222 pEEInfoOut->offsetOfRealProxyServer = (DWORD)-1;
10223
10224 pEEInfoOut->offsetOfObjArrayData = OFFSETOF__PtrArray__m_Array_;
10225
10226 pEEInfoOut->sizeOfReversePInvokeFrame = (DWORD)-1;
10227
10228 pEEInfoOut->osPageSize = GetOsPageSize();
10229 pEEInfoOut->maxUncheckedOffsetForNullObject = MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT;
10230 pEEInfoOut->targetAbi = CORINFO_CORECLR_ABI;
10231
10232 pEEInfoOut->osType = CORINFO_WINNT;
10233
10234 // hardcode OS version to 0.0.0. These fields can be removed from JITEE interface
10235 pEEInfoOut->osMajor = 0;
10236 pEEInfoOut->osMinor = 0;
10237 pEEInfoOut->osBuild = 0;
10238
10239 EE_TO_JIT_TRANSITION();
10240}
10241
10242LPCWSTR CEEInfo::getJitTimeLogFilename()
10243{
10244 CONTRACTL {
10245 SO_TOLERANT;
10246 THROWS;
10247 GC_TRIGGERS;
10248 MODE_PREEMPTIVE;
10249 } CONTRACTL_END;
10250
10251 LPCWSTR result = NULL;
10252
10253 JIT_TO_EE_TRANSITION();
10254 result = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitTimeLogFile);
10255 EE_TO_JIT_TRANSITION();
10256
10257 return result;
10258}
10259
10260
10261
10262 // Return details about EE internal data structures
10263DWORD CEEInfo::getThreadTLSIndex(void **ppIndirection)
10264{
10265 CONTRACTL {
10266 SO_TOLERANT;
10267 THROWS;
10268 GC_TRIGGERS;
10269 MODE_PREEMPTIVE;
10270 } CONTRACTL_END;
10271
10272 DWORD result = (DWORD)-1;
10273
10274 if (ppIndirection != NULL)
10275 *ppIndirection = NULL;
10276
10277 return result;
10278}
10279
10280const void * CEEInfo::getInlinedCallFrameVptr(void **ppIndirection)
10281{
10282 CONTRACTL {
10283 SO_TOLERANT;
10284 NOTHROW;
10285 GC_NOTRIGGER;
10286 MODE_PREEMPTIVE;
10287 } CONTRACTL_END;
10288
10289 void * result = NULL;
10290
10291 if (ppIndirection != NULL)
10292 *ppIndirection = NULL;
10293
10294 JIT_TO_EE_TRANSITION_LEAF();
10295
10296#ifndef CROSSGEN_COMPILE
10297 result = (void*)InlinedCallFrame::GetMethodFrameVPtr();
10298#else
10299 result = (void*)0x43210;
10300#endif
10301
10302 EE_TO_JIT_TRANSITION_LEAF();
10303
10304 return result;
10305}
10306
10307LONG * CEEInfo::getAddrOfCaptureThreadGlobal(void **ppIndirection)
10308{
10309 CONTRACTL {
10310 SO_TOLERANT;
10311 NOTHROW;
10312 GC_NOTRIGGER;
10313 MODE_PREEMPTIVE;
10314 } CONTRACTL_END;
10315
10316 LONG * result = NULL;
10317
10318 if (ppIndirection != NULL)
10319 *ppIndirection = NULL;
10320
10321 JIT_TO_EE_TRANSITION_LEAF();
10322
10323 result = (LONG *)&g_TrapReturningThreads;
10324
10325 EE_TO_JIT_TRANSITION_LEAF();
10326
10327 return result;
10328}
10329
10330
10331
10332HRESULT CEEInfo::GetErrorHRESULT(struct _EXCEPTION_POINTERS *pExceptionPointers)
10333{
10334 CONTRACTL {
10335 SO_TOLERANT;
10336 NOTHROW;
10337 GC_TRIGGERS;
10338 MODE_ANY;
10339 } CONTRACTL_END;
10340
10341 HRESULT hr = S_OK;
10342
10343 //This function is called from the JIT64 exception filter during PEVerify. Because it is a filter, it
10344 //can be "called" from a NOTHROW region in the case of StackOverflow. Security::MapToHR throws
10345 //internally, but it catches all exceptions. Therefore, none of the children can cause an exception to
10346 //percolate out of this function (except for Stack Overflow). Obviously I can't explain most of this to
10347 //the Contracts system, and I can't add this CONTRACT_VIOLATION to the filter in Jit64.
10348 CONTRACT_VIOLATION(ThrowsViolation);
10349
10350 JIT_TO_EE_TRANSITION();
10351
10352 GCX_COOP();
10353
10354 OBJECTREF throwable = GetThread()->LastThrownObject();
10355 hr = GetExceptionHResult(throwable);
10356
10357 EE_TO_JIT_TRANSITION();
10358
10359 return hr;
10360}
10361
10362
10363ULONG CEEInfo::GetErrorMessage(__inout_ecount(bufferLength) LPWSTR buffer, ULONG bufferLength)
10364{
10365 CONTRACTL {
10366 SO_TOLERANT;
10367 THROWS;
10368 GC_TRIGGERS;
10369 MODE_PREEMPTIVE;
10370 } CONTRACTL_END;
10371
10372 ULONG result = 0;
10373
10374#ifndef CROSSGEN_COMPILE
10375 JIT_TO_EE_TRANSITION();
10376
10377 GCX_COOP();
10378
10379 OBJECTREF throwable = GetThread()->LastThrownObject();
10380
10381 if (throwable != NULL)
10382 {
10383 EX_TRY
10384 {
10385 result = GetExceptionMessage(throwable, buffer, bufferLength);
10386 }
10387 EX_CATCH
10388 {
10389 }
10390 EX_END_CATCH(SwallowAllExceptions)
10391 }
10392
10393 EE_TO_JIT_TRANSITION();
10394#endif
10395
10396 return result;
10397}
10398
10399// This method is called from CEEInfo::FilterException which
10400// is run as part of the SEH filter clause for the JIT.
10401// It is fatal to throw an exception while running a SEH filter clause
10402// so our contract is NOTHROW, NOTRIGGER.
10403//
10404LONG EEFilterException(struct _EXCEPTION_POINTERS *pExceptionPointers, void *unused)
10405{
10406 CONTRACTL {
10407 SO_TOLERANT;
10408 NOTHROW;
10409 GC_NOTRIGGER;
10410 } CONTRACTL_END;
10411
10412 int result = 0;
10413
10414 JIT_TO_EE_TRANSITION_LEAF();
10415
10416 VALIDATE_BACKOUT_STACK_CONSUMPTION;
10417
10418 unsigned code = pExceptionPointers->ExceptionRecord->ExceptionCode;
10419
10420#ifdef _DEBUG
10421 if (code == EXCEPTION_ACCESS_VIOLATION)
10422 {
10423 static int hit = 0;
10424 if (hit++ == 0)
10425 {
10426 _ASSERTE(!"Access violation while Jitting!");
10427 // If you set the debugger to catch access violations and 'go'
10428 // you will get back to the point at which the access violation occurred
10429 result = EXCEPTION_CONTINUE_EXECUTION;
10430 }
10431 else
10432 {
10433 result = EXCEPTION_CONTINUE_SEARCH;
10434 }
10435 }
10436 else
10437#endif // _DEBUG
10438 // No one should be catching breakpoint
10439 // Similarly the JIT doesn't know how to reset the guard page, so it shouldn't
10440 // be catching a hard stack overflow
10441 if (code == EXCEPTION_BREAKPOINT || code == EXCEPTION_SINGLE_STEP || code == EXCEPTION_STACK_OVERFLOW)
10442 {
10443 result = EXCEPTION_CONTINUE_SEARCH;
10444 }
10445#ifdef CROSSGEN_COMPILE
10446 else
10447 {
10448 result = EXCEPTION_EXECUTE_HANDLER;
10449 }
10450#else
10451 else if (!IsComPlusException(pExceptionPointers->ExceptionRecord))
10452 {
10453 result = EXCEPTION_EXECUTE_HANDLER;
10454 }
10455 else
10456 {
10457 GCX_COOP();
10458
10459 // This is actually the LastThrown exception object.
10460 OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord(pExceptionPointers->ExceptionRecord);
10461
10462 if (throwable != NULL)
10463 {
10464 struct
10465 {
10466 OBJECTREF oLastThrownObject;
10467 } _gc;
10468
10469 ZeroMemory(&_gc, sizeof(_gc));
10470
10471 // Setup the throwables
10472 _gc.oLastThrownObject = throwable;
10473
10474 GCPROTECT_BEGIN(_gc);
10475
10476 // Don't catch ThreadAbort and other uncatchable exceptions
10477 if (IsUncatchable(&_gc.oLastThrownObject))
10478 result = EXCEPTION_CONTINUE_SEARCH;
10479 else
10480 result = EXCEPTION_EXECUTE_HANDLER;
10481
10482 GCPROTECT_END();
10483 }
10484 }
10485#endif
10486
10487 EE_TO_JIT_TRANSITION_LEAF();
10488
10489 return result;
10490}
10491
10492int CEEInfo::FilterException(struct _EXCEPTION_POINTERS *pExceptionPointers)
10493{
10494 WRAPPER_NO_CONTRACT;
10495 return EEFilterException(pExceptionPointers, nullptr);
10496}
10497
10498// This code is called if FilterException chose to handle the exception.
10499void CEEInfo::HandleException(struct _EXCEPTION_POINTERS *pExceptionPointers)
10500{
10501 CONTRACTL {
10502 SO_TOLERANT;
10503 NOTHROW;
10504 GC_NOTRIGGER;
10505 } CONTRACTL_END;
10506
10507 JIT_TO_EE_TRANSITION_LEAF();
10508
10509#ifndef CROSSGEN_COMPILE
10510 if (IsComPlusException(pExceptionPointers->ExceptionRecord))
10511 {
10512 GCX_COOP();
10513
10514 // This is actually the LastThrown exception object.
10515 OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord(pExceptionPointers->ExceptionRecord);
10516
10517 if (throwable != NULL)
10518 {
10519 struct
10520 {
10521 OBJECTREF oLastThrownObject;
10522 OBJECTREF oCurrentThrowable;
10523 } _gc;
10524
10525 ZeroMemory(&_gc, sizeof(_gc));
10526
10527 PTR_Thread pCurThread = GetThread();
10528
10529 // Setup the throwables
10530 _gc.oLastThrownObject = throwable;
10531
10532 // This will be NULL if no managed exception is active. Otherwise,
10533 // it will reference the active throwable.
10534 _gc.oCurrentThrowable = pCurThread->GetThrowable();
10535
10536 GCPROTECT_BEGIN(_gc);
10537
10538 // JIT does not use or reference managed exceptions at all and simply swallows them,
10539 // or lets them fly through so that they will either get caught in managed code, the VM
10540 // or will go unhandled.
10541 //
10542 // Blind swallowing of managed exceptions can break the semantic of "which exception handler"
10543 // gets to process the managed exception first. The expected handler is managed code exception
10544 // handler (e.g. COMPlusFrameHandler on x86 and ProcessCLRException on 64bit) which will setup
10545 // the exception tracker for the exception that will enable the expected sync between the
10546 // LastThrownObject (LTO), setup in RaiseTheExceptionInternalOnly, and the exception tracker.
10547 //
10548 // However, JIT can break this by swallowing the managed exception before managed code exception
10549 // handler gets a chance to setup an exception tracker for it. Since there is no cleanup
10550 // done for the swallowed exception as part of the unwind (because no exception tracker may have been setup),
10551 // we need to reset the LTO, if it is out of sync from the active throwable.
10552 //
10553 // Hence, check if the LastThrownObject and active-exception throwable are in sync or not.
10554 // If not, bring them in sync.
10555 //
10556 // Example
10557 // -------
10558 // It is possible that an exception was already in progress and while processing it (e.g.
10559 // invoking finally block), we invoked JIT that had another managed exception @ JIT-EE transition boundary
10560 // that is swallowed by the JIT before managed code exception handler sees it. This breaks the sync between
10561 // LTO and the active exception in the exception tracker.
10562 if (_gc.oCurrentThrowable != _gc.oLastThrownObject)
10563 {
10564 // Update the LTO.
10565 //
10566 // Note: Incase of OOM, this will get set to OOM instance.
10567 pCurThread->SafeSetLastThrownObject(_gc.oCurrentThrowable);
10568 }
10569
10570 GCPROTECT_END();
10571 }
10572 }
10573#endif
10574
10575 EE_TO_JIT_TRANSITION_LEAF();
10576}
10577
10578void ThrowExceptionForJit(HRESULT res);
10579
10580void CEEInfo::ThrowExceptionForJitResult(
10581 HRESULT result)
10582{
10583 CONTRACTL {
10584 SO_TOLERANT;
10585 THROWS;
10586 GC_TRIGGERS;
10587 MODE_PREEMPTIVE;
10588 } CONTRACTL_END;
10589
10590 JIT_TO_EE_TRANSITION();
10591
10592 if (!SUCCEEDED(result))
10593 ThrowExceptionForJit(result);
10594
10595 EE_TO_JIT_TRANSITION();
10596}
10597
10598
10599CORINFO_MODULE_HANDLE CEEInfo::embedModuleHandle(CORINFO_MODULE_HANDLE handle,
10600 void **ppIndirection)
10601{
10602 CONTRACTL {
10603 SO_TOLERANT;
10604 NOTHROW;
10605 GC_NOTRIGGER;
10606 MODE_PREEMPTIVE;
10607 PRECONDITION(!IsDynamicScope(handle));
10608 }
10609 CONTRACTL_END;
10610
10611 if (ppIndirection != NULL)
10612 *ppIndirection = NULL;
10613
10614 JIT_TO_EE_TRANSITION_LEAF();
10615
10616 EE_TO_JIT_TRANSITION_LEAF();
10617
10618 return handle;
10619}
10620
10621CORINFO_CLASS_HANDLE CEEInfo::embedClassHandle(CORINFO_CLASS_HANDLE handle,
10622 void **ppIndirection)
10623{
10624 CONTRACTL {
10625 SO_TOLERANT;
10626 NOTHROW;
10627 GC_NOTRIGGER;
10628 MODE_PREEMPTIVE;
10629 }
10630 CONTRACTL_END;
10631
10632 if (ppIndirection != NULL)
10633 *ppIndirection = NULL;
10634
10635 JIT_TO_EE_TRANSITION_LEAF();
10636
10637 EE_TO_JIT_TRANSITION_LEAF();
10638
10639 return handle;
10640}
10641
10642CORINFO_FIELD_HANDLE CEEInfo::embedFieldHandle(CORINFO_FIELD_HANDLE handle,
10643 void **ppIndirection)
10644{
10645 CONTRACTL {
10646 SO_TOLERANT;
10647 NOTHROW;
10648 GC_NOTRIGGER;
10649 MODE_PREEMPTIVE;
10650 }
10651 CONTRACTL_END;
10652
10653 if (ppIndirection != NULL)
10654 *ppIndirection = NULL;
10655
10656 JIT_TO_EE_TRANSITION_LEAF();
10657
10658 EE_TO_JIT_TRANSITION_LEAF();
10659
10660 return handle;
10661}
10662
10663CORINFO_METHOD_HANDLE CEEInfo::embedMethodHandle(CORINFO_METHOD_HANDLE handle,
10664 void **ppIndirection)
10665{
10666 CONTRACTL {
10667 SO_TOLERANT;
10668 NOTHROW;
10669 GC_NOTRIGGER;
10670 MODE_PREEMPTIVE;
10671 }
10672 CONTRACTL_END;
10673
10674 if (ppIndirection != NULL)
10675 *ppIndirection = NULL;
10676
10677 JIT_TO_EE_TRANSITION_LEAF();
10678
10679 EE_TO_JIT_TRANSITION_LEAF();
10680
10681 return handle;
10682}
10683
10684/*********************************************************************/
10685void CEEInfo::setJitFlags(const CORJIT_FLAGS& jitFlags)
10686{
10687 LIMITED_METHOD_CONTRACT;
10688
10689 m_jitFlags = jitFlags;
10690}
10691
10692/*********************************************************************/
10693DWORD CEEInfo::getJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes)
10694{
10695 CONTRACTL {
10696 SO_TOLERANT;
10697 NOTHROW;
10698 GC_NOTRIGGER;
10699 MODE_PREEMPTIVE;
10700 } CONTRACTL_END;
10701
10702 JIT_TO_EE_TRANSITION_LEAF();
10703
10704 _ASSERTE(sizeInBytes >= sizeof(m_jitFlags));
10705 *jitFlags = m_jitFlags;
10706
10707 EE_TO_JIT_TRANSITION_LEAF();
10708
10709 return sizeof(m_jitFlags);
10710}
10711
10712/*********************************************************************/
10713#if !defined(PLATFORM_UNIX)
10714
10715struct RunWithErrorTrapFilterParam
10716{
10717 ICorDynamicInfo* m_corInfo;
10718 void (*m_function)(void*);
10719 void* m_param;
10720 EXCEPTION_POINTERS m_exceptionPointers;
10721};
10722
10723static LONG RunWithErrorTrapFilter(struct _EXCEPTION_POINTERS* exceptionPointers, void* theParam)
10724{
10725 WRAPPER_NO_CONTRACT;
10726
10727 auto* param = reinterpret_cast<RunWithErrorTrapFilterParam*>(theParam);
10728 param->m_exceptionPointers = *exceptionPointers;
10729 return param->m_corInfo->FilterException(exceptionPointers);
10730}
10731
10732#endif // !defined(PLATFORM_UNIX)
10733
10734bool CEEInfo::runWithErrorTrap(void (*function)(void*), void* param)
10735{
10736 // No dynamic contract here because SEH is used
10737 STATIC_CONTRACT_THROWS;
10738 STATIC_CONTRACT_GC_TRIGGERS;
10739 STATIC_CONTRACT_SO_TOLERANT;
10740 STATIC_CONTRACT_MODE_PREEMPTIVE;
10741
10742 // NOTE: the lack of JIT/EE transition markers in this method is intentional. Any
10743 // transitions into the EE proper should occur either via the call to
10744 // `EEFilterException` (which is appropriately marked) or via JIT/EE
10745 // interface calls made by `function`.
10746
10747 bool success = true;
10748
10749#if !defined(PLATFORM_UNIX)
10750
10751 RunWithErrorTrapFilterParam trapParam;
10752 trapParam.m_corInfo = m_pOverride == nullptr ? this : m_pOverride;
10753 trapParam.m_function = function;
10754 trapParam.m_param = param;
10755
10756 PAL_TRY(RunWithErrorTrapFilterParam*, pTrapParam, &trapParam)
10757 {
10758 pTrapParam->m_function(pTrapParam->m_param);
10759 }
10760 PAL_EXCEPT_FILTER(RunWithErrorTrapFilter)
10761 {
10762 HandleException(&trapParam.m_exceptionPointers);
10763 success = false;
10764 }
10765 PAL_ENDTRY
10766
10767#else // !defined(PLATFORM_UNIX)
10768
10769 // We shouldn't need PAL_TRY on *nix: any exceptions that we are able to catch
10770 // ought to originate from the runtime itself and should be catchable inside of
10771 // EX_TRY/EX_CATCH, including emulated SEH exceptions.
10772 EX_TRY
10773 {
10774 function(param);
10775 }
10776 EX_CATCH
10777 {
10778 success = false;
10779 }
10780 EX_END_CATCH(RethrowTerminalExceptions);
10781
10782#endif
10783
10784 return success;
10785}
10786
10787/*********************************************************************/
10788IEEMemoryManager* CEEInfo::getMemoryManager()
10789{
10790 CONTRACTL {
10791 SO_TOLERANT;
10792 NOTHROW;
10793 GC_NOTRIGGER;
10794 MODE_PREEMPTIVE;
10795 } CONTRACTL_END;
10796
10797 IEEMemoryManager* result = NULL;
10798
10799 JIT_TO_EE_TRANSITION_LEAF();
10800
10801 result = GetEEMemoryManager();
10802
10803 EE_TO_JIT_TRANSITION_LEAF();
10804
10805 return result;
10806}
10807
10808/*********************************************************************/
10809int CEEInfo::doAssert(const char* szFile, int iLine, const char* szExpr)
10810{
10811 STATIC_CONTRACT_SO_TOLERANT;
10812 STATIC_CONTRACT_THROWS;
10813 STATIC_CONTRACT_GC_TRIGGERS;
10814 STATIC_CONTRACT_MODE_PREEMPTIVE;
10815 STATIC_CONTRACT_DEBUG_ONLY;
10816
10817 int result = 0;
10818
10819 JIT_TO_EE_TRANSITION();
10820
10821#ifdef CROSSGEN_COMPILE
10822 ThrowHR(COR_E_INVALIDPROGRAM);
10823#else
10824
10825#ifdef _DEBUG
10826 BEGIN_DEBUG_ONLY_CODE;
10827 result = _DbgBreakCheck(szFile, iLine, szExpr);
10828 END_DEBUG_ONLY_CODE;
10829#else // !_DEBUG
10830 result = 1; // break into debugger
10831#endif // !_DEBUG
10832
10833#endif
10834
10835 EE_TO_JIT_TRANSITION();
10836
10837 return result;
10838}
10839
10840void CEEInfo::reportFatalError(CorJitResult result)
10841{
10842 STATIC_CONTRACT_SO_TOLERANT;
10843 STATIC_CONTRACT_THROWS;
10844 STATIC_CONTRACT_GC_TRIGGERS;
10845 STATIC_CONTRACT_MODE_PREEMPTIVE;
10846
10847 JIT_TO_EE_TRANSITION_LEAF();
10848
10849 STRESS_LOG2(LF_JIT,LL_ERROR, "Jit reported error 0x%x while compiling 0x%p\n",
10850 (int)result, (INT_PTR)getMethodBeingCompiled());
10851
10852 EE_TO_JIT_TRANSITION_LEAF();
10853}
10854
10855BOOL CEEInfo::logMsg(unsigned level, const char* fmt, va_list args)
10856{
10857 STATIC_CONTRACT_SO_TOLERANT;
10858 STATIC_CONTRACT_THROWS;
10859 STATIC_CONTRACT_GC_TRIGGERS;
10860 STATIC_CONTRACT_MODE_PREEMPTIVE;
10861 STATIC_CONTRACT_DEBUG_ONLY;
10862
10863 BOOL result = FALSE;
10864
10865 JIT_TO_EE_TRANSITION_LEAF();
10866
10867#ifdef LOGGING
10868 if (LoggingOn(LF_JIT, level))
10869 {
10870 LogSpewValist(LF_JIT, level, (char*) fmt, args);
10871 result = TRUE;
10872 }
10873#endif // LOGGING
10874
10875 EE_TO_JIT_TRANSITION_LEAF();
10876
10877 return result;
10878}
10879
10880void CEEInfo::yieldExecution()
10881{
10882 WRAPPER_NO_CONTRACT;
10883}
10884
10885
10886#ifndef CROSSGEN_COMPILE
10887
10888/*********************************************************************/
10889
10890void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
10891 void ** ppIndirection) /* OUT */
10892{
10893 CONTRACTL {
10894 SO_TOLERANT;
10895 NOTHROW;
10896 GC_NOTRIGGER;
10897 MODE_PREEMPTIVE;
10898 } CONTRACTL_END;
10899
10900 void* result = NULL;
10901
10902 if (ppIndirection != NULL)
10903 *ppIndirection = NULL;
10904
10905 JIT_TO_EE_TRANSITION_LEAF();
10906
10907 _ASSERTE(ftnNum < CORINFO_HELP_COUNT);
10908
10909 void* pfnHelper = hlpFuncTable[ftnNum].pfnHelper;
10910
10911 size_t dynamicFtnNum = ((size_t)pfnHelper - 1);
10912 if (dynamicFtnNum < DYNAMIC_CORINFO_HELP_COUNT)
10913 {
10914#ifdef _PREFAST_
10915#pragma warning(push)
10916#pragma warning(disable:26001) // "Bounds checked above using the underflow trick"
10917#endif /*_PREFAST_ */
10918
10919#if defined(_TARGET_AMD64_)
10920 // To avoid using a jump stub we always call certain helpers using an indirect call.
10921 // Because when using a direct call and the target is father away than 2^31 bytes,
10922 // the direct call instead goes to a jump stub which jumps to the jit helper.
10923 // However in this process the jump stub will corrupt RAX.
10924 //
10925 // The set of helpers for which RAX must be preserved are the profiler probes
10926 // and the STOP_FOR_GC helper which maps to JIT_RareDisableHelper.
10927 // In the case of the STOP_FOR_GC helper RAX can be holding a function return value.
10928 //
10929 if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_STOP_FOR_GC ||
10930 dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_ENTER ||
10931 dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_LEAVE ||
10932 dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_TAILCALL)
10933 {
10934 _ASSERTE(ppIndirection != NULL);
10935 *ppIndirection = &hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10936 return NULL;
10937 }
10938#endif
10939
10940#if defined(ENABLE_FAST_GCPOLL_HELPER)
10941 //always call this indirectly so that we can swap GC Poll helpers.
10942 if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_POLL_GC)
10943 {
10944 _ASSERTE(ppIndirection != NULL);
10945 *ppIndirection = &hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10946 return NULL;
10947 }
10948#endif
10949
10950 pfnHelper = hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10951
10952#ifdef _PREFAST_
10953#pragma warning(pop)
10954#endif /*_PREFAST_*/
10955 }
10956
10957 _ASSERTE(pfnHelper);
10958
10959 result = (LPVOID)GetEEFuncEntryPoint(pfnHelper);
10960
10961 EE_TO_JIT_TRANSITION_LEAF();
10962
10963 return result;
10964}
10965
10966PCODE CEEJitInfo::getHelperFtnStatic(CorInfoHelpFunc ftnNum)
10967{
10968 LIMITED_METHOD_CONTRACT;
10969
10970 void* pfnHelper = hlpFuncTable[ftnNum].pfnHelper;
10971
10972 // If pfnHelper is an index into the dynamic helper table, it should be less
10973 // than DYNAMIC_CORINFO_HELP_COUNT. In this case we need to find the actual pfnHelper
10974 // using an extra indirection. Note the special case
10975 // where pfnHelper==0 where pfnHelper-1 will underflow and we will avoid the indirection.
10976 if (((size_t)pfnHelper - 1) < DYNAMIC_CORINFO_HELP_COUNT)
10977 {
10978 pfnHelper = hlpDynamicFuncTable[((size_t)pfnHelper - 1)].pfnHelper;
10979 }
10980
10981 _ASSERTE(pfnHelper != NULL);
10982
10983 return GetEEFuncEntryPoint(pfnHelper);
10984}
10985
10986void CEEJitInfo::addActiveDependency(CORINFO_MODULE_HANDLE moduleFrom,CORINFO_MODULE_HANDLE moduleTo)
10987{
10988 CONTRACTL
10989 {
10990 STANDARD_VM_CHECK;
10991 PRECONDITION(CheckPointer(moduleFrom));
10992 PRECONDITION(!IsDynamicScope(moduleFrom));
10993 PRECONDITION(CheckPointer(moduleTo));
10994 PRECONDITION(!IsDynamicScope(moduleTo));
10995 PRECONDITION(moduleFrom != moduleTo);
10996 }
10997 CONTRACTL_END;
10998
10999 // This is only called internaly. JIT-EE transition is not needed.
11000 // JIT_TO_EE_TRANSITION();
11001
11002 Module *dependency = (Module *)moduleTo;
11003 _ASSERTE(!dependency->IsSystem());
11004
11005 dependency->EnsureActive();
11006
11007 // EE_TO_JIT_TRANSITION();
11008}
11009
11010
11011// Wrapper around CEEInfo::GetProfilingHandle. The first time this is called for a
11012// method desc, it calls through to EEToProfInterfaceImpl::EEFunctionIDMappe and caches the
11013// result in CEEJitInfo::GetProfilingHandleCache. Thereafter, this wrapper regurgitates the cached values
11014// rather than calling into CEEInfo::GetProfilingHandle each time. This avoids
11015// making duplicate calls into the profiler's FunctionIDMapper callback.
11016void CEEJitInfo::GetProfilingHandle(BOOL *pbHookFunction,
11017 void **pProfilerHandle,
11018 BOOL *pbIndirectedHandles)
11019{
11020 CONTRACTL {
11021 SO_TOLERANT;
11022 THROWS;
11023 GC_TRIGGERS;
11024 MODE_PREEMPTIVE;
11025 } CONTRACTL_END;
11026
11027 _ASSERTE(pbHookFunction != NULL);
11028 _ASSERTE(pProfilerHandle != NULL);
11029 _ASSERTE(pbIndirectedHandles != NULL);
11030
11031 if (!m_gphCache.m_bGphIsCacheValid)
11032 {
11033#ifdef PROFILING_SUPPORTED
11034 JIT_TO_EE_TRANSITION();
11035
11036 // Cache not filled in, so make our first and only call to CEEInfo::GetProfilingHandle here
11037
11038 // methods with no metadata behind cannot be exposed to tools expecting metadata (profiler, debugger...)
11039 // they shouldnever come here as they are called out in GetCompileFlag
11040 _ASSERTE(!m_pMethodBeingCompiled->IsNoMetadata());
11041
11042 // We pass in the typical method definition to the function mapper because in
11043 // Whidbey all the profiling API transactions are done in terms of typical
11044 // method definitions not instantiations.
11045 BOOL bHookFunction = TRUE;
11046 void * profilerHandle = m_pMethodBeingCompiled;
11047
11048 {
11049 BEGIN_PIN_PROFILER(CORProfilerFunctionIDMapperEnabled());
11050 profilerHandle = (void *)g_profControlBlock.pProfInterface->EEFunctionIDMapper((FunctionID) m_pMethodBeingCompiled, &bHookFunction);
11051 END_PIN_PROFILER();
11052 }
11053
11054 m_gphCache.m_pvGphProfilerHandle = profilerHandle;
11055 m_gphCache.m_bGphHookFunction = (bHookFunction != FALSE);
11056 m_gphCache.m_bGphIsCacheValid = true;
11057
11058 EE_TO_JIT_TRANSITION();
11059#endif //PROFILING_SUPPORTED
11060 }
11061
11062 // Our cache of these values are bitfield bools, but the interface requires
11063 // BOOL. So to avoid setting aside a staging area on the stack for these
11064 // values, we filled them in directly in the if (not cached yet) case.
11065 *pbHookFunction = (m_gphCache.m_bGphHookFunction != false);
11066
11067 // At this point, the remaining values must be in the cache by now, so use them
11068 *pProfilerHandle = m_gphCache.m_pvGphProfilerHandle;
11069
11070 //
11071 // This is the JIT case, which is never indirected.
11072 //
11073 *pbIndirectedHandles = FALSE;
11074}
11075
11076/*********************************************************************/
11077void CEEJitInfo::BackoutJitData(EEJitManager * jitMgr)
11078{
11079 CONTRACTL {
11080 NOTHROW;
11081 GC_TRIGGERS;
11082 } CONTRACTL_END;
11083
11084 CodeHeader* pCodeHeader = GetCodeHeader();
11085 if (pCodeHeader)
11086 jitMgr->RemoveJitData(pCodeHeader, m_GCinfo_len, m_EHinfo_len);
11087}
11088
11089/*********************************************************************/
11090// Route jit information to the Jit Debug store.
11091void CEEJitInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap,
11092 ICorDebugInfo::OffsetMapping *pMap)
11093{
11094 CONTRACTL {
11095 SO_TOLERANT;
11096 THROWS;
11097 GC_TRIGGERS;
11098 MODE_PREEMPTIVE;
11099 } CONTRACTL_END;
11100
11101 JIT_TO_EE_TRANSITION();
11102
11103 // We receive ownership of the array
11104 _ASSERTE(m_pOffsetMapping == NULL && m_iOffsetMapping == 0);
11105 m_iOffsetMapping = cMap;
11106 m_pOffsetMapping = pMap;
11107
11108 EE_TO_JIT_TRANSITION();
11109}
11110
11111void CEEJitInfo::setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars)
11112{
11113 CONTRACTL {
11114 SO_TOLERANT;
11115 THROWS;
11116 GC_TRIGGERS;
11117 MODE_PREEMPTIVE;
11118 } CONTRACTL_END;
11119
11120 JIT_TO_EE_TRANSITION();
11121
11122 // We receive ownership of the array
11123 _ASSERTE(m_pNativeVarInfo == NULL && m_iNativeVarInfo == 0);
11124 m_iNativeVarInfo = cVars;
11125 m_pNativeVarInfo = vars;
11126
11127 EE_TO_JIT_TRANSITION();
11128}
11129
11130void CEEJitInfo::CompressDebugInfo()
11131{
11132 CONTRACTL {
11133 SO_TOLERANT;
11134 THROWS;
11135 GC_TRIGGERS;
11136 MODE_PREEMPTIVE;
11137 } CONTRACTL_END;
11138
11139 // Don't track JIT info for DynamicMethods.
11140 if (m_pMethodBeingCompiled->IsDynamicMethod())
11141 return;
11142
11143 if (m_iOffsetMapping == 0 && m_iNativeVarInfo == 0)
11144 return;
11145
11146 JIT_TO_EE_TRANSITION();
11147
11148 EX_TRY
11149 {
11150 PTR_BYTE pDebugInfo = CompressDebugInfo::CompressBoundariesAndVars(
11151 m_pOffsetMapping, m_iOffsetMapping,
11152 m_pNativeVarInfo, m_iNativeVarInfo,
11153 NULL,
11154 m_pMethodBeingCompiled->GetLoaderAllocator()->GetLowFrequencyHeap());
11155
11156 GetCodeHeader()->SetDebugInfo(pDebugInfo);
11157 }
11158 EX_CATCH
11159 {
11160 // Just ignore exceptions here. The debugger's structures will still be in a consistent state.
11161 }
11162 EX_END_CATCH(SwallowAllExceptions)
11163
11164 EE_TO_JIT_TRANSITION();
11165}
11166
11167void reservePersonalityRoutineSpace(ULONG &unwindSize)
11168{
11169#if defined(_TARGET_X86_)
11170 // Do nothing
11171#elif defined(_TARGET_AMD64_)
11172 // Add space for personality routine, it must be 4-byte aligned.
11173 // Everything in the UNWIND_INFO up to the variable-sized UnwindCodes
11174 // array has already had its size included in unwindSize by the caller.
11175 unwindSize += sizeof(ULONG);
11176
11177 // Note that the count of unwind codes (2 bytes each) is stored as a UBYTE
11178 // So the largest size could be 510 bytes, plus the header and language
11179 // specific stuff. This can't overflow.
11180
11181 _ASSERTE(FitsInU4(unwindSize + sizeof(ULONG)));
11182 unwindSize = (ULONG)(ALIGN_UP(unwindSize, sizeof(ULONG)));
11183#elif defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
11184 // The JIT passes in a 4-byte aligned block of unwind data.
11185 _ASSERTE(IS_ALIGNED(unwindSize, sizeof(ULONG)));
11186
11187 // Add space for personality routine, it must be 4-byte aligned.
11188 unwindSize += sizeof(ULONG);
11189#else
11190 PORTABILITY_ASSERT("reservePersonalityRoutineSpace");
11191#endif // !defined(_TARGET_AMD64_)
11192
11193}
11194// Reserve memory for the method/funclet's unwind information.
11195// Note that this must be called before allocMem. It should be
11196// called once for the main method, once for every funclet, and
11197// once for every block of cold code for which allocUnwindInfo
11198// will be called.
11199//
11200// This is necessary because jitted code must allocate all the
11201// memory needed for the unwindInfo at the allocMem call.
11202// For prejitted code we split up the unwinding information into
11203// separate sections .rdata and .pdata.
11204//
11205void CEEJitInfo::reserveUnwindInfo(BOOL isFunclet, BOOL isColdCode, ULONG unwindSize)
11206{
11207#ifdef WIN64EXCEPTIONS
11208 CONTRACTL {
11209 SO_TOLERANT;
11210 NOTHROW;
11211 GC_NOTRIGGER;
11212 MODE_PREEMPTIVE;
11213 }
11214 CONTRACTL_END;
11215
11216 JIT_TO_EE_TRANSITION_LEAF();
11217
11218 CONSISTENCY_CHECK_MSG(!isColdCode, "Hot/Cold splitting is not supported in jitted code");
11219 _ASSERTE_MSG(m_theUnwindBlock == NULL,
11220 "reserveUnwindInfo() can only be called before allocMem(), but allocMem() has already been called. "
11221 "This may indicate the JIT has hit a NO_WAY assert after calling allocMem(), and is re-JITting. "
11222 "Set COMPlus_JitBreakOnBadCode=1 and rerun to get the real error.");
11223
11224 ULONG currentSize = unwindSize;
11225
11226 reservePersonalityRoutineSpace(currentSize);
11227
11228 m_totalUnwindSize += currentSize;
11229
11230 m_totalUnwindInfos++;
11231
11232 EE_TO_JIT_TRANSITION_LEAF();
11233#else // WIN64EXCEPTIONS
11234 LIMITED_METHOD_CONTRACT;
11235 // Dummy implementation to make cross-platform altjit work
11236#endif // WIN64EXCEPTIONS
11237}
11238
11239// Allocate and initialize the .rdata and .pdata for this method or
11240// funclet and get the block of memory needed for the machine specific
11241// unwind information (the info for crawling the stack frame).
11242// Note that allocMem must be called first.
11243//
11244// The pHotCode parameter points at the first byte of the code of the method
11245// The startOffset and endOffset are the region (main or funclet) that
11246// we are to allocate and create .rdata and .pdata for.
11247// The pUnwindBlock is copied and contains the .pdata unwind area
11248//
11249// Parameters:
11250//
11251// pHotCode main method code buffer, always filled in
11252// pColdCode always NULL for jitted code
11253// startOffset start of code block, relative to pHotCode
11254// endOffset end of code block, relative to pHotCode
11255// unwindSize size of unwind info pointed to by pUnwindBlock
11256// pUnwindBlock pointer to unwind info
11257// funcKind type of funclet (main method code, handler, filter)
11258//
11259void CEEJitInfo::allocUnwindInfo (
11260 BYTE * pHotCode, /* IN */
11261 BYTE * pColdCode, /* IN */
11262 ULONG startOffset, /* IN */
11263 ULONG endOffset, /* IN */
11264 ULONG unwindSize, /* IN */
11265 BYTE * pUnwindBlock, /* IN */
11266 CorJitFuncKind funcKind /* IN */
11267 )
11268{
11269#ifdef WIN64EXCEPTIONS
11270 CONTRACTL {
11271 SO_TOLERANT;
11272 THROWS;
11273 GC_TRIGGERS;
11274 MODE_PREEMPTIVE;
11275 PRECONDITION(m_theUnwindBlock != NULL);
11276 PRECONDITION(m_usedUnwindSize < m_totalUnwindSize);
11277 PRECONDITION(m_usedUnwindInfos < m_totalUnwindInfos);
11278 PRECONDITION(endOffset <= m_codeSize);
11279 } CONTRACTL_END;
11280
11281 CONSISTENCY_CHECK_MSG(pColdCode == NULL, "Hot/Cold code splitting not supported for jitted code");
11282
11283 JIT_TO_EE_TRANSITION();
11284
11285 //
11286 // We add one callback-type dynamic function table per range section.
11287 // Therefore, the RUNTIME_FUNCTION info is always relative to the
11288 // image base contained in the dynamic function table, which happens
11289 // to be the LowAddress of the range section. The JIT has no
11290 // knowledge of the range section, so it gives us offsets that are
11291 // relative to the beginning of the method (pHotCode) and we allocate
11292 // and initialize the RUNTIME_FUNCTION data and record its location
11293 // in this function.
11294 //
11295
11296 if (funcKind != CORJIT_FUNC_ROOT)
11297 {
11298 // The main method should be emitted before funclets
11299 _ASSERTE(m_usedUnwindInfos > 0);
11300 }
11301
11302 PT_RUNTIME_FUNCTION pRuntimeFunction = m_CodeHeader->GetUnwindInfo(m_usedUnwindInfos);
11303 m_usedUnwindInfos++;
11304
11305 // Make sure that the RUNTIME_FUNCTION is aligned on a DWORD sized boundary
11306 _ASSERTE(IS_ALIGNED(pRuntimeFunction, sizeof(DWORD)));
11307
11308 UNWIND_INFO * pUnwindInfo = (UNWIND_INFO *) &(m_theUnwindBlock[m_usedUnwindSize]);
11309 m_usedUnwindSize += unwindSize;
11310
11311 reservePersonalityRoutineSpace(m_usedUnwindSize);
11312
11313 _ASSERTE(m_usedUnwindSize <= m_totalUnwindSize);
11314
11315 // Make sure that the UnwindInfo is aligned
11316 _ASSERTE(IS_ALIGNED(pUnwindInfo, sizeof(ULONG)));
11317
11318 /* Calculate Image Relative offset to add to the jit generated unwind offsets */
11319
11320 TADDR baseAddress = m_moduleBase;
11321
11322 size_t currentCodeSizeT = (size_t)pHotCode - baseAddress;
11323
11324 /* Check if currentCodeSizeT offset fits in 32-bits */
11325 if (!FitsInU4(currentCodeSizeT))
11326 {
11327 _ASSERTE(!"Bad currentCodeSizeT");
11328 COMPlusThrowHR(E_FAIL);
11329 }
11330
11331 /* Check if EndAddress offset fits in 32-bit */
11332 if (!FitsInU4(currentCodeSizeT + endOffset))
11333 {
11334 _ASSERTE(!"Bad currentCodeSizeT");
11335 COMPlusThrowHR(E_FAIL);
11336 }
11337
11338 unsigned currentCodeOffset = (unsigned) currentCodeSizeT;
11339
11340 /* Calculate Unwind Info delta */
11341 size_t unwindInfoDeltaT = (size_t) pUnwindInfo - baseAddress;
11342
11343 /* Check if unwindDeltaT offset fits in 32-bits */
11344 if (!FitsInU4(unwindInfoDeltaT))
11345 {
11346 _ASSERTE(!"Bad unwindInfoDeltaT");
11347 COMPlusThrowHR(E_FAIL);
11348 }
11349
11350 unsigned unwindInfoDelta = (unsigned) unwindInfoDeltaT;
11351
11352 RUNTIME_FUNCTION__SetBeginAddress(pRuntimeFunction, currentCodeOffset + startOffset);
11353
11354#ifdef _TARGET_AMD64_
11355 pRuntimeFunction->EndAddress = currentCodeOffset + endOffset;
11356#endif
11357
11358 RUNTIME_FUNCTION__SetUnwindInfoAddress(pRuntimeFunction, unwindInfoDelta);
11359
11360#ifdef _DEBUG
11361 if (funcKind != CORJIT_FUNC_ROOT)
11362 {
11363 // Check the the new funclet doesn't overlap any existing funclet.
11364
11365 for (ULONG iUnwindInfo = 0; iUnwindInfo < m_usedUnwindInfos - 1; iUnwindInfo++)
11366 {
11367 PT_RUNTIME_FUNCTION pOtherFunction = m_CodeHeader->GetUnwindInfo(iUnwindInfo);
11368 _ASSERTE(( RUNTIME_FUNCTION__BeginAddress(pOtherFunction) >= RUNTIME_FUNCTION__EndAddress(pRuntimeFunction, baseAddress)
11369 || RUNTIME_FUNCTION__EndAddress(pOtherFunction, baseAddress) <= RUNTIME_FUNCTION__BeginAddress(pRuntimeFunction)));
11370 }
11371 }
11372#endif // _DEBUG
11373
11374 /* Copy the UnwindBlock */
11375 memcpy(pUnwindInfo, pUnwindBlock, unwindSize);
11376
11377#if defined(_TARGET_X86_)
11378
11379 // Do NOTHING
11380
11381#elif defined(_TARGET_AMD64_)
11382
11383 pUnwindInfo->Flags = UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER;
11384
11385 ULONG * pPersonalityRoutine = (ULONG*)ALIGN_UP(&(pUnwindInfo->UnwindCode[pUnwindInfo->CountOfUnwindCodes]), sizeof(ULONG));
11386 *pPersonalityRoutine = ExecutionManager::GetCLRPersonalityRoutineValue();
11387
11388#elif defined(_TARGET_ARM64_)
11389
11390 *(LONG *)pUnwindInfo |= (1 << 20); // X bit
11391
11392 ULONG * pPersonalityRoutine = (ULONG*)((BYTE *)pUnwindInfo + ALIGN_UP(unwindSize, sizeof(ULONG)));
11393 *pPersonalityRoutine = ExecutionManager::GetCLRPersonalityRoutineValue();
11394
11395#elif defined(_TARGET_ARM_)
11396
11397 *(LONG *)pUnwindInfo |= (1 << 20); // X bit
11398
11399 ULONG * pPersonalityRoutine = (ULONG*)((BYTE *)pUnwindInfo + ALIGN_UP(unwindSize, sizeof(ULONG)));
11400 *pPersonalityRoutine = (TADDR)ProcessCLRException - baseAddress;
11401
11402#endif
11403
11404#if defined(_TARGET_AMD64_)
11405 // Publish the new unwind information in a way that the ETW stack crawler can find
11406 if (m_usedUnwindInfos == m_totalUnwindInfos)
11407 UnwindInfoTable::PublishUnwindInfoForMethod(baseAddress, m_CodeHeader->GetUnwindInfo(0), m_totalUnwindInfos);
11408#endif // defined(_TARGET_AMD64_)
11409
11410 EE_TO_JIT_TRANSITION();
11411#else // WIN64EXCEPTIONS
11412 LIMITED_METHOD_CONTRACT;
11413 // Dummy implementation to make cross-platform altjit work
11414#endif // WIN64EXCEPTIONS
11415}
11416
11417void CEEJitInfo::recordCallSite(ULONG instrOffset,
11418 CORINFO_SIG_INFO * callSig,
11419 CORINFO_METHOD_HANDLE methodHandle)
11420{
11421 // Currently, only testing tools use this method. The EE itself doesn't need record this information.
11422 // N.B. The memory that callSig points to is managed by the JIT and isn't guaranteed to be around after
11423 // this function returns, so future implementations should copy the sig info if they want it to persist.
11424 LIMITED_METHOD_CONTRACT;
11425}
11426
11427// This is a variant for AMD64 or other machines that
11428// cannot always hold the destination address in a 32-bit location
11429// A relocation is recorded if we are pre-jitting.
11430// A jump thunk may be inserted if we are jitting
11431
11432void CEEJitInfo::recordRelocation(void * location,
11433 void * target,
11434 WORD fRelocType,
11435 WORD slot,
11436 INT32 addlDelta)
11437{
11438 CONTRACTL {
11439 SO_TOLERANT;
11440 THROWS;
11441 GC_TRIGGERS;
11442 MODE_PREEMPTIVE;
11443 } CONTRACTL_END;
11444
11445#ifdef _WIN64
11446 JIT_TO_EE_TRANSITION();
11447
11448 INT64 delta;
11449
11450 switch (fRelocType)
11451 {
11452 case IMAGE_REL_BASED_DIR64:
11453 // Write 64-bits into location
11454 *((UINT64 *) ((BYTE *) location + slot)) = (UINT64) target;
11455 break;
11456
11457#ifdef _TARGET_AMD64_
11458 case IMAGE_REL_BASED_REL32:
11459 {
11460 target = (BYTE *)target + addlDelta;
11461
11462 INT32 * fixupLocation = (INT32 *) ((BYTE *) location + slot);
11463 BYTE * baseAddr = (BYTE *)fixupLocation + sizeof(INT32);
11464
11465 delta = (INT64)((BYTE *)target - baseAddr);
11466
11467 //
11468 // Do we need to insert a jump stub to make the source reach the target?
11469 //
11470 // Note that we cannot stress insertion of jump stub by inserting it unconditionally. JIT records the relocations
11471 // for intra-module jumps and calls. It does not expect the register used by the jump stub to be trashed.
11472 //
11473 if (!FitsInI4(delta))
11474 {
11475 if (m_fAllowRel32)
11476 {
11477 //
11478 // When m_fAllowRel32 == TRUE, the JIT will use REL32s for both data addresses and direct code targets.
11479 // Since we cannot tell what the relocation is for, we have to defensively retry.
11480 //
11481 m_fJumpStubOverflow = TRUE;
11482 delta = 0;
11483 }
11484 else
11485 {
11486 //
11487 // When m_fAllowRel32 == FALSE, the JIT will use a REL32s for direct code targets only.
11488 // Use jump stub.
11489 //
11490 delta = rel32UsingJumpStub(fixupLocation, (PCODE)target, m_pMethodBeingCompiled, NULL, false /* throwOnOutOfMemoryWithinRange */);
11491 if (delta == 0)
11492 {
11493 // This forces the JIT to retry the method, which allows us to reserve more space for jump stubs and have a higher chance that
11494 // we will find space for them.
11495 m_fJumpStubOverflow = TRUE;
11496 }
11497
11498 // Keep track of conservative estimate of how much memory may be needed by jump stubs. We will use it to reserve extra memory
11499 // on retry to increase chances that the retry succeeds.
11500 m_reserveForJumpStubs = max(0x400, m_reserveForJumpStubs + 0x10);
11501 }
11502 }
11503
11504 LOG((LF_JIT, LL_INFO100000, "Encoded a PCREL32 at" FMT_ADDR "to" FMT_ADDR "+%d, delta is 0x%04x\n",
11505 DBG_ADDR(fixupLocation), DBG_ADDR(target), addlDelta, delta));
11506
11507 // Write the 32-bits pc-relative delta into location
11508 *fixupLocation = (INT32) delta;
11509 }
11510 break;
11511#endif // _TARGET_AMD64_
11512
11513#ifdef _TARGET_ARM64_
11514 case IMAGE_REL_ARM64_BRANCH26: // 26 bit offset << 2 & sign ext, for B and BL
11515 {
11516 _ASSERTE(slot == 0);
11517 _ASSERTE(addlDelta == 0);
11518
11519 PCODE branchTarget = (PCODE) target;
11520 _ASSERTE((branchTarget & 0x3) == 0); // the low two bits must be zero
11521
11522 PCODE fixupLocation = (PCODE) location;
11523 _ASSERTE((fixupLocation & 0x3) == 0); // the low two bits must be zero
11524
11525 delta = (INT64)(branchTarget - fixupLocation);
11526 _ASSERTE((delta & 0x3) == 0); // the low two bits must be zero
11527
11528 UINT32 branchInstr = *((UINT32*) fixupLocation);
11529 branchInstr &= 0xFC000000; // keep bits 31-26
11530 _ASSERTE((branchInstr & 0x7FFFFFFF) == 0x14000000); // Must be B or BL
11531
11532 //
11533 // Do we need to insert a jump stub to make the source reach the target?
11534 //
11535 //
11536 if (!FitsInRel28(delta))
11537 {
11538 // Use jump stub.
11539 //
11540 TADDR baseAddr = (TADDR)fixupLocation;
11541 TADDR loAddr = baseAddr - 0x08000000; // -2^27
11542 TADDR hiAddr = baseAddr + 0x07FFFFFF; // +2^27-1
11543
11544 // Check for the wrap around cases
11545 if (loAddr > baseAddr)
11546 loAddr = UINT64_MIN; // overflow
11547 if (hiAddr < baseAddr)
11548 hiAddr = UINT64_MAX; // overflow
11549
11550 PCODE jumpStubAddr = ExecutionManager::jumpStub(m_pMethodBeingCompiled,
11551 (PCODE) target,
11552 (BYTE *) loAddr,
11553 (BYTE *) hiAddr,
11554 NULL,
11555 false);
11556
11557 // Keep track of conservative estimate of how much memory may be needed by jump stubs. We will use it to reserve extra memory
11558 // on retry to increase chances that the retry succeeds.
11559 m_reserveForJumpStubs = max(0x400, m_reserveForJumpStubs + 2*BACK_TO_BACK_JUMP_ALLOCATE_SIZE);
11560
11561 if (jumpStubAddr == 0)
11562 {
11563 // This forces the JIT to retry the method, which allows us to reserve more space for jump stubs and have a higher chance that
11564 // we will find space for them.
11565 m_fJumpStubOverflow = TRUE;
11566 break;
11567 }
11568
11569 delta = (INT64)(jumpStubAddr - fixupLocation);
11570
11571 if (!FitsInRel28(delta))
11572 {
11573 _ASSERTE(!"jump stub was not in expected range");
11574 EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
11575 }
11576
11577 LOG((LF_JIT, LL_INFO100000, "Using JumpStub at" FMT_ADDR "that jumps to" FMT_ADDR "\n",
11578 DBG_ADDR(jumpStubAddr), DBG_ADDR(target)));
11579 }
11580
11581 LOG((LF_JIT, LL_INFO100000, "Encoded a BRANCH26 at" FMT_ADDR "to" FMT_ADDR ", delta is 0x%04x\n",
11582 DBG_ADDR(fixupLocation), DBG_ADDR(target), delta));
11583
11584 _ASSERTE(FitsInRel28(delta));
11585
11586 PutArm64Rel28((UINT32*) fixupLocation, (INT32)delta);
11587 }
11588 break;
11589
11590 case IMAGE_REL_ARM64_PAGEBASE_REL21:
11591 {
11592 _ASSERTE(slot == 0);
11593 _ASSERTE(addlDelta == 0);
11594
11595 // Write the 21 bits pc-relative page address into location.
11596 INT64 targetPage = (INT64)target & 0xFFFFFFFFFFFFF000LL;
11597 INT64 locationPage = (INT64)location & 0xFFFFFFFFFFFFF000LL;
11598 INT64 relPage = (INT64)(targetPage - locationPage);
11599 INT32 imm21 = (INT32)(relPage >> 12) & 0x1FFFFF;
11600 PutArm64Rel21((UINT32 *)location, imm21);
11601 }
11602 break;
11603
11604 case IMAGE_REL_ARM64_PAGEOFFSET_12A:
11605 {
11606 _ASSERTE(slot == 0);
11607 _ASSERTE(addlDelta == 0);
11608
11609 // Write the 12 bits page offset into location.
11610 INT32 imm12 = (INT32)target & 0xFFFLL;
11611 PutArm64Rel12((UINT32 *)location, imm12);
11612 }
11613 break;
11614
11615#endif // _TARGET_ARM64_
11616
11617 default:
11618 _ASSERTE(!"Unknown reloc type");
11619 break;
11620 }
11621
11622 EE_TO_JIT_TRANSITION();
11623#else // _WIN64
11624 JIT_TO_EE_TRANSITION_LEAF();
11625
11626 // Nothing to do on 32-bit
11627
11628 EE_TO_JIT_TRANSITION_LEAF();
11629#endif // _WIN64
11630}
11631
11632WORD CEEJitInfo::getRelocTypeHint(void * target)
11633{
11634 CONTRACTL {
11635 SO_TOLERANT;
11636 THROWS;
11637 GC_TRIGGERS;
11638 MODE_PREEMPTIVE;
11639 } CONTRACTL_END;
11640
11641#ifdef _TARGET_AMD64_
11642 if (m_fAllowRel32)
11643 {
11644 // The JIT calls this method for data addresses only. It always uses REL32s for direct code targets.
11645 if (IsPreferredExecutableRange(target))
11646 return IMAGE_REL_BASED_REL32;
11647 }
11648#endif // _TARGET_AMD64_
11649
11650 // No hints
11651 return (WORD)-1;
11652}
11653
11654void CEEJitInfo::getModuleNativeEntryPointRange(void** pStart, void** pEnd)
11655{
11656 CONTRACTL {
11657 SO_TOLERANT;
11658 NOTHROW;
11659 GC_NOTRIGGER;
11660 MODE_PREEMPTIVE;
11661 }
11662 CONTRACTL_END;
11663
11664 JIT_TO_EE_TRANSITION_LEAF();
11665
11666 *pStart = *pEnd = 0;
11667
11668 EE_TO_JIT_TRANSITION_LEAF();
11669}
11670
11671DWORD CEEJitInfo::getExpectedTargetArchitecture()
11672{
11673 LIMITED_METHOD_CONTRACT;
11674
11675 return IMAGE_FILE_MACHINE_NATIVE;
11676}
11677
11678void CEEInfo::JitProcessShutdownWork()
11679{
11680 LIMITED_METHOD_CONTRACT;
11681
11682 EEJitManager* jitMgr = ExecutionManager::GetEEJitManager();
11683
11684 // If we didn't load the JIT, there is no work to do.
11685 if (jitMgr->m_jit != NULL)
11686 {
11687 // Do the shutdown work.
11688 jitMgr->m_jit->ProcessShutdownWork(this);
11689 }
11690
11691#ifdef ALLOW_SXS_JIT
11692 if (jitMgr->m_alternateJit != NULL)
11693 {
11694 jitMgr->m_alternateJit->ProcessShutdownWork(this);
11695 }
11696#endif // ALLOW_SXS_JIT
11697}
11698
11699/*********************************************************************/
11700InfoAccessType CEEJitInfo::constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd,
11701 mdToken metaTok,
11702 void **ppValue)
11703{
11704 CONTRACTL {
11705 SO_TOLERANT;
11706 THROWS;
11707 GC_TRIGGERS;
11708 MODE_PREEMPTIVE;
11709 } CONTRACTL_END;
11710
11711 InfoAccessType result = IAT_PVALUE;
11712
11713 JIT_TO_EE_TRANSITION();
11714
11715 _ASSERTE(ppValue != NULL);
11716
11717 if (IsDynamicScope(scopeHnd))
11718 {
11719 *ppValue = (LPVOID)GetDynamicResolver(scopeHnd)->ConstructStringLiteral(metaTok);
11720 }
11721 else
11722 {
11723 *ppValue = (LPVOID)ConstructStringLiteral(scopeHnd, metaTok); // throws
11724 }
11725
11726 EE_TO_JIT_TRANSITION();
11727
11728 return result;
11729}
11730
11731/*********************************************************************/
11732InfoAccessType CEEJitInfo::emptyStringLiteral(void ** ppValue)
11733{
11734 CONTRACTL {
11735 SO_TOLERANT;
11736 THROWS;
11737 GC_TRIGGERS;
11738 MODE_PREEMPTIVE;
11739 } CONTRACTL_END;
11740
11741 InfoAccessType result = IAT_PVALUE;
11742
11743 if(NingenEnabled())
11744 {
11745 *ppValue = NULL;
11746 return result;
11747 }
11748
11749 JIT_TO_EE_TRANSITION();
11750 *ppValue = StringObject::GetEmptyStringRefPtr();
11751 EE_TO_JIT_TRANSITION();
11752
11753 return result;
11754}
11755
11756/*********************************************************************/
11757void* CEEJitInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd,
11758 void **ppIndirection)
11759{
11760 CONTRACTL {
11761 SO_TOLERANT;
11762 THROWS;
11763 GC_TRIGGERS;
11764 MODE_PREEMPTIVE;
11765 } CONTRACTL_END;
11766
11767 void *result = NULL;
11768
11769 if (ppIndirection != NULL)
11770 *ppIndirection = NULL;
11771
11772 // Do not bother with initialization if we are only verifying the method.
11773 if (isVerifyOnly())
11774 {
11775 return (void *)0x10;
11776 }
11777
11778 JIT_TO_EE_TRANSITION();
11779
11780 FieldDesc* field = (FieldDesc*) fieldHnd;
11781
11782 MethodTable* pMT = field->GetEnclosingMethodTable();
11783
11784 _ASSERTE(!pMT->ContainsGenericVariables());
11785
11786 void *base = NULL;
11787
11788 if (!field->IsRVA())
11789 {
11790 // <REVISIT_TODO>@todo: assert that the current method being compiled is unshared</REVISIT_TODO>
11791 // We must not call here for statics of collectible types.
11792 _ASSERTE(!pMT->Collectible());
11793
11794 // Allocate space for the local class if necessary, but don't trigger
11795 // class construction.
11796 DomainLocalModule *pLocalModule = pMT->GetDomainLocalModule();
11797 pLocalModule->PopulateClass(pMT);
11798
11799 GCX_COOP();
11800
11801 base = (void *) field->GetBase();
11802 }
11803
11804 result = field->GetStaticAddressHandle(base);
11805
11806 EE_TO_JIT_TRANSITION();
11807
11808 return result;
11809}
11810
11811/*********************************************************************/
11812CORINFO_CLASS_HANDLE CEEJitInfo::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE fieldHnd,
11813 bool* pIsSpeculative)
11814{
11815 CONTRACTL {
11816 SO_TOLERANT;
11817 THROWS;
11818 GC_TRIGGERS;
11819 MODE_PREEMPTIVE;
11820 } CONTRACTL_END;
11821
11822 CORINFO_CLASS_HANDLE result = NULL;
11823
11824 if (pIsSpeculative != NULL)
11825 {
11826 *pIsSpeculative = true;
11827 }
11828
11829 // Only examine the field's value if we are producing jitted code.
11830 if (isVerifyOnly() || IsCompilingForNGen() || IsReadyToRunCompilation())
11831 {
11832 return result;
11833 }
11834
11835 JIT_TO_EE_TRANSITION();
11836
11837 FieldDesc* field = (FieldDesc*) fieldHnd;
11838 bool isClassInitialized = false;
11839
11840 // We're only interested in ref class typed static fields
11841 // where the field handle specifies a unique location.
11842 if (field->IsStatic() && field->IsObjRef() && !field->IsThreadStatic())
11843 {
11844 MethodTable* pEnclosingMT = field->GetEnclosingMethodTable();
11845
11846 if (!pEnclosingMT->IsSharedByGenericInstantiations())
11847 {
11848 // Allocate space for the local class if necessary, but don't trigger
11849 // class construction.
11850 DomainLocalModule *pLocalModule = pEnclosingMT->GetDomainLocalModule();
11851 pLocalModule->PopulateClass(pEnclosingMT);
11852
11853 GCX_COOP();
11854
11855 OBJECTREF fieldObj = field->GetStaticOBJECTREF();
11856 VALIDATEOBJECTREF(fieldObj);
11857
11858 // Check for initialization before looking at the value
11859 isClassInitialized = !!pEnclosingMT->IsClassInited();
11860
11861 if (fieldObj != NULL)
11862 {
11863 MethodTable *pObjMT = fieldObj->GetMethodTable();
11864
11865 // TODO: Check if the jit is allowed to embed this handle in jitted code.
11866 // Note for the initonly cases it probably won't embed.
11867 result = (CORINFO_CLASS_HANDLE) pObjMT;
11868 }
11869 }
11870 }
11871
11872 // Did we find a class?
11873 if (result != NULL)
11874 {
11875 // Figure out what to report back.
11876 bool isResultImmutable = isClassInitialized && IsFdInitOnly(field->GetAttributes());
11877
11878 if (pIsSpeculative != NULL)
11879 {
11880 // Caller is ok with potentially mutable results.
11881 *pIsSpeculative = !isResultImmutable;
11882 }
11883 else
11884 {
11885 // Caller only wants to see immutable results.
11886 if (!isResultImmutable)
11887 {
11888 result = NULL;
11889 }
11890 }
11891 }
11892
11893 EE_TO_JIT_TRANSITION();
11894
11895 return result;
11896}
11897
11898/*********************************************************************/
11899static void *GetClassSync(MethodTable *pMT)
11900{
11901 STANDARD_VM_CONTRACT;
11902
11903 GCX_COOP();
11904
11905 OBJECTREF ref = pMT->GetManagedClassObject();
11906 return (void*)ref->GetSyncBlock()->GetMonitor();
11907}
11908
11909/*********************************************************************/
11910void* CEEJitInfo::getMethodSync(CORINFO_METHOD_HANDLE ftnHnd,
11911 void **ppIndirection)
11912{
11913 CONTRACTL {
11914 SO_TOLERANT;
11915 THROWS;
11916 GC_TRIGGERS;
11917 MODE_PREEMPTIVE;
11918 } CONTRACTL_END;
11919
11920 void * result = NULL;
11921
11922 if (ppIndirection != NULL)
11923 *ppIndirection = NULL;
11924
11925 JIT_TO_EE_TRANSITION();
11926
11927 result = GetClassSync((GetMethod(ftnHnd))->GetMethodTable());
11928
11929 EE_TO_JIT_TRANSITION();
11930
11931 return result;
11932}
11933
11934/*********************************************************************/
11935HRESULT CEEJitInfo::allocBBProfileBuffer (
11936 ULONG count,
11937 ICorJitInfo::ProfileBuffer ** profileBuffer
11938 )
11939{
11940 CONTRACTL {
11941 SO_TOLERANT;
11942 THROWS;
11943 GC_TRIGGERS;
11944 MODE_PREEMPTIVE;
11945 } CONTRACTL_END;
11946
11947 HRESULT hr = E_FAIL;
11948
11949 JIT_TO_EE_TRANSITION();
11950
11951#ifdef FEATURE_PREJIT
11952
11953 // We need to know the code size. Typically we can get the code size
11954 // from m_ILHeader. For dynamic methods, m_ILHeader will be NULL, so
11955 // for that case we need to use DynamicResolver to get the code size.
11956
11957 unsigned codeSize = 0;
11958 if (m_pMethodBeingCompiled->IsDynamicMethod())
11959 {
11960 unsigned stackSize, ehSize;
11961 CorInfoOptions options;
11962 DynamicResolver * pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver();
11963 pResolver->GetCodeInfo(&codeSize, &stackSize, &options, &ehSize);
11964 }
11965 else
11966 {
11967 codeSize = m_ILHeader->GetCodeSize();
11968 }
11969
11970 *profileBuffer = m_pMethodBeingCompiled->GetLoaderModule()->AllocateProfileBuffer(m_pMethodBeingCompiled->GetMemberDef(), count, codeSize);
11971 hr = (*profileBuffer ? S_OK : E_OUTOFMEMORY);
11972#else // FEATURE_PREJIT
11973 _ASSERTE(!"allocBBProfileBuffer not implemented on CEEJitInfo!");
11974 hr = E_NOTIMPL;
11975#endif // !FEATURE_PREJIT
11976
11977 EE_TO_JIT_TRANSITION();
11978
11979 return hr;
11980}
11981
11982// Consider implementing getBBProfileData on CEEJitInfo. This will allow us
11983// to use profile info in codegen for non zapped images.
11984HRESULT CEEJitInfo::getBBProfileData (
11985 CORINFO_METHOD_HANDLE ftnHnd,
11986 ULONG * size,
11987 ICorJitInfo::ProfileBuffer ** profileBuffer,
11988 ULONG * numRuns
11989 )
11990{
11991 LIMITED_METHOD_CONTRACT;
11992 _ASSERTE(!"getBBProfileData not implemented on CEEJitInfo!");
11993 return E_NOTIMPL;
11994}
11995
11996void CEEJitInfo::allocMem (
11997 ULONG hotCodeSize, /* IN */
11998 ULONG coldCodeSize, /* IN */
11999 ULONG roDataSize, /* IN */
12000 ULONG xcptnsCount, /* IN */
12001 CorJitAllocMemFlag flag, /* IN */
12002 void ** hotCodeBlock, /* OUT */
12003 void ** coldCodeBlock, /* OUT */
12004 void ** roDataBlock /* OUT */
12005 )
12006{
12007 CONTRACTL {
12008 SO_TOLERANT;
12009 THROWS;
12010 GC_TRIGGERS;
12011 MODE_PREEMPTIVE;
12012 } CONTRACTL_END;
12013
12014 JIT_TO_EE_TRANSITION();
12015
12016 _ASSERTE(coldCodeSize == 0);
12017 if (coldCodeBlock)
12018 {
12019 *coldCodeBlock = NULL;
12020 }
12021
12022 ULONG codeSize = hotCodeSize;
12023 void **codeBlock = hotCodeBlock;
12024
12025 S_SIZE_T totalSize = S_SIZE_T(codeSize);
12026
12027 size_t roDataAlignment = sizeof(void*);
12028 if ((flag & CORJIT_ALLOCMEM_FLG_RODATA_16BYTE_ALIGN)!= 0)
12029 {
12030 roDataAlignment = 16;
12031 }
12032 else if (roDataSize >= 8)
12033 {
12034 roDataAlignment = 8;
12035 }
12036 if (roDataSize > 0)
12037 {
12038 size_t codeAlignment = ((flag & CORJIT_ALLOCMEM_FLG_16BYTE_ALIGN)!= 0)
12039 ? 16 : sizeof(void*);
12040 totalSize.AlignUp(codeAlignment);
12041 if (roDataAlignment > codeAlignment) {
12042 // Add padding to align read-only data.
12043 totalSize += (roDataAlignment - codeAlignment);
12044 }
12045 totalSize += roDataSize;
12046 }
12047
12048#ifdef WIN64EXCEPTIONS
12049 totalSize.AlignUp(sizeof(DWORD));
12050 totalSize += m_totalUnwindSize;
12051#endif
12052
12053 _ASSERTE(m_CodeHeader == 0 &&
12054 // The jit-compiler sometimes tries to compile a method a second time
12055 // if it failed the first time. In such a situation, m_CodeHeader may
12056 // have already been assigned. Its OK to ignore this assert in such a
12057 // situation - we will leak some memory, but that is acceptable
12058 // since this should happen very rarely.
12059 "Note that this may fire if the JITCompiler tries to recompile a method");
12060
12061 if( totalSize.IsOverflow() )
12062 {
12063 COMPlusThrowHR(CORJIT_OUTOFMEM);
12064 }
12065
12066 m_CodeHeader = m_jitManager->allocCode(m_pMethodBeingCompiled, totalSize.Value(), GetReserveForJumpStubs(), flag
12067#ifdef WIN64EXCEPTIONS
12068 , m_totalUnwindInfos
12069 , &m_moduleBase
12070#endif
12071 );
12072
12073 BYTE* current = (BYTE *)m_CodeHeader->GetCodeStartAddress();
12074
12075 *codeBlock = current;
12076 current += codeSize;
12077
12078 if (roDataSize > 0)
12079 {
12080 current = (BYTE *)ALIGN_UP(current, roDataAlignment);
12081 *roDataBlock = current;
12082 current += roDataSize;
12083 }
12084 else
12085 {
12086 *roDataBlock = NULL;
12087 }
12088
12089#ifdef WIN64EXCEPTIONS
12090 current = (BYTE *)ALIGN_UP(current, sizeof(DWORD));
12091
12092 m_theUnwindBlock = current;
12093 current += m_totalUnwindSize;
12094#endif
12095
12096 _ASSERTE((SIZE_T)(current - (BYTE *)m_CodeHeader->GetCodeStartAddress()) <= totalSize.Value());
12097
12098#ifdef _DEBUG
12099 m_codeSize = codeSize;
12100#endif // _DEBUG
12101
12102 EE_TO_JIT_TRANSITION();
12103}
12104
12105/*********************************************************************/
12106void * CEEJitInfo::allocGCInfo (size_t size)
12107{
12108 CONTRACTL {
12109 SO_TOLERANT;
12110 THROWS;
12111 GC_TRIGGERS;
12112 MODE_PREEMPTIVE;
12113 } CONTRACTL_END;
12114
12115 void * block = NULL;
12116
12117 JIT_TO_EE_TRANSITION();
12118
12119 _ASSERTE(m_CodeHeader != 0);
12120 _ASSERTE(m_CodeHeader->GetGCInfo() == 0);
12121
12122#ifdef _WIN64
12123 if (size & 0xFFFFFFFF80000000LL)
12124 {
12125 COMPlusThrowHR(CORJIT_OUTOFMEM);
12126 }
12127#endif // _WIN64
12128
12129 block = m_jitManager->allocGCInfo(m_CodeHeader,(DWORD)size, &m_GCinfo_len);
12130 if (!block)
12131 {
12132 COMPlusThrowHR(CORJIT_OUTOFMEM);
12133 }
12134
12135 _ASSERTE(m_CodeHeader->GetGCInfo() != 0 && block == m_CodeHeader->GetGCInfo());
12136
12137 EE_TO_JIT_TRANSITION();
12138
12139 return block;
12140}
12141
12142/*********************************************************************/
12143void CEEJitInfo::setEHcount (
12144 unsigned cEH)
12145{
12146 CONTRACTL {
12147 SO_TOLERANT;
12148 THROWS;
12149 GC_TRIGGERS;
12150 MODE_PREEMPTIVE;
12151 } CONTRACTL_END;
12152
12153 JIT_TO_EE_TRANSITION();
12154
12155 _ASSERTE(cEH != 0);
12156 _ASSERTE(m_CodeHeader != 0);
12157 _ASSERTE(m_CodeHeader->GetEHInfo() == 0);
12158
12159 EE_ILEXCEPTION* ret;
12160 ret = m_jitManager->allocEHInfo(m_CodeHeader,cEH, &m_EHinfo_len);
12161 _ASSERTE(ret); // allocEHInfo throws if there's not enough memory
12162
12163 _ASSERTE(m_CodeHeader->GetEHInfo() != 0 && m_CodeHeader->GetEHInfo()->EHCount() == cEH);
12164
12165 EE_TO_JIT_TRANSITION();
12166}
12167
12168/*********************************************************************/
12169void CEEJitInfo::setEHinfo (
12170 unsigned EHnumber,
12171 const CORINFO_EH_CLAUSE* clause)
12172{
12173 CONTRACTL {
12174 SO_TOLERANT;
12175 THROWS;
12176 GC_TRIGGERS;
12177 MODE_PREEMPTIVE;
12178 } CONTRACTL_END;
12179
12180 JIT_TO_EE_TRANSITION();
12181
12182 // <REVISIT_TODO> Fix make the Code Manager EH clauses EH_INFO+</REVISIT_TODO>
12183 _ASSERTE(m_CodeHeader->GetEHInfo() != 0 && EHnumber < m_CodeHeader->GetEHInfo()->EHCount());
12184
12185 EE_ILEXCEPTION_CLAUSE* pEHClause = m_CodeHeader->GetEHInfo()->EHClause(EHnumber);
12186
12187 pEHClause->TryStartPC = clause->TryOffset;
12188 pEHClause->TryEndPC = clause->TryLength;
12189 pEHClause->HandlerStartPC = clause->HandlerOffset;
12190 pEHClause->HandlerEndPC = clause->HandlerLength;
12191 pEHClause->ClassToken = clause->ClassToken;
12192 pEHClause->Flags = (CorExceptionFlag)clause->Flags;
12193
12194 LOG((LF_EH, LL_INFO1000000, "Setting EH clause #%d for %s::%s\n", EHnumber, m_pMethodBeingCompiled->m_pszDebugClassName, m_pMethodBeingCompiled->m_pszDebugMethodName));
12195 LOG((LF_EH, LL_INFO1000000, " Flags : 0x%08lx -> 0x%08lx\n", clause->Flags, pEHClause->Flags));
12196 LOG((LF_EH, LL_INFO1000000, " TryOffset : 0x%08lx -> 0x%08lx (startpc)\n", clause->TryOffset, pEHClause->TryStartPC));
12197 LOG((LF_EH, LL_INFO1000000, " TryLength : 0x%08lx -> 0x%08lx (endpc)\n", clause->TryLength, pEHClause->TryEndPC));
12198 LOG((LF_EH, LL_INFO1000000, " HandlerOffset : 0x%08lx -> 0x%08lx\n", clause->HandlerOffset, pEHClause->HandlerStartPC));
12199 LOG((LF_EH, LL_INFO1000000, " HandlerLength : 0x%08lx -> 0x%08lx\n", clause->HandlerLength, pEHClause->HandlerEndPC));
12200 LOG((LF_EH, LL_INFO1000000, " ClassToken : 0x%08lx -> 0x%08lx\n", clause->ClassToken, pEHClause->ClassToken));
12201 LOG((LF_EH, LL_INFO1000000, " FilterOffset : 0x%08lx -> 0x%08lx\n", clause->FilterOffset, pEHClause->FilterOffset));
12202
12203 if (m_pMethodBeingCompiled->IsDynamicMethod() &&
12204 ((pEHClause->Flags & COR_ILEXCEPTION_CLAUSE_FILTER) == 0) &&
12205 (clause->ClassToken != NULL))
12206 {
12207 MethodDesc * pMD; FieldDesc * pFD;
12208 m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver()->ResolveToken(clause->ClassToken, (TypeHandle *)&pEHClause->TypeHandle, &pMD, &pFD);
12209 SetHasCachedTypeHandle(pEHClause);
12210 LOG((LF_EH, LL_INFO1000000, " CachedTypeHandle: 0x%08lx -> 0x%08lx\n", clause->ClassToken, pEHClause->TypeHandle));
12211 }
12212
12213 EE_TO_JIT_TRANSITION();
12214}
12215
12216/*********************************************************************/
12217// get individual exception handler
12218void CEEJitInfo::getEHinfo(
12219 CORINFO_METHOD_HANDLE ftn, /* IN */
12220 unsigned EHnumber, /* IN */
12221 CORINFO_EH_CLAUSE* clause) /* OUT */
12222{
12223 CONTRACTL {
12224 SO_TOLERANT;
12225 THROWS;
12226 GC_TRIGGERS;
12227 MODE_PREEMPTIVE;
12228 } CONTRACTL_END;
12229
12230 JIT_TO_EE_TRANSITION();
12231
12232 if (IsDynamicMethodHandle(ftn))
12233 {
12234 GetMethod(ftn)->AsDynamicMethodDesc()->GetResolver()->GetEHInfo(EHnumber, clause);
12235 }
12236 else
12237 {
12238 _ASSERTE(ftn == CORINFO_METHOD_HANDLE(m_pMethodBeingCompiled)); // For now only support if the method being jitted
12239 getEHinfoHelper(ftn, EHnumber, clause, m_ILHeader);
12240 }
12241
12242 EE_TO_JIT_TRANSITION();
12243}
12244#endif // CROSSGEN_COMPILE
12245
12246#if defined(CROSSGEN_COMPILE)
12247EXTERN_C ICorJitCompiler* __stdcall getJit();
12248#endif // defined(CROSSGEN_COMPILE)
12249
12250#ifdef FEATURE_INTERPRETER
12251static CorJitResult CompileMethodWithEtwWrapper(EEJitManager *jitMgr,
12252 CEEInfo *comp,
12253 struct CORINFO_METHOD_INFO *info,
12254 unsigned flags,
12255 BYTE **nativeEntry,
12256 ULONG *nativeSizeOfCode)
12257{
12258 STATIC_CONTRACT_THROWS;
12259 STATIC_CONTRACT_GC_TRIGGERS;
12260 STATIC_CONTRACT_MODE_PREEMPTIVE;
12261 STATIC_CONTRACT_SO_INTOLERANT;
12262
12263 SString namespaceOrClassName, methodName, methodSignature;
12264 // Fire an ETW event to mark the beginning of JIT'ing
12265 ETW::MethodLog::MethodJitting(reinterpret_cast<MethodDesc*>(info->ftn), &namespaceOrClassName, &methodName, &methodSignature);
12266
12267 CorJitResult ret = jitMgr->m_jit->compileMethod(comp, info, flags, nativeEntry, nativeSizeOfCode);
12268
12269 // Logically, it would seem that the end-of-JITting ETW even should go here, but it must come after the native code has been
12270 // set for the given method desc, which happens in a caller.
12271
12272 return ret;
12273}
12274#endif // FEATURE_INTERPRETER
12275
12276//
12277// Helper function because can't have dtors in BEGIN_SO_TOLERANT_CODE.
12278//
12279CorJitResult invokeCompileMethodHelper(EEJitManager *jitMgr,
12280 CEEInfo *comp,
12281 struct CORINFO_METHOD_INFO *info,
12282 CORJIT_FLAGS jitFlags,
12283 BYTE **nativeEntry,
12284 ULONG *nativeSizeOfCode)
12285{
12286 STATIC_CONTRACT_THROWS;
12287 STATIC_CONTRACT_GC_TRIGGERS;
12288 STATIC_CONTRACT_MODE_PREEMPTIVE;
12289 STATIC_CONTRACT_SO_INTOLERANT;
12290
12291 CorJitResult ret = CORJIT_SKIPPED; // Note that CORJIT_SKIPPED is an error exit status code
12292
12293
12294 comp->setJitFlags(jitFlags);
12295
12296#ifdef FEATURE_STACK_SAMPLING
12297 // SO_INTOLERANT due to init affecting global state.
12298 static ConfigDWORD s_stackSamplingEnabled;
12299 bool samplingEnabled = (s_stackSamplingEnabled.val(CLRConfig::UNSUPPORTED_StackSamplingEnabled) != 0);
12300#endif
12301
12302 BEGIN_SO_TOLERANT_CODE(GetThread());
12303
12304
12305#if defined(ALLOW_SXS_JIT) && !defined(CROSSGEN_COMPILE)
12306 if (FAILED(ret) && jitMgr->m_alternateJit
12307#ifdef FEATURE_STACK_SAMPLING
12308 && (!samplingEnabled || (jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND)))
12309#endif
12310 )
12311 {
12312 ret = jitMgr->m_alternateJit->compileMethod( comp,
12313 info,
12314 CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
12315 nativeEntry,
12316 nativeSizeOfCode );
12317
12318#ifdef FEATURE_STACK_SAMPLING
12319 if (jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND))
12320 {
12321 // Don't bother with failures if we couldn't collect a trace.
12322 ret = CORJIT_OK;
12323 }
12324#endif // FEATURE_STACK_SAMPLING
12325
12326 // If we failed to jit, then fall back to the primary Jit.
12327 if (FAILED(ret))
12328 {
12329 // Consider adding this call:
12330 // ((CEEJitInfo*)comp)->BackoutJitData(jitMgr);
12331 ((CEEJitInfo*)comp)->ResetForJitRetry();
12332 ret = CORJIT_SKIPPED;
12333 }
12334 }
12335#endif // defined(ALLOW_SXS_JIT) && !defined(CROSSGEN_COMPILE)
12336
12337#ifdef FEATURE_INTERPRETER
12338 static ConfigDWORD s_InterpreterFallback;
12339
12340 bool isInterpreterStub = false;
12341 bool interpreterFallback = (s_InterpreterFallback.val(CLRConfig::INTERNAL_InterpreterFallback) != 0);
12342
12343 if (interpreterFallback == false)
12344 {
12345 // If we're doing an "import_only" compilation, it's for verification, so don't interpret.
12346 // (We assume that importation is completely architecture-independent, or at least nearly so.)
12347 if (FAILED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE))
12348 {
12349 if (SUCCEEDED(ret = Interpreter::GenerateInterpreterStub(comp, info, nativeEntry, nativeSizeOfCode)))
12350 {
12351 isInterpreterStub = true;
12352 }
12353 }
12354 }
12355
12356 if (FAILED(ret) && jitMgr->m_jit)
12357 {
12358 ret = CompileMethodWithEtwWrapper(jitMgr,
12359 comp,
12360 info,
12361 CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
12362 nativeEntry,
12363 nativeSizeOfCode);
12364 }
12365
12366 if (interpreterFallback == true)
12367 {
12368 // If we're doing an "import_only" compilation, it's for verification, so don't interpret.
12369 // (We assume that importation is completely architecture-independent, or at least nearly so.)
12370 if (FAILED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE))
12371 {
12372 if (SUCCEEDED(ret = Interpreter::GenerateInterpreterStub(comp, info, nativeEntry, nativeSizeOfCode)))
12373 {
12374 isInterpreterStub = true;
12375 }
12376 }
12377 }
12378#else
12379 if (FAILED(ret))
12380 {
12381 ret = jitMgr->m_jit->compileMethod( comp,
12382 info,
12383 CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
12384 nativeEntry,
12385 nativeSizeOfCode);
12386 }
12387#endif // FEATURE_INTERPRETER
12388
12389#if !defined(CROSSGEN_COMPILE)
12390 // Cleanup any internal data structures allocated
12391 // such as IL code after a successfull JIT compile
12392 // If the JIT fails we keep the IL around and will
12393 // try reJIT the same IL. VSW 525059
12394 //
12395 if (SUCCEEDED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !((CEEJitInfo*)comp)->JitAgain())
12396 {
12397 ((CEEJitInfo*)comp)->CompressDebugInfo();
12398
12399#ifdef FEATURE_INTERPRETER
12400 // We do this cleanup in the prestub, where we know whether the method
12401 // has been interpreted.
12402#else
12403 comp->MethodCompileComplete(info->ftn);
12404#endif // FEATURE_INTERPRETER
12405 }
12406#endif // !defined(CROSSGEN_COMPILE)
12407
12408
12409#if defined(FEATURE_GDBJIT)
12410 bool isJittedEntry = SUCCEEDED(ret) && *nativeEntry != NULL;
12411
12412#ifdef FEATURE_INTERPRETER
12413 isJittedEntry &= !isInterpreterStub;
12414#endif // FEATURE_INTERPRETER
12415
12416 if (isJittedEntry)
12417 {
12418 CodeHeader* pCH = ((CodeHeader*)((PCODE)*nativeEntry & ~1)) - 1;
12419 pCH->SetCalledMethods((PTR_VOID)comp->GetCalledMethods());
12420 }
12421#endif
12422
12423 END_SO_TOLERANT_CODE;
12424
12425 return ret;
12426}
12427
12428
12429/*********************************************************************/
12430CorJitResult invokeCompileMethod(EEJitManager *jitMgr,
12431 CEEInfo *comp,
12432 struct CORINFO_METHOD_INFO *info,
12433 CORJIT_FLAGS jitFlags,
12434 BYTE **nativeEntry,
12435 ULONG *nativeSizeOfCode)
12436{
12437 CONTRACTL {
12438 THROWS;
12439 GC_TRIGGERS;
12440 MODE_COOPERATIVE;
12441 } CONTRACTL_END;
12442 //
12443 // The JIT runs in preemptive mode
12444 //
12445
12446 GCX_PREEMP();
12447
12448 CorJitResult ret = invokeCompileMethodHelper(jitMgr, comp, info, jitFlags, nativeEntry, nativeSizeOfCode);
12449
12450 //
12451 // Verify that we are still in preemptive mode when we return
12452 // from the JIT
12453 //
12454
12455 _ASSERTE(GetThread()->PreemptiveGCDisabled() == FALSE);
12456
12457 return ret;
12458}
12459
12460CorJitResult CallCompileMethodWithSEHWrapper(EEJitManager *jitMgr,
12461 CEEInfo *comp,
12462 struct CORINFO_METHOD_INFO *info,
12463 CORJIT_FLAGS flags,
12464 BYTE **nativeEntry,
12465 ULONG *nativeSizeOfCode,
12466 MethodDesc *ftn)
12467{
12468 // no dynamic contract here because SEH is used, with a finally clause
12469 STATIC_CONTRACT_NOTHROW;
12470 STATIC_CONTRACT_GC_TRIGGERS;
12471
12472 LOG((LF_CORDB, LL_EVERYTHING, "CallCompileMethodWithSEHWrapper called...\n"));
12473
12474 struct Param
12475 {
12476 EEJitManager *jitMgr;
12477 CEEInfo *comp;
12478 struct CORINFO_METHOD_INFO *info;
12479 CORJIT_FLAGS flags;
12480 BYTE **nativeEntry;
12481 ULONG *nativeSizeOfCode;
12482 MethodDesc *ftn;
12483 CorJitResult res;
12484 }; Param param;
12485 param.jitMgr = jitMgr;
12486 param.comp = comp;
12487 param.info = info;
12488 param.flags = flags;
12489 param.nativeEntry = nativeEntry;
12490 param.nativeSizeOfCode = nativeSizeOfCode;
12491 param.ftn = ftn;
12492 param.res = CORJIT_INTERNALERROR;
12493
12494 PAL_TRY(Param *, pParam, &param)
12495 {
12496 //
12497 // Call out to the JIT-compiler
12498 //
12499
12500 pParam->res = invokeCompileMethod( pParam->jitMgr,
12501 pParam->comp,
12502 pParam->info,
12503 pParam->flags,
12504 pParam->nativeEntry,
12505 pParam->nativeSizeOfCode);
12506 }
12507 PAL_FINALLY
12508 {
12509#if defined(DEBUGGING_SUPPORTED) && !defined(CROSSGEN_COMPILE)
12510 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) &&
12511 !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MCJIT_BACKGROUND)
12512#ifdef FEATURE_STACK_SAMPLING
12513 && !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND)
12514#endif // FEATURE_STACK_SAMPLING
12515 )
12516 {
12517 //
12518 // Notify the debugger that we have successfully jitted the function
12519 //
12520 if (g_pDebugInterface)
12521 {
12522 if (param.res == CORJIT_OK && !((CEEJitInfo*)param.comp)->JitAgain())
12523 {
12524 g_pDebugInterface->JITComplete(ftn, (TADDR)*nativeEntry);
12525 }
12526 }
12527 }
12528#endif // DEBUGGING_SUPPORTED && !CROSSGEN_COMPILE
12529 }
12530 PAL_ENDTRY
12531
12532 return param.res;
12533}
12534
12535/*********************************************************************/
12536// Figures out the compile flags that are used by both JIT and NGen
12537
12538/* static */ CORJIT_FLAGS CEEInfo::GetBaseCompileFlags(MethodDesc * ftn)
12539{
12540 CONTRACTL {
12541 THROWS;
12542 GC_TRIGGERS;
12543 } CONTRACTL_END;
12544
12545 //
12546 // Figure out the code quality flags
12547 //
12548
12549 CORJIT_FLAGS flags;
12550 if (g_pConfig->JitFramed())
12551 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FRAMED);
12552 if (g_pConfig->JitAlignLoops())
12553 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_ALIGN_LOOPS);
12554 if (ftn->IsVersionableWithJumpStamp() || g_pConfig->AddRejitNops())
12555 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_REJIT_NOPS);
12556#ifdef _TARGET_X86_
12557 if (g_pConfig->PInvokeRestoreEsp(ftn->GetModule()->IsPreV4Assembly()))
12558 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PINVOKE_RESTORE_ESP);
12559#endif // _TARGET_X86_
12560
12561 //See if we should instruct the JIT to emit calls to JIT_PollGC for thread suspension. If we have a
12562 //non-default value in the EE Config, then use that. Otherwise select the platform specific default.
12563#ifdef FEATURE_ENABLE_GCPOLL
12564 EEConfig::GCPollType pollType = g_pConfig->GetGCPollType();
12565 if (EEConfig::GCPOLL_TYPE_POLL == pollType)
12566 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_GCPOLL_CALLS);
12567 else if (EEConfig::GCPOLL_TYPE_INLINE == pollType)
12568 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_GCPOLL_INLINE);
12569#endif //FEATURE_ENABLE_GCPOLL
12570
12571 // Set flags based on method's ImplFlags.
12572 if (!ftn->IsNoMetadata())
12573 {
12574 DWORD dwImplFlags = 0;
12575 IfFailThrow(ftn->GetMDImport()->GetMethodImplProps(ftn->GetMemberDef(), NULL, &dwImplFlags));
12576
12577 if (IsMiNoOptimization(dwImplFlags))
12578 {
12579 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT);
12580 }
12581
12582 // Always emit frames for methods marked no-inline (see #define ETW_EBP_FRAMED in the JIT)
12583 if (IsMiNoInlining(dwImplFlags))
12584 {
12585 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FRAMED);
12586 }
12587 }
12588
12589 return flags;
12590}
12591
12592/*********************************************************************/
12593// Figures out (some of) the flags to use to compile the method
12594// Returns the new set to use
12595
12596CORJIT_FLAGS GetDebuggerCompileFlags(Module* pModule, CORJIT_FLAGS flags)
12597{
12598 STANDARD_VM_CONTRACT;
12599
12600 //Right now if we don't have a debug interface on CoreCLR, we can't generate debug info. So, in those
12601 //cases don't attempt it.
12602 if (!g_pDebugInterface)
12603 return flags;
12604
12605#ifdef DEBUGGING_SUPPORTED
12606
12607#ifdef _DEBUG
12608 if (g_pConfig->GenDebuggableCode())
12609 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12610#endif // _DEBUG
12611
12612#ifdef EnC_SUPPORTED
12613 if (pModule->IsEditAndContinueEnabled())
12614 {
12615 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_EnC);
12616 }
12617#endif // EnC_SUPPORTED
12618
12619 // Debug info is always tracked
12620 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12621#endif // DEBUGGING_SUPPORTED
12622
12623 if (CORDisableJITOptimizations(pModule->GetDebuggerInfoBits()))
12624 {
12625 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12626 }
12627
12628 if (flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12629 {
12630 // If we are only verifying the method, dont need any debug info and this
12631 // prevents getVars()/getBoundaries() from being called unnecessarily.
12632 flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12633 flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12634 }
12635
12636 return flags;
12637}
12638
12639CORJIT_FLAGS GetCompileFlags(MethodDesc * ftn, CORJIT_FLAGS flags, CORINFO_METHOD_INFO * methodInfo)
12640{
12641 STANDARD_VM_CONTRACT;
12642
12643 _ASSERTE(methodInfo->regionKind == CORINFO_REGION_JIT);
12644
12645 //
12646 // Get the compile flags that are shared between JIT and NGen
12647 //
12648 flags.Add(CEEInfo::GetBaseCompileFlags(ftn));
12649
12650 //
12651 // Get CPU specific flags
12652 //
12653 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12654 {
12655 flags.Add(ExecutionManager::GetEEJitManager()->GetCPUCompileFlags());
12656 }
12657
12658 //
12659 // Find the debugger and profiler related flags
12660 //
12661
12662#ifdef DEBUGGING_SUPPORTED
12663 flags.Add(GetDebuggerCompileFlags(ftn->GetModule(), flags));
12664#endif
12665
12666#ifdef PROFILING_SUPPORTED
12667 if (CORProfilerTrackEnterLeave() && !ftn->IsNoMetadata())
12668 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_ENTERLEAVE);
12669
12670 if (CORProfilerTrackTransitions())
12671 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_NO_PINVOKE_INLINE);
12672#endif // PROFILING_SUPPORTED
12673
12674 // Set optimization flags
12675 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT))
12676 {
12677 unsigned optType = g_pConfig->GenOptimizeType();
12678 _ASSERTE(optType <= OPT_RANDOM);
12679
12680 if (optType == OPT_RANDOM)
12681 optType = methodInfo->ILCodeSize % OPT_RANDOM;
12682
12683 if (g_pConfig->JitMinOpts())
12684 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT);
12685
12686 if (optType == OPT_SIZE)
12687 {
12688 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SIZE_OPT);
12689 }
12690 else if (optType == OPT_SPEED)
12691 {
12692 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SPEED_OPT);
12693 }
12694 }
12695
12696 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION);
12697
12698 if (ftn->IsILStub())
12699 {
12700 // no debug info available for IL stubs
12701 flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12702 }
12703
12704 return flags;
12705}
12706
12707// ********************************************************************
12708
12709// Throw the right type of exception for the given JIT result
12710
12711void ThrowExceptionForJit(HRESULT res)
12712{
12713 CONTRACTL
12714 {
12715 THROWS;
12716 GC_NOTRIGGER;
12717 SO_INTOLERANT;
12718 MODE_ANY;
12719 }
12720 CONTRACTL_END;
12721 switch (res)
12722 {
12723 case CORJIT_OUTOFMEM:
12724 COMPlusThrowOM();
12725 break;
12726
12727 case CORJIT_INTERNALERROR:
12728 COMPlusThrow(kInvalidProgramException, (UINT) IDS_EE_JIT_COMPILER_ERROR);
12729 break;
12730
12731 case CORJIT_BADCODE:
12732 default:
12733 COMPlusThrow(kInvalidProgramException);
12734 break;
12735 }
12736 }
12737
12738// ********************************************************************
12739#ifdef _DEBUG
12740LONG g_JitCount = 0;
12741#endif
12742
12743//#define PERF_TRACK_METHOD_JITTIMES
12744#ifdef _TARGET_AMD64_
12745BOOL g_fAllowRel32 = TRUE;
12746#endif
12747
12748
12749// ********************************************************************
12750// README!!
12751// ********************************************************************
12752
12753// The reason that this is named UnsafeJitFunction is that this helper
12754// method is not thread safe! When multiple threads get in here for
12755// the same pMD, ALL of them MUST return the SAME value.
12756// To insure that this happens you must call MakeJitWorker.
12757// It creates a DeadlockAware list of methods being jitted and prevents us
12758// from trying to jit the same method more that once.
12759//
12760// Calls to this method that occur to check if inlining can occur on x86,
12761// are OK since they discard the return value of this method.
12762
12763PCODE UnsafeJitFunction(MethodDesc* ftn, COR_ILMETHOD_DECODER* ILHeader, CORJIT_FLAGS flags,
12764 ULONG * pSizeOfCode)
12765{
12766 STANDARD_VM_CONTRACT;
12767
12768 PCODE ret = NULL;
12769
12770 COOPERATIVE_TRANSITION_BEGIN();
12771
12772#ifdef FEATURE_PREJIT
12773
12774 if (g_pConfig->RequireZaps() == EEConfig::REQUIRE_ZAPS_ALL &&
12775 ftn->GetModule()->GetDomainFile()->IsZapRequired() &&
12776 PartialNGenStressPercentage() == 0 &&
12777#ifdef FEATURE_STACK_SAMPLING
12778 !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND) &&
12779#endif
12780 !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12781 {
12782 StackSString ss(SString::Ascii, "ZapRequire: JIT compiler invoked for ");
12783 TypeString::AppendMethodInternal(ss, ftn);
12784
12785#ifdef _DEBUG
12786 // Assert as some test may not check their error codes well. So throwing an
12787 // exception may not cause a test failure (as it should).
12788 StackScratchBuffer scratch;
12789 DbgAssertDialog(__FILE__, __LINE__, (char*)ss.GetUTF8(scratch));
12790#endif // _DEBUG
12791
12792 COMPlusThrowNonLocalized(kFileNotFoundException, ss.GetUnicode());
12793 }
12794
12795#endif // FEATURE_PREJIT
12796
12797#ifndef CROSSGEN_COMPILE
12798 EEJitManager *jitMgr = ExecutionManager::GetEEJitManager();
12799 if (!jitMgr->LoadJIT())
12800 {
12801#ifdef ALLOW_SXS_JIT
12802 if (!jitMgr->IsMainJitLoaded())
12803 {
12804 // Don't want to throw InvalidProgram from here.
12805 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load JIT compiler"));
12806 }
12807 if (!jitMgr->IsAltJitLoaded())
12808 {
12809 // Don't want to throw InvalidProgram from here.
12810 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load alternative JIT compiler"));
12811 }
12812#else // ALLOW_SXS_JIT
12813 // Don't want to throw InvalidProgram from here.
12814 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load JIT compiler"));
12815#endif // ALLOW_SXS_JIT
12816 }
12817#endif // CROSSGEN_COMPILE
12818
12819#ifdef _DEBUG
12820 // This is here so we can see the name and class easily in the debugger
12821
12822 LPCUTF8 cls = ftn->GetMethodTable()->GetDebugClassName();
12823 LPCUTF8 name = ftn->GetName();
12824
12825 if (ftn->IsNoMetadata())
12826 {
12827 if (ftn->IsILStub())
12828 {
12829 LOG((LF_JIT, LL_INFO10000, "{ Jitting IL Stub }\n"));
12830 }
12831 else
12832 {
12833 LOG((LF_JIT, LL_INFO10000, "{ Jitting dynamic method }\n"));
12834 }
12835 }
12836 else
12837 {
12838 SString methodString;
12839 if (LoggingOn(LF_JIT, LL_INFO10000))
12840 TypeString::AppendMethodDebug(methodString, ftn);
12841
12842 LOG((LF_JIT, LL_INFO10000, "{ Jitting method (%p) %S %s\n", ftn, methodString.GetUnicode(), ftn->m_pszDebugMethodSignature));
12843 }
12844
12845#if 0
12846 if (!SString::_stricmp(cls,"ENC") &&
12847 (!SString::_stricmp(name,"G")))
12848 {
12849 static count = 0;
12850 count++;
12851 if (count > 0)
12852 DebugBreak();
12853 }
12854#endif // 0
12855#endif // _DEBUG
12856
12857 CORINFO_METHOD_HANDLE ftnHnd = (CORINFO_METHOD_HANDLE)ftn;
12858 CORINFO_METHOD_INFO methodInfo;
12859
12860 getMethodInfoHelper(ftn, ftnHnd, ILHeader, &methodInfo);
12861
12862 // If it's generic then we can only enter through an instantiated md (unless we're just verifying it)
12863 _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) || !ftn->IsGenericMethodDefinition());
12864
12865 // If it's an instance method then it must not be entered from a generic class
12866 _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) || ftn->IsStatic() ||
12867 ftn->GetNumGenericClassArgs() == 0 || ftn->HasClassInstantiation());
12868
12869 // method attributes and signature are consistant
12870 _ASSERTE(!!ftn->IsStatic() == ((methodInfo.args.callConv & CORINFO_CALLCONV_HASTHIS) == 0));
12871
12872 flags = GetCompileFlags(ftn, flags, &methodInfo);
12873
12874#ifdef _DEBUG
12875 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION))
12876 {
12877 SString methodString;
12878 if (LoggingOn(LF_VERIFIER, LL_INFO100))
12879 TypeString::AppendMethodDebug(methodString, ftn);
12880
12881 LOG((LF_VERIFIER, LL_INFO100, "{ Will verify method (%p) %S %s\n", ftn, methodString.GetUnicode(), ftn->m_pszDebugMethodSignature));
12882 }
12883#endif //_DEBUG
12884
12885#if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
12886 BOOL fForceJumpStubOverflow = FALSE;
12887
12888#ifdef _DEBUG
12889 // Always exercise the overflow codepath with force relocs
12890 if (PEDecoder::GetForceRelocs())
12891 fForceJumpStubOverflow = TRUE;
12892#endif
12893
12894#if defined(_TARGET_AMD64_)
12895 BOOL fAllowRel32 = (g_fAllowRel32 | fForceJumpStubOverflow);
12896#endif
12897
12898 size_t reserveForJumpStubs = 0;
12899
12900#endif // defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
12901
12902 for (;;)
12903 {
12904#ifndef CROSSGEN_COMPILE
12905 CEEJitInfo jitInfo(ftn, ILHeader, jitMgr, flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY),
12906 !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_NO_INLINING));
12907#else
12908 // This path should be only ever used for verification in crossgen and so we should not need EEJitManager
12909 _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY));
12910 CEEInfo jitInfo(ftn, true);
12911 EEJitManager *jitMgr = NULL;
12912#endif
12913
12914#if (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)) && !defined(CROSSGEN_COMPILE)
12915#ifdef _TARGET_AMD64_
12916 if (fForceJumpStubOverflow)
12917 jitInfo.SetJumpStubOverflow(fAllowRel32);
12918 jitInfo.SetAllowRel32(fAllowRel32);
12919#else
12920 if (fForceJumpStubOverflow)
12921 jitInfo.SetJumpStubOverflow(fForceJumpStubOverflow);
12922#endif
12923 jitInfo.SetReserveForJumpStubs(reserveForJumpStubs);
12924#endif
12925
12926 MethodDesc * pMethodForSecurity = jitInfo.GetMethodForSecurity(ftnHnd);
12927
12928 //Since the check could trigger a demand, we have to do this every time.
12929 //This is actually an overly complicated way to make sure that a method can access all its arguments
12930 //and its return type.
12931 AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
12932 TypeHandle ownerTypeForSecurity = TypeHandle(pMethodForSecurity->GetMethodTable());
12933 DynamicResolver *pAccessContext = NULL;
12934 BOOL doAccessCheck = TRUE;
12935 if (pMethodForSecurity->IsDynamicMethod())
12936 {
12937 doAccessCheck = ModifyCheckForDynamicMethod(pMethodForSecurity->AsDynamicMethodDesc()->GetResolver(),
12938 &ownerTypeForSecurity,
12939 &accessCheckType, &pAccessContext);
12940 }
12941 if (doAccessCheck)
12942 {
12943 AccessCheckOptions accessCheckOptions(accessCheckType,
12944 pAccessContext,
12945 TRUE /*Throw on error*/,
12946 pMethodForSecurity);
12947
12948 StaticAccessCheckContext accessContext(pMethodForSecurity, ownerTypeForSecurity.GetMethodTable());
12949
12950 // We now do an access check from pMethodForSecurity to pMethodForSecurity, its sole purpose is to
12951 // verify that pMethodForSecurity/ownerTypeForSecurity has access to all its parameters.
12952
12953 // ownerTypeForSecurity.GetMethodTable() can be null if the pMethodForSecurity is a DynamicMethod
12954 // associated with a TypeDesc (Array, Ptr, Ref, or FnPtr). That doesn't make any sense, but we will
12955 // just do an access check from a NULL context which means only public types are accessible.
12956 if (!ClassLoader::CanAccess(&accessContext,
12957 ownerTypeForSecurity.GetMethodTable(),
12958 ownerTypeForSecurity.GetAssembly(),
12959 pMethodForSecurity->GetAttrs(),
12960 pMethodForSecurity,
12961 NULL,
12962 accessCheckOptions))
12963 {
12964 EX_THROW(EEMethodException, (pMethodForSecurity));
12965 }
12966 }
12967
12968 CorJitResult res;
12969 PBYTE nativeEntry;
12970 ULONG sizeOfCode;
12971
12972 {
12973 GCX_COOP();
12974
12975 /* There is a double indirection to call compileMethod - can we
12976 improve this with the new structure? */
12977
12978#ifdef PERF_TRACK_METHOD_JITTIMES
12979 //Because we're not calling QPC enough. I'm not going to track times if we're just importing.
12980 LARGE_INTEGER methodJitTimeStart = {0};
12981 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12982 QueryPerformanceCounter (&methodJitTimeStart);
12983
12984#endif
12985#if defined(ENABLE_PERF_COUNTERS)
12986 START_JIT_PERF();
12987#endif
12988
12989#if defined(ENABLE_PERF_COUNTERS)
12990 LARGE_INTEGER CycleStart;
12991 QueryPerformanceCounter (&CycleStart);
12992#endif // defined(ENABLE_PERF_COUNTERS)
12993
12994 // Note on debuggerTrackInfo arg: if we're only importing (ie, verifying/
12995 // checking to make sure we could JIT, but not actually generating code (
12996 // eg, for inlining), then DON'T TELL THE DEBUGGER about this.
12997 res = CallCompileMethodWithSEHWrapper(jitMgr,
12998 &jitInfo,
12999 &methodInfo,
13000 flags,
13001 &nativeEntry,
13002 &sizeOfCode,
13003 (MethodDesc*)ftn);
13004 LOG((LF_CORDB, LL_EVERYTHING, "Got through CallCompile MethodWithSEHWrapper\n"));
13005
13006#if FEATURE_PERFMAP
13007 // Save the code size so that it can be reported to the perfmap.
13008 if (pSizeOfCode != NULL)
13009 {
13010 *pSizeOfCode = sizeOfCode;
13011 }
13012#endif
13013
13014#if defined(ENABLE_PERF_COUNTERS)
13015 LARGE_INTEGER CycleStop;
13016 QueryPerformanceCounter(&CycleStop);
13017 GetPerfCounters().m_Jit.timeInJitBase = GetPerfCounters().m_Jit.timeInJit;
13018 GetPerfCounters().m_Jit.timeInJit += static_cast<DWORD>(CycleStop.QuadPart - CycleStart.QuadPart);
13019 GetPerfCounters().m_Jit.cMethodsJitted++;
13020 GetPerfCounters().m_Jit.cbILJitted+=methodInfo.ILCodeSize;
13021
13022#endif // defined(ENABLE_PERF_COUNTERS)
13023
13024#if defined(ENABLE_PERF_COUNTERS)
13025 STOP_JIT_PERF();
13026#endif
13027
13028#ifdef PERF_TRACK_METHOD_JITTIMES
13029 //store the time in the string buffer. Module name and token are unique enough. Also, do not
13030 //capture importing time, just actual compilation time.
13031 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
13032 {
13033 LARGE_INTEGER methodJitTimeStop;
13034 QueryPerformanceCounter(&methodJitTimeStop);
13035 SString codeBase;
13036 ftn->GetModule()->GetDomainFile()->GetFile()->GetCodeBaseOrName(codeBase);
13037 codeBase.AppendPrintf(W(",0x%x,%d,%d\n"),
13038 //(const WCHAR *)codeBase, //module name
13039 ftn->GetMemberDef(), //method token
13040 (unsigned)(methodJitTimeStop.QuadPart - methodJitTimeStart.QuadPart), //cycle count
13041 methodInfo.ILCodeSize //il size
13042 );
13043 WszOutputDebugString((const WCHAR*)codeBase);
13044 }
13045#endif // PERF_TRACK_METHOD_JITTIMES
13046
13047 }
13048
13049 LOG((LF_JIT, LL_INFO10000, "Done Jitting method %s::%s %s }\n",cls,name, ftn->m_pszDebugMethodSignature));
13050
13051 if (!SUCCEEDED(res))
13052 {
13053 COUNTER_ONLY(GetPerfCounters().m_Jit.cJitFailures++);
13054
13055#ifndef CROSSGEN_COMPILE
13056 jitInfo.BackoutJitData(jitMgr);
13057#endif
13058
13059 ThrowExceptionForJit(res);
13060 }
13061
13062 if (flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
13063 {
13064 // We are done
13065 break;
13066 }
13067
13068 if (!nativeEntry)
13069 COMPlusThrow(kInvalidProgramException);
13070
13071#if (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)) && !defined(CROSSGEN_COMPILE)
13072 if (jitInfo.IsJumpStubOverflow())
13073 {
13074 // Backout and try again with fAllowRel32 == FALSE.
13075 jitInfo.BackoutJitData(jitMgr);
13076
13077#ifdef _TARGET_AMD64_
13078 // Disallow rel32 relocs in future.
13079 g_fAllowRel32 = FALSE;
13080
13081 fAllowRel32 = FALSE;
13082#endif // _TARGET_AMD64_
13083#ifdef _TARGET_ARM64_
13084 fForceJumpStubOverflow = FALSE;
13085#endif // _TARGET_ARM64_
13086
13087 reserveForJumpStubs = jitInfo.GetReserveForJumpStubs();
13088 continue;
13089 }
13090#endif // (_TARGET_AMD64_ || _TARGET_ARM64_) && !CROSSGEN_COMPILE
13091
13092 LOG((LF_JIT, LL_INFO10000,
13093 "Jitted Entry at" FMT_ADDR "method %s::%s %s\n", DBG_ADDR(nativeEntry),
13094 ftn->m_pszDebugClassName, ftn->m_pszDebugMethodName, ftn->m_pszDebugMethodSignature));
13095
13096#if defined(FEATURE_CORESYSTEM)
13097
13098#ifdef _DEBUG
13099 LPCUTF8 pszDebugClassName = ftn->m_pszDebugClassName;
13100 LPCUTF8 pszDebugMethodName = ftn->m_pszDebugMethodName;
13101 LPCUTF8 pszDebugMethodSignature = ftn->m_pszDebugMethodSignature;
13102#else
13103 LPCUTF8 pszNamespace;
13104 LPCUTF8 pszDebugClassName = ftn->GetMethodTable()->GetFullyQualifiedNameInfo(&pszNamespace);
13105 LPCUTF8 pszDebugMethodName = ftn->GetName();
13106 LPCUTF8 pszDebugMethodSignature = "";
13107#endif
13108
13109 //DbgPrintf("Jitted Entry at" FMT_ADDR "method %s::%s %s size %08x\n", DBG_ADDR(nativeEntry),
13110 // pszDebugClassName, pszDebugMethodName, pszDebugMethodSignature, sizeOfCode);
13111#endif
13112
13113 ClrFlushInstructionCache(nativeEntry, sizeOfCode);
13114 ret = (PCODE)nativeEntry;
13115
13116#ifdef _TARGET_ARM_
13117 ret |= THUMB_CODE;
13118#endif
13119
13120 // We are done
13121 break;
13122 }
13123
13124#ifdef _DEBUG
13125 FastInterlockIncrement(&g_JitCount);
13126 static BOOL fHeartbeat = -1;
13127
13128 if (fHeartbeat == -1)
13129 fHeartbeat = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitHeartbeat);
13130
13131 if (fHeartbeat)
13132 printf(".");
13133#endif // _DEBUG
13134
13135 COOPERATIVE_TRANSITION_END();
13136 return ret;
13137}
13138
13139extern "C" unsigned __stdcall PartialNGenStressPercentage()
13140{
13141 LIMITED_METHOD_CONTRACT;
13142#ifndef _DEBUG
13143 return 0;
13144#else // _DEBUG
13145 static ConfigDWORD partialNGenStress;
13146 DWORD partialNGenStressVal = partialNGenStress.val(CLRConfig::INTERNAL_partialNGenStress);
13147 _ASSERTE(partialNGenStressVal <= 100);
13148 return partialNGenStressVal;
13149#endif // _DEBUG
13150}
13151
13152#ifdef FEATURE_PREJIT
13153/*********************************************************************/
13154
13155//
13156// Table loading functions
13157//
13158void Module::LoadHelperTable()
13159{
13160 STANDARD_VM_CONTRACT;
13161
13162#ifndef CROSSGEN_COMPILE
13163 COUNT_T tableSize;
13164 BYTE * table = (BYTE *) GetNativeImage()->GetNativeHelperTable(&tableSize);
13165
13166 if (tableSize == 0)
13167 return;
13168
13169 EnsureWritableExecutablePages(table, tableSize);
13170
13171 BYTE * curEntry = table;
13172 BYTE * tableEnd = table + tableSize;
13173
13174#ifdef FEATURE_PERFMAP
13175 PerfMap::LogStubs(__FUNCTION__, GetSimpleName(), (PCODE)table, tableSize);
13176#endif
13177
13178#ifdef LOGGING
13179 int iEntryNumber = 0;
13180#endif // LOGGING
13181
13182 //
13183 // Fill in helpers
13184 //
13185
13186 while (curEntry < tableEnd)
13187 {
13188 DWORD dwHelper = *(DWORD *)curEntry;
13189
13190 int iHelper = (USHORT)dwHelper;
13191 _ASSERTE(iHelper < CORINFO_HELP_COUNT);
13192
13193 LOG((LF_JIT, LL_INFO1000000, "JIT helper %3d (%-40s: table @ %p, size 0x%x, entry %3d @ %p, pfnHelper %p)\n",
13194 iHelper, hlpFuncTable[iHelper].name, table, tableSize, iEntryNumber, curEntry, hlpFuncTable[iHelper].pfnHelper));
13195
13196#if defined(ENABLE_FAST_GCPOLL_HELPER)
13197 // The fast GC poll helper works by calling indirect through a pointer that points to either
13198 // JIT_PollGC or JIT_PollGC_Nop, based on whether we need to poll or not. The JIT_PollGC_Nop
13199 // version is just a "ret". The pointer is stored in hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].
13200 // See EnableJitGCPoll() and DisableJitGCPoll().
13201 // In NGEN images, we generate a direct call to the helper table. Here, we replace that with
13202 // an indirect jump through the pointer in hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].
13203 if (iHelper == CORINFO_HELP_POLL_GC)
13204 {
13205 LOG((LF_JIT, LL_INFO1000000, "JIT helper CORINFO_HELP_POLL_GC (%d); emitting indirect jump to 0x%x\n",
13206 CORINFO_HELP_POLL_GC, &hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].pfnHelper));
13207
13208 emitJumpInd(curEntry, &hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].pfnHelper);
13209 curEntry = curEntry + HELPER_TABLE_ENTRY_LEN;
13210 }
13211 else
13212#endif // ENABLE_FAST_GCPOLL_HELPER
13213 {
13214 PCODE pfnHelper = CEEJitInfo::getHelperFtnStatic((CorInfoHelpFunc)iHelper);
13215
13216 if (dwHelper & CORCOMPILE_HELPER_PTR)
13217 {
13218 //
13219 // Indirection cell
13220 //
13221
13222 *(TADDR *)curEntry = pfnHelper;
13223
13224 curEntry = curEntry + sizeof(TADDR);
13225 }
13226 else
13227 {
13228 //
13229 // Jump thunk
13230 //
13231
13232#if defined(_TARGET_AMD64_)
13233 *curEntry = X86_INSTR_JMP_REL32;
13234 *(INT32 *)(curEntry + 1) = rel32UsingJumpStub((INT32 *)(curEntry + 1), pfnHelper, NULL, GetLoaderAllocator());
13235#else // all other platforms
13236 emitJump(curEntry, (LPVOID)pfnHelper);
13237 _ASSERTE(HELPER_TABLE_ENTRY_LEN >= JUMP_ALLOCATE_SIZE);
13238#endif
13239
13240 curEntry = curEntry + HELPER_TABLE_ENTRY_LEN;
13241 }
13242 }
13243#ifdef LOGGING
13244 // Note that some table entries are sizeof(TADDR) in length, and some are HELPER_TABLE_ENTRY_LEN in length
13245 ++iEntryNumber;
13246#endif // LOGGING
13247 }
13248
13249 ClrFlushInstructionCache(table, tableSize);
13250#endif // CROSSGEN_COMPILE
13251}
13252
13253#ifdef FEATURE_READYTORUN
13254CorInfoHelpFunc MapReadyToRunHelper(ReadyToRunHelper helperNum)
13255{
13256 LIMITED_METHOD_CONTRACT;
13257
13258 switch (helperNum)
13259 {
13260#define HELPER(readyToRunHelper, corInfoHelpFunc, flags) \
13261 case readyToRunHelper: return corInfoHelpFunc;
13262#include "readytorunhelpers.h"
13263
13264 case READYTORUN_HELPER_GetString: return CORINFO_HELP_STRCNS;
13265
13266 default: return CORINFO_HELP_UNDEF;
13267 }
13268}
13269
13270void ComputeGCRefMap(MethodTable * pMT, BYTE * pGCRefMap, size_t cbGCRefMap)
13271{
13272 STANDARD_VM_CONTRACT;
13273
13274 ZeroMemory(pGCRefMap, cbGCRefMap);
13275
13276 if (!pMT->ContainsPointers())
13277 return;
13278
13279 CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
13280 CGCDescSeries* cur = map->GetHighestSeries();
13281 CGCDescSeries* last = map->GetLowestSeries();
13282 DWORD size = pMT->GetBaseSize();
13283 _ASSERTE(cur >= last);
13284
13285 do
13286 {
13287 // offset to embedded references in this series must be
13288 // adjusted by the VTable pointer, when in the unboxed state.
13289 size_t offset = cur->GetSeriesOffset() - TARGET_POINTER_SIZE;
13290 size_t offsetStop = offset + cur->GetSeriesSize() + size;
13291 while (offset < offsetStop)
13292 {
13293 size_t bit = offset / TARGET_POINTER_SIZE;
13294
13295 size_t index = bit / 8;
13296 _ASSERTE(index < cbGCRefMap);
13297 pGCRefMap[index] |= (1 << (bit & 7));
13298
13299 offset += TARGET_POINTER_SIZE;
13300 }
13301 cur--;
13302 } while (cur >= last);
13303}
13304
13305//
13306// Type layout check verifies that there was no incompatible change in the value type layout.
13307// If there was one, we will fall back to JIT instead of using the pre-generated code from the ready to run image.
13308// This should be rare situation. Changes in value type layout not common.
13309//
13310// The following properties of the value type layout are checked:
13311// - Size
13312// - HFA-ness (on platform that support HFAs)
13313// - Alignment
13314// - Position of GC references
13315//
13316BOOL TypeLayoutCheck(MethodTable * pMT, PCCOR_SIGNATURE pBlob)
13317{
13318 STANDARD_VM_CONTRACT;
13319
13320 SigPointer p(pBlob);
13321 IfFailThrow(p.SkipExactlyOne());
13322
13323 DWORD dwFlags;
13324 IfFailThrow(p.GetData(&dwFlags));
13325
13326 // Size is checked unconditionally
13327 DWORD dwExpectedSize;
13328 IfFailThrow(p.GetData(&dwExpectedSize));
13329
13330 DWORD dwActualSize = pMT->GetNumInstanceFieldBytes();
13331 if (dwExpectedSize != dwActualSize)
13332 return FALSE;
13333
13334#ifdef FEATURE_HFA
13335 if (dwFlags & READYTORUN_LAYOUT_HFA)
13336 {
13337 DWORD dwExpectedHFAType;
13338 IfFailThrow(p.GetData(&dwExpectedHFAType));
13339
13340 DWORD dwActualHFAType = pMT->GetHFAType();
13341 if (dwExpectedHFAType != dwActualHFAType)
13342 return FALSE;
13343 }
13344 else
13345 {
13346 if (pMT->IsHFA())
13347 return FALSE;
13348 }
13349#else
13350 _ASSERTE(!(dwFlags & READYTORUN_LAYOUT_HFA));
13351#endif
13352
13353 if (dwFlags & READYTORUN_LAYOUT_Alignment)
13354 {
13355 DWORD dwExpectedAlignment = TARGET_POINTER_SIZE;
13356 if (!(dwFlags & READYTORUN_LAYOUT_Alignment_Native))
13357 {
13358 IfFailThrow(p.GetData(&dwExpectedAlignment));
13359 }
13360
13361 DWORD dwActualAlignment = CEEInfo::getClassAlignmentRequirementStatic(pMT);
13362 if (dwExpectedAlignment != dwActualAlignment)
13363 return FALSE;
13364
13365 }
13366
13367 if (dwFlags & READYTORUN_LAYOUT_GCLayout)
13368 {
13369 if (dwFlags & READYTORUN_LAYOUT_GCLayout_Empty)
13370 {
13371 if (pMT->ContainsPointers())
13372 return FALSE;
13373 }
13374 else
13375 {
13376 size_t cbGCRefMap = (dwActualSize / TARGET_POINTER_SIZE + 7) / 8;
13377 _ASSERTE(cbGCRefMap > 0);
13378
13379 BYTE * pGCRefMap = (BYTE *)_alloca(cbGCRefMap);
13380
13381 ComputeGCRefMap(pMT, pGCRefMap, cbGCRefMap);
13382
13383 if (memcmp(pGCRefMap, p.GetPtr(), cbGCRefMap) != 0)
13384 return FALSE;
13385 }
13386 }
13387
13388 return TRUE;
13389}
13390
13391#endif // FEATURE_READYTORUN
13392
13393BOOL LoadDynamicInfoEntry(Module *currentModule,
13394 RVA fixupRva,
13395 SIZE_T *entry)
13396{
13397 STANDARD_VM_CONTRACT;
13398
13399 PCCOR_SIGNATURE pBlob = currentModule->GetNativeFixupBlobData(fixupRva);
13400
13401 BYTE kind = *pBlob++;
13402
13403 Module * pInfoModule = currentModule;
13404
13405 if (kind & ENCODE_MODULE_OVERRIDE)
13406 {
13407 pInfoModule = currentModule->GetModuleFromIndex(CorSigUncompressData(pBlob));
13408 kind &= ~ENCODE_MODULE_OVERRIDE;
13409 }
13410
13411 MethodDesc * pMD = NULL;
13412
13413#ifndef CROSSGEN_COMPILE
13414 PCCOR_SIGNATURE pSig;
13415 DWORD cSig;
13416#endif // CROSSGEN_COMPILE
13417
13418 size_t result = 0;
13419
13420 switch (kind)
13421 {
13422 case ENCODE_MODULE_HANDLE:
13423 result = (size_t)pInfoModule;
13424 break;
13425
13426 case ENCODE_TYPE_HANDLE:
13427 case ENCODE_TYPE_DICTIONARY:
13428 {
13429 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13430
13431 if (!th.IsTypeDesc())
13432 {
13433 if (currentModule->IsReadyToRun())
13434 {
13435 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13436 th.AsMethodTable()->EnsureInstanceActive();
13437 }
13438 else
13439 {
13440#ifdef FEATURE_WINMD_RESILIENT
13441 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13442 th.AsMethodTable()->EnsureInstanceActive();
13443#endif
13444 }
13445 }
13446
13447 result = (size_t)th.AsPtr();
13448 }
13449 break;
13450
13451 case ENCODE_METHOD_HANDLE:
13452 case ENCODE_METHOD_DICTIONARY:
13453 {
13454 MethodDesc * pMD = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13455
13456 if (currentModule->IsReadyToRun())
13457 {
13458 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13459 pMD->EnsureActive();
13460 }
13461
13462 result = (size_t)pMD;
13463 }
13464 break;
13465
13466 case ENCODE_FIELD_HANDLE:
13467 result = (size_t) ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13468 break;
13469
13470#ifndef CROSSGEN_COMPILE
13471 case ENCODE_STRING_HANDLE:
13472 {
13473 // We need to update strings atomically (due to NoStringInterning attribute). Note
13474 // that modules with string interning dont really need this, as the hash tables have
13475 // their own locking, but dont add more complexity for what will be the non common
13476 // case.
13477
13478 // We will have to lock and update the entry. (this is really a double check, where
13479 // the first check is done in the caller of this function)
13480 DWORD rid = CorSigUncompressData(pBlob);
13481 if (rid == 0)
13482 {
13483 // Empty string
13484 result = (size_t)StringObject::GetEmptyStringRefPtr();
13485 }
13486 else
13487 {
13488 CrstHolder ch(pInfoModule->GetFixupCrst());
13489
13490 if (!CORCOMPILE_IS_POINTER_TAGGED(*entry) && (*entry != NULL))
13491 {
13492 // We lost the race, just return
13493 return TRUE;
13494 }
13495
13496 // For generic instantiations compiled into the ngen image of some other
13497 // client assembly, we need to ensure that we intern the string
13498 // in the defining assembly.
13499 bool mayNeedToSyncWithFixups = pInfoModule != currentModule;
13500
13501 result = (size_t) pInfoModule->ResolveStringRef(TokenFromRid(rid, mdtString), currentModule->GetDomain(), mayNeedToSyncWithFixups);
13502 }
13503 }
13504 break;
13505
13506 case ENCODE_VARARGS_SIG:
13507 {
13508 mdSignature token = TokenFromRid(
13509 CorSigUncompressData(pBlob),
13510 mdtSignature);
13511
13512 IfFailThrow(pInfoModule->GetMDImport()->GetSigFromToken(token, &cSig, &pSig));
13513
13514 goto VarArgs;
13515 }
13516 break;
13517
13518 case ENCODE_VARARGS_METHODREF:
13519 {
13520 mdSignature token = TokenFromRid(
13521 CorSigUncompressData(pBlob),
13522 mdtMemberRef);
13523
13524 LPCSTR szName_Ignore;
13525 IfFailThrow(pInfoModule->GetMDImport()->GetNameAndSigOfMemberRef(token, &pSig, &cSig, &szName_Ignore));
13526
13527 goto VarArgs;
13528 }
13529 break;
13530
13531 case ENCODE_VARARGS_METHODDEF:
13532 {
13533 mdSignature token = TokenFromRid(
13534 CorSigUncompressData(pBlob),
13535 mdtMethodDef);
13536
13537 IfFailThrow(pInfoModule->GetMDImport()->GetSigOfMethodDef(token, &cSig, &pSig));
13538 }
13539 {
13540 VarArgs:
13541 result = (size_t) CORINFO_VARARGS_HANDLE(currentModule->GetVASigCookie(Signature(pSig, cSig)));
13542 }
13543 break;
13544
13545 // ENCODE_METHOD_NATIVECALLABLE_HANDLE is same as ENCODE_METHOD_ENTRY_DEF_TOKEN
13546 // except for AddrOfCode
13547 case ENCODE_METHOD_NATIVE_ENTRY:
13548 case ENCODE_METHOD_ENTRY_DEF_TOKEN:
13549 {
13550 mdToken MethodDef = TokenFromRid(CorSigUncompressData(pBlob), mdtMethodDef);
13551 pMD = MemberLoader::GetMethodDescFromMethodDef(pInfoModule, MethodDef, FALSE);
13552
13553 pMD->PrepareForUseAsADependencyOfANativeImage();
13554
13555 if (currentModule->IsReadyToRun())
13556 {
13557 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13558 pMD->EnsureActive();
13559 }
13560
13561 goto MethodEntry;
13562 }
13563
13564 case ENCODE_METHOD_ENTRY_REF_TOKEN:
13565 {
13566 SigTypeContext typeContext;
13567 mdToken MemberRef = TokenFromRid(CorSigUncompressData(pBlob), mdtMemberRef);
13568 FieldDesc * pFD = NULL;
13569 TypeHandle th;
13570
13571 MemberLoader::GetDescFromMemberRef(pInfoModule, MemberRef, &pMD, &pFD, &typeContext, FALSE /* strict metadata checks */, &th);
13572 _ASSERTE(pMD != NULL);
13573
13574 pMD->PrepareForUseAsADependencyOfANativeImage();
13575
13576 if (currentModule->IsReadyToRun())
13577 {
13578 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13579 pMD->EnsureActive();
13580 }
13581 else
13582 {
13583#ifdef FEATURE_WINMD_RESILIENT
13584 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13585 pMD->EnsureActive();
13586#endif
13587 }
13588
13589 goto MethodEntry;
13590 }
13591
13592 case ENCODE_METHOD_ENTRY:
13593 {
13594 pMD = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13595
13596 if (currentModule->IsReadyToRun())
13597 {
13598 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13599 pMD->EnsureActive();
13600 }
13601
13602 MethodEntry:
13603 if (kind == ENCODE_METHOD_NATIVE_ENTRY)
13604 {
13605 result = COMDelegate::ConvertToCallback(pMD);
13606 }
13607 else
13608 {
13609 result = pMD->GetMultiCallableAddrOfCode(CORINFO_ACCESS_ANY);
13610 }
13611
13612 #ifndef _TARGET_ARM_
13613 if (CORCOMPILE_IS_PCODE_TAGGED(result))
13614 {
13615 // There is a rare case where the function entrypoint may not be aligned. This could happen only for FCalls,
13616 // only on x86 and only if we failed to hardbind the fcall (e.g. ngen image for mscorlib.dll does not exist
13617 // and /nodependencies flag for ngen was used). The function entrypoints should be aligned in all other cases.
13618 //
13619 // We will wrap the unaligned method entrypoint by funcptr stub with aligned entrypoint.
13620 _ASSERTE(pMD->IsFCall());
13621 result = pMD->GetLoaderAllocator()->GetFuncPtrStubs()->GetFuncPtrStub(pMD);
13622 }
13623 #endif
13624 }
13625 break;
13626
13627 case ENCODE_SYNC_LOCK:
13628 {
13629 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13630
13631 result = (size_t) GetClassSync(th.AsMethodTable());
13632 }
13633 break;
13634
13635 case ENCODE_INDIRECT_PINVOKE_TARGET:
13636 {
13637 MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13638
13639 _ASSERTE(pMethod->IsNDirect());
13640 NDirectMethodDesc *pMD = (NDirectMethodDesc*)pMethod;
13641 result = (size_t)(LPVOID)&(pMD->GetWriteableData()->m_pNDirectTarget);
13642 }
13643 break;
13644
13645#if defined(PROFILING_SUPPORTED)
13646 case ENCODE_PROFILING_HANDLE:
13647 {
13648 MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13649
13650 // methods with no metadata behind cannot be exposed to tools expecting metadata (profiler, debugger...)
13651 // they shouldnever come here as they are called out in GetCompileFlag
13652 _ASSERTE(!pMethod->IsNoMetadata());
13653
13654 FunctionID funId = (FunctionID)pMethod;
13655
13656 BOOL bHookFunction = TRUE;
13657 CORINFO_PROFILING_HANDLE profilerHandle = (CORINFO_PROFILING_HANDLE)funId;
13658
13659 {
13660 BEGIN_PIN_PROFILER(CORProfilerFunctionIDMapperEnabled());
13661 profilerHandle = (CORINFO_PROFILING_HANDLE) g_profControlBlock.pProfInterface->EEFunctionIDMapper(funId, &bHookFunction);
13662 END_PIN_PROFILER();
13663 }
13664
13665 // Profiling handle is opaque token. It does not have to be aligned thus we can not store it in the same location as token.
13666 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexClientData) = (SIZE_T)profilerHandle;
13667
13668 if (bHookFunction)
13669 {
13670 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexEnterAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_ENTER].pfnHelper;
13671 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexLeaveAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_LEAVE].pfnHelper;
13672 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexTailcallAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_TAILCALL].pfnHelper;
13673 }
13674 else
13675 {
13676 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexEnterAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13677 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexLeaveAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13678 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexTailcallAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13679 }
13680 }
13681 break;
13682#endif // PROFILING_SUPPORTED
13683
13684 case ENCODE_STATIC_FIELD_ADDRESS:
13685 {
13686 FieldDesc *pField = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13687
13688 pField->GetEnclosingMethodTable()->CheckRestore();
13689
13690 // We can take address of RVA field only since ngened code is domain neutral
13691 _ASSERTE(pField->IsRVA());
13692
13693 // Field address is not aligned thus we can not store it in the same location as token.
13694 *EnsureWritablePages(entry+1) = (size_t)pField->GetStaticAddressHandle(NULL);
13695 }
13696 break;
13697
13698 case ENCODE_VIRTUAL_ENTRY_SLOT:
13699 {
13700 DWORD slot = CorSigUncompressData(pBlob);
13701
13702 TypeHandle ownerType = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13703
13704 LOG((LF_ZAP, LL_INFO100000, " Fixup stub dispatch\n"));
13705
13706 VirtualCallStubManager * pMgr = currentModule->GetLoaderAllocator()->GetVirtualCallStubManager();
13707
13708 // <REVISIT_TODO>
13709 // We should be generating a stub indirection here, but the zapper already uses one level
13710 // of indirection, i.e. we would have to return IAT_PPVALUE to the JIT, and on the whole the JITs
13711 // aren't quite set up to accept that. Furthermore the call sequences would be different - at
13712 // the moment an indirection cell uses "call [cell-addr]" on x86, and instead we would want the
13713 // euqivalent of "call [[call-addr]]". This could perhaps be implemented as "call [eax]" </REVISIT_TODO>
13714 result = pMgr->GetCallStub(ownerType, slot);
13715 }
13716 break;
13717
13718 case ENCODE_CLASS_ID_FOR_STATICS:
13719 {
13720 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13721
13722 MethodTable * pMT = th.AsMethodTable();
13723 if (pMT->IsDynamicStatics())
13724 {
13725 result = pMT->GetModuleDynamicEntryID();
13726 }
13727 else
13728 {
13729 result = pMT->GetClassIndex();
13730 }
13731 }
13732 break;
13733
13734 case ENCODE_MODULE_ID_FOR_STATICS:
13735 {
13736 result = pInfoModule->GetModuleID();
13737 }
13738 break;
13739
13740 case ENCODE_MODULE_ID_FOR_GENERIC_STATICS:
13741 {
13742 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13743
13744 MethodTable * pMT = th.AsMethodTable();
13745
13746 result = pMT->GetModuleForStatics()->GetModuleID();
13747 }
13748 break;
13749
13750 case ENCODE_ACTIVE_DEPENDENCY:
13751 {
13752 Module* pModule = currentModule->GetModuleFromIndex(CorSigUncompressData(pBlob));
13753
13754 STRESS_LOG3(LF_ZAP,LL_INFO10000,"Modules are: %08x,%08x,%08x",currentModule,pInfoModule,pModule);
13755 pInfoModule->AddActiveDependency(pModule, FALSE);
13756 }
13757 break;
13758
13759#ifdef FEATURE_READYTORUN
13760 case ENCODE_READYTORUN_HELPER:
13761 {
13762 DWORD helperNum = CorSigUncompressData(pBlob);
13763
13764 CorInfoHelpFunc corInfoHelpFunc = MapReadyToRunHelper((ReadyToRunHelper)helperNum);
13765 if (corInfoHelpFunc != CORINFO_HELP_UNDEF)
13766 {
13767 result = (size_t)CEEJitInfo::getHelperFtnStatic(corInfoHelpFunc);
13768 }
13769 else
13770 {
13771 switch (helperNum)
13772 {
13773 case READYTORUN_HELPER_Module:
13774 {
13775 Module * pPrevious = InterlockedCompareExchangeT(EnsureWritablePages((Module **)entry), pInfoModule, NULL);
13776 if (pPrevious != pInfoModule && pPrevious != NULL)
13777 COMPlusThrowHR(COR_E_FILELOAD, IDS_NATIVE_IMAGE_CANNOT_BE_LOADED_MULTIPLE_TIMES, pInfoModule->GetPath());
13778 return TRUE;
13779 }
13780 break;
13781
13782 case READYTORUN_HELPER_GSCookie:
13783 result = (size_t)GetProcessGSCookie();
13784 break;
13785
13786 case READYTORUN_HELPER_DelayLoad_MethodCall:
13787 result = (size_t)GetEEFuncEntryPoint(DelayLoad_MethodCall);
13788 break;
13789
13790 case READYTORUN_HELPER_DelayLoad_Helper:
13791 result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper);
13792 break;
13793
13794 case READYTORUN_HELPER_DelayLoad_Helper_Obj:
13795 result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper_Obj);
13796 break;
13797
13798 case READYTORUN_HELPER_DelayLoad_Helper_ObjObj:
13799 result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper_ObjObj);
13800 break;
13801
13802 default:
13803 STRESS_LOG1(LF_ZAP, LL_WARNING, "Unknown READYTORUN_HELPER %d\n", helperNum);
13804 _ASSERTE(!"Unknown READYTORUN_HELPER");
13805 return FALSE;
13806 }
13807 }
13808 }
13809 break;
13810
13811 case ENCODE_FIELD_OFFSET:
13812 {
13813 FieldDesc * pFD = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13814 _ASSERTE(!pFD->IsStatic());
13815 _ASSERTE(!pFD->IsFieldOfValueType());
13816
13817 DWORD dwOffset = (DWORD)sizeof(Object) + pFD->GetOffset();
13818
13819 if (dwOffset > MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT)
13820 return FALSE;
13821 result = dwOffset;
13822 }
13823 break;
13824
13825 case ENCODE_FIELD_BASE_OFFSET:
13826 {
13827 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13828
13829 MethodTable * pMT = th.AsMethodTable();
13830 _ASSERTE(!pMT->IsValueType());
13831
13832 DWORD dwOffsetBase = ReadyToRunInfo::GetFieldBaseOffset(pMT);
13833 if (dwOffsetBase > MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT)
13834 return FALSE;
13835 result = dwOffsetBase;
13836 }
13837 break;
13838
13839 case ENCODE_CHECK_TYPE_LAYOUT:
13840 {
13841 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13842 MethodTable * pMT = th.AsMethodTable();
13843 _ASSERTE(pMT->IsValueType());
13844
13845 if (!TypeLayoutCheck(pMT, pBlob))
13846 return FALSE;
13847
13848 result = 1;
13849 }
13850 break;
13851
13852 case ENCODE_CHECK_FIELD_OFFSET:
13853 {
13854 DWORD dwExpectedOffset = CorSigUncompressData(pBlob);
13855
13856 FieldDesc * pFD = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13857 _ASSERTE(!pFD->IsStatic());
13858
13859 DWORD dwOffset = pFD->GetOffset();
13860 if (!pFD->IsFieldOfValueType())
13861 dwOffset += sizeof(Object);
13862
13863 if (dwExpectedOffset != dwOffset)
13864 return FALSE;
13865
13866 result = 1;
13867 }
13868 break;
13869#endif // FEATURE_READYTORUN
13870
13871#endif // CROSSGEN_COMPILE
13872
13873 default:
13874 STRESS_LOG1(LF_ZAP, LL_WARNING, "Unknown FIXUP_BLOB_KIND %d\n", kind);
13875 _ASSERTE(!"Unknown FIXUP_BLOB_KIND");
13876 return FALSE;
13877 }
13878
13879 MemoryBarrier();
13880 *EnsureWritablePages(entry) = result;
13881
13882 return TRUE;
13883}
13884#endif // FEATURE_PREJIT
13885
13886void* CEEInfo::getTailCallCopyArgsThunk(CORINFO_SIG_INFO *pSig,
13887 CorInfoHelperTailCallSpecialHandling flags)
13888{
13889 CONTRACTL {
13890 SO_TOLERANT;
13891 THROWS;
13892 GC_TRIGGERS;
13893 MODE_PREEMPTIVE;
13894 } CONTRACTL_END;
13895
13896 void * ftn = NULL;
13897
13898#if (defined(_TARGET_AMD64_) || defined(_TARGET_ARM_)) && !defined(FEATURE_PAL)
13899
13900 JIT_TO_EE_TRANSITION();
13901
13902 Stub* pStub = CPUSTUBLINKER::CreateTailCallCopyArgsThunk(pSig, m_pMethodBeingCompiled, flags);
13903
13904 ftn = (void*)pStub->GetEntryPoint();
13905
13906 EE_TO_JIT_TRANSITION();
13907
13908#endif // (_TARGET_AMD64_ || _TARGET_ARM_) && !FEATURE_PAL
13909
13910 return ftn;
13911}
13912
13913bool CEEInfo::convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fMustConvert)
13914{
13915 return false;
13916}
13917
13918void CEEInfo::allocMem (
13919 ULONG hotCodeSize, /* IN */
13920 ULONG coldCodeSize, /* IN */
13921 ULONG roDataSize, /* IN */
13922 ULONG xcptnsCount, /* IN */
13923 CorJitAllocMemFlag flag, /* IN */
13924 void ** hotCodeBlock, /* OUT */
13925 void ** coldCodeBlock, /* OUT */
13926 void ** roDataBlock /* OUT */
13927 )
13928{
13929 LIMITED_METHOD_CONTRACT;
13930 UNREACHABLE(); // only called on derived class.
13931}
13932
13933void CEEInfo::reserveUnwindInfo (
13934 BOOL isFunclet, /* IN */
13935 BOOL isColdCode, /* IN */
13936 ULONG unwindSize /* IN */
13937 )
13938{
13939 LIMITED_METHOD_CONTRACT;
13940 UNREACHABLE(); // only called on derived class.
13941}
13942
13943void CEEInfo::allocUnwindInfo (
13944 BYTE * pHotCode, /* IN */
13945 BYTE * pColdCode, /* IN */
13946 ULONG startOffset, /* IN */
13947 ULONG endOffset, /* IN */
13948 ULONG unwindSize, /* IN */
13949 BYTE * pUnwindBlock, /* IN */
13950 CorJitFuncKind funcKind /* IN */
13951 )
13952{
13953 LIMITED_METHOD_CONTRACT;
13954 UNREACHABLE(); // only called on derived class.
13955}
13956
13957void * CEEInfo::allocGCInfo (
13958 size_t size /* IN */
13959 )
13960{
13961 LIMITED_METHOD_CONTRACT;
13962 UNREACHABLE_RET(); // only called on derived class.
13963}
13964
13965void CEEInfo::setEHcount (
13966 unsigned cEH /* IN */
13967 )
13968{
13969 LIMITED_METHOD_CONTRACT;
13970 UNREACHABLE(); // only called on derived class.
13971}
13972
13973void CEEInfo::setEHinfo (
13974 unsigned EHnumber, /* IN */
13975 const CORINFO_EH_CLAUSE *clause /* IN */
13976 )
13977{
13978 LIMITED_METHOD_CONTRACT;
13979 UNREACHABLE(); // only called on derived class.
13980}
13981
13982InfoAccessType CEEInfo::constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd,
13983 mdToken metaTok,
13984 void **ppValue)
13985{
13986 LIMITED_METHOD_CONTRACT;
13987 UNREACHABLE(); // only called on derived class.
13988}
13989
13990InfoAccessType CEEInfo::emptyStringLiteral(void ** ppValue)
13991{
13992 LIMITED_METHOD_CONTRACT;
13993 _ASSERTE(isVerifyOnly());
13994 *ppValue = (void *)0x10;
13995 return IAT_PVALUE;
13996}
13997
13998void* CEEInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd,
13999 void **ppIndirection)
14000{
14001 CONTRACTL{
14002 SO_TOLERANT;
14003 THROWS;
14004 GC_TRIGGERS;
14005 MODE_PREEMPTIVE;
14006 } CONTRACTL_END;
14007
14008 void *result = NULL;
14009
14010 if (ppIndirection != NULL)
14011 *ppIndirection = NULL;
14012
14013 // Do not bother with initialization if we are only verifying the method.
14014 if (isVerifyOnly())
14015 {
14016 return (void *)0x10;
14017 }
14018
14019 JIT_TO_EE_TRANSITION();
14020
14021 FieldDesc* field = (FieldDesc*)fieldHnd;
14022
14023 _ASSERTE(field->IsRVA());
14024
14025 result = field->GetStaticAddressHandle(NULL);
14026
14027 EE_TO_JIT_TRANSITION();
14028
14029 return result;
14030}
14031
14032CORINFO_CLASS_HANDLE CEEInfo::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE fieldHnd,
14033 bool* pIsSpeculative)
14034{
14035 LIMITED_METHOD_CONTRACT;
14036 _ASSERTE(isVerifyOnly());
14037 if (pIsSpeculative != NULL)
14038 *pIsSpeculative = true;
14039 return NULL;
14040}
14041
14042void* CEEInfo::getMethodSync(CORINFO_METHOD_HANDLE ftnHnd,
14043 void **ppIndirection)
14044{
14045 LIMITED_METHOD_CONTRACT;
14046 UNREACHABLE(); // only called on derived class.
14047}
14048
14049HRESULT CEEInfo::allocBBProfileBuffer (
14050 ULONG count, // The number of basic blocks that we have
14051 ProfileBuffer ** profileBuffer
14052 )
14053{
14054 LIMITED_METHOD_CONTRACT;
14055 UNREACHABLE_RET(); // only called on derived class.
14056}
14057
14058HRESULT CEEInfo::getBBProfileData(
14059 CORINFO_METHOD_HANDLE ftnHnd,
14060 ULONG * count, // The number of basic blocks that we have
14061 ProfileBuffer ** profileBuffer,
14062 ULONG * numRuns
14063 )
14064{
14065 LIMITED_METHOD_CONTRACT;
14066 UNREACHABLE_RET(); // only called on derived class.
14067}
14068
14069
14070void CEEInfo::recordCallSite(
14071 ULONG instrOffset, /* IN */
14072 CORINFO_SIG_INFO * callSig, /* IN */
14073 CORINFO_METHOD_HANDLE methodHandle /* IN */
14074 )
14075{
14076 LIMITED_METHOD_CONTRACT;
14077 UNREACHABLE(); // only called on derived class.
14078}
14079
14080void CEEInfo::recordRelocation(
14081 void * location, /* IN */
14082 void * target, /* IN */
14083 WORD fRelocType, /* IN */
14084 WORD slotNum, /* IN */
14085 INT32 addlDelta /* IN */
14086 )
14087{
14088 LIMITED_METHOD_CONTRACT;
14089 UNREACHABLE(); // only called on derived class.
14090}
14091
14092WORD CEEInfo::getRelocTypeHint(void * target)
14093{
14094 LIMITED_METHOD_CONTRACT;
14095 UNREACHABLE_RET(); // only called on derived class.
14096}
14097
14098void CEEInfo::getModuleNativeEntryPointRange(
14099 void ** pStart, /* OUT */
14100 void ** pEnd /* OUT */
14101 )
14102{
14103 LIMITED_METHOD_CONTRACT;
14104 UNREACHABLE(); // only called on derived class.
14105}
14106
14107DWORD CEEInfo::getExpectedTargetArchitecture()
14108{
14109 LIMITED_METHOD_CONTRACT;
14110
14111 return IMAGE_FILE_MACHINE_NATIVE;
14112}
14113
14114void CEEInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap,
14115 ICorDebugInfo::OffsetMapping *pMap)
14116{
14117 LIMITED_METHOD_CONTRACT;
14118 UNREACHABLE(); // only called on derived class.
14119}
14120
14121void CEEInfo::setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars)
14122{
14123 LIMITED_METHOD_CONTRACT;
14124 UNREACHABLE(); // only called on derived class.
14125}
14126
14127void* CEEInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
14128 void ** ppIndirection) /* OUT */
14129{
14130 LIMITED_METHOD_CONTRACT;
14131 UNREACHABLE(); // only called on derived class.
14132}
14133
14134// Active dependency helpers
14135void CEEInfo::addActiveDependency(CORINFO_MODULE_HANDLE moduleFrom,CORINFO_MODULE_HANDLE moduleTo)
14136{
14137 LIMITED_METHOD_CONTRACT;
14138 UNREACHABLE(); // only called on derived class.
14139}
14140
14141void CEEInfo::GetProfilingHandle(BOOL *pbHookFunction,
14142 void **pProfilerHandle,
14143 BOOL *pbIndirectedHandles)
14144{
14145 LIMITED_METHOD_CONTRACT;
14146 UNREACHABLE(); // only called on derived class.
14147}
14148
14149#endif // !DACCESS_COMPILE
14150
14151EECodeInfo::EECodeInfo()
14152{
14153 WRAPPER_NO_CONTRACT;
14154
14155 m_codeAddress = NULL;
14156
14157 m_pJM = NULL;
14158 m_pMD = NULL;
14159 m_relOffset = 0;
14160
14161#ifdef WIN64EXCEPTIONS
14162 m_pFunctionEntry = NULL;
14163#endif
14164}
14165
14166void EECodeInfo::Init(PCODE codeAddress)
14167{
14168 CONTRACTL {
14169 NOTHROW;
14170 GC_NOTRIGGER;
14171 SO_TOLERANT;
14172 } CONTRACTL_END;
14173
14174 Init(codeAddress, ExecutionManager::GetScanFlags());
14175}
14176
14177void EECodeInfo::Init(PCODE codeAddress, ExecutionManager::ScanFlag scanFlag)
14178{
14179 CONTRACTL {
14180 NOTHROW;
14181 GC_NOTRIGGER;
14182 SO_TOLERANT;
14183 } CONTRACTL_END;
14184
14185 m_codeAddress = codeAddress;
14186
14187 RangeSection * pRS = ExecutionManager::FindCodeRange(codeAddress, scanFlag);
14188 if (pRS == NULL)
14189 goto Invalid;
14190
14191 if (!pRS->pjit->JitCodeToMethodInfo(pRS, codeAddress, &m_pMD, this))
14192 goto Invalid;
14193
14194 m_pJM = pRS->pjit;
14195 return;
14196
14197Invalid:
14198 m_pJM = NULL;
14199 m_pMD = NULL;
14200 m_relOffset = 0;
14201
14202#ifdef WIN64EXCEPTIONS
14203 m_pFunctionEntry = NULL;
14204#endif
14205}
14206
14207TADDR EECodeInfo::GetSavedMethodCode()
14208{
14209 CONTRACTL {
14210 // All EECodeInfo methods must be NOTHROW/GC_NOTRIGGER since they can
14211 // be used during GC.
14212 NOTHROW;
14213 GC_NOTRIGGER;
14214 HOST_NOCALLS;
14215 SUPPORTS_DAC;
14216 } CONTRACTL_END;
14217#ifndef _WIN64
14218#if defined(HAVE_GCCOVER)
14219 _ASSERTE (!m_pMD->m_GcCover || GCStress<cfg_instr>::IsEnabled());
14220 if (GCStress<cfg_instr>::IsEnabled()
14221 && m_pMD->m_GcCover)
14222 {
14223 _ASSERTE(m_pMD->m_GcCover->savedCode);
14224
14225 // Make sure we return the TADDR of savedCode here. The byte array is not marshaled automatically.
14226 // The caller is responsible for any necessary marshaling.
14227 return PTR_TO_MEMBER_TADDR(GCCoverageInfo, m_pMD->m_GcCover, savedCode);
14228 }
14229#endif //defined(HAVE_GCCOVER)
14230#endif
14231
14232 return GetStartAddress();
14233}
14234
14235TADDR EECodeInfo::GetStartAddress()
14236{
14237 CONTRACTL {
14238 NOTHROW;
14239 GC_NOTRIGGER;
14240 HOST_NOCALLS;
14241 SUPPORTS_DAC;
14242 } CONTRACTL_END;
14243
14244 return m_pJM->JitTokenToStartAddress(m_methodToken);
14245}
14246
14247#if defined(WIN64EXCEPTIONS)
14248
14249// ----------------------------------------------------------------------------
14250// EECodeInfo::GetMainFunctionInfo
14251//
14252// Description:
14253// Simple helper to transform a funclet's EECodeInfo into a parent function EECodeInfo.
14254//
14255// Return Value:
14256// An EECodeInfo for the start of the main function body (offset 0).
14257//
14258
14259EECodeInfo EECodeInfo::GetMainFunctionInfo()
14260{
14261 LIMITED_METHOD_CONTRACT;
14262 SUPPORTS_DAC;
14263
14264 EECodeInfo result = *this;
14265 result.m_relOffset = 0;
14266 result.m_codeAddress = this->GetStartAddress();
14267 result.m_pFunctionEntry = NULL;
14268
14269 return result;
14270}
14271
14272PTR_RUNTIME_FUNCTION EECodeInfo::GetFunctionEntry()
14273{
14274 LIMITED_METHOD_CONTRACT;
14275 SUPPORTS_DAC;
14276
14277 if (m_pFunctionEntry == NULL)
14278 m_pFunctionEntry = m_pJM->LazyGetFunctionEntry(this);
14279 return m_pFunctionEntry;
14280}
14281
14282#if defined(_TARGET_AMD64_)
14283
14284BOOL EECodeInfo::HasFrameRegister()
14285{
14286 LIMITED_METHOD_CONTRACT;
14287
14288 PTR_RUNTIME_FUNCTION pFuncEntry = GetFunctionEntry();
14289 _ASSERTE(pFuncEntry != NULL);
14290
14291 BOOL fHasFrameRegister = FALSE;
14292 PUNWIND_INFO pUnwindInfo = (PUNWIND_INFO)(GetModuleBase() + pFuncEntry->UnwindData);
14293 if (pUnwindInfo->FrameRegister != 0)
14294 {
14295 fHasFrameRegister = TRUE;
14296 _ASSERTE(pUnwindInfo->FrameRegister == kRBP);
14297 }
14298
14299 return fHasFrameRegister;
14300}
14301#endif // defined(_TARGET_AMD64_)
14302
14303#endif // defined(WIN64EXCEPTIONS)
14304
14305
14306#if defined(_TARGET_AMD64_)
14307// ----------------------------------------------------------------------------
14308// EECodeInfo::GetUnwindInfoHelper
14309//
14310// Description:
14311// Simple helper to return a pointer to the UNWIND_INFO given the offset to the unwind info.
14312// On DAC builds, this function will read the memory from the target process and create a host copy.
14313//
14314// Arguments:
14315// * unwindInfoOffset - This is the offset to the unwind info, relative to the beginning of the code heap
14316// for jitted code or to the module base for ngned code. this->GetModuleBase() will return the correct
14317// module base.
14318//
14319// Return Value:
14320// Return a pointer to the UNWIND_INFO. On DAC builds, this function will create a host copy of the
14321// UNWIND_INFO and return a host pointer. It will correctly read all of the memory for the variable-sized
14322// unwind info.
14323//
14324
14325UNWIND_INFO * EECodeInfo::GetUnwindInfoHelper(ULONG unwindInfoOffset)
14326{
14327#if defined(DACCESS_COMPILE)
14328 return DacGetUnwindInfo(static_cast<TADDR>(this->GetModuleBase() + unwindInfoOffset));
14329#else // !DACCESS_COMPILE
14330 return reinterpret_cast<UNWIND_INFO *>(this->GetModuleBase() + unwindInfoOffset);
14331#endif // !DACCESS_COMPILE
14332}
14333
14334// ----------------------------------------------------------------------------
14335// EECodeInfo::GetFixedStackSize
14336//
14337// Description:
14338// Return the fixed stack size of a specified managed method. This function DOES NOT take current control
14339// PC into account. So the fixed stack size returned by this function is not valid in the prolog or
14340// the epilog.
14341//
14342// Return Value:
14343// Return the fixed stack size.
14344//
14345// Notes:
14346// * For method with dynamic stack allocations, this function will return the fixed stack size on X64 (the
14347// stack size immediately after the prolog), and it will return 0 on IA64. This difference is due to
14348// the different unwind info encoding.
14349//
14350
14351ULONG EECodeInfo::GetFixedStackSize()
14352{
14353 WRAPPER_NO_CONTRACT;
14354 SUPPORTS_DAC;
14355
14356 ULONG uFixedStackSize = 0;
14357
14358 ULONG uDummy = 0;
14359 GetOffsetsFromUnwindInfo(&uFixedStackSize, &uDummy);
14360
14361 return uFixedStackSize;
14362}
14363
14364#define kRBP 5
14365// The information returned by this method is only valid if we are not in a prolog or an epilog.
14366// Since this method is only used for the security stackwalk cache, this assumption is valid, since
14367// we cannot make a call in a prolog or an epilog.
14368//
14369// The next assumption is that only rbp is used as a frame register in jitted code. There is an
14370// assert below to guard this assumption.
14371void EECodeInfo::GetOffsetsFromUnwindInfo(ULONG* pRSPOffset, ULONG* pRBPOffset)
14372{
14373 LIMITED_METHOD_CONTRACT;
14374 SUPPORTS_DAC;
14375
14376 _ASSERTE((pRSPOffset != NULL) && (pRBPOffset != NULL));
14377
14378 // moduleBase is a target address.
14379 TADDR moduleBase = GetModuleBase();
14380
14381 DWORD unwindInfo = RUNTIME_FUNCTION__GetUnwindInfoAddress(GetFunctionEntry());
14382
14383 if ((unwindInfo & RUNTIME_FUNCTION_INDIRECT) != 0)
14384 {
14385 unwindInfo = RUNTIME_FUNCTION__GetUnwindInfoAddress(PTR_RUNTIME_FUNCTION(moduleBase + (unwindInfo & ~RUNTIME_FUNCTION_INDIRECT)));
14386 }
14387
14388 UNWIND_INFO * pInfo = GetUnwindInfoHelper(unwindInfo);
14389 if (pInfo->Flags & UNW_FLAG_CHAININFO)
14390 {
14391 _ASSERTE(!"GetRbpOffset() - chained unwind info used, violating assumptions of the security stackwalk cache");
14392 DebugBreak();
14393 }
14394
14395 // Either we are not using a frame pointer, or we are using rbp as the frame pointer.
14396 if ( (pInfo->FrameRegister != 0) && (pInfo->FrameRegister != kRBP) )
14397 {
14398 _ASSERTE(!"GetRbpOffset() - non-RBP frame pointer used, violating assumptions of the security stackwalk cache");
14399 DebugBreak();
14400 }
14401
14402 // Walk the unwind info.
14403 ULONG StackOffset = 0;
14404 ULONG StackSize = 0;
14405 for (int i = 0; i < pInfo->CountOfUnwindCodes; i++)
14406 {
14407 ULONG UnwindOp = pInfo->UnwindCode[i].UnwindOp;
14408 ULONG OpInfo = pInfo->UnwindCode[i].OpInfo;
14409
14410 if (UnwindOp == UWOP_SAVE_NONVOL)
14411 {
14412 if (OpInfo == kRBP)
14413 {
14414 StackOffset = pInfo->UnwindCode[i+1].FrameOffset * 8;
14415 }
14416 }
14417 else if (UnwindOp == UWOP_SAVE_NONVOL_FAR)
14418 {
14419 if (OpInfo == kRBP)
14420 {
14421 StackOffset = pInfo->UnwindCode[i + 1].FrameOffset;
14422 StackOffset += (pInfo->UnwindCode[i + 2].FrameOffset << 16);
14423 }
14424 }
14425 else if (UnwindOp == UWOP_ALLOC_SMALL)
14426 {
14427 StackSize += (OpInfo * 8) + 8;
14428 }
14429 else if (UnwindOp == UWOP_ALLOC_LARGE)
14430 {
14431 ULONG IncrementalStackSize = pInfo->UnwindCode[i + 1].FrameOffset;
14432 if (OpInfo == 0)
14433 {
14434 IncrementalStackSize *= 8;
14435 }
14436 else
14437 {
14438 IncrementalStackSize += (pInfo->UnwindCode[i + 2].FrameOffset << 16);
14439
14440 // This is a special opcode. We need to increment the index by 1 in addition to the normal adjustments.
14441 i += 1;
14442 }
14443 StackSize += IncrementalStackSize;
14444 }
14445 else if (UnwindOp == UWOP_PUSH_NONVOL)
14446 {
14447 // Because of constraints on epilogs, this unwind opcode is always last in the unwind code array.
14448 // This means that StackSize has been initialized already when we first see this unwind opcode.
14449 // Note that the intial value of StackSize does not include the stack space used for pushes.
14450 // Thus, here we only need to increment StackSize 8 bytes at a time until we see the unwind code for "push rbp".
14451 if (OpInfo == kRBP)
14452 {
14453 StackOffset = StackSize;
14454 }
14455
14456 StackSize += 8;
14457 }
14458
14459 // Adjust the index into the unwind code array.
14460 i += UnwindOpExtraSlotTable[UnwindOp];
14461 }
14462
14463 *pRSPOffset = StackSize + 8; // add 8 for the return address
14464 *pRBPOffset = StackOffset;
14465}
14466#undef kRBP
14467
14468
14469#if defined(_DEBUG) && defined(HAVE_GCCOVER)
14470
14471LPVOID EECodeInfo::findNextFunclet (LPVOID pvFuncletStart, SIZE_T cbCode, LPVOID *ppvFuncletEnd)
14472{
14473 CONTRACTL {
14474 NOTHROW;
14475 GC_NOTRIGGER;
14476 } CONTRACTL_END;
14477
14478 while (cbCode > 0)
14479 {
14480 PT_RUNTIME_FUNCTION pFunctionEntry;
14481 ULONGLONG uImageBase;
14482#ifdef FEATURE_PAL
14483 EECodeInfo codeInfo;
14484 codeInfo.Init((PCODE)pvFuncletStart);
14485 pFunctionEntry = codeInfo.GetFunctionEntry();
14486 uImageBase = (ULONGLONG)codeInfo.GetModuleBase();
14487#else // !FEATURE_PAL
14488 //
14489 // This is GCStress debug only - use the slow OS APIs to enumerate funclets
14490 //
14491
14492 pFunctionEntry = (PT_RUNTIME_FUNCTION) RtlLookupFunctionEntry((ULONGLONG)pvFuncletStart,
14493 &uImageBase
14494 AMD64_ARG(NULL)
14495 );
14496#endif
14497
14498 if (pFunctionEntry != NULL)
14499 {
14500#ifdef FEATURE_PREJIT
14501 // workaround: Check for indirect entry that is generated for cold part of main method body.
14502 if ((TADDR)pvFuncletStart < (TADDR)uImageBase + pFunctionEntry->BeginAddress ||
14503 (TADDR)uImageBase + pFunctionEntry->EndAddress <= (TADDR)pvFuncletStart)
14504 {
14505 Module * pZapModule = ExecutionManager::FindZapModule((TADDR)pvFuncletStart);
14506 NGenLayoutInfo * pLayoutInfo = pZapModule->GetNGenLayoutInfo();
14507
14508 int ColdFunctionIndex = NativeUnwindInfoLookupTable::LookupUnwindInfoForMethod((DWORD)((TADDR)pvFuncletStart - uImageBase),
14509 pLayoutInfo->m_pRuntimeFunctions[2],
14510 0, pLayoutInfo->m_nRuntimeFunctions[2] - 1);
14511
14512 pFunctionEntry = pLayoutInfo->m_pRuntimeFunctions[2] + ColdFunctionIndex;
14513 }
14514#endif
14515
14516 _ASSERTE((TADDR)pvFuncletStart == (TADDR)uImageBase + pFunctionEntry->BeginAddress);
14517 _ASSERTE((TADDR)uImageBase + pFunctionEntry->EndAddress <= (TADDR)pvFuncletStart + cbCode);
14518 *ppvFuncletEnd = (LPVOID)(uImageBase + pFunctionEntry->EndAddress);
14519 return (LPVOID)(uImageBase + pFunctionEntry->BeginAddress);
14520 }
14521
14522 pvFuncletStart = (LPVOID)((TADDR)pvFuncletStart + 1);
14523 cbCode--;
14524 }
14525
14526 return NULL;
14527}
14528#endif // defined(_DEBUG) && !defined(HAVE_GCCOVER)
14529#endif // defined(_TARGET_AMD64_)
14530