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/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7XX XX
8XX ee_jit.cpp XX
9XX XX
10XX The functionality needed for the JIT DLL. Includes the DLL entry point XX
11XX XX
12XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
13XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
14*/
15
16#include "jitpch.h"
17#ifdef _MSC_VER
18#pragma hdrstop
19#endif
20#include "emit.h"
21#include "corexcep.h"
22
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
27#endif
28
29/*****************************************************************************/
30
31FILE* jitstdout = nullptr;
32
33ICorJitHost* g_jitHost = nullptr;
34static CILJit* ILJitter = nullptr; // The one and only JITTER I return
35bool g_jitInitialized = false;
36#ifndef FEATURE_MERGE_JIT_AND_ENGINE
37HINSTANCE g_hInst = nullptr;
38#endif // FEATURE_MERGE_JIT_AND_ENGINE
39
40/*****************************************************************************/
41
42#ifdef DEBUG
43
44JitOptions jitOpts = {
45 nullptr, // methodName
46 nullptr, // className
47 0.1, // CGknob
48 0, // testMask
49
50 (JitOptions*)nullptr // lastDummyField.
51};
52
53#endif // DEBUG
54
55/*****************************************************************************/
56
57extern "C" void __stdcall jitStartup(ICorJitHost* jitHost)
58{
59 if (g_jitInitialized)
60 {
61 if (jitHost != g_jitHost)
62 {
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);
73 g_jitHost = jitHost;
74 }
75 return;
76 }
77
78 g_jitHost = jitHost;
79
80 assert(!JitConfig.isInitialized());
81 JitConfig.initialize(jitHost);
82
83#ifdef DEBUG
84 const wchar_t* jitStdOutFile = JitConfig.JitStdOutFile();
85 if (jitStdOutFile != nullptr)
86 {
87 jitstdout = _wfopen(jitStdOutFile, W("a"));
88 assert(jitstdout != nullptr);
89 }
90#endif // DEBUG
91
92#if !defined(_HOST_UNIX_)
93 if (jitstdout == nullptr)
94 {
95 int stdoutFd = _fileno(procstdout());
96 // Check fileno error output(s) -1 may overlap with errno result
97 // but is included for completness.
98 // We want to detect the case where the initial handle is null
99 // or bogus and avoid making further calls.
100 if ((stdoutFd != -1) && (stdoutFd != -2) && (errno != EINVAL))
101 {
102 int jitstdoutFd = _dup(_fileno(procstdout()));
103 // Check the error status returned by dup.
104 if (jitstdoutFd != -1)
105 {
106 _setmode(jitstdoutFd, _O_TEXT);
107 jitstdout = _fdopen(jitstdoutFd, "w");
108 assert(jitstdout != nullptr);
109
110 // Prevent the FILE* from buffering its output in order to avoid calls to
111 // `fflush()` throughout the code.
112 setvbuf(jitstdout, nullptr, _IONBF, 0);
113 }
114 }
115 }
116#endif // !_HOST_UNIX_
117
118 // If jitstdout is still null, fallback to whatever procstdout() was
119 // initially set to.
120 if (jitstdout == nullptr)
121 {
122 jitstdout = procstdout();
123 }
124
125#ifdef FEATURE_TRACELOGGING
126 JitTelemetry::NotifyDllProcessAttach();
127#endif
128 Compiler::compStartup();
129
130 g_jitInitialized = true;
131}
132
133void jitShutdown(bool processIsTerminating)
134{
135 if (!g_jitInitialized)
136 {
137 return;
138 }
139
140 Compiler::compShutdown();
141
142 if (jitstdout != procstdout())
143 {
144 // When the process is terminating, the fclose call is unnecessary and is also prone to
145 // crashing since the UCRT itself often frees the backing memory earlier on in the
146 // termination sequence.
147 if (!processIsTerminating)
148 {
149 fclose(jitstdout);
150 }
151 }
152
153#ifdef FEATURE_TRACELOGGING
154 JitTelemetry::NotifyDllProcessDetach();
155#endif
156
157 g_jitInitialized = false;
158}
159
160#ifndef FEATURE_MERGE_JIT_AND_ENGINE
161
162extern "C" BOOL WINAPI DllMain(HANDLE hInstance, DWORD dwReason, LPVOID pvReserved)
163{
164 if (dwReason == DLL_PROCESS_ATTACH)
165 {
166 g_hInst = (HINSTANCE)hInstance;
167 DisableThreadLibraryCalls((HINSTANCE)hInstance);
168 }
169 else if (dwReason == DLL_PROCESS_DETACH)
170 {
171 // From MSDN: If fdwReason is DLL_PROCESS_DETACH, lpvReserved is NULL if FreeLibrary has
172 // been called or the DLL load failed and non-NULL if the process is terminating.
173 bool processIsTerminating = (pvReserved != nullptr);
174 jitShutdown(processIsTerminating);
175 }
176
177 return TRUE;
178}
179
180HINSTANCE GetModuleInst()
181{
182 return (g_hInst);
183}
184
185extern "C" void __stdcall sxsJitStartup(CoreClrCallbacks const& cccallbacks)
186{
187#ifndef SELF_NO_HOST
188 InitUtilcode(cccallbacks);
189#endif
190}
191
192#endif // !FEATURE_MERGE_JIT_AND_ENGINE
193
194/*****************************************************************************/
195
196struct CILJitSingletonAllocator
197{
198 int x;
199};
200const CILJitSingletonAllocator CILJitSingleton = {0};
201
202void* __cdecl operator new(size_t, const CILJitSingletonAllocator&)
203{
204 static char CILJitBuff[sizeof(CILJit)];
205 return CILJitBuff;
206}
207
208ICorJitCompiler* g_realJitCompiler = nullptr;
209
210ICorJitCompiler* __stdcall getJit()
211{
212 if (ILJitter == nullptr)
213 {
214 ILJitter = new (CILJitSingleton) CILJit();
215 }
216 return (ILJitter);
217}
218
219/*****************************************************************************/
220
221// Information kept in thread-local storage. This is used in the noway_assert exceptional path.
222// If you are using it more broadly in retail code, you would need to understand the
223// performance implications of accessing TLS.
224
225__declspec(thread) void* gJitTls = nullptr;
226
227static void* GetJitTls()
228{
229 return gJitTls;
230}
231
232void SetJitTls(void* value)
233{
234 gJitTls = value;
235}
236
237#if defined(DEBUG)
238
239JitTls::JitTls(ICorJitInfo* jitInfo) : m_compiler(nullptr), m_logEnv(jitInfo)
240{
241 m_next = reinterpret_cast<JitTls*>(GetJitTls());
242 SetJitTls(this);
243}
244
245JitTls::~JitTls()
246{
247 SetJitTls(m_next);
248}
249
250LogEnv* JitTls::GetLogEnv()
251{
252 return &reinterpret_cast<JitTls*>(GetJitTls())->m_logEnv;
253}
254
255Compiler* JitTls::GetCompiler()
256{
257 return reinterpret_cast<JitTls*>(GetJitTls())->m_compiler;
258}
259
260void JitTls::SetCompiler(Compiler* compiler)
261{
262 reinterpret_cast<JitTls*>(GetJitTls())->m_compiler = compiler;
263}
264
265#else // defined(DEBUG)
266
267JitTls::JitTls(ICorJitInfo* jitInfo)
268{
269}
270
271JitTls::~JitTls()
272{
273}
274
275Compiler* JitTls::GetCompiler()
276{
277 return reinterpret_cast<Compiler*>(GetJitTls());
278}
279
280void JitTls::SetCompiler(Compiler* compiler)
281{
282 SetJitTls(compiler);
283}
284
285#endif // !defined(DEBUG)
286
287//****************************************************************************
288// The main JIT function for the 32 bit JIT. See code:ICorJitCompiler#EEToJitInterface for more on the EE-JIT
289// interface. Things really don't get going inside the JIT until the code:Compiler::compCompile#Phases
290// method. Usually that is where you want to go.
291
292CorJitResult CILJit::compileMethod(
293 ICorJitInfo* compHnd, CORINFO_METHOD_INFO* methodInfo, unsigned flags, BYTE** entryAddress, ULONG* nativeSizeOfCode)
294{
295 if (g_realJitCompiler != nullptr)
296 {
297 return g_realJitCompiler->compileMethod(compHnd, methodInfo, flags, entryAddress, nativeSizeOfCode);
298 }
299
300 JitFlags jitFlags;
301
302 assert(flags == CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS);
303 CORJIT_FLAGS corJitFlags;
304 DWORD jitFlagsSize = compHnd->getJitFlags(&corJitFlags, sizeof(corJitFlags));
305 assert(jitFlagsSize == sizeof(corJitFlags));
306 jitFlags.SetFromFlags(corJitFlags);
307
308 int result;
309 void* methodCodePtr = nullptr;
310 CORINFO_METHOD_HANDLE methodHandle = methodInfo->ftn;
311
312 JitTls jitTls(compHnd); // Initialize any necessary thread-local state
313
314 assert(methodInfo->ILCode);
315
316 result = jitNativeCode(methodHandle, methodInfo->scope, compHnd, methodInfo, &methodCodePtr, nativeSizeOfCode,
317 &jitFlags, nullptr);
318
319 if (result == CORJIT_OK)
320 {
321 *entryAddress = (BYTE*)methodCodePtr;
322 }
323
324 return CorJitResult(result);
325}
326
327/*****************************************************************************
328 * Notification from VM to clear any caches
329 */
330void CILJit::clearCache(void)
331{
332 if (g_realJitCompiler != nullptr)
333 {
334 g_realJitCompiler->clearCache();
335 // Continue...
336 }
337
338 return;
339}
340
341/*****************************************************************************
342 * Notify vm that we have something to clean up
343 */
344BOOL CILJit::isCacheCleanupRequired(void)
345{
346 if (g_realJitCompiler != nullptr)
347 {
348 if (g_realJitCompiler->isCacheCleanupRequired())
349 {
350 return TRUE;
351 }
352 // Continue...
353 }
354
355 return FALSE;
356}
357
358void CILJit::ProcessShutdownWork(ICorStaticInfo* statInfo)
359{
360 if (g_realJitCompiler != nullptr)
361 {
362 g_realJitCompiler->ProcessShutdownWork(statInfo);
363 // Continue, by shutting down this JIT as well.
364 }
365
366 jitShutdown(false);
367
368 Compiler::ProcessShutdownWork(statInfo);
369}
370
371/*****************************************************************************
372 * Verify the JIT/EE interface identifier.
373 */
374void CILJit::getVersionIdentifier(GUID* versionIdentifier)
375{
376 if (g_realJitCompiler != nullptr)
377 {
378 g_realJitCompiler->getVersionIdentifier(versionIdentifier);
379 return;
380 }
381
382 assert(versionIdentifier != nullptr);
383 memcpy(versionIdentifier, &JITEEVersionIdentifier, sizeof(GUID));
384}
385
386/*****************************************************************************
387 * Determine the maximum length of SIMD vector supported by this JIT.
388 */
389
390unsigned CILJit::getMaxIntrinsicSIMDVectorLength(CORJIT_FLAGS cpuCompileFlags)
391{
392 if (g_realJitCompiler != nullptr)
393 {
394 return g_realJitCompiler->getMaxIntrinsicSIMDVectorLength(cpuCompileFlags);
395 }
396
397 JitFlags jitFlags;
398 jitFlags.SetFromFlags(cpuCompileFlags);
399
400#ifdef FEATURE_SIMD
401#if defined(_TARGET_XARCH_)
402 if (!jitFlags.IsSet(JitFlags::JIT_FLAG_PREJIT) && jitFlags.IsSet(JitFlags::JIT_FLAG_FEATURE_SIMD) &&
403 jitFlags.IsSet(JitFlags::JIT_FLAG_USE_AVX2))
404 {
405 // Since the ISAs can be disabled individually and since they are hierarchical in nature (that is
406 // disabling SSE also disables SSE2 through AVX2), we need to check each ISA in the hierarchy to
407 // ensure that AVX2 is actually supported. Otherwise, we will end up getting asserts downstream.
408 if ((JitConfig.EnableAVX2() != 0) && (JitConfig.EnableAVX() != 0) && (JitConfig.EnableSSE42() != 0) &&
409 (JitConfig.EnableSSE41() != 0) && (JitConfig.EnableSSSE3() != 0) && (JitConfig.EnableSSE3() != 0) &&
410 (JitConfig.EnableSSE2() != 0) && (JitConfig.EnableSSE() != 0))
411 {
412 if (GetJitTls() != nullptr && JitTls::GetCompiler() != nullptr)
413 {
414 JITDUMP("getMaxIntrinsicSIMDVectorLength: returning 32\n");
415 }
416 return 32;
417 }
418 }
419#endif // defined(_TARGET_XARCH_)
420 if (GetJitTls() != nullptr && JitTls::GetCompiler() != nullptr)
421 {
422 JITDUMP("getMaxIntrinsicSIMDVectorLength: returning 16\n");
423 }
424 return 16;
425#else // !FEATURE_SIMD
426 if (GetJitTls() != nullptr && JitTls::GetCompiler() != nullptr)
427 {
428 JITDUMP("getMaxIntrinsicSIMDVectorLength: returning 0\n");
429 }
430 return 0;
431#endif // !FEATURE_SIMD
432}
433
434void CILJit::setRealJit(ICorJitCompiler* realJitCompiler)
435{
436 g_realJitCompiler = realJitCompiler;
437}
438
439/*****************************************************************************
440 * Returns the number of bytes required for the given type argument
441 */
442
443unsigned Compiler::eeGetArgSize(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig)
444{
445#if defined(_TARGET_AMD64_)
446
447 // Everything fits into a single 'slot' size
448 // to accommodate irregular sized structs, they are passed byref
449 CLANG_FORMAT_COMMENT_ANCHOR;
450
451#ifdef UNIX_AMD64_ABI
452 CORINFO_CLASS_HANDLE argClass;
453 CorInfoType argTypeJit = strip(info.compCompHnd->getArgType(sig, list, &argClass));
454 var_types argType = JITtype2varType(argTypeJit);
455 if (varTypeIsStruct(argType))
456 {
457 unsigned structSize = info.compCompHnd->getClassSize(argClass);
458 return structSize; // TODO: roundUp() needed here?
459 }
460#endif // UNIX_AMD64_ABI
461 return TARGET_POINTER_SIZE;
462
463#else // !_TARGET_AMD64_
464
465 CORINFO_CLASS_HANDLE argClass;
466 CorInfoType argTypeJit = strip(info.compCompHnd->getArgType(sig, list, &argClass));
467 var_types argType = JITtype2varType(argTypeJit);
468
469 if (varTypeIsStruct(argType))
470 {
471 unsigned structSize = info.compCompHnd->getClassSize(argClass);
472
473 // make certain the EE passes us back the right thing for refanys
474 assert(argTypeJit != CORINFO_TYPE_REFANY || structSize == 2 * TARGET_POINTER_SIZE);
475
476 // For each target that supports passing struct args in multiple registers
477 // apply the target specific rules for them here:
478 CLANG_FORMAT_COMMENT_ANCHOR;
479
480#if FEATURE_MULTIREG_ARGS
481#if defined(_TARGET_ARM64_)
482 // Any structs that are larger than MAX_PASS_MULTIREG_BYTES are always passed by reference
483 if (structSize > MAX_PASS_MULTIREG_BYTES)
484 {
485 // This struct is passed by reference using a single 'slot'
486 return TARGET_POINTER_SIZE;
487 }
488 else
489 {
490 // Is the struct larger than 16 bytes
491 if (structSize > (2 * TARGET_POINTER_SIZE))
492 {
493 var_types hfaType = GetHfaType(argClass); // set to float or double if it is an HFA, otherwise TYP_UNDEF
494 bool isHfa = (hfaType != TYP_UNDEF);
495#ifndef _TARGET_UNIX_
496 if (info.compIsVarArgs)
497 {
498 // Arm64 Varargs ABI requires passing in general purpose
499 // registers. Force the decision of whether this is an HFA
500 // to false to correctly pass as if it was not an HFA.
501 isHfa = false;
502 }
503#endif // _TARGET_UNIX_
504 if (!isHfa)
505 {
506 // This struct is passed by reference using a single 'slot'
507 return TARGET_POINTER_SIZE;
508 }
509 }
510 // otherwise will we pass this struct by value in multiple registers
511 }
512#elif defined(_TARGET_ARM_)
513// otherwise will we pass this struct by value in multiple registers
514#else
515 NYI("unknown target");
516#endif // defined(_TARGET_XXX_)
517#endif // FEATURE_MULTIREG_ARGS
518
519 // we pass this struct by value in multiple registers
520 return roundUp(structSize, TARGET_POINTER_SIZE);
521 }
522 else
523 {
524 unsigned argSize = sizeof(int) * genTypeStSz(argType);
525 assert(0 < argSize && argSize <= sizeof(__int64));
526 return roundUp(argSize, TARGET_POINTER_SIZE);
527 }
528#endif
529}
530
531/*****************************************************************************/
532
533GenTree* Compiler::eeGetPInvokeCookie(CORINFO_SIG_INFO* szMetaSig)
534{
535 void *cookie, *pCookie;
536 cookie = info.compCompHnd->GetCookieForPInvokeCalliSig(szMetaSig, &pCookie);
537 assert((cookie == nullptr) != (pCookie == nullptr));
538
539 return gtNewIconEmbHndNode(cookie, pCookie, GTF_ICON_PINVKI_HDL, szMetaSig);
540}
541
542//------------------------------------------------------------------------
543// eeGetArrayDataOffset: Gets the offset of a SDArray's first element
544//
545// Arguments:
546// type - The array element type
547//
548// Return Value:
549// The offset to the first array element.
550
551unsigned Compiler::eeGetArrayDataOffset(var_types type)
552{
553 return varTypeIsGC(type) ? eeGetEEInfo()->offsetOfObjArrayData : OFFSETOF__CORINFO_Array__data;
554}
555
556//------------------------------------------------------------------------
557// eeGetMDArrayDataOffset: Gets the offset of a MDArray's first element
558//
559// Arguments:
560// type - The array element type
561// rank - The array rank
562//
563// Return Value:
564// The offset to the first array element.
565//
566// Assumptions:
567// The rank should be greater than 0.
568
569unsigned Compiler::eeGetMDArrayDataOffset(var_types type, unsigned rank)
570{
571 assert(rank > 0);
572 // Note that below we're specifically using genTypeSize(TYP_INT) because array
573 // indices are not native int.
574 return eeGetArrayDataOffset(type) + 2 * genTypeSize(TYP_INT) * rank;
575}
576
577/*****************************************************************************/
578
579void Compiler::eeGetStmtOffsets()
580{
581 ULONG32 offsetsCount;
582 DWORD* offsets;
583 ICorDebugInfo::BoundaryTypes offsetsImplicit;
584
585 info.compCompHnd->getBoundaries(info.compMethodHnd, &offsetsCount, &offsets, &offsetsImplicit);
586
587 /* Set the implicit boundaries */
588
589 info.compStmtOffsetsImplicit = (ICorDebugInfo::BoundaryTypes)offsetsImplicit;
590
591 /* Process the explicit boundaries */
592
593 info.compStmtOffsetsCount = 0;
594
595 if (offsetsCount == 0)
596 {
597 return;
598 }
599
600 info.compStmtOffsets = new (this, CMK_DebugInfo) IL_OFFSET[offsetsCount];
601
602 for (unsigned i = 0; i < offsetsCount; i++)
603 {
604 if (offsets[i] > info.compILCodeSize)
605 {
606 continue;
607 }
608
609 info.compStmtOffsets[info.compStmtOffsetsCount] = offsets[i];
610 info.compStmtOffsetsCount++;
611 }
612
613 info.compCompHnd->freeArray(offsets);
614}
615
616/*****************************************************************************
617 *
618 * Debugging support - Local var info
619 */
620
621void Compiler::eeSetLVcount(unsigned count)
622{
623 assert(opts.compScopeInfo);
624
625 JITDUMP("VarLocInfo count is %d\n", count);
626
627 eeVarsCount = count;
628 if (eeVarsCount)
629 {
630 eeVars = (VarResultInfo*)info.compCompHnd->allocateArray(eeVarsCount * sizeof(eeVars[0]));
631 }
632 else
633 {
634 eeVars = nullptr;
635 }
636}
637
638void Compiler::eeSetLVinfo(unsigned which,
639 UNATIVE_OFFSET startOffs,
640 UNATIVE_OFFSET length,
641 unsigned varNum,
642 unsigned LVnum,
643 VarName name,
644 bool avail,
645 const Compiler::siVarLoc& varLoc)
646{
647 // ICorDebugInfo::VarLoc and Compiler::siVarLoc have to overlap
648 // This is checked in siInit()
649
650 assert(opts.compScopeInfo);
651 assert(eeVarsCount > 0);
652 assert(which < eeVarsCount);
653
654 if (eeVars != nullptr)
655 {
656 eeVars[which].startOffset = startOffs;
657 eeVars[which].endOffset = startOffs + length;
658 eeVars[which].varNumber = varNum;
659 eeVars[which].loc = varLoc;
660 }
661}
662
663void Compiler::eeSetLVdone()
664{
665 // necessary but not sufficient condition that the 2 struct definitions overlap
666 assert(sizeof(eeVars[0]) == sizeof(ICorDebugInfo::NativeVarInfo));
667 assert(opts.compScopeInfo);
668
669#ifdef DEBUG
670 if (verbose || opts.dspDebugInfo)
671 {
672 eeDispVars(info.compMethodHnd, eeVarsCount, (ICorDebugInfo::NativeVarInfo*)eeVars);
673 }
674#endif // DEBUG
675
676 info.compCompHnd->setVars(info.compMethodHnd, eeVarsCount, (ICorDebugInfo::NativeVarInfo*)eeVars);
677
678 eeVars = nullptr; // We give up ownership after setVars()
679}
680
681void Compiler::eeGetVars()
682{
683 ICorDebugInfo::ILVarInfo* varInfoTable;
684 ULONG32 varInfoCount;
685 bool extendOthers;
686
687 info.compCompHnd->getVars(info.compMethodHnd, &varInfoCount, &varInfoTable, &extendOthers);
688
689#ifdef DEBUG
690 if (verbose)
691 {
692 printf("getVars() returned cVars = %d, extendOthers = %s\n", varInfoCount, extendOthers ? "true" : "false");
693 }
694#endif
695
696 // Over allocate in case extendOthers is set.
697
698 SIZE_T varInfoCountExtra = varInfoCount;
699 if (extendOthers)
700 {
701 varInfoCountExtra += info.compLocalsCount;
702 }
703
704 if (varInfoCountExtra == 0)
705 {
706 return;
707 }
708
709 info.compVarScopes = new (this, CMK_DebugInfo) VarScopeDsc[varInfoCountExtra];
710
711 VarScopeDsc* localVarPtr = info.compVarScopes;
712 ICorDebugInfo::ILVarInfo* v = varInfoTable;
713
714 for (unsigned i = 0; i < varInfoCount; i++, v++)
715 {
716#ifdef DEBUG
717 if (verbose)
718 {
719 printf("var:%d start:%d end:%d\n", v->varNumber, v->startOffset, v->endOffset);
720 }
721#endif
722
723 if (v->startOffset >= v->endOffset)
724 {
725 continue;
726 }
727
728 assert(v->startOffset <= info.compILCodeSize);
729 assert(v->endOffset <= info.compILCodeSize);
730
731 localVarPtr->vsdLifeBeg = v->startOffset;
732 localVarPtr->vsdLifeEnd = v->endOffset;
733 localVarPtr->vsdLVnum = i;
734 localVarPtr->vsdVarNum = compMapILvarNum(v->varNumber);
735
736#ifdef DEBUG
737 localVarPtr->vsdName = gtGetLclVarName(localVarPtr->vsdVarNum);
738#endif
739
740 localVarPtr++;
741 info.compVarScopesCount++;
742 }
743
744 /* If extendOthers is set, then assume the scope of unreported vars
745 is the entire method. Note that this will cause fgExtendDbgLifetimes()
746 to zero-initalize all of them. This will be expensive if it's used
747 for too many variables.
748 */
749 if (extendOthers)
750 {
751 // Allocate a bit-array for all the variables and initialize to false
752
753 bool* varInfoProvided = getAllocator(CMK_Unknown).allocate<bool>(info.compLocalsCount);
754 unsigned i;
755 for (i = 0; i < info.compLocalsCount; i++)
756 {
757 varInfoProvided[i] = false;
758 }
759
760 // Find which vars have absolutely no varInfo provided
761
762 for (i = 0; i < info.compVarScopesCount; i++)
763 {
764 varInfoProvided[info.compVarScopes[i].vsdVarNum] = true;
765 }
766
767 // Create entries for the variables with no varInfo
768
769 for (unsigned varNum = 0; varNum < info.compLocalsCount; varNum++)
770 {
771 if (varInfoProvided[varNum])
772 {
773 continue;
774 }
775
776 // Create a varInfo with scope over the entire method
777
778 localVarPtr->vsdLifeBeg = 0;
779 localVarPtr->vsdLifeEnd = info.compILCodeSize;
780 localVarPtr->vsdVarNum = varNum;
781 localVarPtr->vsdLVnum = info.compVarScopesCount;
782
783#ifdef DEBUG
784 localVarPtr->vsdName = gtGetLclVarName(localVarPtr->vsdVarNum);
785#endif
786
787 localVarPtr++;
788 info.compVarScopesCount++;
789 }
790 }
791
792 assert(localVarPtr <= info.compVarScopes + varInfoCountExtra);
793
794 if (varInfoCount != 0)
795 {
796 info.compCompHnd->freeArray(varInfoTable);
797 }
798
799#ifdef DEBUG
800 if (verbose)
801 {
802 compDispLocalVars();
803 }
804#endif // DEBUG
805}
806
807#ifdef DEBUG
808void Compiler::eeDispVar(ICorDebugInfo::NativeVarInfo* var)
809{
810 const char* name = nullptr;
811
812 if (var->varNumber == (DWORD)ICorDebugInfo::VARARGS_HND_ILNUM)
813 {
814 name = "varargsHandle";
815 }
816 else if (var->varNumber == (DWORD)ICorDebugInfo::RETBUF_ILNUM)
817 {
818 name = "retBuff";
819 }
820 else if (var->varNumber == (DWORD)ICorDebugInfo::TYPECTXT_ILNUM)
821 {
822 name = "typeCtx";
823 }
824 printf("%3d(%10s) : From %08Xh to %08Xh, in ", var->varNumber,
825 (VarNameToStr(name) == nullptr) ? "UNKNOWN" : VarNameToStr(name), var->startOffset, var->endOffset);
826
827 switch ((Compiler::siVarLocType)var->loc.vlType)
828 {
829 case VLT_REG:
830 case VLT_REG_BYREF:
831 case VLT_REG_FP:
832 printf("%s", getRegName(var->loc.vlReg.vlrReg));
833 if (var->loc.vlType == (ICorDebugInfo::VarLocType)VLT_REG_BYREF)
834 {
835 printf(" byref");
836 }
837 break;
838
839 case VLT_STK:
840 case VLT_STK_BYREF:
841 if ((int)var->loc.vlStk.vlsBaseReg != (int)ICorDebugInfo::REGNUM_AMBIENT_SP)
842 {
843 printf("%s[%d] (1 slot)", getRegName(var->loc.vlStk.vlsBaseReg), var->loc.vlStk.vlsOffset);
844 }
845 else
846 {
847 printf(STR_SPBASE "'[%d] (1 slot)", var->loc.vlStk.vlsOffset);
848 }
849 if (var->loc.vlType == (ICorDebugInfo::VarLocType)VLT_REG_BYREF)
850 {
851 printf(" byref");
852 }
853 break;
854
855#ifndef _TARGET_AMD64_
856 case VLT_REG_REG:
857 printf("%s-%s", getRegName(var->loc.vlRegReg.vlrrReg1), getRegName(var->loc.vlRegReg.vlrrReg2));
858 break;
859
860 case VLT_REG_STK:
861 if ((int)var->loc.vlRegStk.vlrsStk.vlrssBaseReg != (int)ICorDebugInfo::REGNUM_AMBIENT_SP)
862 {
863 printf("%s-%s[%d]", getRegName(var->loc.vlRegStk.vlrsReg),
864 getRegName(var->loc.vlRegStk.vlrsStk.vlrssBaseReg), var->loc.vlRegStk.vlrsStk.vlrssOffset);
865 }
866 else
867 {
868 printf("%s-" STR_SPBASE "'[%d]", getRegName(var->loc.vlRegStk.vlrsReg),
869 var->loc.vlRegStk.vlrsStk.vlrssOffset);
870 }
871 break;
872
873 case VLT_STK_REG:
874 unreached(); // unexpected
875
876 case VLT_STK2:
877 if ((int)var->loc.vlStk2.vls2BaseReg != (int)ICorDebugInfo::REGNUM_AMBIENT_SP)
878 {
879 printf("%s[%d] (2 slots)", getRegName(var->loc.vlStk2.vls2BaseReg), var->loc.vlStk2.vls2Offset);
880 }
881 else
882 {
883 printf(STR_SPBASE "'[%d] (2 slots)", var->loc.vlStk2.vls2Offset);
884 }
885 break;
886
887 case VLT_FPSTK:
888 printf("ST(L-%d)", var->loc.vlFPstk.vlfReg);
889 break;
890
891 case VLT_FIXED_VA:
892 printf("fxd_va[%d]", var->loc.vlFixedVarArg.vlfvOffset);
893 break;
894#endif // !_TARGET_AMD64_
895
896 default:
897 unreached(); // unexpected
898 }
899
900 printf("\n");
901}
902
903// Same parameters as ICorStaticInfo::setVars().
904void Compiler::eeDispVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo* vars)
905{
906 printf("*************** Variable debug info\n");
907 printf("%d vars\n", cVars);
908 for (unsigned i = 0; i < cVars; i++)
909 {
910 eeDispVar(&vars[i]);
911 }
912}
913#endif // DEBUG
914
915/*****************************************************************************
916 *
917 * Debugging support - Line number info
918 */
919
920void Compiler::eeSetLIcount(unsigned count)
921{
922 assert(opts.compDbgInfo);
923
924 eeBoundariesCount = count;
925 if (eeBoundariesCount)
926 {
927 eeBoundaries = (boundariesDsc*)info.compCompHnd->allocateArray(eeBoundariesCount * sizeof(eeBoundaries[0]));
928 }
929 else
930 {
931 eeBoundaries = nullptr;
932 }
933}
934
935void Compiler::eeSetLIinfo(
936 unsigned which, UNATIVE_OFFSET nativeOffset, IL_OFFSET ilOffset, bool stkEmpty, bool callInstruction)
937{
938 assert(opts.compDbgInfo);
939 assert(eeBoundariesCount > 0);
940 assert(which < eeBoundariesCount);
941
942 if (eeBoundaries != nullptr)
943 {
944 eeBoundaries[which].nativeIP = nativeOffset;
945 eeBoundaries[which].ilOffset = ilOffset;
946 eeBoundaries[which].sourceReason = stkEmpty ? ICorDebugInfo::STACK_EMPTY : 0;
947 eeBoundaries[which].sourceReason |= callInstruction ? ICorDebugInfo::CALL_INSTRUCTION : 0;
948 }
949}
950
951void Compiler::eeSetLIdone()
952{
953 assert(opts.compDbgInfo);
954
955#if defined(DEBUG)
956 if (verbose || opts.dspDebugInfo)
957 {
958 eeDispLineInfos();
959 }
960#endif // DEBUG
961
962 // necessary but not sufficient condition that the 2 struct definitions overlap
963 assert(sizeof(eeBoundaries[0]) == sizeof(ICorDebugInfo::OffsetMapping));
964
965 info.compCompHnd->setBoundaries(info.compMethodHnd, eeBoundariesCount, (ICorDebugInfo::OffsetMapping*)eeBoundaries);
966
967 eeBoundaries = nullptr; // we give up ownership after setBoundaries();
968}
969
970#if defined(DEBUG)
971
972/* static */
973void Compiler::eeDispILOffs(IL_OFFSET offs)
974{
975 const char* specialOffs[] = {"EPILOG", "PROLOG", "NO_MAP"};
976
977 switch ((int)offs) // Need the cast since offs is unsigned and the case statements are comparing to signed.
978 {
979 case ICorDebugInfo::EPILOG:
980 case ICorDebugInfo::PROLOG:
981 case ICorDebugInfo::NO_MAPPING:
982 assert(DWORD(ICorDebugInfo::EPILOG) + 1 == (unsigned)ICorDebugInfo::PROLOG);
983 assert(DWORD(ICorDebugInfo::EPILOG) + 2 == (unsigned)ICorDebugInfo::NO_MAPPING);
984 int specialOffsNum;
985 specialOffsNum = offs - DWORD(ICorDebugInfo::EPILOG);
986 printf("%s", specialOffs[specialOffsNum]);
987 break;
988 default:
989 printf("0x%04X", offs);
990 }
991}
992
993/* static */
994void Compiler::eeDispLineInfo(const boundariesDsc* line)
995{
996 printf("IL offs ");
997
998 eeDispILOffs(line->ilOffset);
999
1000 printf(" : 0x%08X", line->nativeIP);
1001 if (line->sourceReason != 0)
1002 {
1003 // It seems like it should probably never be zero since ICorDebugInfo::SOURCE_TYPE_INVALID is zero.
1004 // However, the JIT has always generated this and printed "stack non-empty".
1005
1006 printf(" ( ");
1007 if ((line->sourceReason & ICorDebugInfo::STACK_EMPTY) != 0)
1008 {
1009 printf("STACK_EMPTY ");
1010 }
1011 if ((line->sourceReason & ICorDebugInfo::CALL_INSTRUCTION) != 0)
1012 {
1013 printf("CALL_INSTRUCTION ");
1014 }
1015 if ((line->sourceReason & ICorDebugInfo::CALL_SITE) != 0)
1016 {
1017 printf("CALL_SITE ");
1018 }
1019 printf(")");
1020 }
1021 printf("\n");
1022
1023 // We don't expect to see any other bits.
1024 assert((line->sourceReason & ~(ICorDebugInfo::STACK_EMPTY | ICorDebugInfo::CALL_INSTRUCTION)) == 0);
1025}
1026
1027void Compiler::eeDispLineInfos()
1028{
1029 printf("IP mapping count : %d\n", eeBoundariesCount); // this might be zero
1030 for (unsigned i = 0; i < eeBoundariesCount; i++)
1031 {
1032 eeDispLineInfo(&eeBoundaries[i]);
1033 }
1034 printf("\n");
1035}
1036#endif // DEBUG
1037
1038/*****************************************************************************
1039 *
1040 * ICorJitInfo wrapper functions
1041 *
1042 * In many cases here, we don't tell the VM about various unwind or EH information if
1043 * we're an altjit for an unexpected architecture. If it's not a same architecture JIT
1044 * (e.g., host AMD64, target ARM64), then VM will get confused anyway.
1045 */
1046
1047void Compiler::eeReserveUnwindInfo(BOOL isFunclet, BOOL isColdCode, ULONG unwindSize)
1048{
1049#ifdef DEBUG
1050 if (verbose)
1051 {
1052 printf("reserveUnwindInfo(isFunclet=%s, isColdCode=%s, unwindSize=0x%x)\n", isFunclet ? "TRUE" : "FALSE",
1053 isColdCode ? "TRUE" : "FALSE", unwindSize);
1054 }
1055#endif // DEBUG
1056
1057 if (info.compMatchedVM)
1058 {
1059 info.compCompHnd->reserveUnwindInfo(isFunclet, isColdCode, unwindSize);
1060 }
1061}
1062
1063void Compiler::eeAllocUnwindInfo(BYTE* pHotCode,
1064 BYTE* pColdCode,
1065 ULONG startOffset,
1066 ULONG endOffset,
1067 ULONG unwindSize,
1068 BYTE* pUnwindBlock,
1069 CorJitFuncKind funcKind)
1070{
1071#ifdef DEBUG
1072 if (verbose)
1073 {
1074 printf("allocUnwindInfo(pHotCode=0x%p, pColdCode=0x%p, startOffset=0x%x, endOffset=0x%x, unwindSize=0x%x, "
1075 "pUnwindBlock=0x%p, funKind=%d",
1076 dspPtr(pHotCode), dspPtr(pColdCode), startOffset, endOffset, unwindSize, dspPtr(pUnwindBlock), funcKind);
1077 switch (funcKind)
1078 {
1079 case CORJIT_FUNC_ROOT:
1080 printf(" (main function)");
1081 break;
1082 case CORJIT_FUNC_HANDLER:
1083 printf(" (handler)");
1084 break;
1085 case CORJIT_FUNC_FILTER:
1086 printf(" (filter)");
1087 break;
1088 default:
1089 printf(" (ILLEGAL)");
1090 break;
1091 }
1092 printf(")\n");
1093 }
1094#endif // DEBUG
1095
1096 if (info.compMatchedVM)
1097 {
1098 info.compCompHnd->allocUnwindInfo(pHotCode, pColdCode, startOffset, endOffset, unwindSize, pUnwindBlock,
1099 funcKind);
1100 }
1101}
1102
1103void Compiler::eeSetEHcount(unsigned cEH)
1104{
1105#ifdef DEBUG
1106 if (verbose)
1107 {
1108 printf("setEHcount(cEH=%u)\n", cEH);
1109 }
1110#endif // DEBUG
1111
1112 if (info.compMatchedVM)
1113 {
1114 info.compCompHnd->setEHcount(cEH);
1115 }
1116}
1117
1118void Compiler::eeSetEHinfo(unsigned EHnumber, const CORINFO_EH_CLAUSE* clause)
1119{
1120#ifdef DEBUG
1121 if (opts.dspEHTable)
1122 {
1123 dispOutgoingEHClause(EHnumber, *clause);
1124 }
1125#endif // DEBUG
1126
1127 if (info.compMatchedVM)
1128 {
1129 info.compCompHnd->setEHinfo(EHnumber, clause);
1130 }
1131}
1132
1133WORD Compiler::eeGetRelocTypeHint(void* target)
1134{
1135 if (info.compMatchedVM)
1136 {
1137 return info.compCompHnd->getRelocTypeHint(target);
1138 }
1139 else
1140 {
1141 // No hints
1142 return (WORD)-1;
1143 }
1144}
1145
1146CORINFO_FIELD_HANDLE Compiler::eeFindJitDataOffs(unsigned dataOffs)
1147{
1148 // Data offsets are marked by the fact that the low two bits are 0b01 0x1
1149 assert(dataOffs < 0x40000000);
1150 return (CORINFO_FIELD_HANDLE)(size_t)((dataOffs << iaut_SHIFT) | iaut_DATA_OFFSET);
1151}
1152
1153bool Compiler::eeIsJitDataOffs(CORINFO_FIELD_HANDLE field)
1154{
1155 // if 'field' is a jit data offset it has to fit into a 32-bit unsigned int
1156 unsigned value = static_cast<unsigned>(reinterpret_cast<uintptr_t>(field));
1157 if (((CORINFO_FIELD_HANDLE)(size_t)value) != field)
1158 {
1159 return false; // upper bits were set, not a jit data offset
1160 }
1161
1162 // Data offsets are marked by the fact that the low two bits are 0b01 0x1
1163 return (value & iaut_MASK) == iaut_DATA_OFFSET;
1164}
1165
1166int Compiler::eeGetJitDataOffs(CORINFO_FIELD_HANDLE field)
1167{
1168 // Data offsets are marked by the fact that the low two bits are 0b01 0x1
1169 if (eeIsJitDataOffs(field))
1170 {
1171 unsigned dataOffs = static_cast<unsigned>(reinterpret_cast<uintptr_t>(field));
1172 assert(((CORINFO_FIELD_HANDLE)(size_t)dataOffs) == field);
1173 assert(dataOffs < 0x40000000);
1174 return (static_cast<int>(reinterpret_cast<intptr_t>(field))) >> iaut_SHIFT;
1175 }
1176 else
1177 {
1178 return -1;
1179 }
1180}
1181
1182/*****************************************************************************
1183 *
1184 * ICorStaticInfo wrapper functions
1185 */
1186
1187#if defined(UNIX_AMD64_ABI)
1188
1189#ifdef DEBUG
1190void Compiler::dumpSystemVClassificationType(SystemVClassificationType ct)
1191{
1192 switch (ct)
1193 {
1194 case SystemVClassificationTypeUnknown:
1195 printf("UNKNOWN");
1196 break;
1197 case SystemVClassificationTypeStruct:
1198 printf("Struct");
1199 break;
1200 case SystemVClassificationTypeNoClass:
1201 printf("NoClass");
1202 break;
1203 case SystemVClassificationTypeMemory:
1204 printf("Memory");
1205 break;
1206 case SystemVClassificationTypeInteger:
1207 printf("Integer");
1208 break;
1209 case SystemVClassificationTypeIntegerReference:
1210 printf("IntegerReference");
1211 break;
1212 case SystemVClassificationTypeIntegerByRef:
1213 printf("IntegerByReference");
1214 break;
1215 case SystemVClassificationTypeSSE:
1216 printf("SSE");
1217 break;
1218 default:
1219 printf("ILLEGAL");
1220 break;
1221 }
1222}
1223#endif // DEBUG
1224
1225void Compiler::eeGetSystemVAmd64PassStructInRegisterDescriptor(
1226 /*IN*/ CORINFO_CLASS_HANDLE structHnd,
1227 /*OUT*/ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr)
1228{
1229 bool ok = info.compCompHnd->getSystemVAmd64PassStructInRegisterDescriptor(structHnd, structPassInRegDescPtr);
1230 noway_assert(ok);
1231
1232#ifdef DEBUG
1233 if (verbose)
1234 {
1235 printf("**** getSystemVAmd64PassStructInRegisterDescriptor(0x%x (%s), ...) =>\n", dspPtr(structHnd),
1236 eeGetClassName(structHnd));
1237 printf(" passedInRegisters = %s\n", dspBool(structPassInRegDescPtr->passedInRegisters));
1238 if (structPassInRegDescPtr->passedInRegisters)
1239 {
1240 printf(" eightByteCount = %d\n", structPassInRegDescPtr->eightByteCount);
1241 for (unsigned int i = 0; i < structPassInRegDescPtr->eightByteCount; i++)
1242 {
1243 printf(" eightByte #%d -- classification: ", i);
1244 dumpSystemVClassificationType(structPassInRegDescPtr->eightByteClassifications[i]);
1245 printf(", byteSize: %d, byteOffset: %d\n", structPassInRegDescPtr->eightByteSizes[i],
1246 structPassInRegDescPtr->eightByteOffsets[i]);
1247 }
1248 }
1249 }
1250#endif // DEBUG
1251}
1252
1253#endif // UNIX_AMD64_ABI
1254
1255bool Compiler::eeTryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken)
1256{
1257 return info.compCompHnd->tryResolveToken(resolvedToken);
1258}
1259
1260bool Compiler::eeRunWithErrorTrapImp(void (*function)(void*), void* param)
1261{
1262 return info.compCompHnd->runWithErrorTrap(function, param);
1263}
1264
1265/*****************************************************************************
1266 *
1267 * Utility functions
1268 */
1269
1270#if defined(DEBUG) || defined(FEATURE_JIT_METHOD_PERF) || defined(FEATURE_SIMD) || defined(FEATURE_TRACELOGGING)
1271
1272/*****************************************************************************/
1273
1274// static helper names - constant array
1275const char* jitHlpFuncTable[CORINFO_HELP_COUNT] = {
1276#define JITHELPER(code, pfnHelper, sig) #code,
1277#define DYNAMICJITHELPER(code, pfnHelper, sig) #code,
1278#include "jithelpers.h"
1279};
1280
1281/*****************************************************************************
1282*
1283* Filter wrapper to handle exception filtering.
1284* On Unix compilers don't support SEH.
1285*/
1286
1287struct FilterSuperPMIExceptionsParam_ee_il
1288{
1289 Compiler* pThis;
1290 Compiler::Info* pJitInfo;
1291 CORINFO_FIELD_HANDLE field;
1292 CORINFO_METHOD_HANDLE method;
1293 CORINFO_CLASS_HANDLE clazz;
1294 const char** classNamePtr;
1295 const char* fieldOrMethodOrClassNamePtr;
1296 EXCEPTION_POINTERS exceptionPointers;
1297};
1298
1299static LONG FilterSuperPMIExceptions_ee_il(PEXCEPTION_POINTERS pExceptionPointers, LPVOID lpvParam)
1300{
1301 FilterSuperPMIExceptionsParam_ee_il* pSPMIEParam = (FilterSuperPMIExceptionsParam_ee_il*)lpvParam;
1302 pSPMIEParam->exceptionPointers = *pExceptionPointers;
1303
1304 if (pSPMIEParam->pThis->IsSuperPMIException(pExceptionPointers->ExceptionRecord->ExceptionCode))
1305 {
1306 return EXCEPTION_EXECUTE_HANDLER;
1307 }
1308
1309 return EXCEPTION_CONTINUE_SEARCH;
1310}
1311
1312const char* Compiler::eeGetMethodName(CORINFO_METHOD_HANDLE method, const char** classNamePtr)
1313{
1314 if (eeGetHelperNum(method))
1315 {
1316 if (classNamePtr != nullptr)
1317 {
1318 *classNamePtr = "HELPER";
1319 }
1320 CorInfoHelpFunc ftnNum = eeGetHelperNum(method);
1321 const char* name = info.compCompHnd->getHelperName(ftnNum);
1322
1323 // If it's something unknown from a RET VM, or from SuperPMI, then use our own helper name table.
1324 if ((strcmp(name, "AnyJITHelper") == 0) || (strcmp(name, "Yickish helper name") == 0))
1325 {
1326 if ((unsigned)ftnNum < CORINFO_HELP_COUNT)
1327 {
1328 name = jitHlpFuncTable[ftnNum];
1329 }
1330 }
1331 return name;
1332 }
1333
1334 if (eeIsNativeMethod(method))
1335 {
1336 if (classNamePtr != nullptr)
1337 {
1338 *classNamePtr = "NATIVE";
1339 }
1340 method = eeGetMethodHandleForNative(method);
1341 }
1342
1343 FilterSuperPMIExceptionsParam_ee_il param;
1344
1345 param.pThis = this;
1346 param.pJitInfo = &info;
1347 param.method = method;
1348 param.classNamePtr = classNamePtr;
1349
1350 PAL_TRY(FilterSuperPMIExceptionsParam_ee_il*, pParam, &param)
1351 {
1352 pParam->fieldOrMethodOrClassNamePtr =
1353 pParam->pJitInfo->compCompHnd->getMethodName(pParam->method, pParam->classNamePtr);
1354 }
1355 PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_ee_il)
1356 {
1357 if (param.classNamePtr != nullptr)
1358 {
1359 *(param.classNamePtr) = "hackishClassName";
1360 }
1361
1362 param.fieldOrMethodOrClassNamePtr = "hackishMethodName";
1363 }
1364 PAL_ENDTRY
1365
1366 return param.fieldOrMethodOrClassNamePtr;
1367}
1368
1369const char* Compiler::eeGetFieldName(CORINFO_FIELD_HANDLE field, const char** classNamePtr)
1370{
1371 FilterSuperPMIExceptionsParam_ee_il param;
1372
1373 param.pThis = this;
1374 param.pJitInfo = &info;
1375 param.field = field;
1376 param.classNamePtr = classNamePtr;
1377
1378 PAL_TRY(FilterSuperPMIExceptionsParam_ee_il*, pParam, &param)
1379 {
1380 pParam->fieldOrMethodOrClassNamePtr =
1381 pParam->pJitInfo->compCompHnd->getFieldName(pParam->field, pParam->classNamePtr);
1382 }
1383 PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_ee_il)
1384 {
1385 param.fieldOrMethodOrClassNamePtr = "hackishFieldName";
1386 }
1387 PAL_ENDTRY
1388
1389 return param.fieldOrMethodOrClassNamePtr;
1390}
1391
1392const char* Compiler::eeGetClassName(CORINFO_CLASS_HANDLE clsHnd)
1393{
1394 FilterSuperPMIExceptionsParam_ee_il param;
1395
1396 param.pThis = this;
1397 param.pJitInfo = &info;
1398 param.clazz = clsHnd;
1399
1400 PAL_TRY(FilterSuperPMIExceptionsParam_ee_il*, pParam, &param)
1401 {
1402 pParam->fieldOrMethodOrClassNamePtr = pParam->pJitInfo->compCompHnd->getClassName(pParam->clazz);
1403 }
1404 PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_ee_il)
1405 {
1406 param.fieldOrMethodOrClassNamePtr = "hackishClassName";
1407 }
1408 PAL_ENDTRY
1409 return param.fieldOrMethodOrClassNamePtr;
1410}
1411
1412#endif // DEBUG || FEATURE_JIT_METHOD_PERF
1413
1414#ifdef DEBUG
1415
1416const wchar_t* Compiler::eeGetCPString(size_t strHandle)
1417{
1418#ifdef FEATURE_PAL
1419 return nullptr;
1420#else
1421 char buff[512 + sizeof(CORINFO_String)];
1422
1423 // make this bulletproof, so it works even if we are wrong.
1424 if (ReadProcessMemory(GetCurrentProcess(), (void*)strHandle, buff, 4, nullptr) == 0)
1425 {
1426 return (nullptr);
1427 }
1428
1429 CORINFO_String* asString = *((CORINFO_String**)strHandle);
1430
1431 if (ReadProcessMemory(GetCurrentProcess(), asString, buff, sizeof(buff), nullptr) == 0)
1432 {
1433 return (nullptr);
1434 }
1435
1436 if (asString->stringLen >= 255 || asString->chars[asString->stringLen] != 0)
1437 {
1438 return nullptr;
1439 }
1440
1441 return (asString->chars);
1442#endif // FEATURE_PAL
1443}
1444
1445#endif // DEBUG
1446