Harden stdout at startup
[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(PLATFORM_UNIX)
24 #include <io.h>    // For _dup, _setmode
25 #include <fcntl.h> // For _O_TEXT
26 #endif
27
28 /*****************************************************************************/
29
30 FILE* jitstdout = nullptr;
31
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
38
39 /*****************************************************************************/
40
41 #ifdef  DEBUG
42
43 JitOptions jitOpts =
44 {
45     NULL,   // methodName
46     NULL,   // className
47     0.1,    // CGknob
48     0,      // testMask
49
50     (JitOptions *)NULL // lastDummyField.
51 };
52
53 #endif // DEBUG
54
55 /*****************************************************************************/
56
57 extern "C"
58 void __stdcall jitStartup(ICorJitHost* jitHost)
59 {
60     if (g_jitInitialized)
61     {
62         return;
63     }
64
65     g_jitHost = jitHost;
66
67     assert(!JitConfig.isInitialized());
68     JitConfig.initialize(jitHost);
69
70 #if defined(PLATFORM_UNIX)
71     jitstdout = procstdout();
72 #else
73     if (jitstdout == nullptr)
74     {
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))
81         {
82             int jitstdoutFd = _dup(_fileno(procstdout()));
83             // Check the error status returned by dup.
84             if (jitstdoutFd != -1)
85             {
86                 _setmode(jitstdoutFd, _O_TEXT);
87                 jitstdout = _fdopen(jitstdoutFd, "w");
88                 assert(jitstdout != nullptr);
89
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);
93             }
94         }
95     }
96
97     // If jitstdout is still null, fallback to whatever procstdout() was
98     // initially set to.
99     if (jitstdout == nullptr)
100     {
101         jitstdout = procstdout();
102     }
103 #endif // PLATFORM_UNIX
104
105 #ifdef FEATURE_TRACELOGGING
106     JitTelemetry::NotifyDllProcessAttach();
107 #endif
108     Compiler::compStartup();
109
110     g_jitInitialized = true;
111 }
112
113 void jitShutdown()
114 {
115     if (!g_jitInitialized)
116     {
117         return;
118     }
119
120     Compiler::compShutdown();
121
122     if (jitstdout != procstdout())
123     {
124         fclose(jitstdout);
125     }
126
127 #ifdef FEATURE_TRACELOGGING
128     JitTelemetry::NotifyDllProcessDetach();
129 #endif
130 }
131
132 #ifndef FEATURE_MERGE_JIT_AND_ENGINE
133
134 extern "C"
135 BOOL WINAPI     DllMain(HANDLE hInstance, DWORD dwReason, LPVOID pvReserved)
136 {
137     if (dwReason == DLL_PROCESS_ATTACH)
138     {
139         g_hInst = (HINSTANCE)hInstance;
140         DisableThreadLibraryCalls((HINSTANCE)hInstance);
141 #if defined(SELF_NO_HOST) && COR_JIT_EE_VERSION <= 460
142         jitStartup(JitHost::getJitHost());
143 #endif
144     }
145     else if (dwReason == DLL_PROCESS_DETACH)
146     {
147         jitShutdown();
148     }
149
150     return TRUE;
151 }
152
153 HINSTANCE GetModuleInst()
154 {
155     return (g_hInst);
156 }
157
158 extern "C"
159 void __stdcall sxsJitStartup(CoreClrCallbacks const & cccallbacks)
160 {
161 #ifndef SELF_NO_HOST
162     InitUtilcode(cccallbacks);
163 #endif
164
165 #if COR_JIT_EE_VERSION <= 460
166     jitStartup(JitHost::getJitHost());
167 #endif
168 }
169
170 #endif // !FEATURE_MERGE_JIT_AND_ENGINE
171
172 /*****************************************************************************/
173
174 struct CILJitSingletonAllocator { int x; };
175 const CILJitSingletonAllocator CILJitSingleton = { 0 };
176
177 void *__cdecl operator new(size_t, const CILJitSingletonAllocator&)
178 {
179     static char CILJitBuff[sizeof(CILJit)];
180     return CILJitBuff;
181 }
182
183 ICorJitCompiler* g_realJitCompiler = nullptr;
184
185 ICorJitCompiler* __stdcall getJit()
186 {
187     if (ILJitter == 0)
188     {
189         ILJitter = new (CILJitSingleton) CILJit();
190     }
191     return(ILJitter);
192 }
193
194 /*****************************************************************************/
195
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.
199 //
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)
202
203 __declspec(thread) void* gJitTls = nullptr;
204
205 static void* GetJitTls()
206 {
207     return gJitTls;
208 }
209
210 void SetJitTls(void* value)
211 {
212     gJitTls = value;
213 }
214
215 #else // !defined(FEATURE_MERGE_JIT_AND_ENGINE) || !defined(FEATURE_IMPLICIT_TLS)
216
217 extern "C"
218 {
219 void* GetJitTls();
220 void SetJitTls(void* value);
221 }
222
223 #endif // // defined(FEATURE_MERGE_JIT_AND_ENGINE) && defined(FEATURE_IMPLICIT_TLS)
224
225 #if defined(DEBUG)
226
227 JitTls::JitTls(ICorJitInfo* jitInfo)
228     : m_compiler(nullptr)
229     , m_logEnv(jitInfo)
230 {
231     m_next = reinterpret_cast<JitTls*>(GetJitTls());
232     SetJitTls(this);
233 }
234
235 JitTls::~JitTls()
236 {
237     SetJitTls(m_next);
238 }
239
240 LogEnv* JitTls::GetLogEnv()
241 {
242     return &reinterpret_cast<JitTls*>(GetJitTls())->m_logEnv;
243 }
244
245 Compiler* JitTls::GetCompiler()
246 {
247     return reinterpret_cast<JitTls*>(GetJitTls())->m_compiler;
248 }
249
250 void JitTls::SetCompiler(Compiler* compiler)
251 {
252     reinterpret_cast<JitTls*>(GetJitTls())->m_compiler = compiler;
253 }
254
255 #else // defined(DEBUG)
256
257 JitTls::JitTls(ICorJitInfo* jitInfo)
258 {
259 }
260
261 JitTls::~JitTls()
262 {
263 }
264
265 Compiler* JitTls::GetCompiler()
266 {
267     return reinterpret_cast<Compiler*>(GetJitTls());
268 }
269
270 void JitTls::SetCompiler(Compiler* compiler)
271 {
272     SetJitTls(compiler);
273 }
274
275 #endif // !defined(DEBUG)
276
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. 
281
282 CorJitResult CILJit::compileMethod (
283             ICorJitInfo*       compHnd,
284             CORINFO_METHOD_INFO* methodInfo,
285             unsigned        flags,
286             BYTE **         entryAddress,
287             ULONG  *        nativeSizeOfCode)
288 {
289     if (g_realJitCompiler != nullptr)
290     {
291         return g_realJitCompiler->compileMethod(compHnd, methodInfo, flags, entryAddress, nativeSizeOfCode);
292     }
293
294     CORJIT_FLAGS jitFlags = { 0 };
295
296     DWORD jitFlagsSize = 0;
297 #if COR_JIT_EE_VERSION > 460
298     if (flags == CORJIT_FLG_CALL_GETJITFLAGS)
299     {
300         jitFlagsSize = compHnd->getJitFlags(&jitFlags, sizeof(jitFlags));
301     }
302 #endif
303
304     assert(jitFlagsSize <= sizeof(jitFlags));
305     if (jitFlagsSize == 0)
306     {
307         jitFlags.corJitFlags = flags;
308     }
309
310     int                     result;
311     void *                  methodCodePtr = NULL;
312     CORINFO_METHOD_HANDLE   methodHandle  = methodInfo->ftn;
313
314     JitTls jitTls(compHnd); // Initialize any necessary thread-local state
315
316     assert(methodInfo->ILCode);
317
318     result = jitNativeCode(methodHandle,
319                            methodInfo->scope,
320                            compHnd,
321                            methodInfo,
322                            &methodCodePtr,
323                            nativeSizeOfCode,
324                            &jitFlags,
325                            NULL);
326
327     if (result == CORJIT_OK)
328         *entryAddress = (BYTE*)methodCodePtr;
329
330     return CorJitResult(result);
331 }
332
333 /*****************************************************************************
334  * Notification from VM to clear any caches
335  */
336 void CILJit::clearCache ( void )
337 {
338     if (g_realJitCompiler != nullptr)
339     {
340         g_realJitCompiler->clearCache();
341         // Continue...
342     }
343
344     return;
345 }
346
347 /*****************************************************************************
348  * Notify vm that we have something to clean up
349  */
350 BOOL CILJit::isCacheCleanupRequired ( void )
351 {
352     BOOL doCleanup;
353
354     if (g_realJitCompiler != nullptr)
355     {
356         if (g_realJitCompiler->isCacheCleanupRequired())
357             return TRUE;
358         // Continue...
359     }
360
361     return FALSE;
362 }
363
364 void CILJit::ProcessShutdownWork(ICorStaticInfo* statInfo)
365 {
366     if (g_realJitCompiler != nullptr)
367     {
368         g_realJitCompiler->ProcessShutdownWork(statInfo);
369         // Continue, by shutting down this JIT as well.
370     }
371
372 #ifdef FEATURE_MERGE_JIT_AND_ENGINE
373     jitShutdown();
374 #endif
375
376     Compiler::ProcessShutdownWork(statInfo);
377 }
378
379 /*****************************************************************************
380  * Verify the JIT/EE interface identifier.
381  */
382 void CILJit::getVersionIdentifier(GUID* versionIdentifier)
383 {
384     if (g_realJitCompiler != nullptr)
385     {
386         g_realJitCompiler->getVersionIdentifier(versionIdentifier);
387         return;
388     }
389
390     assert(versionIdentifier != nullptr);
391     memcpy(versionIdentifier, &JITEEVersionIdentifier, sizeof(GUID));
392 }
393
394 /*****************************************************************************
395  * Determine the maximum length of SIMD vector supported by this JIT.
396  */
397 unsigned CILJit::getMaxIntrinsicSIMDVectorLength(DWORD cpuCompileFlags)
398 {
399     if (g_realJitCompiler != nullptr)
400     {
401         return g_realJitCompiler->getMaxIntrinsicSIMDVectorLength(cpuCompileFlags);
402     }
403
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))
409     {
410         if (JitConfig.EnableAVX() != 0)
411         {
412             return 32;
413         }
414     }
415 #endif // FEATURE_AVX_SUPPORT
416     return 16;
417 #else // !_TARGET_AMD64_
418     return 0;
419 #endif // !_TARGET_AMD64_
420 }
421
422 void CILJit::setRealJit(ICorJitCompiler* realJitCompiler)
423 {
424     g_realJitCompiler = realJitCompiler;
425 }
426
427
428 /*****************************************************************************
429  * Returns the number of bytes required for the given type argument
430  */
431
432 unsigned           Compiler::eeGetArgSize(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig)
433 {
434 #if defined(_TARGET_AMD64_) 
435
436     // Everything fits into a single 'slot' size
437     // to accommodate irregular sized structs, they are passed byref
438
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))
444     {
445         unsigned structSize = info.compCompHnd->getClassSize(argClass);
446         return structSize;  // TODO: roundUp() needed here?
447     }
448 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
449     return sizeof(size_t);
450
451 #else // !_TARGET_AMD64_ 
452
453     CORINFO_CLASS_HANDLE        argClass;
454     CorInfoType argTypeJit = strip(info.compCompHnd->getArgType(sig, list, &argClass));
455     var_types argType = JITtype2varType(argTypeJit);
456
457     if (varTypeIsStruct(argType))
458     {
459         unsigned structSize = info.compCompHnd->getClassSize(argClass);
460
461         // make certain the EE passes us back the right thing for refanys
462         assert(argTypeJit != CORINFO_TYPE_REFANY || structSize == 2*sizeof(void*));
463
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)
470         {
471             // This struct is passed by reference using a single 'slot'
472             return TARGET_POINTER_SIZE;
473         }
474         else
475         {
476             // Is the struct larger than 16 bytes
477             if (structSize > (2 * TARGET_POINTER_SIZE))
478             {
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);
481                 if (!isHfa)
482                 {
483                     // This struct is passed by reference using a single 'slot'
484                     return TARGET_POINTER_SIZE;
485                 }
486             }
487         }
488         // otherwise will we pass this struct by value in multiple registers
489         //
490 #elif defined(_TARGET_ARM_)
491         //  otherwise will we pass this struct by value in multiple registers
492 #else // 
493         NYI("unknown target");
494 #endif // defined(_TARGET_XXX_)
495 #endif // FEATURE_MULTIREG_ARGS
496
497         // we pass this struct by value in multiple registers
498         return (unsigned)roundUp(structSize, TARGET_POINTER_SIZE);
499     }
500     else
501     {
502         unsigned  argSize = sizeof(int) * genTypeStSz(argType);
503         assert(0 < argSize && argSize <= sizeof(__int64));
504         return (unsigned)roundUp(argSize, TARGET_POINTER_SIZE);
505     }
506 #endif
507 }
508
509 /*****************************************************************************/
510
511 GenTreePtr          Compiler::eeGetPInvokeCookie(CORINFO_SIG_INFO *szMetaSig)
512 {
513     void * cookie, * pCookie;
514     cookie = info.compCompHnd->GetCookieForPInvokeCalliSig(szMetaSig, &pCookie);
515     assert((cookie == NULL) != (pCookie == NULL));
516
517     return gtNewIconEmbHndNode(cookie, pCookie, GTF_ICON_PINVKI_HDL);
518 }
519
520 //------------------------------------------------------------------------
521 // eeGetArrayDataOffset: Gets the offset of a SDArray's first element
522 //
523 // Arguments:
524 //    type - The array element type
525 //
526 // Return Value:
527 //    The offset to the first array element. 
528
529 unsigned           Compiler::eeGetArrayDataOffset(var_types type)
530 {
531     return varTypeIsGC(type) ? eeGetEEInfo()->offsetOfObjArrayData 
532                                                  : offsetof(CORINFO_Array, u1Elems);
533 }
534
535 //------------------------------------------------------------------------
536 // eeGetMDArrayDataOffset: Gets the offset of a MDArray's first element
537 //
538 // Arguments:
539 //    type - The array element type
540 //    rank - The array rank
541 //
542 // Return Value:
543 //    The offset to the first array element.
544 //
545 // Assumptions:
546 //    The rank should be greater than 0.
547
548 unsigned           Compiler::eeGetMDArrayDataOffset(var_types type, unsigned rank)
549 {
550     assert(rank > 0);
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;
554 }
555
556 /*****************************************************************************/
557
558 void                Compiler::eeGetStmtOffsets()
559 {
560     ULONG32                      offsetsCount;
561     DWORD                   *    offsets;
562     ICorDebugInfo::BoundaryTypes offsetsImplicit;
563
564     info.compCompHnd->getBoundaries(info.compMethodHnd,
565                                     &offsetsCount,
566                                     &offsets,
567                                     &offsetsImplicit);
568
569     /* Set the implicit boundaries */
570
571     info.compStmtOffsetsImplicit = (ICorDebugInfo::BoundaryTypes)offsetsImplicit;
572
573     /* Process the explicit boundaries */
574
575     info.compStmtOffsetsCount = 0;
576
577     if (offsetsCount == 0)
578         return;
579
580     info.compStmtOffsets = new (this, CMK_DebugInfo) IL_OFFSET[offsetsCount];
581
582     for (unsigned i = 0; i < offsetsCount; i++)
583     {
584         if (offsets[i] > info.compILCodeSize)
585             continue;
586
587         info.compStmtOffsets[info.compStmtOffsetsCount] = offsets[i];
588         info.compStmtOffsetsCount++;
589     }
590
591     info.compCompHnd->freeArray(offsets);
592 }
593
594 /*****************************************************************************
595  *
596  *                  Debugging support - Local var info
597  */
598
599 void                Compiler::eeSetLVcount  (unsigned      count)
600 {
601     assert(opts.compScopeInfo);
602     
603     JITDUMP("VarLocInfo count is %d\n", count);
604
605     eeVarsCount = count;
606     if (eeVarsCount)
607         eeVars = (VarResultInfo *)info.compCompHnd->allocateArray(eeVarsCount * sizeof(eeVars[0]));
608     else
609         eeVars = NULL;
610 }
611
612 void                Compiler::eeSetLVinfo
613                                 (unsigned                   which,
614                                  UNATIVE_OFFSET             startOffs,
615                                  UNATIVE_OFFSET             length,
616                                  unsigned                   varNum,
617                                  unsigned                   LVnum,
618                                  VarName                    name,
619                                  bool                       avail,
620                                  const Compiler::siVarLoc & varLoc)
621 {
622     // ICorDebugInfo::VarLoc and Compiler::siVarLoc have to overlap
623     // This is checked in siInit()
624
625     assert(opts.compScopeInfo);
626     assert(eeVarsCount > 0);
627     assert(which < eeVarsCount);
628
629     if (eeVars != NULL)
630     {
631         eeVars[which].startOffset   = startOffs;
632         eeVars[which].endOffset     = startOffs + length;
633         eeVars[which].varNumber     = varNum;
634         eeVars[which].loc           = varLoc;
635     }
636 }
637
638 void                Compiler::eeSetLVdone()
639 {
640     // necessary but not sufficient condition that the 2 struct definitions overlap
641     assert(sizeof(eeVars[0]) == sizeof(ICorDebugInfo::NativeVarInfo));
642     assert(opts.compScopeInfo);
643
644 #ifdef DEBUG
645     if (verbose)
646     {
647         eeDispVars(info.compMethodHnd,
648                    eeVarsCount,
649                    (ICorDebugInfo::NativeVarInfo *) eeVars);
650     }
651 #endif // DEBUG
652
653     info.compCompHnd->setVars(info.compMethodHnd,
654                               eeVarsCount,
655                               (ICorDebugInfo::NativeVarInfo *) eeVars);
656
657     eeVars = NULL; // We give up ownership after setVars()
658 }
659
660 void            Compiler::eeGetVars()
661 {
662     ICorDebugInfo::ILVarInfo *  varInfoTable;
663     ULONG32                     varInfoCount;
664     bool                        extendOthers;
665
666     info.compCompHnd->getVars(info.compMethodHnd,
667                               &varInfoCount, &varInfoTable, &extendOthers);
668
669 #ifdef DEBUG
670     if (verbose)
671         printf("getVars() returned cVars = %d, extendOthers = %s\n", varInfoCount, extendOthers ? "true" : "false");
672 #endif
673
674     // Over allocate in case extendOthers is set.
675
676     SIZE_T  varInfoCountExtra = varInfoCount;
677     if (extendOthers)
678         varInfoCountExtra += info.compLocalsCount;
679
680     if (varInfoCountExtra == 0)
681         return;
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             printf("var:%d start:%d end:%d\n",
693                    v->varNumber,
694                    v->startOffset,
695                    v->endOffset);
696 #endif
697
698         if (v->startOffset >= v->endOffset)
699             continue;
700
701         assert(v->startOffset <= info.compILCodeSize);
702         assert(v->endOffset   <= info.compILCodeSize);
703
704         localVarPtr->vsdLifeBeg = v->startOffset;
705         localVarPtr->vsdLifeEnd = v->endOffset;
706         localVarPtr->vsdLVnum   = i;
707         localVarPtr->vsdVarNum  = compMapILvarNum(v->varNumber);
708
709 #ifdef DEBUG
710         localVarPtr->vsdName    = gtGetLclVarName(localVarPtr->vsdVarNum);
711 #endif
712
713         localVarPtr++;
714         info.compVarScopesCount++;
715     }
716
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.
721      */
722     if  (extendOthers)
723     {
724         // Allocate a bit-array for all the variables and initialize to false
725
726         bool * varInfoProvided = (bool *)compGetMemA(info.compLocalsCount *
727                                                 sizeof(varInfoProvided[0]));
728         unsigned i;
729         for (i = 0; i < info.compLocalsCount; i++)
730             varInfoProvided[i] = false;
731
732         // Find which vars have absolutely no varInfo provided
733
734         for (i = 0; i < info.compVarScopesCount; i++)
735             varInfoProvided[info.compVarScopes[i].vsdVarNum] = true;
736
737         // Create entries for the variables with no varInfo
738
739         for (unsigned varNum = 0; varNum < info.compLocalsCount; varNum++)
740         {
741             if (varInfoProvided[varNum])
742                 continue;
743
744             // Create a varInfo with scope over the entire method
745
746             localVarPtr->vsdLifeBeg = 0;
747             localVarPtr->vsdLifeEnd = info.compILCodeSize;
748             localVarPtr->vsdVarNum  = varNum;
749             localVarPtr->vsdLVnum   = info.compVarScopesCount;
750
751 #ifdef DEBUG
752             localVarPtr->vsdName    = gtGetLclVarName(localVarPtr->vsdVarNum);
753 #endif
754
755             localVarPtr++;
756             info.compVarScopesCount++;
757         }
758     }
759
760     assert(localVarPtr <= info.compVarScopes + varInfoCountExtra);
761
762     if (varInfoCount != 0)
763         info.compCompHnd->freeArray(varInfoTable);
764
765 #ifdef DEBUG
766     if (verbose)
767         compDispLocalVars();
768 #endif // DEBUG
769 }
770
771 #ifdef DEBUG
772 void                Compiler::eeDispVar(ICorDebugInfo::NativeVarInfo* var)
773 {
774     const char* name = NULL;
775
776     if (var->varNumber == (DWORD)ICorDebugInfo::VARARGS_HND_ILNUM)
777         name = "varargsHandle";
778     else if (var->varNumber == (DWORD)ICorDebugInfo::RETBUF_ILNUM)
779         name = "retBuff";
780     else if (var->varNumber == (DWORD)ICorDebugInfo::TYPECTXT_ILNUM)
781         name = "typeCtx";
782
783     printf("%3d(%10s) : From %08Xh to %08Xh, in ",
784         var->varNumber,
785         (VarNameToStr(name) == NULL) ? "UNKNOWN" : VarNameToStr(name),
786         var->startOffset,
787         var->endOffset);
788
789     switch (var->loc.vlType)
790     {
791     case VLT_REG:
792     case VLT_REG_BYREF:
793     case VLT_REG_FP:
794         printf("%s", getRegName(var->loc.vlReg.vlrReg));
795         if (var->loc.vlType == (ICorDebugInfo::VarLocType)VLT_REG_BYREF)
796         {
797             printf(" byref");
798         }
799         break;
800
801     case VLT_STK:
802     case VLT_STK_BYREF:
803         if ((int) var->loc.vlStk.vlsBaseReg != (int) ICorDebugInfo::REGNUM_AMBIENT_SP)
804         {
805             printf("%s[%d] (1 slot)",    getRegName(var->loc.vlStk.vlsBaseReg),
806                                           var->loc.vlStk.vlsOffset);
807         }
808         else
809         {
810             printf(STR_SPBASE "'[%d] (1 slot)",  var->loc.vlStk.vlsOffset);
811         }
812         if (var->loc.vlType == (ICorDebugInfo::VarLocType)VLT_REG_BYREF)
813         {
814             printf(" byref");
815         }
816         break;
817
818 #ifndef _TARGET_AMD64_
819     case VLT_REG_REG:
820         printf("%s-%s",     getRegName(var->loc.vlRegReg.vlrrReg1),
821                             getRegName(var->loc.vlRegReg.vlrrReg2));
822         break;
823
824     case VLT_REG_STK:
825         if ((int) var->loc.vlRegStk.vlrsStk.vlrssBaseReg != (int) ICorDebugInfo::REGNUM_AMBIENT_SP)
826         {
827             printf("%s-%s[%d]", getRegName(var->loc.vlRegStk.vlrsReg),
828                                 getRegName(var->loc.vlRegStk.vlrsStk.vlrssBaseReg),
829                                 var->loc.vlRegStk.vlrsStk.vlrssOffset);
830         }
831         else
832         {
833             printf("%s-" STR_SPBASE "'[%d]", getRegName(var->loc.vlRegStk.vlrsReg),
834                                              var->loc.vlRegStk.vlrsStk.vlrssOffset);
835         }
836         break;
837
838     case VLT_STK_REG:
839         unreached(); // unexpected
840
841     case VLT_STK2:
842         if ((int) var->loc.vlStk2.vls2BaseReg != (int) ICorDebugInfo::REGNUM_AMBIENT_SP)
843         {
844             printf("%s[%d] (2 slots)", getRegName(var->loc.vlStk2.vls2BaseReg),
845                                       var->loc.vlStk2.vls2Offset);
846         }
847         else
848         {
849             printf(STR_SPBASE "'[%d] (2 slots)", var->loc.vlStk2.vls2Offset);
850         }
851         break;
852
853     case VLT_FPSTK:
854         printf("ST(L-%d)",  var->loc.vlFPstk.vlfReg);
855         break;
856
857     case VLT_FIXED_VA:
858         printf("fxd_va[%d]", var->loc.vlFixedVarArg.vlfvOffset);
859         break;
860 #endif // !_TARGET_AMD64_
861
862     default:
863         unreached(); // unexpected
864     }
865
866     printf("\n");
867 }
868
869 // Same parameters as ICorStaticInfo::setVars().
870 void                Compiler::eeDispVars(CORINFO_METHOD_HANDLE           ftn,
871                                          ULONG32                         cVars,
872                                          ICorDebugInfo::NativeVarInfo*   vars)
873 {
874     printf("*************** Variable debug info\n");
875     printf("%d vars\n", cVars);
876     for (unsigned i = 0; i < cVars; i++)
877     {
878         eeDispVar(&vars[i]);
879     }
880 }
881 #endif // DEBUG
882
883 /*****************************************************************************
884  *
885  *                  Debugging support - Line number info
886  */
887
888 void                Compiler::eeSetLIcount   (unsigned       count)
889 {
890     assert(opts.compDbgInfo);
891     
892     eeBoundariesCount = count;
893     if (eeBoundariesCount)
894         eeBoundaries = (boundariesDsc *) info.compCompHnd->allocateArray(eeBoundariesCount * sizeof(eeBoundaries[0]));
895     else
896         eeBoundaries = NULL;
897 }
898
899 void                Compiler::eeSetLIinfo  (unsigned       which,
900                                             UNATIVE_OFFSET nativeOffset,
901                                             IL_OFFSET      ilOffset,
902                                             bool           stkEmpty,
903                                             bool           callInstruction)
904 {
905     assert(opts.compDbgInfo);
906     assert(eeBoundariesCount > 0);
907     assert(which < eeBoundariesCount);
908
909     if (eeBoundaries != NULL)
910     {
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;
915     }
916 }
917
918 void                Compiler::eeSetLIdone()
919 {
920     assert(opts.compDbgInfo);
921
922 #if defined(DEBUG)
923     if (verbose)
924     {
925         eeDispLineInfos();
926     }
927 #endif // DEBUG
928
929     // necessary but not sufficient condition that the 2 struct definitions overlap
930     assert(sizeof(eeBoundaries[0]) == sizeof(ICorDebugInfo::OffsetMapping));
931
932     info.compCompHnd->setBoundaries(info.compMethodHnd,
933                                     eeBoundariesCount,
934                                     (ICorDebugInfo::OffsetMapping *) eeBoundaries);
935
936     eeBoundaries = NULL; // we give up ownership after setBoundaries();
937 }
938
939 #if defined(DEBUG)
940
941 /* static */
942 void                Compiler::eeDispILOffs(IL_OFFSET offs)
943 {
944     const char * specialOffs[] = { "EPILOG", "PROLOG", "NO_MAP" };
945
946     switch ((int)offs) // Need the cast since offs is unsigned and the case statements are comparing to signed.
947     {
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);
953         int specialOffsNum;
954         specialOffsNum = offs - DWORD(ICorDebugInfo::EPILOG);
955         printf("%s", specialOffs[specialOffsNum]);
956         break;
957     default:
958         printf("0x%04X", offs);
959     }
960 }
961
962 /* static */
963 void                Compiler::eeDispLineInfo(const boundariesDsc* line)
964 {
965     printf("IL offs ");
966
967     eeDispILOffs(line->ilOffset);
968
969     printf(" : 0x%08X", line->nativeIP);
970     if (line->sourceReason != 0)
971     {
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".
974
975         printf(" ( ");
976         if ((line->sourceReason & ICorDebugInfo::STACK_EMPTY) != 0)
977         {
978             printf("STACK_EMPTY ");
979         }
980         if ((line->sourceReason & ICorDebugInfo::CALL_INSTRUCTION) != 0)
981         {
982             printf("CALL_INSTRUCTION ");
983         }
984         if ((line->sourceReason & ICorDebugInfo::CALL_SITE) != 0)
985         {
986             printf("CALL_SITE ");
987         }
988         printf(")");
989     }
990     printf("\n");
991
992     // We don't expect to see any other bits.
993     assert((line->sourceReason & ~(ICorDebugInfo::STACK_EMPTY | ICorDebugInfo::CALL_INSTRUCTION)) == 0);
994 }
995
996 void                Compiler::eeDispLineInfos()
997 {
998     printf("IP mapping count : %d\n", eeBoundariesCount); // this might be zero
999     for (unsigned i = 0; i < eeBoundariesCount; i++)
1000     {
1001         eeDispLineInfo(&eeBoundaries[i]);
1002     }
1003     printf("\n");
1004 }
1005 #endif // DEBUG
1006
1007 /*****************************************************************************
1008  *
1009  *                      ICorJitInfo wrapper functions
1010  *
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.
1014  */
1015
1016 void            Compiler::eeReserveUnwindInfo(BOOL isFunclet,
1017                                               BOOL isColdCode,
1018                                               ULONG unwindSize)
1019 {
1020 #ifdef DEBUG
1021     if (verbose)
1022     {
1023         printf("reserveUnwindInfo(isFunclet=%s, isColdCode=%s, unwindSize=0x%x)\n",
1024             isFunclet  ? "TRUE" : "FALSE",
1025             isColdCode ? "TRUE" : "FALSE",
1026             unwindSize);
1027     }
1028 #endif // DEBUG
1029
1030     if (info.compMatchedVM)
1031     {
1032         info.compCompHnd->reserveUnwindInfo(isFunclet, isColdCode, unwindSize);
1033     }
1034 }
1035
1036 void            Compiler::eeAllocUnwindInfo(BYTE*  pHotCode,
1037                                             BYTE*  pColdCode,
1038                                             ULONG  startOffset,
1039                                             ULONG  endOffset,
1040                                             ULONG  unwindSize,
1041                                             BYTE*  pUnwindBlock,
1042                                             CorJitFuncKind funcKind)
1043 {
1044 #ifdef DEBUG
1045     if (verbose)
1046     {
1047         printf("allocUnwindInfo(pHotCode=0x%p, pColdCode=0x%p, startOffset=0x%x, endOffset=0x%x, unwindSize=0x%x, pUnwindBlock=0x%p, funKind=%d",
1048             dspPtr(pHotCode),
1049             dspPtr(pColdCode),
1050             startOffset,
1051             endOffset,
1052             unwindSize,
1053             dspPtr(pUnwindBlock),
1054             funcKind);
1055         switch (funcKind)
1056         {
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;
1061         }
1062         printf(")\n");
1063     }
1064 #endif // DEBUG
1065
1066     if (info.compMatchedVM)
1067     {
1068         info.compCompHnd->allocUnwindInfo(
1069             pHotCode,
1070             pColdCode,
1071             startOffset,
1072             endOffset,
1073             unwindSize,
1074             pUnwindBlock,
1075             funcKind);
1076     }
1077 }
1078
1079 void                Compiler::eeSetEHcount(unsigned cEH)
1080 {
1081 #ifdef DEBUG
1082     if (verbose)
1083     {
1084         printf("setEHcount(cEH=%u)\n", cEH);
1085     }
1086 #endif // DEBUG
1087
1088     if (info.compMatchedVM)
1089     {
1090         info.compCompHnd->setEHcount(cEH);
1091     }
1092 }
1093
1094 void                Compiler::eeSetEHinfo(unsigned                 EHnumber,
1095                                           const CORINFO_EH_CLAUSE *clause)
1096 {
1097 #ifdef DEBUG
1098     if (opts.dspEHTable)
1099     {
1100         dispOutgoingEHClause(EHnumber, *clause);
1101     }
1102 #endif // DEBUG
1103
1104     if (info.compMatchedVM)
1105     {
1106         info.compCompHnd->setEHinfo(EHnumber, clause);
1107     }
1108 }
1109
1110 WORD                Compiler::eeGetRelocTypeHint(void * target)
1111 {
1112     if (info.compMatchedVM)
1113     {
1114         return info.compCompHnd->getRelocTypeHint(target);
1115     }
1116     else
1117     {
1118         // No hints
1119         return (WORD)-1;
1120     }
1121 }
1122
1123
1124 CORINFO_FIELD_HANDLE Compiler::eeFindJitDataOffs(unsigned dataOffs)
1125 {
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);
1129 }
1130
1131 bool Compiler::eeIsJitDataOffs(CORINFO_FIELD_HANDLE field)
1132 {
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)
1136     {
1137         return false;   // upper bits were set, not a jit data offset
1138     }
1139
1140     // Data offsets are marked by the fact that the low two bits are 0b01 0x1
1141     return (value & iaut_MASK) == iaut_DATA_OFFSET;
1142 }
1143
1144 int Compiler::eeGetJitDataOffs(CORINFO_FIELD_HANDLE  field)
1145 {
1146     // Data offsets are marked by the fact that the low two bits are 0b01 0x1
1147     if (eeIsJitDataOffs(field))
1148     {
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;
1153     }
1154     else
1155     {
1156         return -1;
1157     }
1158 }
1159
1160
1161 /*****************************************************************************
1162  *
1163  *                      ICorStaticInfo wrapper functions
1164  */
1165
1166 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
1167
1168 #ifdef DEBUG
1169 void Compiler::dumpSystemVClassificationType(SystemVClassificationType ct)
1170 {
1171     switch (ct)
1172     {
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;
1182     }
1183 }
1184 #endif // DEBUG
1185
1186 void Compiler::eeGetSystemVAmd64PassStructInRegisterDescriptor(/*IN*/  CORINFO_CLASS_HANDLE structHnd,
1187                                                                /*OUT*/ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr)
1188 {
1189     bool ok = info.compCompHnd->getSystemVAmd64PassStructInRegisterDescriptor(structHnd, structPassInRegDescPtr);
1190     noway_assert(ok);
1191
1192 #ifdef DEBUG
1193     if (verbose)
1194     {
1195         printf("**** getSystemVAmd64PassStructInRegisterDescriptor(0x%x (%s), ...) =>\n", dspPtr(structHnd), eeGetClassName(structHnd));
1196         printf("        passedInRegisters = %s\n", dspBool(structPassInRegDescPtr->passedInRegisters));
1197         if (structPassInRegDescPtr->passedInRegisters)
1198         {
1199             printf("        eightByteCount   = %d\n", structPassInRegDescPtr->eightByteCount);
1200             for (unsigned int i = 0; i < structPassInRegDescPtr->eightByteCount; i++)
1201             {
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]);
1207             }
1208         }
1209     }
1210 #endif // DEBUG
1211 }
1212
1213 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
1214
1215 #if COR_JIT_EE_VERSION <= 460
1216
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)
1220 {
1221     if (!corInfo->isValidToken(resolvedToken->tokenScope, resolvedToken->token))
1222         return false;
1223
1224     CorInfoTokenKind tokenType = resolvedToken->tokenType;
1225     switch (TypeFromToken(resolvedToken->token))
1226     {
1227     case mdtModuleRef:
1228     case mdtTypeDef:
1229     case mdtTypeRef:
1230     case mdtTypeSpec:
1231         if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1232             return false;
1233         break;
1234
1235     case mdtMethodDef:
1236     case mdtMethodSpec:
1237         if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1238             return false;
1239         break;
1240
1241     case mdtFieldDef:
1242         if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1243             return false;
1244         break;
1245
1246     case mdtMemberRef:
1247         if ((tokenType & (CORINFO_TOKENKIND_Method | CORINFO_TOKENKIND_Field)) == 0)
1248             return false;
1249         break;
1250
1251     default:
1252         return false;
1253     }
1254
1255     return true;
1256 }
1257
1258 // This type encapsulates the information necessary for `TryResolveTokenFilter` and
1259 // `eeTryResolveToken` below.
1260 struct TryResolveTokenFilterParam
1261 {
1262     ICorJitInfo* m_corInfo;
1263     CORINFO_RESOLVED_TOKEN* m_resolvedToken;
1264     EXCEPTION_POINTERS m_exceptionPointers;
1265     bool m_success;
1266 };
1267
1268 LONG TryResolveTokenFilter(struct _EXCEPTION_POINTERS* exceptionPointers, void* theParam)
1269 {
1270     assert(exceptionPointers->ExceptionRecord->ExceptionCode != SEH_VERIFICATION_EXCEPTION);
1271
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)
1277     {
1278         auto* param = reinterpret_cast<TryResolveTokenFilterParam*>(theParam);
1279         if (!isValidTokenForTryResolveToken(param->m_corInfo, param->m_resolvedToken))
1280         {
1281             param->m_exceptionPointers = *exceptionPointers;
1282             return param->m_corInfo->FilterException(exceptionPointers);
1283         }
1284     }
1285
1286     return EXCEPTION_CONTINUE_SEARCH;
1287 }
1288
1289 bool Compiler::eeTryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken)
1290 {
1291     TryResolveTokenFilterParam param;
1292     param.m_corInfo = info.compCompHnd;
1293     param.m_resolvedToken = resolvedToken;
1294     param.m_success = true;
1295
1296     PAL_TRY(TryResolveTokenFilterParam*, pParam, &param)
1297     {
1298         pParam->m_corInfo->resolveToken(pParam->m_resolvedToken);
1299     }
1300     PAL_EXCEPT_FILTER(TryResolveTokenFilter)
1301     {
1302         if (param.m_exceptionPointers.ExceptionRecord->ExceptionCode == EXCEPTION_COMPLUS)
1303         {
1304             param.m_corInfo->HandleException(&param.m_exceptionPointers);
1305         }
1306
1307         param.m_success = false;
1308     }
1309     PAL_ENDTRY
1310
1311     return param.m_success;
1312 }
1313
1314 struct TrapParam
1315 {
1316     ICorJitInfo* m_corInfo;
1317     EXCEPTION_POINTERS m_exceptionPointers;
1318
1319     void (*m_function)(void*);
1320     void* m_param;
1321     bool m_success;
1322 };
1323
1324 static LONG __EEFilter(PEXCEPTION_POINTERS exceptionPointers, void* param)
1325 {
1326     auto* trapParam = reinterpret_cast<TrapParam*>(param);
1327     trapParam->m_exceptionPointers = *exceptionPointers;
1328     return trapParam->m_corInfo->FilterException(exceptionPointers);
1329 }
1330
1331 bool Compiler::eeRunWithErrorTrapImp(void (*function)(void*), void* param)
1332 {
1333     TrapParam trapParam;
1334     trapParam.m_corInfo = info.compCompHnd;
1335     trapParam.m_function = function;
1336     trapParam.m_param = param;
1337     trapParam.m_success = true;
1338
1339     PAL_TRY(TrapParam*, __trapParam, &trapParam)
1340     {
1341         __trapParam->m_function(__trapParam->m_param);
1342     }
1343     PAL_EXCEPT_FILTER(__EEFilter)
1344     {
1345         trapParam.m_corInfo->HandleException(&trapParam.m_exceptionPointers);
1346         trapParam.m_success = false;
1347     }
1348     PAL_ENDTRY
1349
1350     return trapParam.m_success;
1351 }
1352
1353 #else // CORJIT_EE_VER <= 460
1354     
1355 bool Compiler::eeTryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken)
1356 {
1357     return info.compCompHnd->tryResolveToken(resolvedToken);
1358 }
1359
1360 bool Compiler::eeRunWithErrorTrapImp(void (*function)(void*), void* param)
1361 {
1362     return info.compCompHnd->runWithErrorTrap(function, param);
1363 }
1364
1365 #endif // CORJIT_EE_VER > 460
1366
1367 /*****************************************************************************
1368  *
1369  *                      Utility functions
1370  */
1371
1372 #if defined(DEBUG) || defined(FEATURE_JIT_METHOD_PERF) || defined(FEATURE_SIMD)
1373
1374 /*****************************************************************************/
1375
1376 // static helper names - constant array
1377 const char* jitHlpFuncTable[CORINFO_HELP_COUNT] =
1378 {
1379 #define JITHELPER(code, pfnHelper, sig)       #code,
1380 #define DYNAMICJITHELPER(code, pfnHelper,sig) #code,
1381 #include "jithelpers.h"
1382 };
1383
1384 /*****************************************************************************
1385 *
1386 *  Filter wrapper to handle exception filtering.
1387 *  On Unix compilers don't support SEH.
1388 */
1389
1390 struct FilterSuperPMIExceptionsParam_ee_il
1391 {
1392     Compiler*               pThis;
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;
1400 };
1401
1402 static LONG FilterSuperPMIExceptions_ee_il(PEXCEPTION_POINTERS pExceptionPointers, LPVOID lpvParam)
1403 {
1404     FilterSuperPMIExceptionsParam_ee_il *pSPMIEParam =
1405         (FilterSuperPMIExceptionsParam_ee_il *)lpvParam;
1406     pSPMIEParam->exceptionPointers = *pExceptionPointers;
1407
1408     if (pSPMIEParam->pThis->IsSuperPMIException(pExceptionPointers->ExceptionRecord->ExceptionCode))
1409         return EXCEPTION_EXECUTE_HANDLER;
1410     
1411     return EXCEPTION_CONTINUE_SEARCH;
1412 }
1413
1414 const char*         Compiler::eeGetMethodName(CORINFO_METHOD_HANDLE       method,
1415                                               const char** classNamePtr)
1416 {
1417     if  (eeGetHelperNum(method))
1418     {
1419         if (classNamePtr != 0)
1420             *classNamePtr = "HELPER";
1421
1422         CorInfoHelpFunc ftnNum = eeGetHelperNum(method);
1423         const char* name = info.compCompHnd->getHelperName(ftnNum);
1424
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))
1428         {
1429             if (ftnNum < CORINFO_HELP_COUNT)
1430             {
1431                 name = jitHlpFuncTable[ftnNum];
1432             }
1433         }
1434         return name;
1435     }
1436
1437     if (eeIsNativeMethod(method))
1438     {
1439         if (classNamePtr != 0)
1440             *classNamePtr = "NATIVE";        
1441         method = eeGetMethodHandleForNative(method);
1442     }
1443
1444     FilterSuperPMIExceptionsParam_ee_il param;
1445
1446     param.pThis = this;
1447     param.pJitInfo = &info;
1448     param.method = method;
1449     param.classNamePtr = classNamePtr;
1450
1451     PAL_TRY(FilterSuperPMIExceptionsParam_ee_il *, pParam, &param)
1452     {
1453         pParam->fieldOrMethodOrClassNamePtr = pParam->pJitInfo->compCompHnd->getMethodName(pParam->method, pParam->classNamePtr);
1454     }
1455     PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_ee_il)
1456     {
1457         if (param.classNamePtr != nullptr)
1458         {
1459             *(param.classNamePtr) = "hackishClassName";
1460         }
1461
1462         param.fieldOrMethodOrClassNamePtr = "hackishMethodName";
1463     }
1464     PAL_ENDTRY
1465
1466     return param.fieldOrMethodOrClassNamePtr;
1467 }
1468
1469 const char *        Compiler::eeGetFieldName  (CORINFO_FIELD_HANDLE field,
1470                                              const char * *     classNamePtr)
1471 {
1472     FilterSuperPMIExceptionsParam_ee_il param;
1473
1474     param.pThis = this;
1475     param.pJitInfo = &info;
1476     param.field = field;
1477     param.classNamePtr = classNamePtr;
1478
1479     PAL_TRY(FilterSuperPMIExceptionsParam_ee_il *, pParam, &param)
1480     {
1481         pParam->fieldOrMethodOrClassNamePtr = pParam->pJitInfo->compCompHnd->getFieldName(pParam->field, pParam->classNamePtr);
1482     }
1483     PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_ee_il)
1484     {
1485         param.fieldOrMethodOrClassNamePtr = "hackishFieldName";
1486     }
1487     PAL_ENDTRY
1488
1489     return param.fieldOrMethodOrClassNamePtr;
1490 }
1491
1492 const char*         Compiler::eeGetClassName(CORINFO_CLASS_HANDLE clsHnd)
1493 {
1494     FilterSuperPMIExceptionsParam_ee_il param;
1495
1496     param.pThis = this;
1497     param.pJitInfo = &info;
1498     param.clazz = clsHnd;
1499
1500     PAL_TRY(FilterSuperPMIExceptionsParam_ee_il *, pParam, &param)
1501     {
1502         pParam->fieldOrMethodOrClassNamePtr = pParam->pJitInfo->compCompHnd->getClassName(pParam->clazz);
1503     }
1504     PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_ee_il)
1505     {
1506         param.fieldOrMethodOrClassNamePtr = "hackishClassName";
1507     }
1508     PAL_ENDTRY
1509     return param.fieldOrMethodOrClassNamePtr;
1510 }
1511
1512 #endif // DEBUG || FEATURE_JIT_METHOD_PERF
1513
1514
1515 #ifdef DEBUG
1516
1517 const wchar_t *            Compiler::eeGetCPString (size_t strHandle)
1518 {
1519     char buff[512 + sizeof(CORINFO_String)];
1520
1521     // make this bulletproof, so it works even if we are wrong.  
1522     if (ReadProcessMemory(GetCurrentProcess(), (void*) strHandle, buff, 4, 0) == 0)
1523         return(0);
1524
1525     CORINFO_String* asString = *((CORINFO_String**) strHandle);
1526
1527     if (ReadProcessMemory(GetCurrentProcess(), asString, buff, sizeof(buff), 0) == 0)
1528         return(0);
1529
1530     if (asString->stringLen >= 255  || 
1531         asString->chars[asString->stringLen] != 0   )
1532     {
1533         return 0;
1534     }
1535
1536     return(asString->chars);
1537 }
1538
1539 #endif // DEBUG