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.
5 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10 XX The functionality needed for the JIT DLL. Includes the DLL entry point XX
12 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
13 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
23 #if !defined(_HOST_UNIX_)
24 #include <io.h> // For _dup, _setmode
25 #include <fcntl.h> // For _O_TEXT
26 #include <errno.h> // For EINVAL
29 /*****************************************************************************/
31 FILE* jitstdout = nullptr;
33 ICorJitHost* g_jitHost = nullptr;
34 static CILJit* ILJitter = nullptr; // The one and only JITTER I return
35 bool g_jitInitialized = false;
36 #ifndef FEATURE_MERGE_JIT_AND_ENGINE
37 HINSTANCE g_hInst = nullptr;
38 #endif // FEATURE_MERGE_JIT_AND_ENGINE
40 /*****************************************************************************/
44 JitOptions jitOpts = {
45 nullptr, // methodName
50 (JitOptions*)nullptr // lastDummyField.
55 /*****************************************************************************/
57 extern "C" void __stdcall jitStartup(ICorJitHost* jitHost)
61 if (jitHost != g_jitHost)
63 // We normally don't expect jitStartup() to be invoked more than once.
64 // (We check whether it has been called once due to an abundance of caution.)
65 // However, during SuperPMI playback of MCH file, we need to JIT many different methods.
66 // Each one carries its own environment configuration state.
67 // So, we need the JIT to reload the JitConfig state for each change in the environment state of the
68 // replayed compilations.
69 // We do this by calling jitStartup with a different ICorJitHost,
70 // and have the JIT re-initialize its JitConfig state when this happens.
71 JitConfig.destroy(g_jitHost);
72 JitConfig.initialize(jitHost);
80 assert(!JitConfig.isInitialized());
81 JitConfig.initialize(jitHost);
83 #if defined(_HOST_UNIX_)
84 jitstdout = procstdout();
86 if (jitstdout == nullptr)
88 int stdoutFd = _fileno(procstdout());
89 // Check fileno error output(s) -1 may overlap with errno result
90 // but is included for completness.
91 // We want to detect the case where the initial handle is null
92 // or bogus and avoid making further calls.
93 if ((stdoutFd != -1) && (stdoutFd != -2) && (errno != EINVAL))
95 int jitstdoutFd = _dup(_fileno(procstdout()));
96 // Check the error status returned by dup.
97 if (jitstdoutFd != -1)
99 _setmode(jitstdoutFd, _O_TEXT);
100 jitstdout = _fdopen(jitstdoutFd, "w");
101 assert(jitstdout != nullptr);
103 // Prevent the FILE* from buffering its output in order to avoid calls to
104 // `fflush()` throughout the code.
105 setvbuf(jitstdout, nullptr, _IONBF, 0);
110 // If jitstdout is still null, fallback to whatever procstdout() was
112 if (jitstdout == nullptr)
114 jitstdout = procstdout();
116 #endif // !_HOST_UNIX_
118 #ifdef FEATURE_TRACELOGGING
119 JitTelemetry::NotifyDllProcessAttach();
121 Compiler::compStartup();
123 g_jitInitialized = true;
128 if (!g_jitInitialized)
133 Compiler::compShutdown();
135 if (jitstdout != procstdout())
140 #ifdef FEATURE_TRACELOGGING
141 JitTelemetry::NotifyDllProcessDetach();
144 g_jitInitialized = false;
147 #ifndef FEATURE_MERGE_JIT_AND_ENGINE
149 extern "C" BOOL WINAPI DllMain(HANDLE hInstance, DWORD dwReason, LPVOID pvReserved)
151 if (dwReason == DLL_PROCESS_ATTACH)
153 g_hInst = (HINSTANCE)hInstance;
154 DisableThreadLibraryCalls((HINSTANCE)hInstance);
156 else if (dwReason == DLL_PROCESS_DETACH)
164 HINSTANCE GetModuleInst()
169 extern "C" void __stdcall sxsJitStartup(CoreClrCallbacks const& cccallbacks)
172 InitUtilcode(cccallbacks);
176 #endif // !FEATURE_MERGE_JIT_AND_ENGINE
178 /*****************************************************************************/
180 struct CILJitSingletonAllocator
184 const CILJitSingletonAllocator CILJitSingleton = {0};
186 void* __cdecl operator new(size_t, const CILJitSingletonAllocator&)
188 static char CILJitBuff[sizeof(CILJit)];
192 ICorJitCompiler* g_realJitCompiler = nullptr;
194 ICorJitCompiler* __stdcall getJit()
196 if (ILJitter == nullptr)
198 ILJitter = new (CILJitSingleton) CILJit();
203 /*****************************************************************************/
205 // Information kept in thread-local storage. This is used in the noway_assert exceptional path.
206 // If you are using it more broadly in retail code, you would need to understand the
207 // performance implications of accessing TLS.
209 __declspec(thread) void* gJitTls = nullptr;
211 static void* GetJitTls()
216 void SetJitTls(void* value)
223 JitTls::JitTls(ICorJitInfo* jitInfo) : m_compiler(nullptr), m_logEnv(jitInfo)
225 m_next = reinterpret_cast<JitTls*>(GetJitTls());
234 LogEnv* JitTls::GetLogEnv()
236 return &reinterpret_cast<JitTls*>(GetJitTls())->m_logEnv;
239 Compiler* JitTls::GetCompiler()
241 return reinterpret_cast<JitTls*>(GetJitTls())->m_compiler;
244 void JitTls::SetCompiler(Compiler* compiler)
246 reinterpret_cast<JitTls*>(GetJitTls())->m_compiler = compiler;
249 #else // defined(DEBUG)
251 JitTls::JitTls(ICorJitInfo* jitInfo)
259 Compiler* JitTls::GetCompiler()
261 return reinterpret_cast<Compiler*>(GetJitTls());
264 void JitTls::SetCompiler(Compiler* compiler)
269 #endif // !defined(DEBUG)
271 //****************************************************************************
272 // The main JIT function for the 32 bit JIT. See code:ICorJitCompiler#EEToJitInterface for more on the EE-JIT
273 // interface. Things really don't get going inside the JIT until the code:Compiler::compCompile#Phases
274 // method. Usually that is where you want to go.
276 CorJitResult CILJit::compileMethod(
277 ICorJitInfo* compHnd, CORINFO_METHOD_INFO* methodInfo, unsigned flags, BYTE** entryAddress, ULONG* nativeSizeOfCode)
279 if (g_realJitCompiler != nullptr)
281 return g_realJitCompiler->compileMethod(compHnd, methodInfo, flags, entryAddress, nativeSizeOfCode);
286 assert(flags == CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS);
287 CORJIT_FLAGS corJitFlags;
288 DWORD jitFlagsSize = compHnd->getJitFlags(&corJitFlags, sizeof(corJitFlags));
289 assert(jitFlagsSize == sizeof(corJitFlags));
290 jitFlags.SetFromFlags(corJitFlags);
293 void* methodCodePtr = nullptr;
294 CORINFO_METHOD_HANDLE methodHandle = methodInfo->ftn;
296 JitTls jitTls(compHnd); // Initialize any necessary thread-local state
298 assert(methodInfo->ILCode);
300 result = jitNativeCode(methodHandle, methodInfo->scope, compHnd, methodInfo, &methodCodePtr, nativeSizeOfCode,
303 if (result == CORJIT_OK)
305 *entryAddress = (BYTE*)methodCodePtr;
308 return CorJitResult(result);
311 /*****************************************************************************
312 * Notification from VM to clear any caches
314 void CILJit::clearCache(void)
316 if (g_realJitCompiler != nullptr)
318 g_realJitCompiler->clearCache();
325 /*****************************************************************************
326 * Notify vm that we have something to clean up
328 BOOL CILJit::isCacheCleanupRequired(void)
330 if (g_realJitCompiler != nullptr)
332 if (g_realJitCompiler->isCacheCleanupRequired())
342 void CILJit::ProcessShutdownWork(ICorStaticInfo* statInfo)
344 if (g_realJitCompiler != nullptr)
346 g_realJitCompiler->ProcessShutdownWork(statInfo);
347 // Continue, by shutting down this JIT as well.
352 Compiler::ProcessShutdownWork(statInfo);
355 /*****************************************************************************
356 * Verify the JIT/EE interface identifier.
358 void CILJit::getVersionIdentifier(GUID* versionIdentifier)
360 if (g_realJitCompiler != nullptr)
362 g_realJitCompiler->getVersionIdentifier(versionIdentifier);
366 assert(versionIdentifier != nullptr);
367 memcpy(versionIdentifier, &JITEEVersionIdentifier, sizeof(GUID));
370 /*****************************************************************************
371 * Determine the maximum length of SIMD vector supported by this JIT.
374 unsigned CILJit::getMaxIntrinsicSIMDVectorLength(CORJIT_FLAGS cpuCompileFlags)
376 if (g_realJitCompiler != nullptr)
378 return g_realJitCompiler->getMaxIntrinsicSIMDVectorLength(cpuCompileFlags);
382 jitFlags.SetFromFlags(cpuCompileFlags);
385 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
386 if (!jitFlags.IsSet(JitFlags::JIT_FLAG_PREJIT) && jitFlags.IsSet(JitFlags::JIT_FLAG_FEATURE_SIMD) &&
387 jitFlags.IsSet(JitFlags::JIT_FLAG_USE_AVX2))
389 if (JitConfig.EnableAVX() != 0
391 && JitConfig.EnableAVX2() != 0
395 if (GetJitTls() != nullptr && JitTls::GetCompiler() != nullptr)
397 JITDUMP("getMaxIntrinsicSIMDVectorLength: returning 32\n");
402 #endif // !(defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND))
403 if (GetJitTls() != nullptr && JitTls::GetCompiler() != nullptr)
405 JITDUMP("getMaxIntrinsicSIMDVectorLength: returning 16\n");
408 #else // !FEATURE_SIMD
409 if (GetJitTls() != nullptr && JitTls::GetCompiler() != nullptr)
411 JITDUMP("getMaxIntrinsicSIMDVectorLength: returning 0\n");
414 #endif // !FEATURE_SIMD
417 void CILJit::setRealJit(ICorJitCompiler* realJitCompiler)
419 g_realJitCompiler = realJitCompiler;
422 /*****************************************************************************
423 * Returns the number of bytes required for the given type argument
426 unsigned Compiler::eeGetArgSize(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig)
428 #if defined(_TARGET_AMD64_)
430 // Everything fits into a single 'slot' size
431 // to accommodate irregular sized structs, they are passed byref
432 CLANG_FORMAT_COMMENT_ANCHOR;
434 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
435 CORINFO_CLASS_HANDLE argClass;
436 CorInfoType argTypeJit = strip(info.compCompHnd->getArgType(sig, list, &argClass));
437 var_types argType = JITtype2varType(argTypeJit);
438 if (varTypeIsStruct(argType))
440 unsigned structSize = info.compCompHnd->getClassSize(argClass);
441 return structSize; // TODO: roundUp() needed here?
443 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
444 return TARGET_POINTER_SIZE;
446 #else // !_TARGET_AMD64_
448 CORINFO_CLASS_HANDLE argClass;
449 CorInfoType argTypeJit = strip(info.compCompHnd->getArgType(sig, list, &argClass));
450 var_types argType = JITtype2varType(argTypeJit);
452 if (varTypeIsStruct(argType))
454 unsigned structSize = info.compCompHnd->getClassSize(argClass);
456 // make certain the EE passes us back the right thing for refanys
457 assert(argTypeJit != CORINFO_TYPE_REFANY || structSize == 2 * TARGET_POINTER_SIZE);
459 // For each target that supports passing struct args in multiple registers
460 // apply the target specific rules for them here:
461 CLANG_FORMAT_COMMENT_ANCHOR;
463 #if FEATURE_MULTIREG_ARGS
464 #if defined(_TARGET_ARM64_)
465 // Any structs that are larger than MAX_PASS_MULTIREG_BYTES are always passed by reference
466 if (structSize > MAX_PASS_MULTIREG_BYTES)
468 // This struct is passed by reference using a single 'slot'
469 return TARGET_POINTER_SIZE;
473 // Is the struct larger than 16 bytes
474 if (structSize > (2 * TARGET_POINTER_SIZE))
476 var_types hfaType = GetHfaType(argClass); // set to float or double if it is an HFA, otherwise TYP_UNDEF
477 bool isHfa = (hfaType != TYP_UNDEF);
480 // This struct is passed by reference using a single 'slot'
481 return TARGET_POINTER_SIZE;
484 // otherwise will we pass this struct by value in multiple registers
486 #elif defined(_TARGET_ARM_)
487 // otherwise will we pass this struct by value in multiple registers
489 NYI("unknown target");
490 #endif // defined(_TARGET_XXX_)
491 #endif // FEATURE_MULTIREG_ARGS
493 // we pass this struct by value in multiple registers
494 return (unsigned)roundUp(structSize, TARGET_POINTER_SIZE);
498 unsigned argSize = sizeof(int) * genTypeStSz(argType);
499 assert(0 < argSize && argSize <= sizeof(__int64));
500 return (unsigned)roundUp(argSize, TARGET_POINTER_SIZE);
505 /*****************************************************************************/
507 GenTree* Compiler::eeGetPInvokeCookie(CORINFO_SIG_INFO* szMetaSig)
509 void *cookie, *pCookie;
510 cookie = info.compCompHnd->GetCookieForPInvokeCalliSig(szMetaSig, &pCookie);
511 assert((cookie == nullptr) != (pCookie == nullptr));
513 return gtNewIconEmbHndNode(cookie, pCookie, GTF_ICON_PINVKI_HDL, szMetaSig);
516 //------------------------------------------------------------------------
517 // eeGetArrayDataOffset: Gets the offset of a SDArray's first element
520 // type - The array element type
523 // The offset to the first array element.
525 unsigned Compiler::eeGetArrayDataOffset(var_types type)
527 return varTypeIsGC(type) ? eeGetEEInfo()->offsetOfObjArrayData : offsetof(CORINFO_Array, u1Elems);
530 //------------------------------------------------------------------------
531 // eeGetMDArrayDataOffset: Gets the offset of a MDArray's first element
534 // type - The array element type
535 // rank - The array rank
538 // The offset to the first array element.
541 // The rank should be greater than 0.
543 unsigned Compiler::eeGetMDArrayDataOffset(var_types type, unsigned rank)
546 // Note that below we're specifically using genTypeSize(TYP_INT) because array
547 // indices are not native int.
548 return eeGetArrayDataOffset(type) + 2 * genTypeSize(TYP_INT) * rank;
551 /*****************************************************************************/
553 void Compiler::eeGetStmtOffsets()
555 ULONG32 offsetsCount;
557 ICorDebugInfo::BoundaryTypes offsetsImplicit;
559 info.compCompHnd->getBoundaries(info.compMethodHnd, &offsetsCount, &offsets, &offsetsImplicit);
561 /* Set the implicit boundaries */
563 info.compStmtOffsetsImplicit = (ICorDebugInfo::BoundaryTypes)offsetsImplicit;
565 /* Process the explicit boundaries */
567 info.compStmtOffsetsCount = 0;
569 if (offsetsCount == 0)
574 info.compStmtOffsets = new (this, CMK_DebugInfo) IL_OFFSET[offsetsCount];
576 for (unsigned i = 0; i < offsetsCount; i++)
578 if (offsets[i] > info.compILCodeSize)
583 info.compStmtOffsets[info.compStmtOffsetsCount] = offsets[i];
584 info.compStmtOffsetsCount++;
587 info.compCompHnd->freeArray(offsets);
590 /*****************************************************************************
592 * Debugging support - Local var info
595 void Compiler::eeSetLVcount(unsigned count)
597 assert(opts.compScopeInfo);
599 JITDUMP("VarLocInfo count is %d\n", count);
604 eeVars = (VarResultInfo*)info.compCompHnd->allocateArray(eeVarsCount * sizeof(eeVars[0]));
612 void Compiler::eeSetLVinfo(unsigned which,
613 UNATIVE_OFFSET startOffs,
614 UNATIVE_OFFSET length,
619 const Compiler::siVarLoc& varLoc)
621 // ICorDebugInfo::VarLoc and Compiler::siVarLoc have to overlap
622 // This is checked in siInit()
624 assert(opts.compScopeInfo);
625 assert(eeVarsCount > 0);
626 assert(which < eeVarsCount);
628 if (eeVars != nullptr)
630 eeVars[which].startOffset = startOffs;
631 eeVars[which].endOffset = startOffs + length;
632 eeVars[which].varNumber = varNum;
633 eeVars[which].loc = varLoc;
637 void Compiler::eeSetLVdone()
639 // necessary but not sufficient condition that the 2 struct definitions overlap
640 assert(sizeof(eeVars[0]) == sizeof(ICorDebugInfo::NativeVarInfo));
641 assert(opts.compScopeInfo);
646 eeDispVars(info.compMethodHnd, eeVarsCount, (ICorDebugInfo::NativeVarInfo*)eeVars);
650 info.compCompHnd->setVars(info.compMethodHnd, eeVarsCount, (ICorDebugInfo::NativeVarInfo*)eeVars);
652 eeVars = nullptr; // We give up ownership after setVars()
655 void Compiler::eeGetVars()
657 ICorDebugInfo::ILVarInfo* varInfoTable;
658 ULONG32 varInfoCount;
661 info.compCompHnd->getVars(info.compMethodHnd, &varInfoCount, &varInfoTable, &extendOthers);
666 printf("getVars() returned cVars = %d, extendOthers = %s\n", varInfoCount, extendOthers ? "true" : "false");
670 // Over allocate in case extendOthers is set.
672 SIZE_T varInfoCountExtra = varInfoCount;
675 varInfoCountExtra += info.compLocalsCount;
678 if (varInfoCountExtra == 0)
683 info.compVarScopes = new (this, CMK_DebugInfo) VarScopeDsc[varInfoCountExtra];
685 VarScopeDsc* localVarPtr = info.compVarScopes;
686 ICorDebugInfo::ILVarInfo* v = varInfoTable;
688 for (unsigned i = 0; i < varInfoCount; i++, v++)
693 printf("var:%d start:%d end:%d\n", v->varNumber, v->startOffset, v->endOffset);
697 if (v->startOffset >= v->endOffset)
702 assert(v->startOffset <= info.compILCodeSize);
703 assert(v->endOffset <= info.compILCodeSize);
705 localVarPtr->vsdLifeBeg = v->startOffset;
706 localVarPtr->vsdLifeEnd = v->endOffset;
707 localVarPtr->vsdLVnum = i;
708 localVarPtr->vsdVarNum = compMapILvarNum(v->varNumber);
711 localVarPtr->vsdName = gtGetLclVarName(localVarPtr->vsdVarNum);
715 info.compVarScopesCount++;
718 /* If extendOthers is set, then assume the scope of unreported vars
719 is the entire method. Note that this will cause fgExtendDbgLifetimes()
720 to zero-initalize all of them. This will be expensive if it's used
721 for too many variables.
725 // Allocate a bit-array for all the variables and initialize to false
727 bool* varInfoProvided = (bool*)compGetMem(info.compLocalsCount * sizeof(varInfoProvided[0]));
729 for (i = 0; i < info.compLocalsCount; i++)
731 varInfoProvided[i] = false;
734 // Find which vars have absolutely no varInfo provided
736 for (i = 0; i < info.compVarScopesCount; i++)
738 varInfoProvided[info.compVarScopes[i].vsdVarNum] = true;
741 // Create entries for the variables with no varInfo
743 for (unsigned varNum = 0; varNum < info.compLocalsCount; varNum++)
745 if (varInfoProvided[varNum])
750 // Create a varInfo with scope over the entire method
752 localVarPtr->vsdLifeBeg = 0;
753 localVarPtr->vsdLifeEnd = info.compILCodeSize;
754 localVarPtr->vsdVarNum = varNum;
755 localVarPtr->vsdLVnum = info.compVarScopesCount;
758 localVarPtr->vsdName = gtGetLclVarName(localVarPtr->vsdVarNum);
762 info.compVarScopesCount++;
766 assert(localVarPtr <= info.compVarScopes + varInfoCountExtra);
768 if (varInfoCount != 0)
770 info.compCompHnd->freeArray(varInfoTable);
782 void Compiler::eeDispVar(ICorDebugInfo::NativeVarInfo* var)
784 const char* name = nullptr;
786 if (var->varNumber == (DWORD)ICorDebugInfo::VARARGS_HND_ILNUM)
788 name = "varargsHandle";
790 else if (var->varNumber == (DWORD)ICorDebugInfo::RETBUF_ILNUM)
794 else if (var->varNumber == (DWORD)ICorDebugInfo::TYPECTXT_ILNUM)
798 printf("%3d(%10s) : From %08Xh to %08Xh, in ", var->varNumber,
799 (VarNameToStr(name) == nullptr) ? "UNKNOWN" : VarNameToStr(name), var->startOffset, var->endOffset);
801 switch ((Compiler::siVarLocType)var->loc.vlType)
806 printf("%s", getRegName(var->loc.vlReg.vlrReg));
807 if (var->loc.vlType == (ICorDebugInfo::VarLocType)VLT_REG_BYREF)
815 if ((int)var->loc.vlStk.vlsBaseReg != (int)ICorDebugInfo::REGNUM_AMBIENT_SP)
817 printf("%s[%d] (1 slot)", getRegName(var->loc.vlStk.vlsBaseReg), var->loc.vlStk.vlsOffset);
821 printf(STR_SPBASE "'[%d] (1 slot)", var->loc.vlStk.vlsOffset);
823 if (var->loc.vlType == (ICorDebugInfo::VarLocType)VLT_REG_BYREF)
829 #ifndef _TARGET_AMD64_
831 printf("%s-%s", getRegName(var->loc.vlRegReg.vlrrReg1), getRegName(var->loc.vlRegReg.vlrrReg2));
835 if ((int)var->loc.vlRegStk.vlrsStk.vlrssBaseReg != (int)ICorDebugInfo::REGNUM_AMBIENT_SP)
837 printf("%s-%s[%d]", getRegName(var->loc.vlRegStk.vlrsReg),
838 getRegName(var->loc.vlRegStk.vlrsStk.vlrssBaseReg), var->loc.vlRegStk.vlrsStk.vlrssOffset);
842 printf("%s-" STR_SPBASE "'[%d]", getRegName(var->loc.vlRegStk.vlrsReg),
843 var->loc.vlRegStk.vlrsStk.vlrssOffset);
848 unreached(); // unexpected
851 if ((int)var->loc.vlStk2.vls2BaseReg != (int)ICorDebugInfo::REGNUM_AMBIENT_SP)
853 printf("%s[%d] (2 slots)", getRegName(var->loc.vlStk2.vls2BaseReg), var->loc.vlStk2.vls2Offset);
857 printf(STR_SPBASE "'[%d] (2 slots)", var->loc.vlStk2.vls2Offset);
862 printf("ST(L-%d)", var->loc.vlFPstk.vlfReg);
866 printf("fxd_va[%d]", var->loc.vlFixedVarArg.vlfvOffset);
868 #endif // !_TARGET_AMD64_
871 unreached(); // unexpected
877 // Same parameters as ICorStaticInfo::setVars().
878 void Compiler::eeDispVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo* vars)
880 printf("*************** Variable debug info\n");
881 printf("%d vars\n", cVars);
882 for (unsigned i = 0; i < cVars; i++)
889 /*****************************************************************************
891 * Debugging support - Line number info
894 void Compiler::eeSetLIcount(unsigned count)
896 assert(opts.compDbgInfo);
898 eeBoundariesCount = count;
899 if (eeBoundariesCount)
901 eeBoundaries = (boundariesDsc*)info.compCompHnd->allocateArray(eeBoundariesCount * sizeof(eeBoundaries[0]));
905 eeBoundaries = nullptr;
909 void Compiler::eeSetLIinfo(
910 unsigned which, UNATIVE_OFFSET nativeOffset, IL_OFFSET ilOffset, bool stkEmpty, bool callInstruction)
912 assert(opts.compDbgInfo);
913 assert(eeBoundariesCount > 0);
914 assert(which < eeBoundariesCount);
916 if (eeBoundaries != nullptr)
918 eeBoundaries[which].nativeIP = nativeOffset;
919 eeBoundaries[which].ilOffset = ilOffset;
920 eeBoundaries[which].sourceReason = stkEmpty ? ICorDebugInfo::STACK_EMPTY : 0;
921 eeBoundaries[which].sourceReason |= callInstruction ? ICorDebugInfo::CALL_INSTRUCTION : 0;
925 void Compiler::eeSetLIdone()
927 assert(opts.compDbgInfo);
936 // necessary but not sufficient condition that the 2 struct definitions overlap
937 assert(sizeof(eeBoundaries[0]) == sizeof(ICorDebugInfo::OffsetMapping));
939 info.compCompHnd->setBoundaries(info.compMethodHnd, eeBoundariesCount, (ICorDebugInfo::OffsetMapping*)eeBoundaries);
941 eeBoundaries = nullptr; // we give up ownership after setBoundaries();
947 void Compiler::eeDispILOffs(IL_OFFSET offs)
949 const char* specialOffs[] = {"EPILOG", "PROLOG", "NO_MAP"};
951 switch ((int)offs) // Need the cast since offs is unsigned and the case statements are comparing to signed.
953 case ICorDebugInfo::EPILOG:
954 case ICorDebugInfo::PROLOG:
955 case ICorDebugInfo::NO_MAPPING:
956 assert(DWORD(ICorDebugInfo::EPILOG) + 1 == (unsigned)ICorDebugInfo::PROLOG);
957 assert(DWORD(ICorDebugInfo::EPILOG) + 2 == (unsigned)ICorDebugInfo::NO_MAPPING);
959 specialOffsNum = offs - DWORD(ICorDebugInfo::EPILOG);
960 printf("%s", specialOffs[specialOffsNum]);
963 printf("0x%04X", offs);
968 void Compiler::eeDispLineInfo(const boundariesDsc* line)
972 eeDispILOffs(line->ilOffset);
974 printf(" : 0x%08X", line->nativeIP);
975 if (line->sourceReason != 0)
977 // It seems like it should probably never be zero since ICorDebugInfo::SOURCE_TYPE_INVALID is zero.
978 // However, the JIT has always generated this and printed "stack non-empty".
981 if ((line->sourceReason & ICorDebugInfo::STACK_EMPTY) != 0)
983 printf("STACK_EMPTY ");
985 if ((line->sourceReason & ICorDebugInfo::CALL_INSTRUCTION) != 0)
987 printf("CALL_INSTRUCTION ");
989 if ((line->sourceReason & ICorDebugInfo::CALL_SITE) != 0)
991 printf("CALL_SITE ");
997 // We don't expect to see any other bits.
998 assert((line->sourceReason & ~(ICorDebugInfo::STACK_EMPTY | ICorDebugInfo::CALL_INSTRUCTION)) == 0);
1001 void Compiler::eeDispLineInfos()
1003 printf("IP mapping count : %d\n", eeBoundariesCount); // this might be zero
1004 for (unsigned i = 0; i < eeBoundariesCount; i++)
1006 eeDispLineInfo(&eeBoundaries[i]);
1012 /*****************************************************************************
1014 * ICorJitInfo wrapper functions
1016 * In many cases here, we don't tell the VM about various unwind or EH information if
1017 * we're an altjit for an unexpected architecture. If it's not a same architecture JIT
1018 * (e.g., host AMD64, target ARM64), then VM will get confused anyway.
1021 void Compiler::eeReserveUnwindInfo(BOOL isFunclet, BOOL isColdCode, ULONG unwindSize)
1026 printf("reserveUnwindInfo(isFunclet=%s, isColdCode=%s, unwindSize=0x%x)\n", isFunclet ? "TRUE" : "FALSE",
1027 isColdCode ? "TRUE" : "FALSE", unwindSize);
1031 if (info.compMatchedVM)
1033 info.compCompHnd->reserveUnwindInfo(isFunclet, isColdCode, unwindSize);
1037 void Compiler::eeAllocUnwindInfo(BYTE* pHotCode,
1043 CorJitFuncKind funcKind)
1048 printf("allocUnwindInfo(pHotCode=0x%p, pColdCode=0x%p, startOffset=0x%x, endOffset=0x%x, unwindSize=0x%x, "
1049 "pUnwindBlock=0x%p, funKind=%d",
1050 dspPtr(pHotCode), dspPtr(pColdCode), startOffset, endOffset, unwindSize, dspPtr(pUnwindBlock), funcKind);
1053 case CORJIT_FUNC_ROOT:
1054 printf(" (main function)");
1056 case CORJIT_FUNC_HANDLER:
1057 printf(" (handler)");
1059 case CORJIT_FUNC_FILTER:
1060 printf(" (filter)");
1063 printf(" (ILLEGAL)");
1070 if (info.compMatchedVM)
1072 info.compCompHnd->allocUnwindInfo(pHotCode, pColdCode, startOffset, endOffset, unwindSize, pUnwindBlock,
1077 void Compiler::eeSetEHcount(unsigned cEH)
1082 printf("setEHcount(cEH=%u)\n", cEH);
1086 if (info.compMatchedVM)
1088 info.compCompHnd->setEHcount(cEH);
1092 void Compiler::eeSetEHinfo(unsigned EHnumber, const CORINFO_EH_CLAUSE* clause)
1095 if (opts.dspEHTable)
1097 dispOutgoingEHClause(EHnumber, *clause);
1101 if (info.compMatchedVM)
1103 info.compCompHnd->setEHinfo(EHnumber, clause);
1107 WORD Compiler::eeGetRelocTypeHint(void* target)
1109 if (info.compMatchedVM)
1111 return info.compCompHnd->getRelocTypeHint(target);
1120 CORINFO_FIELD_HANDLE Compiler::eeFindJitDataOffs(unsigned dataOffs)
1122 // Data offsets are marked by the fact that the low two bits are 0b01 0x1
1123 assert(dataOffs < 0x40000000);
1124 return (CORINFO_FIELD_HANDLE)(size_t)((dataOffs << iaut_SHIFT) | iaut_DATA_OFFSET);
1127 bool Compiler::eeIsJitDataOffs(CORINFO_FIELD_HANDLE field)
1129 // if 'field' is a jit data offset it has to fit into a 32-bit unsigned int
1130 unsigned value = static_cast<unsigned>(reinterpret_cast<uintptr_t>(field));
1131 if (((CORINFO_FIELD_HANDLE)(size_t)value) != field)
1133 return false; // upper bits were set, not a jit data offset
1136 // Data offsets are marked by the fact that the low two bits are 0b01 0x1
1137 return (value & iaut_MASK) == iaut_DATA_OFFSET;
1140 int Compiler::eeGetJitDataOffs(CORINFO_FIELD_HANDLE field)
1142 // Data offsets are marked by the fact that the low two bits are 0b01 0x1
1143 if (eeIsJitDataOffs(field))
1145 unsigned dataOffs = static_cast<unsigned>(reinterpret_cast<uintptr_t>(field));
1146 assert(((CORINFO_FIELD_HANDLE)(size_t)dataOffs) == field);
1147 assert(dataOffs < 0x40000000);
1148 return (static_cast<int>(reinterpret_cast<intptr_t>(field))) >> iaut_SHIFT;
1156 /*****************************************************************************
1158 * ICorStaticInfo wrapper functions
1161 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
1164 void Compiler::dumpSystemVClassificationType(SystemVClassificationType ct)
1168 case SystemVClassificationTypeUnknown:
1171 case SystemVClassificationTypeStruct:
1174 case SystemVClassificationTypeNoClass:
1177 case SystemVClassificationTypeMemory:
1180 case SystemVClassificationTypeInteger:
1183 case SystemVClassificationTypeIntegerReference:
1184 printf("IntegerReference");
1186 case SystemVClassificationTypeIntegerByRef:
1187 printf("IntegerByReference");
1189 case SystemVClassificationTypeSSE:
1199 void Compiler::eeGetSystemVAmd64PassStructInRegisterDescriptor(
1200 /*IN*/ CORINFO_CLASS_HANDLE structHnd,
1201 /*OUT*/ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr)
1203 bool ok = info.compCompHnd->getSystemVAmd64PassStructInRegisterDescriptor(structHnd, structPassInRegDescPtr);
1209 printf("**** getSystemVAmd64PassStructInRegisterDescriptor(0x%x (%s), ...) =>\n", dspPtr(structHnd),
1210 eeGetClassName(structHnd));
1211 printf(" passedInRegisters = %s\n", dspBool(structPassInRegDescPtr->passedInRegisters));
1212 if (structPassInRegDescPtr->passedInRegisters)
1214 printf(" eightByteCount = %d\n", structPassInRegDescPtr->eightByteCount);
1215 for (unsigned int i = 0; i < structPassInRegDescPtr->eightByteCount; i++)
1217 printf(" eightByte #%d -- classification: ", i);
1218 dumpSystemVClassificationType(structPassInRegDescPtr->eightByteClassifications[i]);
1219 printf(", byteSize: %d, byteOffset: %d\n", structPassInRegDescPtr->eightByteSizes[i],
1220 structPassInRegDescPtr->eightByteOffsets[i]);
1227 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
1229 bool Compiler::eeTryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken)
1231 return info.compCompHnd->tryResolveToken(resolvedToken);
1234 bool Compiler::eeRunWithErrorTrapImp(void (*function)(void*), void* param)
1236 return info.compCompHnd->runWithErrorTrap(function, param);
1239 /*****************************************************************************
1244 #if defined(DEBUG) || defined(FEATURE_JIT_METHOD_PERF) || defined(FEATURE_SIMD) || defined(FEATURE_TRACELOGGING)
1246 /*****************************************************************************/
1248 // static helper names - constant array
1249 const char* jitHlpFuncTable[CORINFO_HELP_COUNT] = {
1250 #define JITHELPER(code, pfnHelper, sig) #code,
1251 #define DYNAMICJITHELPER(code, pfnHelper, sig) #code,
1252 #include "jithelpers.h"
1255 /*****************************************************************************
1257 * Filter wrapper to handle exception filtering.
1258 * On Unix compilers don't support SEH.
1261 struct FilterSuperPMIExceptionsParam_ee_il
1264 Compiler::Info* pJitInfo;
1265 CORINFO_FIELD_HANDLE field;
1266 CORINFO_METHOD_HANDLE method;
1267 CORINFO_CLASS_HANDLE clazz;
1268 const char** classNamePtr;
1269 const char* fieldOrMethodOrClassNamePtr;
1270 EXCEPTION_POINTERS exceptionPointers;
1273 static LONG FilterSuperPMIExceptions_ee_il(PEXCEPTION_POINTERS pExceptionPointers, LPVOID lpvParam)
1275 FilterSuperPMIExceptionsParam_ee_il* pSPMIEParam = (FilterSuperPMIExceptionsParam_ee_il*)lpvParam;
1276 pSPMIEParam->exceptionPointers = *pExceptionPointers;
1278 if (pSPMIEParam->pThis->IsSuperPMIException(pExceptionPointers->ExceptionRecord->ExceptionCode))
1280 return EXCEPTION_EXECUTE_HANDLER;
1283 return EXCEPTION_CONTINUE_SEARCH;
1286 const char* Compiler::eeGetMethodName(CORINFO_METHOD_HANDLE method, const char** classNamePtr)
1288 if (eeGetHelperNum(method))
1290 if (classNamePtr != nullptr)
1292 *classNamePtr = "HELPER";
1294 CorInfoHelpFunc ftnNum = eeGetHelperNum(method);
1295 const char* name = info.compCompHnd->getHelperName(ftnNum);
1297 // If it's something unknown from a RET VM, or from SuperPMI, then use our own helper name table.
1298 if ((strcmp(name, "AnyJITHelper") == 0) || (strcmp(name, "Yickish helper name") == 0))
1300 if ((unsigned)ftnNum < CORINFO_HELP_COUNT)
1302 name = jitHlpFuncTable[ftnNum];
1308 if (eeIsNativeMethod(method))
1310 if (classNamePtr != nullptr)
1312 *classNamePtr = "NATIVE";
1314 method = eeGetMethodHandleForNative(method);
1317 FilterSuperPMIExceptionsParam_ee_il param;
1320 param.pJitInfo = &info;
1321 param.method = method;
1322 param.classNamePtr = classNamePtr;
1324 PAL_TRY(FilterSuperPMIExceptionsParam_ee_il*, pParam, ¶m)
1326 pParam->fieldOrMethodOrClassNamePtr =
1327 pParam->pJitInfo->compCompHnd->getMethodName(pParam->method, pParam->classNamePtr);
1329 PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_ee_il)
1331 if (param.classNamePtr != nullptr)
1333 *(param.classNamePtr) = "hackishClassName";
1336 param.fieldOrMethodOrClassNamePtr = "hackishMethodName";
1340 return param.fieldOrMethodOrClassNamePtr;
1343 const char* Compiler::eeGetFieldName(CORINFO_FIELD_HANDLE field, const char** classNamePtr)
1345 FilterSuperPMIExceptionsParam_ee_il param;
1348 param.pJitInfo = &info;
1349 param.field = field;
1350 param.classNamePtr = classNamePtr;
1352 PAL_TRY(FilterSuperPMIExceptionsParam_ee_il*, pParam, ¶m)
1354 pParam->fieldOrMethodOrClassNamePtr =
1355 pParam->pJitInfo->compCompHnd->getFieldName(pParam->field, pParam->classNamePtr);
1357 PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_ee_il)
1359 param.fieldOrMethodOrClassNamePtr = "hackishFieldName";
1363 return param.fieldOrMethodOrClassNamePtr;
1366 const char* Compiler::eeGetClassName(CORINFO_CLASS_HANDLE clsHnd)
1368 FilterSuperPMIExceptionsParam_ee_il param;
1371 param.pJitInfo = &info;
1372 param.clazz = clsHnd;
1374 PAL_TRY(FilterSuperPMIExceptionsParam_ee_il*, pParam, ¶m)
1376 pParam->fieldOrMethodOrClassNamePtr = pParam->pJitInfo->compCompHnd->getClassName(pParam->clazz);
1378 PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_ee_il)
1380 param.fieldOrMethodOrClassNamePtr = "hackishClassName";
1383 return param.fieldOrMethodOrClassNamePtr;
1386 #endif // DEBUG || FEATURE_JIT_METHOD_PERF
1390 const wchar_t* Compiler::eeGetCPString(size_t strHandle)
1395 char buff[512 + sizeof(CORINFO_String)];
1397 // make this bulletproof, so it works even if we are wrong.
1398 if (ReadProcessMemory(GetCurrentProcess(), (void*)strHandle, buff, 4, nullptr) == 0)
1403 CORINFO_String* asString = *((CORINFO_String**)strHandle);
1405 if (ReadProcessMemory(GetCurrentProcess(), asString, buff, sizeof(buff), nullptr) == 0)
1410 if (asString->stringLen >= 255 || asString->chars[asString->stringLen] != 0)
1415 return (asString->chars);
1416 #endif // FEATURE_PAL