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