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(PLATFORM_UNIX)
24 #include <io.h> // For _dup, _setmode
25 #include <fcntl.h> // For _O_TEXT
28 /*****************************************************************************/
30 FILE* jitstdout = nullptr;
32 ICorJitHost* g_jitHost = nullptr;
33 static CILJit* ILJitter = 0; // The one and only JITTER I return
34 bool g_jitInitialized = false;
35 #ifndef FEATURE_MERGE_JIT_AND_ENGINE
36 HINSTANCE g_hInst = NULL;
37 #endif // FEATURE_MERGE_JIT_AND_ENGINE
39 /*****************************************************************************/
50 (JitOptions *)NULL // lastDummyField.
55 /*****************************************************************************/
58 void __stdcall jitStartup(ICorJitHost* jitHost)
67 assert(!JitConfig.isInitialized());
68 JitConfig.initialize(jitHost);
70 #if defined(PLATFORM_UNIX)
71 jitstdout = procstdout();
73 if (jitstdout == nullptr)
75 int stdoutFd = _fileno(procstdout());
76 // Check fileno error output(s) -1 may overlap with errno result
77 // but is included for completness.
78 // We want to detect the case where the initial handle is null
79 // or bogus and avoid making further calls.
80 if ((stdoutFd != -1) && (stdoutFd != -2) && (errno != EINVAL))
82 int jitstdoutFd = _dup(_fileno(procstdout()));
83 // Check the error status returned by dup.
84 if (jitstdoutFd != -1)
86 _setmode(jitstdoutFd, _O_TEXT);
87 jitstdout = _fdopen(jitstdoutFd, "w");
88 assert(jitstdout != nullptr);
90 // Prevent the FILE* from buffering its output in order to avoid calls to
91 // `fflush()` throughout the code.
92 setvbuf(jitstdout, nullptr, _IONBF, 0);
97 // If jitstdout is still null, fallback to whatever procstdout() was
99 if (jitstdout == nullptr)
101 jitstdout = procstdout();
103 #endif // PLATFORM_UNIX
105 #ifdef FEATURE_TRACELOGGING
106 JitTelemetry::NotifyDllProcessAttach();
108 Compiler::compStartup();
110 g_jitInitialized = true;
115 if (!g_jitInitialized)
120 Compiler::compShutdown();
122 if (jitstdout != procstdout())
127 #ifdef FEATURE_TRACELOGGING
128 JitTelemetry::NotifyDllProcessDetach();
132 #ifndef FEATURE_MERGE_JIT_AND_ENGINE
135 BOOL WINAPI DllMain(HANDLE hInstance, DWORD dwReason, LPVOID pvReserved)
137 if (dwReason == DLL_PROCESS_ATTACH)
139 g_hInst = (HINSTANCE)hInstance;
140 DisableThreadLibraryCalls((HINSTANCE)hInstance);
141 #if defined(SELF_NO_HOST) && COR_JIT_EE_VERSION <= 460
142 jitStartup(JitHost::getJitHost());
145 else if (dwReason == DLL_PROCESS_DETACH)
153 HINSTANCE GetModuleInst()
159 void __stdcall sxsJitStartup(CoreClrCallbacks const & cccallbacks)
162 InitUtilcode(cccallbacks);
165 #if COR_JIT_EE_VERSION <= 460
166 jitStartup(JitHost::getJitHost());
170 #endif // !FEATURE_MERGE_JIT_AND_ENGINE
172 /*****************************************************************************/
174 struct CILJitSingletonAllocator { int x; };
175 const CILJitSingletonAllocator CILJitSingleton = { 0 };
177 void *__cdecl operator new(size_t, const CILJitSingletonAllocator&)
179 static char CILJitBuff[sizeof(CILJit)];
183 ICorJitCompiler* g_realJitCompiler = nullptr;
185 ICorJitCompiler* __stdcall getJit()
189 ILJitter = new (CILJitSingleton) CILJit();
194 /*****************************************************************************/
196 // Information kept in thread-local storage. This is used in the noway_assert exceptional path.
197 // If you are using it more broadly in retail code, you would need to understand the
198 // performance implications of accessing TLS.
200 // If the JIT is being statically linked, these methods must be implemented by the consumer.
201 #if !defined(FEATURE_MERGE_JIT_AND_ENGINE) || !defined(FEATURE_IMPLICIT_TLS)
203 __declspec(thread) void* gJitTls = nullptr;
205 static void* GetJitTls()
210 void SetJitTls(void* value)
215 #else // !defined(FEATURE_MERGE_JIT_AND_ENGINE) || !defined(FEATURE_IMPLICIT_TLS)
220 void SetJitTls(void* value);
223 #endif // // defined(FEATURE_MERGE_JIT_AND_ENGINE) && defined(FEATURE_IMPLICIT_TLS)
227 JitTls::JitTls(ICorJitInfo* jitInfo)
228 : m_compiler(nullptr)
231 m_next = reinterpret_cast<JitTls*>(GetJitTls());
240 LogEnv* JitTls::GetLogEnv()
242 return &reinterpret_cast<JitTls*>(GetJitTls())->m_logEnv;
245 Compiler* JitTls::GetCompiler()
247 return reinterpret_cast<JitTls*>(GetJitTls())->m_compiler;
250 void JitTls::SetCompiler(Compiler* compiler)
252 reinterpret_cast<JitTls*>(GetJitTls())->m_compiler = compiler;
255 #else // defined(DEBUG)
257 JitTls::JitTls(ICorJitInfo* jitInfo)
265 Compiler* JitTls::GetCompiler()
267 return reinterpret_cast<Compiler*>(GetJitTls());
270 void JitTls::SetCompiler(Compiler* compiler)
275 #endif // !defined(DEBUG)
277 //****************************************************************************
278 // The main JIT function for the 32 bit JIT. See code:ICorJitCompiler#EEToJitInterface for more on the EE-JIT
279 // interface. Things really don't get going inside the JIT until the code:Compiler::compCompile#Phases
280 // method. Usually that is where you want to go.
282 CorJitResult CILJit::compileMethod (
283 ICorJitInfo* compHnd,
284 CORINFO_METHOD_INFO* methodInfo,
286 BYTE ** entryAddress,
287 ULONG * nativeSizeOfCode)
289 if (g_realJitCompiler != nullptr)
291 return g_realJitCompiler->compileMethod(compHnd, methodInfo, flags, entryAddress, nativeSizeOfCode);
294 CORJIT_FLAGS jitFlags = { 0 };
296 DWORD jitFlagsSize = 0;
297 #if COR_JIT_EE_VERSION > 460
298 if (flags == CORJIT_FLG_CALL_GETJITFLAGS)
300 jitFlagsSize = compHnd->getJitFlags(&jitFlags, sizeof(jitFlags));
304 assert(jitFlagsSize <= sizeof(jitFlags));
305 if (jitFlagsSize == 0)
307 jitFlags.corJitFlags = flags;
311 void * methodCodePtr = NULL;
312 CORINFO_METHOD_HANDLE methodHandle = methodInfo->ftn;
314 JitTls jitTls(compHnd); // Initialize any necessary thread-local state
316 assert(methodInfo->ILCode);
318 result = jitNativeCode(methodHandle,
327 if (result == CORJIT_OK)
328 *entryAddress = (BYTE*)methodCodePtr;
330 return CorJitResult(result);
333 /*****************************************************************************
334 * Notification from VM to clear any caches
336 void CILJit::clearCache ( void )
338 if (g_realJitCompiler != nullptr)
340 g_realJitCompiler->clearCache();
347 /*****************************************************************************
348 * Notify vm that we have something to clean up
350 BOOL CILJit::isCacheCleanupRequired ( void )
354 if (g_realJitCompiler != nullptr)
356 if (g_realJitCompiler->isCacheCleanupRequired())
364 void CILJit::ProcessShutdownWork(ICorStaticInfo* statInfo)
366 if (g_realJitCompiler != nullptr)
368 g_realJitCompiler->ProcessShutdownWork(statInfo);
369 // Continue, by shutting down this JIT as well.
372 #ifdef FEATURE_MERGE_JIT_AND_ENGINE
376 Compiler::ProcessShutdownWork(statInfo);
379 /*****************************************************************************
380 * Verify the JIT/EE interface identifier.
382 void CILJit::getVersionIdentifier(GUID* versionIdentifier)
384 if (g_realJitCompiler != nullptr)
386 g_realJitCompiler->getVersionIdentifier(versionIdentifier);
390 assert(versionIdentifier != nullptr);
391 memcpy(versionIdentifier, &JITEEVersionIdentifier, sizeof(GUID));
394 /*****************************************************************************
395 * Determine the maximum length of SIMD vector supported by this JIT.
397 unsigned CILJit::getMaxIntrinsicSIMDVectorLength(DWORD cpuCompileFlags)
399 if (g_realJitCompiler != nullptr)
401 return g_realJitCompiler->getMaxIntrinsicSIMDVectorLength(cpuCompileFlags);
404 #ifdef _TARGET_AMD64_
405 #ifdef FEATURE_AVX_SUPPORT
406 if (((cpuCompileFlags & CORJIT_FLG_PREJIT) == 0) &&
407 ((cpuCompileFlags & CORJIT_FLG_FEATURE_SIMD) != 0) &&
408 ((cpuCompileFlags & CORJIT_FLG_USE_AVX2) != 0))
410 if (JitConfig.EnableAVX() != 0)
415 #endif // FEATURE_AVX_SUPPORT
417 #else // !_TARGET_AMD64_
419 #endif // !_TARGET_AMD64_
422 void CILJit::setRealJit(ICorJitCompiler* realJitCompiler)
424 g_realJitCompiler = realJitCompiler;
428 /*****************************************************************************
429 * Returns the number of bytes required for the given type argument
432 unsigned Compiler::eeGetArgSize(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig)
434 #if defined(_TARGET_AMD64_)
436 // Everything fits into a single 'slot' size
437 // to accommodate irregular sized structs, they are passed byref
439 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
440 CORINFO_CLASS_HANDLE argClass;
441 CorInfoType argTypeJit = strip(info.compCompHnd->getArgType(sig, list, &argClass));
442 var_types argType = JITtype2varType(argTypeJit);
443 if (varTypeIsStruct(argType))
445 unsigned structSize = info.compCompHnd->getClassSize(argClass);
446 return structSize; // TODO: roundUp() needed here?
448 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
449 return sizeof(size_t);
451 #else // !_TARGET_AMD64_
453 CORINFO_CLASS_HANDLE argClass;
454 CorInfoType argTypeJit = strip(info.compCompHnd->getArgType(sig, list, &argClass));
455 var_types argType = JITtype2varType(argTypeJit);
457 if (varTypeIsStruct(argType))
459 unsigned structSize = info.compCompHnd->getClassSize(argClass);
461 // make certain the EE passes us back the right thing for refanys
462 assert(argTypeJit != CORINFO_TYPE_REFANY || structSize == 2*sizeof(void*));
464 #if FEATURE_MULTIREG_ARGS
465 // For each target that supports passing struct args in multiple registers
466 // apply the target specific rules for them here:
467 #if defined(_TARGET_ARM64_)
468 // Any structs that are larger than MAX_PASS_MULTIREG_BYTES are always passed by reference
469 if (structSize > MAX_PASS_MULTIREG_BYTES)
471 // This struct is passed by reference using a single 'slot'
472 return TARGET_POINTER_SIZE;
476 // Is the struct larger than 16 bytes
477 if (structSize > (2 * TARGET_POINTER_SIZE))
479 var_types hfaType = GetHfaType(argClass); // set to float or double if it is an HFA, otherwise TYP_UNDEF
480 bool isHfa = (hfaType != TYP_UNDEF);
483 // This struct is passed by reference using a single 'slot'
484 return TARGET_POINTER_SIZE;
488 // otherwise will we pass this struct by value in multiple registers
490 #elif defined(_TARGET_ARM_)
491 // otherwise will we pass this struct by value in multiple registers
493 NYI("unknown target");
494 #endif // defined(_TARGET_XXX_)
495 #endif // FEATURE_MULTIREG_ARGS
497 // we pass this struct by value in multiple registers
498 return (unsigned)roundUp(structSize, TARGET_POINTER_SIZE);
502 unsigned argSize = sizeof(int) * genTypeStSz(argType);
503 assert(0 < argSize && argSize <= sizeof(__int64));
504 return (unsigned)roundUp(argSize, TARGET_POINTER_SIZE);
509 /*****************************************************************************/
511 GenTreePtr Compiler::eeGetPInvokeCookie(CORINFO_SIG_INFO *szMetaSig)
513 void * cookie, * pCookie;
514 cookie = info.compCompHnd->GetCookieForPInvokeCalliSig(szMetaSig, &pCookie);
515 assert((cookie == NULL) != (pCookie == NULL));
517 return gtNewIconEmbHndNode(cookie, pCookie, GTF_ICON_PINVKI_HDL);
520 //------------------------------------------------------------------------
521 // eeGetArrayDataOffset: Gets the offset of a SDArray's first element
524 // type - The array element type
527 // The offset to the first array element.
529 unsigned Compiler::eeGetArrayDataOffset(var_types type)
531 return varTypeIsGC(type) ? eeGetEEInfo()->offsetOfObjArrayData
532 : offsetof(CORINFO_Array, u1Elems);
535 //------------------------------------------------------------------------
536 // eeGetMDArrayDataOffset: Gets the offset of a MDArray's first element
539 // type - The array element type
540 // rank - The array rank
543 // The offset to the first array element.
546 // The rank should be greater than 0.
548 unsigned Compiler::eeGetMDArrayDataOffset(var_types type, unsigned rank)
551 // Note that below we're specifically using genTypeSize(TYP_INT) because array
552 // indices are not native int.
553 return eeGetArrayDataOffset(type) + 2 * genTypeSize(TYP_INT) * rank;
556 /*****************************************************************************/
558 void Compiler::eeGetStmtOffsets()
560 ULONG32 offsetsCount;
562 ICorDebugInfo::BoundaryTypes offsetsImplicit;
564 info.compCompHnd->getBoundaries(info.compMethodHnd,
569 /* Set the implicit boundaries */
571 info.compStmtOffsetsImplicit = (ICorDebugInfo::BoundaryTypes)offsetsImplicit;
573 /* Process the explicit boundaries */
575 info.compStmtOffsetsCount = 0;
577 if (offsetsCount == 0)
580 info.compStmtOffsets = new (this, CMK_DebugInfo) IL_OFFSET[offsetsCount];
582 for (unsigned i = 0; i < offsetsCount; i++)
584 if (offsets[i] > info.compILCodeSize)
587 info.compStmtOffsets[info.compStmtOffsetsCount] = offsets[i];
588 info.compStmtOffsetsCount++;
591 info.compCompHnd->freeArray(offsets);
594 /*****************************************************************************
596 * Debugging support - Local var info
599 void Compiler::eeSetLVcount (unsigned count)
601 assert(opts.compScopeInfo);
603 JITDUMP("VarLocInfo count is %d\n", count);
607 eeVars = (VarResultInfo *)info.compCompHnd->allocateArray(eeVarsCount * sizeof(eeVars[0]));
612 void Compiler::eeSetLVinfo
614 UNATIVE_OFFSET startOffs,
615 UNATIVE_OFFSET length,
620 const Compiler::siVarLoc & varLoc)
622 // ICorDebugInfo::VarLoc and Compiler::siVarLoc have to overlap
623 // This is checked in siInit()
625 assert(opts.compScopeInfo);
626 assert(eeVarsCount > 0);
627 assert(which < eeVarsCount);
631 eeVars[which].startOffset = startOffs;
632 eeVars[which].endOffset = startOffs + length;
633 eeVars[which].varNumber = varNum;
634 eeVars[which].loc = varLoc;
638 void Compiler::eeSetLVdone()
640 // necessary but not sufficient condition that the 2 struct definitions overlap
641 assert(sizeof(eeVars[0]) == sizeof(ICorDebugInfo::NativeVarInfo));
642 assert(opts.compScopeInfo);
647 eeDispVars(info.compMethodHnd,
649 (ICorDebugInfo::NativeVarInfo *) eeVars);
653 info.compCompHnd->setVars(info.compMethodHnd,
655 (ICorDebugInfo::NativeVarInfo *) eeVars);
657 eeVars = NULL; // We give up ownership after setVars()
660 void Compiler::eeGetVars()
662 ICorDebugInfo::ILVarInfo * varInfoTable;
663 ULONG32 varInfoCount;
666 info.compCompHnd->getVars(info.compMethodHnd,
667 &varInfoCount, &varInfoTable, &extendOthers);
671 printf("getVars() returned cVars = %d, extendOthers = %s\n", varInfoCount, extendOthers ? "true" : "false");
674 // Over allocate in case extendOthers is set.
676 SIZE_T varInfoCountExtra = varInfoCount;
678 varInfoCountExtra += info.compLocalsCount;
680 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++)
692 printf("var:%d start:%d end:%d\n",
698 if (v->startOffset >= v->endOffset)
701 assert(v->startOffset <= info.compILCodeSize);
702 assert(v->endOffset <= info.compILCodeSize);
704 localVarPtr->vsdLifeBeg = v->startOffset;
705 localVarPtr->vsdLifeEnd = v->endOffset;
706 localVarPtr->vsdLVnum = i;
707 localVarPtr->vsdVarNum = compMapILvarNum(v->varNumber);
710 localVarPtr->vsdName = gtGetLclVarName(localVarPtr->vsdVarNum);
714 info.compVarScopesCount++;
717 /* If extendOthers is set, then assume the scope of unreported vars
718 is the entire method. Note that this will cause fgExtendDbgLifetimes()
719 to zero-initalize all of them. This will be expensive if it's used
720 for too many variables.
724 // Allocate a bit-array for all the variables and initialize to false
726 bool * varInfoProvided = (bool *)compGetMemA(info.compLocalsCount *
727 sizeof(varInfoProvided[0]));
729 for (i = 0; i < info.compLocalsCount; i++)
730 varInfoProvided[i] = false;
732 // Find which vars have absolutely no varInfo provided
734 for (i = 0; i < info.compVarScopesCount; i++)
735 varInfoProvided[info.compVarScopes[i].vsdVarNum] = true;
737 // Create entries for the variables with no varInfo
739 for (unsigned varNum = 0; varNum < info.compLocalsCount; varNum++)
741 if (varInfoProvided[varNum])
744 // Create a varInfo with scope over the entire method
746 localVarPtr->vsdLifeBeg = 0;
747 localVarPtr->vsdLifeEnd = info.compILCodeSize;
748 localVarPtr->vsdVarNum = varNum;
749 localVarPtr->vsdLVnum = info.compVarScopesCount;
752 localVarPtr->vsdName = gtGetLclVarName(localVarPtr->vsdVarNum);
756 info.compVarScopesCount++;
760 assert(localVarPtr <= info.compVarScopes + varInfoCountExtra);
762 if (varInfoCount != 0)
763 info.compCompHnd->freeArray(varInfoTable);
772 void Compiler::eeDispVar(ICorDebugInfo::NativeVarInfo* var)
774 const char* name = NULL;
776 if (var->varNumber == (DWORD)ICorDebugInfo::VARARGS_HND_ILNUM)
777 name = "varargsHandle";
778 else if (var->varNumber == (DWORD)ICorDebugInfo::RETBUF_ILNUM)
780 else if (var->varNumber == (DWORD)ICorDebugInfo::TYPECTXT_ILNUM)
783 printf("%3d(%10s) : From %08Xh to %08Xh, in ",
785 (VarNameToStr(name) == NULL) ? "UNKNOWN" : VarNameToStr(name),
789 switch (var->loc.vlType)
794 printf("%s", getRegName(var->loc.vlReg.vlrReg));
795 if (var->loc.vlType == (ICorDebugInfo::VarLocType)VLT_REG_BYREF)
803 if ((int) var->loc.vlStk.vlsBaseReg != (int) ICorDebugInfo::REGNUM_AMBIENT_SP)
805 printf("%s[%d] (1 slot)", getRegName(var->loc.vlStk.vlsBaseReg),
806 var->loc.vlStk.vlsOffset);
810 printf(STR_SPBASE "'[%d] (1 slot)", var->loc.vlStk.vlsOffset);
812 if (var->loc.vlType == (ICorDebugInfo::VarLocType)VLT_REG_BYREF)
818 #ifndef _TARGET_AMD64_
820 printf("%s-%s", getRegName(var->loc.vlRegReg.vlrrReg1),
821 getRegName(var->loc.vlRegReg.vlrrReg2));
825 if ((int) var->loc.vlRegStk.vlrsStk.vlrssBaseReg != (int) ICorDebugInfo::REGNUM_AMBIENT_SP)
827 printf("%s-%s[%d]", getRegName(var->loc.vlRegStk.vlrsReg),
828 getRegName(var->loc.vlRegStk.vlrsStk.vlrssBaseReg),
829 var->loc.vlRegStk.vlrsStk.vlrssOffset);
833 printf("%s-" STR_SPBASE "'[%d]", getRegName(var->loc.vlRegStk.vlrsReg),
834 var->loc.vlRegStk.vlrsStk.vlrssOffset);
839 unreached(); // unexpected
842 if ((int) var->loc.vlStk2.vls2BaseReg != (int) ICorDebugInfo::REGNUM_AMBIENT_SP)
844 printf("%s[%d] (2 slots)", getRegName(var->loc.vlStk2.vls2BaseReg),
845 var->loc.vlStk2.vls2Offset);
849 printf(STR_SPBASE "'[%d] (2 slots)", var->loc.vlStk2.vls2Offset);
854 printf("ST(L-%d)", var->loc.vlFPstk.vlfReg);
858 printf("fxd_va[%d]", var->loc.vlFixedVarArg.vlfvOffset);
860 #endif // !_TARGET_AMD64_
863 unreached(); // unexpected
869 // Same parameters as ICorStaticInfo::setVars().
870 void Compiler::eeDispVars(CORINFO_METHOD_HANDLE ftn,
872 ICorDebugInfo::NativeVarInfo* vars)
874 printf("*************** Variable debug info\n");
875 printf("%d vars\n", cVars);
876 for (unsigned i = 0; i < cVars; i++)
883 /*****************************************************************************
885 * Debugging support - Line number info
888 void Compiler::eeSetLIcount (unsigned count)
890 assert(opts.compDbgInfo);
892 eeBoundariesCount = count;
893 if (eeBoundariesCount)
894 eeBoundaries = (boundariesDsc *) info.compCompHnd->allocateArray(eeBoundariesCount * sizeof(eeBoundaries[0]));
899 void Compiler::eeSetLIinfo (unsigned which,
900 UNATIVE_OFFSET nativeOffset,
903 bool callInstruction)
905 assert(opts.compDbgInfo);
906 assert(eeBoundariesCount > 0);
907 assert(which < eeBoundariesCount);
909 if (eeBoundaries != NULL)
911 eeBoundaries[which].nativeIP = nativeOffset;
912 eeBoundaries[which].ilOffset = ilOffset;
913 eeBoundaries[which].sourceReason = stkEmpty ? ICorDebugInfo::STACK_EMPTY : 0;
914 eeBoundaries[which].sourceReason |= callInstruction ? ICorDebugInfo::CALL_INSTRUCTION : 0;
918 void Compiler::eeSetLIdone()
920 assert(opts.compDbgInfo);
929 // necessary but not sufficient condition that the 2 struct definitions overlap
930 assert(sizeof(eeBoundaries[0]) == sizeof(ICorDebugInfo::OffsetMapping));
932 info.compCompHnd->setBoundaries(info.compMethodHnd,
934 (ICorDebugInfo::OffsetMapping *) eeBoundaries);
936 eeBoundaries = NULL; // we give up ownership after setBoundaries();
942 void Compiler::eeDispILOffs(IL_OFFSET offs)
944 const char * specialOffs[] = { "EPILOG", "PROLOG", "NO_MAP" };
946 switch ((int)offs) // Need the cast since offs is unsigned and the case statements are comparing to signed.
948 case ICorDebugInfo::EPILOG:
949 case ICorDebugInfo::PROLOG:
950 case ICorDebugInfo::NO_MAPPING:
951 assert(DWORD(ICorDebugInfo::EPILOG) + 1 == (unsigned)ICorDebugInfo::PROLOG);
952 assert(DWORD(ICorDebugInfo::EPILOG) + 2 == (unsigned)ICorDebugInfo::NO_MAPPING);
954 specialOffsNum = offs - DWORD(ICorDebugInfo::EPILOG);
955 printf("%s", specialOffs[specialOffsNum]);
958 printf("0x%04X", offs);
963 void Compiler::eeDispLineInfo(const boundariesDsc* line)
967 eeDispILOffs(line->ilOffset);
969 printf(" : 0x%08X", line->nativeIP);
970 if (line->sourceReason != 0)
972 // It seems like it should probably never be zero since ICorDebugInfo::SOURCE_TYPE_INVALID is zero.
973 // However, the JIT has always generated this and printed "stack non-empty".
976 if ((line->sourceReason & ICorDebugInfo::STACK_EMPTY) != 0)
978 printf("STACK_EMPTY ");
980 if ((line->sourceReason & ICorDebugInfo::CALL_INSTRUCTION) != 0)
982 printf("CALL_INSTRUCTION ");
984 if ((line->sourceReason & ICorDebugInfo::CALL_SITE) != 0)
986 printf("CALL_SITE ");
992 // We don't expect to see any other bits.
993 assert((line->sourceReason & ~(ICorDebugInfo::STACK_EMPTY | ICorDebugInfo::CALL_INSTRUCTION)) == 0);
996 void Compiler::eeDispLineInfos()
998 printf("IP mapping count : %d\n", eeBoundariesCount); // this might be zero
999 for (unsigned i = 0; i < eeBoundariesCount; i++)
1001 eeDispLineInfo(&eeBoundaries[i]);
1007 /*****************************************************************************
1009 * ICorJitInfo wrapper functions
1011 * In many cases here, we don't tell the VM about various unwind or EH information if
1012 * we're an altjit for an unexpected architecture. If it's not a same architecture JIT
1013 * (e.g., host AMD64, target ARM64), then VM will get confused anyway.
1016 void Compiler::eeReserveUnwindInfo(BOOL isFunclet,
1023 printf("reserveUnwindInfo(isFunclet=%s, isColdCode=%s, unwindSize=0x%x)\n",
1024 isFunclet ? "TRUE" : "FALSE",
1025 isColdCode ? "TRUE" : "FALSE",
1030 if (info.compMatchedVM)
1032 info.compCompHnd->reserveUnwindInfo(isFunclet, isColdCode, unwindSize);
1036 void Compiler::eeAllocUnwindInfo(BYTE* pHotCode,
1042 CorJitFuncKind funcKind)
1047 printf("allocUnwindInfo(pHotCode=0x%p, pColdCode=0x%p, startOffset=0x%x, endOffset=0x%x, unwindSize=0x%x, pUnwindBlock=0x%p, funKind=%d",
1053 dspPtr(pUnwindBlock),
1057 case CORJIT_FUNC_ROOT: printf(" (main function)"); break;
1058 case CORJIT_FUNC_HANDLER: printf(" (handler)"); break;
1059 case CORJIT_FUNC_FILTER: printf(" (filter)"); break;
1060 default: printf(" (ILLEGAL)"); break;
1066 if (info.compMatchedVM)
1068 info.compCompHnd->allocUnwindInfo(
1079 void Compiler::eeSetEHcount(unsigned cEH)
1084 printf("setEHcount(cEH=%u)\n", cEH);
1088 if (info.compMatchedVM)
1090 info.compCompHnd->setEHcount(cEH);
1094 void Compiler::eeSetEHinfo(unsigned EHnumber,
1095 const CORINFO_EH_CLAUSE *clause)
1098 if (opts.dspEHTable)
1100 dispOutgoingEHClause(EHnumber, *clause);
1104 if (info.compMatchedVM)
1106 info.compCompHnd->setEHinfo(EHnumber, clause);
1110 WORD Compiler::eeGetRelocTypeHint(void * target)
1112 if (info.compMatchedVM)
1114 return info.compCompHnd->getRelocTypeHint(target);
1124 CORINFO_FIELD_HANDLE Compiler::eeFindJitDataOffs(unsigned dataOffs)
1126 // Data offsets are marked by the fact that the low two bits are 0b01 0x1
1127 assert(dataOffs < 0x40000000);
1128 return (CORINFO_FIELD_HANDLE)(size_t)((dataOffs << iaut_SHIFT) | iaut_DATA_OFFSET);
1131 bool Compiler::eeIsJitDataOffs(CORINFO_FIELD_HANDLE field)
1133 // if 'field' is a jit data offset it has to fit into a 32-bit unsigned int
1134 unsigned value = static_cast<unsigned>(reinterpret_cast<uintptr_t>(field));
1135 if (((CORINFO_FIELD_HANDLE)(size_t)value) != field)
1137 return false; // upper bits were set, not a jit data offset
1140 // Data offsets are marked by the fact that the low two bits are 0b01 0x1
1141 return (value & iaut_MASK) == iaut_DATA_OFFSET;
1144 int Compiler::eeGetJitDataOffs(CORINFO_FIELD_HANDLE field)
1146 // Data offsets are marked by the fact that the low two bits are 0b01 0x1
1147 if (eeIsJitDataOffs(field))
1149 unsigned dataOffs = static_cast<unsigned>(reinterpret_cast<uintptr_t>(field));
1150 assert(((CORINFO_FIELD_HANDLE)(size_t)dataOffs) == field);
1151 assert(dataOffs < 0x40000000);
1152 return (static_cast<int>(reinterpret_cast<intptr_t>(field))) >> iaut_SHIFT;
1161 /*****************************************************************************
1163 * ICorStaticInfo wrapper functions
1166 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
1169 void Compiler::dumpSystemVClassificationType(SystemVClassificationType ct)
1173 case SystemVClassificationTypeUnknown: printf("UNKNOWN"); break;
1174 case SystemVClassificationTypeStruct: printf("Struct"); break;
1175 case SystemVClassificationTypeNoClass: printf("NoClass"); break;
1176 case SystemVClassificationTypeMemory: printf("Memory"); break;
1177 case SystemVClassificationTypeInteger: printf("Integer"); break;
1178 case SystemVClassificationTypeIntegerReference: printf("IntegerReference"); break;
1179 case SystemVClassificationTypeIntegerByRef: printf("IntegerByReference"); break;
1180 case SystemVClassificationTypeSSE: printf("SSE"); break;
1181 default: printf("ILLEGAL"); break;
1186 void Compiler::eeGetSystemVAmd64PassStructInRegisterDescriptor(/*IN*/ CORINFO_CLASS_HANDLE structHnd,
1187 /*OUT*/ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr)
1189 bool ok = info.compCompHnd->getSystemVAmd64PassStructInRegisterDescriptor(structHnd, structPassInRegDescPtr);
1195 printf("**** getSystemVAmd64PassStructInRegisterDescriptor(0x%x (%s), ...) =>\n", dspPtr(structHnd), eeGetClassName(structHnd));
1196 printf(" passedInRegisters = %s\n", dspBool(structPassInRegDescPtr->passedInRegisters));
1197 if (structPassInRegDescPtr->passedInRegisters)
1199 printf(" eightByteCount = %d\n", structPassInRegDescPtr->eightByteCount);
1200 for (unsigned int i = 0; i < structPassInRegDescPtr->eightByteCount; i++)
1202 printf(" eightByte #%d -- classification: ", i);
1203 dumpSystemVClassificationType(structPassInRegDescPtr->eightByteClassifications[i]);
1204 printf(", byteSize: %d, byteOffset: %d\n",
1205 structPassInRegDescPtr->eightByteSizes[i],
1206 structPassInRegDescPtr->eightByteOffsets[i]);
1213 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
1215 #if COR_JIT_EE_VERSION <= 460
1217 // Validate the token to determine whether to turn the bad image format exception into
1218 // verification failure (for backward compatibility)
1219 static bool isValidTokenForTryResolveToken(ICorJitInfo* corInfo, CORINFO_RESOLVED_TOKEN* resolvedToken)
1221 if (!corInfo->isValidToken(resolvedToken->tokenScope, resolvedToken->token))
1224 CorInfoTokenKind tokenType = resolvedToken->tokenType;
1225 switch (TypeFromToken(resolvedToken->token))
1231 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1237 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1242 if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1247 if ((tokenType & (CORINFO_TOKENKIND_Method | CORINFO_TOKENKIND_Field)) == 0)
1258 // This type encapsulates the information necessary for `TryResolveTokenFilter` and
1259 // `eeTryResolveToken` below.
1260 struct TryResolveTokenFilterParam
1262 ICorJitInfo* m_corInfo;
1263 CORINFO_RESOLVED_TOKEN* m_resolvedToken;
1264 EXCEPTION_POINTERS m_exceptionPointers;
1268 LONG TryResolveTokenFilter(struct _EXCEPTION_POINTERS* exceptionPointers, void* theParam)
1270 assert(exceptionPointers->ExceptionRecord->ExceptionCode != SEH_VERIFICATION_EXCEPTION);
1272 // Backward compatibility: Convert bad image format exceptions thrown by the EE while resolving token to verification exceptions
1273 // if we are verifying. Verification exceptions will cause the JIT of the basic block to fail, but the JITing of the whole method
1274 // is still going to succeed. This is done for backward compatibility only. Ideally, we would always treat bad tokens in the IL
1275 // stream as fatal errors.
1276 if (exceptionPointers->ExceptionRecord->ExceptionCode == EXCEPTION_COMPLUS)
1278 auto* param = reinterpret_cast<TryResolveTokenFilterParam*>(theParam);
1279 if (!isValidTokenForTryResolveToken(param->m_corInfo, param->m_resolvedToken))
1281 param->m_exceptionPointers = *exceptionPointers;
1282 return param->m_corInfo->FilterException(exceptionPointers);
1286 return EXCEPTION_CONTINUE_SEARCH;
1289 bool Compiler::eeTryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken)
1291 TryResolveTokenFilterParam param;
1292 param.m_corInfo = info.compCompHnd;
1293 param.m_resolvedToken = resolvedToken;
1294 param.m_success = true;
1296 PAL_TRY(TryResolveTokenFilterParam*, pParam, ¶m)
1298 pParam->m_corInfo->resolveToken(pParam->m_resolvedToken);
1300 PAL_EXCEPT_FILTER(TryResolveTokenFilter)
1302 if (param.m_exceptionPointers.ExceptionRecord->ExceptionCode == EXCEPTION_COMPLUS)
1304 param.m_corInfo->HandleException(¶m.m_exceptionPointers);
1307 param.m_success = false;
1311 return param.m_success;
1316 ICorJitInfo* m_corInfo;
1317 EXCEPTION_POINTERS m_exceptionPointers;
1319 void (*m_function)(void*);
1324 static LONG __EEFilter(PEXCEPTION_POINTERS exceptionPointers, void* param)
1326 auto* trapParam = reinterpret_cast<TrapParam*>(param);
1327 trapParam->m_exceptionPointers = *exceptionPointers;
1328 return trapParam->m_corInfo->FilterException(exceptionPointers);
1331 bool Compiler::eeRunWithErrorTrapImp(void (*function)(void*), void* param)
1333 TrapParam trapParam;
1334 trapParam.m_corInfo = info.compCompHnd;
1335 trapParam.m_function = function;
1336 trapParam.m_param = param;
1337 trapParam.m_success = true;
1339 PAL_TRY(TrapParam*, __trapParam, &trapParam)
1341 __trapParam->m_function(__trapParam->m_param);
1343 PAL_EXCEPT_FILTER(__EEFilter)
1345 trapParam.m_corInfo->HandleException(&trapParam.m_exceptionPointers);
1346 trapParam.m_success = false;
1350 return trapParam.m_success;
1353 #else // CORJIT_EE_VER <= 460
1355 bool Compiler::eeTryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken)
1357 return info.compCompHnd->tryResolveToken(resolvedToken);
1360 bool Compiler::eeRunWithErrorTrapImp(void (*function)(void*), void* param)
1362 return info.compCompHnd->runWithErrorTrap(function, param);
1365 #endif // CORJIT_EE_VER > 460
1367 /*****************************************************************************
1372 #if defined(DEBUG) || defined(FEATURE_JIT_METHOD_PERF) || defined(FEATURE_SIMD)
1374 /*****************************************************************************/
1376 // static helper names - constant array
1377 const char* jitHlpFuncTable[CORINFO_HELP_COUNT] =
1379 #define JITHELPER(code, pfnHelper, sig) #code,
1380 #define DYNAMICJITHELPER(code, pfnHelper,sig) #code,
1381 #include "jithelpers.h"
1384 /*****************************************************************************
1386 * Filter wrapper to handle exception filtering.
1387 * On Unix compilers don't support SEH.
1390 struct FilterSuperPMIExceptionsParam_ee_il
1393 Compiler::Info* pJitInfo;
1394 CORINFO_FIELD_HANDLE field;
1395 CORINFO_METHOD_HANDLE method;
1396 CORINFO_CLASS_HANDLE clazz;
1397 const char** classNamePtr;
1398 const char* fieldOrMethodOrClassNamePtr;
1399 EXCEPTION_POINTERS exceptionPointers;
1402 static LONG FilterSuperPMIExceptions_ee_il(PEXCEPTION_POINTERS pExceptionPointers, LPVOID lpvParam)
1404 FilterSuperPMIExceptionsParam_ee_il *pSPMIEParam =
1405 (FilterSuperPMIExceptionsParam_ee_il *)lpvParam;
1406 pSPMIEParam->exceptionPointers = *pExceptionPointers;
1408 if (pSPMIEParam->pThis->IsSuperPMIException(pExceptionPointers->ExceptionRecord->ExceptionCode))
1409 return EXCEPTION_EXECUTE_HANDLER;
1411 return EXCEPTION_CONTINUE_SEARCH;
1414 const char* Compiler::eeGetMethodName(CORINFO_METHOD_HANDLE method,
1415 const char** classNamePtr)
1417 if (eeGetHelperNum(method))
1419 if (classNamePtr != 0)
1420 *classNamePtr = "HELPER";
1422 CorInfoHelpFunc ftnNum = eeGetHelperNum(method);
1423 const char* name = info.compCompHnd->getHelperName(ftnNum);
1425 // If it's something unknown from a RET VM, or from SuperPMI, then use our own helper name table.
1426 if ((strcmp(name, "AnyJITHelper") == 0) ||
1427 (strcmp(name, "Yickish helper name") == 0))
1429 if (ftnNum < CORINFO_HELP_COUNT)
1431 name = jitHlpFuncTable[ftnNum];
1437 if (eeIsNativeMethod(method))
1439 if (classNamePtr != 0)
1440 *classNamePtr = "NATIVE";
1441 method = eeGetMethodHandleForNative(method);
1444 FilterSuperPMIExceptionsParam_ee_il param;
1447 param.pJitInfo = &info;
1448 param.method = method;
1449 param.classNamePtr = classNamePtr;
1451 PAL_TRY(FilterSuperPMIExceptionsParam_ee_il *, pParam, ¶m)
1453 pParam->fieldOrMethodOrClassNamePtr = pParam->pJitInfo->compCompHnd->getMethodName(pParam->method, pParam->classNamePtr);
1455 PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_ee_il)
1457 if (param.classNamePtr != nullptr)
1459 *(param.classNamePtr) = "hackishClassName";
1462 param.fieldOrMethodOrClassNamePtr = "hackishMethodName";
1466 return param.fieldOrMethodOrClassNamePtr;
1469 const char * Compiler::eeGetFieldName (CORINFO_FIELD_HANDLE field,
1470 const char * * classNamePtr)
1472 FilterSuperPMIExceptionsParam_ee_il param;
1475 param.pJitInfo = &info;
1476 param.field = field;
1477 param.classNamePtr = classNamePtr;
1479 PAL_TRY(FilterSuperPMIExceptionsParam_ee_il *, pParam, ¶m)
1481 pParam->fieldOrMethodOrClassNamePtr = pParam->pJitInfo->compCompHnd->getFieldName(pParam->field, pParam->classNamePtr);
1483 PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_ee_il)
1485 param.fieldOrMethodOrClassNamePtr = "hackishFieldName";
1489 return param.fieldOrMethodOrClassNamePtr;
1492 const char* Compiler::eeGetClassName(CORINFO_CLASS_HANDLE clsHnd)
1494 FilterSuperPMIExceptionsParam_ee_il param;
1497 param.pJitInfo = &info;
1498 param.clazz = clsHnd;
1500 PAL_TRY(FilterSuperPMIExceptionsParam_ee_il *, pParam, ¶m)
1502 pParam->fieldOrMethodOrClassNamePtr = pParam->pJitInfo->compCompHnd->getClassName(pParam->clazz);
1504 PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_ee_il)
1506 param.fieldOrMethodOrClassNamePtr = "hackishClassName";
1509 return param.fieldOrMethodOrClassNamePtr;
1512 #endif // DEBUG || FEATURE_JIT_METHOD_PERF
1517 const wchar_t * Compiler::eeGetCPString (size_t strHandle)
1519 char buff[512 + sizeof(CORINFO_String)];
1521 // make this bulletproof, so it works even if we are wrong.
1522 if (ReadProcessMemory(GetCurrentProcess(), (void*) strHandle, buff, 4, 0) == 0)
1525 CORINFO_String* asString = *((CORINFO_String**) strHandle);
1527 if (ReadProcessMemory(GetCurrentProcess(), asString, buff, sizeof(buff), 0) == 0)
1530 if (asString->stringLen >= 255 ||
1531 asString->chars[asString->stringLen] != 0 )
1536 return(asString->chars);