1//
2// Copyright (c) Microsoft. All rights reserved.
3// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4//
5
6//----------------------------------------------------------
7// CompileResult.cpp - CompileResult contains the stuff generated by a compilation
8//----------------------------------------------------------
9
10#include "standardpch.h"
11#include "compileresult.h"
12#include "methodcontext.h"
13
14CompileResult::CompileResult()
15{
16#define LWM(map, key, value) map = nullptr;
17#include "crlwmlist.h"
18
19 // Not persisted to disk. though should it be?
20 CallTargetTypes = new LightWeightMap<DWORDLONG, DWORD>();
21
22 allocMemDets.hotCodeSize = 0;
23 allocMemDets.coldCodeSize = 0;
24 allocMemDets.roDataSize = 0;
25 allocMemDets.xcptnsCount = 0;
26 allocMemDets.flag = (CorJitAllocMemFlag)0;
27 allocMemDets.hotCodeBlock = 0;
28 allocMemDets.coldCodeBlock = 0;
29 allocMemDets.roDataBlock = 0;
30
31 allocGCInfoDets.retval = 0;
32 allocGCInfoDets.size = 0;
33
34 codeHeap = nullptr;
35}
36
37CompileResult::~CompileResult()
38{
39#define LWM(map, key, value) \
40 if (map != nullptr) \
41 delete map;
42#include "crlwmlist.h"
43
44 if (CallTargetTypes != nullptr)
45 delete CallTargetTypes;
46
47#ifndef FEATURE_PAL // PAL doesn't have HeapDestroy()
48 if (codeHeap != nullptr)
49 ::HeapDestroy(codeHeap);
50#endif // !FEATURE_PAL
51}
52
53// Is the CompileResult empty? Define this as whether all the maps that store information given by the JIT are empty.
54// This is useful when determining if a function won't apply after a "mcs -removeDump -thin" operation has been run.
55bool CompileResult::IsEmpty()
56{
57 bool isEmpty = true;
58
59#define LWM(map, key, value) \
60 if (map != nullptr) \
61 isEmpty = false;
62#include "crlwmlist.h"
63
64 return isEmpty;
65}
66
67HANDLE CompileResult::getCodeHeap()
68{
69 if (codeHeap == nullptr)
70 codeHeap = ::HeapCreate(0, 0, 0);
71 if (codeHeap == nullptr)
72 {
73 LogError("CompileResult::codeHeap() failed to acquire a heap.");
74 __debugbreak();
75 }
76 return codeHeap;
77}
78
79void CompileResult::recAssert(const char* assertText)
80{
81 if (AssertLog == nullptr)
82 AssertLog = new DenseLightWeightMap<DWORD>();
83
84 AssertLog->Append(AssertLog->AddBuffer((const unsigned char*)assertText, (DWORD)strlen(assertText) + 1));
85}
86void CompileResult::dmpAssertLog(DWORD key, DWORD value)
87{
88 const char* assert = (const char*)AssertLog->GetBuffer(value);
89 printf("AssertLog key %u, value '%s'", key, assert);
90 AssertLog->Unlock();
91}
92const char* CompileResult::repAssert()
93{
94 if ((AssertLog == nullptr) || (AssertLog->GetCount() == 0))
95 return nullptr;
96 return (const char*)AssertLog->GetBuffer(AssertLog->Get((DWORD)0));
97}
98
99void CompileResult::AddCall(const char* name)
100{
101 if (CallLog == nullptr)
102 CallLog = new DenseLightWeightMap<DWORD>();
103 // if(name[0] != '+')
104 // CallLog->Append(CallLog->AddBuffer((const unsigned char *)name, (DWORD)strlen(name)+1));
105}
106unsigned int CompileResult::CallLog_GetCount()
107{
108 return CallLog->GetCount();
109}
110
111bool CompileResult::CallLog_Contains(const char* str)
112{
113 return (CallLog->Contains((unsigned char*)str, (unsigned int)strlen(str)) > 0);
114}
115void CompileResult::dmpCallLog(DWORD key, DWORD value)
116{
117 const char* temp = (const char*)CallLog->GetBuffer(value);
118 printf("CallLog %u '%s'", key, temp);
119 CallLog->Unlock();
120}
121
122void CompileResult::dumpToConsole()
123{
124 printf("***************************************** CompileResult\n");
125
126#define LWM(map, key, value) dumpLWM(this, map)
127#define DENSELWM(map, value) dumpLWMDense(this, map)
128#include "crlwmlist.h"
129
130 printf("-----------------------------------------\n");
131}
132
133// Note - EE allocates these blocks (and the exception blocks) in a single linear region.
134// Note - EE assures that RoBlock is 8 byte aligned
135void CompileResult::recAllocMem(ULONG hotCodeSize,
136 ULONG coldCodeSize,
137 ULONG roDataSize,
138 ULONG xcptnsCount,
139 CorJitAllocMemFlag flag,
140 void** hotCodeBlock,
141 void** coldCodeBlock,
142 void** roDataBlock)
143{
144 // Grab the values, so we can scrape the real answers in the capture method
145 allocMemDets.hotCodeSize = hotCodeSize;
146 allocMemDets.coldCodeSize = coldCodeSize;
147 allocMemDets.roDataSize = roDataSize;
148 allocMemDets.xcptnsCount = xcptnsCount;
149 allocMemDets.flag = flag;
150 allocMemDets.hotCodeBlock = *hotCodeBlock;
151 allocMemDets.coldCodeBlock = *coldCodeBlock;
152 allocMemDets.roDataBlock = *roDataBlock;
153}
154void CompileResult::recAllocMemCapture()
155{
156 if (AllocMem == nullptr)
157 AllocMem = new LightWeightMap<DWORD, Agnostic_AllocMemDetails>();
158
159 Agnostic_AllocMemDetails value;
160
161 value.hotCodeSize = (DWORD)allocMemDets.hotCodeSize;
162 value.coldCodeSize = (DWORD)allocMemDets.coldCodeSize;
163 value.roDataSize = (DWORD)allocMemDets.roDataSize;
164 value.xcptnsCount = (DWORD)allocMemDets.xcptnsCount;
165 value.flag = (DWORD)allocMemDets.flag;
166 value.hotCodeBlock_offset =
167 (DWORD)AllocMem->AddBuffer((const unsigned char*)allocMemDets.hotCodeBlock, allocMemDets.hotCodeSize);
168 value.coldCodeBlock_offset =
169 (DWORD)AllocMem->AddBuffer((const unsigned char*)allocMemDets.coldCodeBlock, allocMemDets.coldCodeSize);
170 value.roDataBlock_offset =
171 (DWORD)AllocMem->AddBuffer((const unsigned char*)allocMemDets.roDataBlock, allocMemDets.roDataSize);
172 value.hotCodeBlock = (DWORDLONG)allocMemDets.hotCodeBlock;
173 value.coldCodeBlock = (DWORDLONG)allocMemDets.coldCodeBlock;
174 value.roDataBlock = (DWORDLONG)allocMemDets.roDataBlock;
175
176 AllocMem->Add(0, value);
177}
178void CompileResult::dmpAllocMem(DWORD key, const Agnostic_AllocMemDetails& value)
179{
180 printf("AllocMem key 0, value hotCodeSize-%u coldCodeSize-%u roDataSize-%u xcptnsCount-%u flag-%08X "
181 "hotCodeBlock_offset-%u coldCodeBlock_offset-%u roDataBlock_offset-%u hotCodeBlock-%016llX "
182 "coldCodeBlock-%016llX roDataBlock-%016llX",
183 value.hotCodeSize, value.coldCodeSize, value.roDataSize, value.xcptnsCount, value.flag,
184 value.hotCodeBlock_offset, value.coldCodeBlock_offset, value.roDataBlock_offset, value.hotCodeBlock,
185 value.coldCodeBlock, value.roDataBlock);
186}
187
188// We can't allocate memory in the same place is was during recording, so we pass back code/data block pointers
189// that point into the AllocMem LightWeightMap, but also return what the original addresses were during recording.
190void CompileResult::repAllocMem(ULONG* hotCodeSize,
191 ULONG* coldCodeSize,
192 ULONG* roDataSize,
193 ULONG* xcptnsCount,
194 CorJitAllocMemFlag* flag,
195 unsigned char** hotCodeBlock,
196 unsigned char** coldCodeBlock,
197 unsigned char** roDataBlock,
198 void** orig_hotCodeBlock,
199 void** orig_coldCodeBlock,
200 void** orig_roDataBlock)
201{
202 Agnostic_AllocMemDetails value;
203
204 value = AllocMem->Get(0);
205
206 *hotCodeSize = (ULONG)value.hotCodeSize;
207 *coldCodeSize = (ULONG)value.coldCodeSize;
208 *roDataSize = (ULONG)value.roDataSize;
209 *xcptnsCount = (ULONG)value.xcptnsCount;
210 *flag = (CorJitAllocMemFlag)value.flag;
211
212 if (*hotCodeSize > 0)
213 *hotCodeBlock = AllocMem->GetBuffer(value.hotCodeBlock_offset);
214 else
215 *hotCodeBlock = nullptr;
216
217 if (*coldCodeSize > 0)
218 *coldCodeBlock = AllocMem->GetBuffer(value.coldCodeBlock_offset);
219 else
220 *coldCodeBlock = nullptr;
221
222 if (*roDataSize > 0)
223 *roDataBlock = AllocMem->GetBuffer(value.roDataBlock_offset);
224 else
225 *roDataBlock = nullptr;
226
227 *orig_hotCodeBlock = (void*)value.hotCodeBlock;
228 *orig_coldCodeBlock = (void*)value.coldCodeBlock;
229 *orig_roDataBlock = (void*)value.roDataBlock;
230}
231
232// Note - Ownership of pMap is transfered with this call. In replay icorjitinfo we should free it.
233void CompileResult::recSetBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap, ICorDebugInfo::OffsetMapping* pMap)
234{
235 if (SetBoundaries == nullptr)
236 SetBoundaries = new LightWeightMap<DWORD, Agnostic_SetBoundaries>();
237
238 Agnostic_SetBoundaries value;
239
240 value.ftn = (DWORDLONG)ftn;
241 value.cMap = (DWORD)cMap;
242 value.pMap_offset =
243 (DWORD)SetBoundaries->AddBuffer((const unsigned char*)pMap, sizeof(ICorDebugInfo::OffsetMapping) * cMap);
244
245 SetBoundaries->Add(0, value);
246}
247void CompileResult::dmpSetBoundaries(DWORD key, const Agnostic_SetBoundaries& value)
248{
249 ICorDebugInfo::OffsetMapping* om = (ICorDebugInfo::OffsetMapping*)SetBoundaries->GetBuffer(value.pMap_offset);
250 printf("SetBoundaries key 0, value ftn-%016llX cMap-%u %u{", value.ftn, value.cMap, value.pMap_offset);
251 for (unsigned int i = 0; i < value.cMap; i++)
252 {
253 if (i != 0)
254 printf(", ");
255 printf("%u %u %u", om[i].ilOffset, om[i].nativeOffset, om[i].source);
256 }
257 printf("}");
258 SetBoundaries->Unlock();
259}
260bool CompileResult::repSetBoundaries(CORINFO_METHOD_HANDLE* ftn, ULONG32* cMap, ICorDebugInfo::OffsetMapping** pMap)
261{
262 if ((SetBoundaries == nullptr) || (SetBoundaries->GetCount() == 0))
263 {
264 *ftn = (CORINFO_METHOD_HANDLE)-1;
265 *cMap = -1;
266 *pMap = nullptr;
267 return false;
268 }
269 Agnostic_SetBoundaries value;
270
271 value = SetBoundaries->Get(0);
272
273 *ftn = (CORINFO_METHOD_HANDLE)value.ftn;
274 *cMap = (ULONG32)value.cMap;
275 *pMap = (ICorDebugInfo::OffsetMapping*)SetBoundaries->GetBuffer(value.pMap_offset);
276 return true;
277}
278
279// Note - Ownership of vars is transfered with this call. In replay icorjitinfo we should free it.
280void CompileResult::recSetVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo* vars)
281{
282 if (SetVars == nullptr)
283 SetVars = new LightWeightMap<DWORD, Agnostic_SetVars>();
284
285 Agnostic_SetVars value;
286
287 value.ftn = (DWORDLONG)ftn;
288 value.cVars = (DWORD)cVars;
289 value.vars_offset = (DWORD)SetVars->AddBuffer((const unsigned char*)vars,
290 sizeof(ICorDebugInfo::NativeVarInfo) *
291 cVars); // not deep enough.. vlt memory is pointer sized.
292
293 SetVars->Add(0, value);
294}
295void CompileResult::dmpSetVars(DWORD key, const Agnostic_SetVars& value)
296{
297 ICorDebugInfo::NativeVarInfo* om = (ICorDebugInfo::NativeVarInfo*)SetVars->GetBuffer(value.vars_offset);
298 printf("SetVars key %u, value ftn-%016llX cVars-%u %u{", key, value.ftn, value.cVars, value.vars_offset);
299 for (unsigned int i = 0; i < value.cVars; i++)
300 {
301 if (i != 0)
302 printf(", ");
303 printf("so-%u eo-%u var-%u", om[i].startOffset, om[i].endOffset, om[i].varNumber);
304 }
305 printf("}");
306 SetVars->Unlock();
307}
308bool CompileResult::repSetVars(CORINFO_METHOD_HANDLE* ftn, ULONG32* cVars, ICorDebugInfo::NativeVarInfo** vars)
309{
310 if ((SetVars == nullptr) || (SetVars->GetCount() == 0))
311 {
312 *ftn = (CORINFO_METHOD_HANDLE)-1;
313 *cVars = -1;
314 *vars = nullptr;
315 return false;
316 }
317
318 Agnostic_SetVars value;
319
320 value = SetVars->Get(0);
321
322 *ftn = (CORINFO_METHOD_HANDLE)value.ftn;
323 *cVars = (ULONG32)value.cVars;
324 *vars = (ICorDebugInfo::NativeVarInfo*)SetVars->GetBuffer(value.vars_offset);
325
326 return true;
327}
328
329void CompileResult::recAllocGCInfo(size_t size, void* retval)
330{
331 allocGCInfoDets.size = size;
332 allocGCInfoDets.retval = retval;
333}
334void CompileResult::recAllocGCInfoCapture()
335{
336 if (AllocGCInfo == nullptr)
337 AllocGCInfo = new LightWeightMap<DWORD, Agnostic_AllocGCInfo>();
338
339 Agnostic_AllocGCInfo value;
340
341 value.size = allocGCInfoDets.size;
342 value.retval_offset =
343 (DWORD)AllocGCInfo->AddBuffer((const unsigned char*)allocGCInfoDets.retval, (DWORD)allocGCInfoDets.size);
344
345 AllocGCInfo->Add(0, value);
346}
347void CompileResult::dmpAllocGCInfo(DWORD key, const Agnostic_AllocGCInfo& value)
348{
349 const unsigned char* buff = AllocGCInfo->GetBuffer(value.retval_offset);
350 printf("AllocGCInfo key 0, ");
351 printf("sz-%llu %p{ ", value.size, buff);
352 for (unsigned int i = 0; i < value.size; i++)
353 printf("%02X ", *(buff + i));
354 printf("}");
355 AllocGCInfo->Unlock();
356}
357void CompileResult::repAllocGCInfo(size_t* size, void** retval)
358{
359 Agnostic_AllocGCInfo value;
360
361 value = AllocGCInfo->Get(0);
362
363 *size = (size_t)value.size;
364 if (*size > 0)
365 *retval = (void*)AllocGCInfo->GetBuffer(value.retval_offset);
366}
367
368void CompileResult::recCompileMethod(BYTE** nativeEntry, ULONG* nativeSizeOfCode, CorJitResult result)
369{
370 if (CompileMethod == nullptr)
371 CompileMethod = new LightWeightMap<DWORD, Agnostic_CompileMethodResults>();
372
373 Agnostic_CompileMethodResults value;
374 value.nativeEntry = (DWORDLONG)*nativeEntry;
375 value.nativeSizeOfCode = (DWORD)*nativeSizeOfCode;
376 value.CorJitResult = (DWORD)result;
377
378 CompileMethod->Add(0, value);
379}
380void CompileResult::dmpCompileMethod(DWORD key, const Agnostic_CompileMethodResults& value)
381{
382 printf("CompileMethod key %u, value nativeEntry-%016llX nativeSizeOfCode-%u CorJitResult-%u", key,
383 value.nativeEntry, value.nativeSizeOfCode, value.CorJitResult);
384}
385void CompileResult::repCompileMethod(BYTE** nativeEntry, ULONG* nativeSizeOfCode, CorJitResult* result)
386{
387 Agnostic_CompileMethodResults value;
388 value = CompileMethod->Get(0);
389 *nativeEntry = (BYTE*)value.nativeEntry;
390 *nativeSizeOfCode = (ULONG)value.nativeSizeOfCode;
391 *result = (CorJitResult)value.CorJitResult;
392}
393
394void CompileResult::recMessageLog(const char* fmt, ...)
395{
396 // TODO-Cleanup: ???
397 return;
398 if (MessageLog == nullptr)
399 MessageLog = new DenseLightWeightMap<DWORD>();
400
401 va_list args;
402
403 // retrieve the variable arguments
404 va_start(args, fmt);
405
406 size_t len = _vscprintf(fmt, args) + 1; // space for the terminator
407
408 unsigned char* messageLogBuffer = new unsigned char[len];
409 vsprintf_s((char*)messageLogBuffer, len, fmt, args);
410 messageLogBuffer[len - 1] = 0;
411 MessageLog->Append(MessageLog->AddBuffer(messageLogBuffer, (DWORD)len));
412 delete[] messageLogBuffer;
413}
414void CompileResult::dmpMessageLog(DWORD key, DWORD value)
415{
416 printf("MessageLog NYI");
417}
418
419void CompileResult::recClassMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_HANDLE cls)
420{
421 if (ClassMustBeLoadedBeforeCodeIsRun == nullptr)
422 ClassMustBeLoadedBeforeCodeIsRun = new DenseLightWeightMap<DWORDLONG>();
423
424 ClassMustBeLoadedBeforeCodeIsRun->Append((DWORDLONG)cls);
425}
426void CompileResult::dmpClassMustBeLoadedBeforeCodeIsRun(DWORD key, DWORDLONG value)
427{
428 printf("ClassMustBeLoadedBeforeCodeIsRun key %u, value cls-%016llX", key, value);
429}
430
431void CompileResult::recReportInliningDecision(CORINFO_METHOD_HANDLE inlinerHnd,
432 CORINFO_METHOD_HANDLE inlineeHnd,
433 CorInfoInline inlineResult,
434 const char* reason)
435{
436 if (ReportInliningDecision == nullptr)
437 ReportInliningDecision = new DenseLightWeightMap<Agnostic_ReportInliningDecision>();
438
439 Agnostic_ReportInliningDecision value;
440
441 value.inlinerHnd = (DWORDLONG)inlinerHnd;
442 value.inlineeHnd = (DWORDLONG)inlineeHnd;
443 value.inlineResult = (DWORD)inlineResult;
444 if (reason != nullptr)
445 value.reason_offset =
446 (DWORD)ReportInliningDecision->AddBuffer((unsigned char*)reason, (DWORD)strlen(reason) + 1);
447 else
448 value.reason_offset = -1;
449
450 ReportInliningDecision->Append(value);
451}
452void CompileResult::dmpReportInliningDecision(DWORD key, const Agnostic_ReportInliningDecision& value)
453{
454 const char* reason = (const char*)ReportInliningDecision->GetBuffer(value.reason_offset);
455 printf("ReportInliningDecision key %u, value inliner-%016llX inlinee-%016llX res-%u reason-'%s'", key,
456 value.inlinerHnd, value.inlineeHnd, value.inlineResult, reason);
457 ReportInliningDecision->Unlock();
458}
459CorInfoInline CompileResult::repReportInliningDecision(CORINFO_METHOD_HANDLE inlinerHnd,
460 CORINFO_METHOD_HANDLE inlineeHnd)
461{
462 CorInfoInline result = INLINE_FAIL;
463 if (ReportInliningDecision != nullptr)
464 {
465 Agnostic_ReportInliningDecision* items = ReportInliningDecision->GetRawItems();
466 unsigned int cnt = ReportInliningDecision->GetCount();
467 for (unsigned int i = 0; i < cnt; i++)
468 {
469 if ((items[i].inlinerHnd == (DWORDLONG)inlinerHnd) && (items[i].inlineeHnd == (DWORDLONG)inlineeHnd) &&
470 (items[i].inlineResult == INLINE_PASS))
471 result = INLINE_PASS;
472 }
473 }
474 return result;
475}
476
477void CompileResult::recSetEHcount(unsigned cEH)
478{
479 if (SetEHcount == nullptr)
480 SetEHcount = new LightWeightMap<DWORD, DWORD>();
481
482 SetEHcount->Add((DWORD)0, (DWORD)cEH);
483}
484void CompileResult::dmpSetEHcount(DWORD key, DWORD value)
485{
486 printf("SetEHcount key %u, value %u", key, value);
487}
488ULONG CompileResult::repSetEHcount()
489{
490 if (SetEHcount == nullptr)
491 SetEHcount = new LightWeightMap<DWORD, DWORD>();
492
493 ULONG ehCount;
494 int index = SetEHcount->GetIndex(0);
495 if (index < 0)
496 ehCount = 0;
497 else
498 ehCount = (ULONG)SetEHcount->Get(index);
499 return ehCount;
500}
501
502void CompileResult::recSetEHinfo(unsigned EHnumber, const CORINFO_EH_CLAUSE* clause)
503{
504 if (SetEHinfo == nullptr)
505 SetEHinfo = new LightWeightMap<DWORD, Agnostic_CORINFO_EH_CLAUSE2>();
506
507 Agnostic_CORINFO_EH_CLAUSE2 value;
508 value.Flags = (DWORD)clause->Flags;
509 value.TryOffset = (DWORD)clause->TryOffset;
510 value.TryLength = (DWORD)clause->TryLength;
511 value.HandlerOffset = (DWORD)clause->HandlerOffset;
512 value.HandlerLength = (DWORD)clause->HandlerLength;
513 value.ClassToken = (DWORD)clause->ClassToken;
514
515 SetEHinfo->Add((DWORD)EHnumber, value);
516}
517void CompileResult::dmpSetEHinfo(DWORD key, const Agnostic_CORINFO_EH_CLAUSE2& value)
518{
519 printf("SetEHinfo key %u, value flg-%u to-%u tl-%u ho-%u hl-%u", key, value.Flags, value.TryOffset, value.TryLength,
520 value.HandlerOffset, value.HandlerLength);
521 if ((CORINFO_EH_CLAUSE_FLAGS)value.Flags == CORINFO_EH_CLAUSE_FILTER)
522 {
523 printf(" fo-%u", value.ClassToken); // FilterOffset
524 }
525 else if ((CORINFO_EH_CLAUSE_FLAGS)value.Flags == CORINFO_EH_CLAUSE_NONE)
526 {
527 printf(" cls-%08X", value.ClassToken);
528 }
529 // else, no need to print for finally/fault handlers
530}
531void CompileResult::repSetEHinfo(unsigned EHnumber,
532 ULONG* flags,
533 ULONG* tryOffset,
534 ULONG* tryLength,
535 ULONG* handlerOffset,
536 ULONG* handlerLength,
537 ULONG* classToken)
538{
539 Agnostic_CORINFO_EH_CLAUSE2 value;
540 value = SetEHinfo->Get(EHnumber);
541
542 *flags = (ULONG)value.Flags;
543 *tryOffset = (ULONG)value.TryOffset;
544 *tryLength = (ULONG)value.TryLength;
545 *handlerOffset = (ULONG)value.HandlerOffset;
546 *handlerLength = (ULONG)value.HandlerLength;
547 *classToken = (ULONG)value.ClassToken;
548}
549
550void CompileResult::recSetMethodAttribs(CORINFO_METHOD_HANDLE ftn, CorInfoMethodRuntimeFlags attribs)
551{
552 if (SetMethodAttribs == nullptr)
553 SetMethodAttribs = new LightWeightMap<DWORDLONG, DWORD>();
554
555 SetMethodAttribs->Add((DWORDLONG)ftn, (DWORD)attribs);
556}
557void CompileResult::dmpSetMethodAttribs(DWORDLONG key, DWORD value)
558{
559 printf("SetMethodAttribs key ftn-%016llX, value attr-%08X", key, value);
560}
561CorInfoMethodRuntimeFlags CompileResult::repSetMethodAttribs(CORINFO_METHOD_HANDLE ftn)
562{
563 if ((SetMethodAttribs == nullptr) || (SetMethodAttribs->GetIndex((DWORDLONG)ftn) == -1))
564 return (CorInfoMethodRuntimeFlags)0;
565 CorInfoMethodRuntimeFlags result = (CorInfoMethodRuntimeFlags)SetMethodAttribs->Get((DWORDLONG)ftn);
566 return result;
567}
568
569void CompileResult::recMethodMustBeLoadedBeforeCodeIsRun(CORINFO_METHOD_HANDLE method)
570{
571 if (MethodMustBeLoadedBeforeCodeIsRun == nullptr)
572 MethodMustBeLoadedBeforeCodeIsRun = new DenseLightWeightMap<DWORDLONG>();
573
574 MethodMustBeLoadedBeforeCodeIsRun->Append((DWORDLONG)method);
575}
576void CompileResult::dmpMethodMustBeLoadedBeforeCodeIsRun(DWORD key, DWORDLONG value)
577{
578 printf("MethodMustBeLoadedBeforeCodeIsRun key %u, value ftn-%016llX", key, value);
579}
580
581void CompileResult::recReportTailCallDecision(CORINFO_METHOD_HANDLE callerHnd,
582 CORINFO_METHOD_HANDLE calleeHnd,
583 bool fIsTailPrefix,
584 CorInfoTailCall tailCallResult,
585 const char* reason)
586{
587 if (ReportTailCallDecision == nullptr)
588 ReportTailCallDecision = new DenseLightWeightMap<Agnostic_ReportTailCallDecision>();
589
590 Agnostic_ReportTailCallDecision value;
591
592 value.callerHnd = (DWORDLONG)callerHnd;
593 value.calleeHnd = (DWORDLONG)calleeHnd;
594 value.fIsTailPrefix = (DWORD)fIsTailPrefix;
595 value.tailCallResult = (DWORD)tailCallResult;
596 if (reason != nullptr) // protect strlen
597 value.reason_index =
598 (DWORD)ReportTailCallDecision->AddBuffer((unsigned char*)reason, (DWORD)strlen(reason) + 1);
599 else
600 value.reason_index = (DWORD)-1;
601
602 ReportTailCallDecision->Append(value);
603}
604void CompileResult::dmpReportTailCallDecision(DWORD key, const Agnostic_ReportTailCallDecision& value)
605{
606 const char* reason = (const char*)ReportTailCallDecision->GetBuffer(value.reason_index);
607 printf("ReportTailCallDecision key-%u, value cr-%016llX ce-%016llX tail-%u call-%u -%s", key, value.callerHnd,
608 value.calleeHnd, value.tailCallResult, value.tailCallResult, reason);
609 ReportTailCallDecision->Unlock();
610}
611
612void CompileResult::recReportFatalError(CorJitResult result)
613{
614 if (ReportFatalError == nullptr)
615 ReportFatalError = new DenseLightWeightMap<DWORD>();
616
617 ReportFatalError->Append((DWORD)result);
618}
619void CompileResult::dmpReportFatalError(DWORD key, DWORD value)
620{
621 printf("ReportFatalError key Count-%u, value result-%08X", key, value);
622}
623
624void CompileResult::recRecordRelocation(void* location, void* target, WORD fRelocType, WORD slotNum, INT32 addlDelta)
625{
626 repRecordRelocation(location, target, fRelocType, slotNum, addlDelta);
627}
628
629const char* relocationTypeToString(WORD fRelocType)
630{
631 switch (fRelocType)
632 {
633 // From winnt.h
634 case IMAGE_REL_BASED_ABSOLUTE:
635 return "absolute";
636 case IMAGE_REL_BASED_HIGH:
637 return "high";
638 case IMAGE_REL_BASED_LOW:
639 return "low";
640 case IMAGE_REL_BASED_HIGHLOW:
641 return "highlow";
642 case IMAGE_REL_BASED_HIGHADJ:
643 return "highadj";
644 case IMAGE_REL_BASED_DIR64:
645 return "dir64";
646
647 // From corinfo.h
648 case IMAGE_REL_BASED_REL32:
649 return "rel32";
650 case IMAGE_REL_BASED_THUMB_BRANCH24:
651 return "thumb_branch24";
652 default:
653 return "UNKNOWN";
654 }
655}
656void CompileResult::dmpRecordRelocation(DWORD key, const Agnostic_RecordRelocation& value)
657{
658 printf("RecordRelocation key %u, value loc-%016llX tgt-%016llX fRelocType-%u(%s) slotNum-%u addlDelta-%d", key,
659 value.location, value.target, value.fRelocType, relocationTypeToString((WORD)value.fRelocType),
660 value.slotNum, (INT32)value.addlDelta);
661}
662void CompileResult::repRecordRelocation(void* location, void* target, WORD fRelocType, WORD slotNum, INT32 addlDelta)
663{
664 if (RecordRelocation == nullptr)
665 RecordRelocation = new DenseLightWeightMap<Agnostic_RecordRelocation>();
666
667 Agnostic_RecordRelocation value;
668
669 value.location = (DWORDLONG)location;
670 value.target = (DWORDLONG)target;
671 value.fRelocType = (DWORD)fRelocType;
672 value.slotNum = (DWORD)slotNum;
673 value.addlDelta = (DWORD)addlDelta;
674
675 Assert(value.slotNum == 0);
676
677 RecordRelocation->Append(value);
678}
679
680// When we do a replay, we replace the CompileResult that was originally recorded. In most cases,
681// though, as part of our collection process we do a "thinning" operation, using "mcs -removeDup -thin",
682// which removes the CompileResult from the stored file. Because of this, we lose access to the original
683// addresses.
684//
685// Unfortunately, we may have generated code based on the original relative addresses. For example,
686// we might have generated a relocation based on the results of a call to GetFunctionEntryPoint, and
687// the delta from the generated code to that address fit in a rel32 reloc. Or, it didn't fit, but the
688// VM constructed a jump stub in the JIT code section that would fit, and returned that.
689//
690// Ideally, we would just keep all the original addresses and relocations, even if we delete the CompileResult.
691// If a new relocation has the same target as an original relocation, then simply substitute the original
692// delta and use that instead of the newly computed delta.
693//
694// For now, for rel32 relocations, if it doesn't fit, then simply pick an address immediately after the
695// current section (using originalAddr), assuming we needed a jump stub. We'll let multiple calls to potentially
696// different functions use the same address because even if they used different ones, and diffs were generated,
697// no textual diffs would appear because most of the textual call names are "hackishMethodName".
698void CompileResult::applyRelocs(unsigned char* block1, ULONG blocksize1, void* originalAddr)
699{
700 if (RecordRelocation == nullptr)
701 return;
702 if (blocksize1 == 0)
703 return;
704
705 size_t section_begin = (size_t)block1;
706 size_t section_end = (size_t)block1 + (size_t)blocksize1; // address is exclusive
707
708 LogDebug("applyRelocs block [%p,%p) block size %u, orig addr %p", block1, block1 + blocksize1, blocksize1,
709 originalAddr);
710
711 for (unsigned int i = 0; i < RecordRelocation->GetCount(); i++)
712 {
713 Agnostic_RecordRelocation tmp = RecordRelocation->GetRawItems()[i];
714
715 if (Logger::IsLogLevelEnabled(LOGLEVEL_DEBUG))
716 {
717 printf(" ");
718 dmpRecordRelocation(i, tmp);
719 printf("\n");
720 }
721
722 switch (tmp.fRelocType)
723 {
724#if defined(_TARGET_X86_)
725 case IMAGE_REL_BASED_HIGHLOW:
726 {
727 DWORDLONG fixupLocation = tmp.location;
728
729 size_t address = section_begin + (size_t)fixupLocation - (size_t)originalAddr;
730 if ((section_begin <= address) && (address < section_end)) // A reloc for our section?
731 {
732 LogDebug(" fixupLoc-%016llX (@%p) : %08X => %08X", fixupLocation, address, *(DWORD*)address,
733 (DWORD)tmp.target);
734 *(DWORD*)address = (DWORD)tmp.target;
735 }
736 }
737 break;
738#endif // _TARGET_X86_
739
740#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_) || defined(_TARGET_ARM_)
741 case IMAGE_REL_BASED_REL32:
742 {
743 DWORDLONG target = tmp.target + tmp.addlDelta;
744 DWORDLONG fixupLocation = tmp.location + tmp.slotNum;
745 DWORDLONG baseAddr = fixupLocation + sizeof(INT32);
746 INT64 delta = (INT64)((BYTE*)target - baseAddr);
747
748#if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
749 if (delta != (INT64)(int)delta)
750 {
751 // This isn't going to fit in a signed 32-bit address. Use something that will fit,
752 // since we assume that original compilation fit fine. This is only an issue for
753 // 32-bit offsets on 64-bit targets.
754 target = (DWORDLONG)originalAddr + (DWORDLONG)blocksize1;
755 INT64 newdelta = (INT64)((BYTE*)target - baseAddr);
756
757 LogDebug(" REL32 overflow. Mapping target to %016llX. Mapping delta: %016llX => %016llX", target,
758 delta, newdelta);
759
760 delta = newdelta;
761 }
762#endif // defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
763
764 if (delta != (INT64)(int)delta)
765 {
766#if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
767 LogError("REL32 relocation overflows field! delta=0x%016llX", delta);
768#else
769 LogError("REL32 relocation overflows field! delta=0x%08X", delta);
770#endif
771 }
772
773 // Write 32-bits into location
774 size_t address = section_begin + (size_t)fixupLocation - (size_t)originalAddr;
775 if ((section_begin <= address) && (address < section_end)) // A reloc for our section?
776 {
777 LogDebug(" fixupLoc-%016llX (@%p) : %08X => %08X", fixupLocation, address, *(DWORD*)address,
778 delta);
779 *(DWORD*)address = (DWORD)delta;
780 }
781 }
782 break;
783#endif // defined(_TARGET_X86_) || defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_) || defined(_TARGET_ARM_)
784
785#if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
786 case IMAGE_REL_BASED_DIR64:
787 {
788 DWORDLONG fixupLocation = tmp.location + tmp.slotNum;
789
790 // Write 64-bits into location
791 size_t address = section_begin + (size_t)fixupLocation - (size_t)originalAddr;
792 if ((section_begin <= address) && (address < section_end)) // A reloc for our section?
793 {
794 LogDebug(" fixupLoc-%016llX (@%p) %016llX => %016llX", fixupLocation, address,
795 *(DWORDLONG*)address, tmp.target);
796 *(DWORDLONG*)address = tmp.target;
797 }
798 }
799 break;
800#endif // defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
801
802#ifdef _TARGET_ARM64_
803 case IMAGE_REL_ARM64_BRANCH26: // 26 bit offset << 2 & sign ext, for B and BL
804 case IMAGE_REL_ARM64_PAGEBASE_REL21:
805 case IMAGE_REL_ARM64_PAGEOFFSET_12A:
806 LogError("Unimplemented reloc type %u", tmp.fRelocType);
807 break;
808#endif // _TARGET_ARM64_
809
810 default:
811 LogError("Unknown reloc type %u", tmp.fRelocType);
812 break;
813 }
814 }
815}
816
817void CompileResult::recProcessName(const char* name)
818{
819 if (ProcessName == nullptr)
820 ProcessName = new DenseLightWeightMap<DWORD>();
821
822 DWORD index = (DWORD)-1;
823 if (name != nullptr)
824 index = (DWORD)ProcessName->AddBuffer((unsigned char*)name, (DWORD)strlen(name) + 1);
825
826 ProcessName->Append(index);
827}
828void CompileResult::dmpProcessName(DWORD key, DWORD value)
829{
830 const char* procName = (const char*)ProcessName->GetBuffer(value);
831 printf("ProcessName key %u, value '%s'", key, procName);
832 ProcessName->Unlock();
833}
834const char* CompileResult::repProcessName()
835{
836 if (ProcessName == nullptr)
837 return "hackishProcessName";
838
839 if (ProcessName->GetCount() > 0)
840 {
841 return (const char*)ProcessName->GetBuffer(ProcessName->Get((DWORD)0));
842 }
843 return nullptr;
844}
845
846void CompileResult::recAddressMap(void* originalAddress, void* replayAddress, unsigned int size)
847{
848 if (AddressMap == nullptr)
849 AddressMap = new LightWeightMap<DWORDLONG, Agnostic_AddressMap>();
850
851 Agnostic_AddressMap value;
852
853 value.Address = (DWORDLONG)originalAddress;
854 value.size = (DWORD)size;
855
856 AddressMap->Add((DWORDLONG)replayAddress, value);
857}
858void CompileResult::dmpAddressMap(DWORDLONG key, const Agnostic_AddressMap& value)
859{
860 printf("AddressMap key %016llX, value addr-%016llX, size-%u", key, value.Address, value.size);
861}
862void* CompileResult::repAddressMap(void* replayAddress)
863{
864 if (AddressMap == nullptr)
865 return nullptr;
866 Agnostic_AddressMap value;
867 value = AddressMap->Get((DWORDLONG)replayAddress);
868 return (void*)value.Address;
869}
870void* CompileResult::searchAddressMap(void* newAddress)
871{
872 if (AddressMap == nullptr)
873 return (void*)-1;
874 for (unsigned int i = 0; i < AddressMap->GetCount(); i++)
875 {
876 DWORDLONG replayAddress = AddressMap->GetRawKeys()[i];
877 Agnostic_AddressMap value = AddressMap->Get(replayAddress);
878 if ((replayAddress <= (DWORDLONG)newAddress) && ((DWORDLONG)newAddress < (replayAddress + value.size)))
879 return (void*)(value.Address + ((DWORDLONG)newAddress - replayAddress));
880 }
881 return (void*)-1;
882}
883
884void CompileResult::recReserveUnwindInfo(BOOL isFunclet, BOOL isColdCode, ULONG unwindSize)
885{
886 if (ReserveUnwindInfo == nullptr)
887 ReserveUnwindInfo = new DenseLightWeightMap<Agnostic_ReserveUnwindInfo>();
888
889 Agnostic_ReserveUnwindInfo value;
890
891 value.isFunclet = (DWORD)isFunclet;
892 value.isColdCode = (DWORD)isColdCode;
893 value.unwindSize = (DWORD)unwindSize;
894
895 ReserveUnwindInfo->Append(value);
896}
897void CompileResult::dmpReserveUnwindInfo(DWORD key, const Agnostic_ReserveUnwindInfo& value)
898{
899 printf("ReserveUnwindInfo key %u, value isFun-%u isCold-%u usz-%u", key, value.isFunclet, value.isColdCode,
900 value.unwindSize);
901}
902
903void CompileResult::recAllocUnwindInfo(BYTE* pHotCode,
904 BYTE* pColdCode,
905 ULONG startOffset,
906 ULONG endOffset,
907 ULONG unwindSize,
908 BYTE* pUnwindBlock,
909 CorJitFuncKind funcKind)
910{
911 if (AllocUnwindInfo == nullptr)
912 AllocUnwindInfo = new DenseLightWeightMap<Agnostic_AllocUnwindInfo>();
913
914 Agnostic_AllocUnwindInfo value;
915 value.pHotCode = (DWORDLONG)pHotCode;
916 value.pColdCode = (DWORDLONG)pColdCode;
917 value.startOffset = (DWORD)startOffset;
918 value.endOffset = (DWORD)endOffset;
919 value.unwindSize = (DWORD)unwindSize;
920 value.pUnwindBlock_index = AllocUnwindInfo->AddBuffer((unsigned char*)pUnwindBlock, unwindSize);
921 value.funcKind = funcKind;
922
923 AllocUnwindInfo->Append(value);
924}
925void CompileResult::dmpAllocUnwindInfo(DWORD key, const Agnostic_AllocUnwindInfo& value)
926{
927 printf("AllocUnwindInfo key %u, value pHot-%016llX pCold-%016llX startOff-%u endOff-%u unwindSz-%u blki-%u "
928 "funcKind-%u",
929 key, value.pHotCode, value.pColdCode, value.startOffset, value.endOffset, value.unwindSize,
930 value.pUnwindBlock_index, value.funcKind);
931}
932
933void CompileResult::recAllocBBProfileBuffer(ULONG count, ICorJitInfo::ProfileBuffer** profileBuffer, HRESULT result)
934{
935 if (AllocBBProfileBuffer == nullptr)
936 AllocBBProfileBuffer = new LightWeightMap<DWORD, Agnostic_AllocBBProfileBuffer>();
937
938 Agnostic_AllocBBProfileBuffer value;
939
940 value.count = (DWORD)count;
941 value.result = (DWORD)result;
942 value.profileBuffer_index =
943 AllocBBProfileBuffer->AddBuffer((unsigned char*)*profileBuffer, count * sizeof(ICorJitInfo::ProfileBuffer));
944
945 AllocBBProfileBuffer->Add((DWORD)0, value);
946}
947void CompileResult::dmpAllocBBProfileBuffer(DWORD key, const Agnostic_AllocBBProfileBuffer& value)
948{
949 printf("AllocBBProfileBuffer key %u, value cnt-%u ind-%u res-%08X", key, value.count, value.profileBuffer_index,
950 value.result);
951}
952HRESULT CompileResult::repAllocBBProfileBuffer(ULONG count, ICorJitInfo::ProfileBuffer** profileBuffer)
953{
954 Agnostic_AllocBBProfileBuffer value;
955 value = AllocBBProfileBuffer->Get((DWORD)0);
956
957 if (count != value.count)
958 __debugbreak();
959
960 HRESULT result = (HRESULT)value.result;
961 *profileBuffer = (ICorJitInfo::ProfileBuffer*)AllocBBProfileBuffer->GetBuffer(value.profileBuffer_index);
962 recAddressMap((void*)0x4242, (void*)*profileBuffer, count * (sizeof(ICorJitInfo::ProfileBuffer)));
963 return result;
964}
965
966void CompileResult::recRecordCallSite(ULONG instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_HANDLE methodHandle)
967{
968 repRecordCallSite(instrOffset, callSig, methodHandle);
969}
970
971void CompileResult::dmpRecordCallSite(DWORD key, const Agnostic_RecordCallSite& value)
972{
973 printf("RecordCallSite key %u, callSig{cc-%u rtc-%016llX rts-%016llX rt-%u flg-%u na-%u cc-%u ci-%u mc-%u mi-%u "
974 "sig-%u pSig-%u scp-%016llX tok-%08X} ftn-%016llX",
975 key, value.callSig.callConv, value.callSig.retTypeClass, value.callSig.retTypeSigClass,
976 value.callSig.retType, value.callSig.flags, value.callSig.numArgs, value.callSig.sigInst_classInstCount,
977 value.callSig.sigInst_classInst_Index, value.callSig.sigInst_methInstCount,
978 value.callSig.sigInst_methInst_Index, value.callSig.cbSig, value.callSig.pSig_Index, value.callSig.scope,
979 value.callSig.token, value.methodHandle);
980}
981
982void CompileResult::repRecordCallSite(ULONG instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_HANDLE methodHandle)
983{
984 if (RecordCallSite == nullptr)
985 RecordCallSite = new LightWeightMap<DWORD, Agnostic_RecordCallSite>();
986
987 Agnostic_RecordCallSite value;
988 ZeroMemory(&value, sizeof(Agnostic_RecordCallSite));
989
990 if (callSig != nullptr)
991 {
992 value.callSig.callConv = (DWORD)callSig->callConv;
993 value.callSig.retTypeClass = (DWORDLONG)callSig->retTypeClass;
994 value.callSig.retTypeSigClass = (DWORDLONG)callSig->retTypeSigClass;
995 value.callSig.retType = (DWORD)callSig->retType;
996 value.callSig.flags = (DWORD)callSig->flags;
997 value.callSig.numArgs = (DWORD)callSig->numArgs;
998 value.callSig.sigInst_classInstCount = (DWORD)callSig->sigInst.classInstCount;
999 value.callSig.sigInst_classInst_Index =
1000 RecordCallSite->AddBuffer((unsigned char*)callSig->sigInst.classInst,
1001 callSig->sigInst.classInstCount * 8); // porting issue
1002 value.callSig.sigInst_methInstCount = (DWORD)callSig->sigInst.methInstCount;
1003 value.callSig.sigInst_methInst_Index =
1004 RecordCallSite->AddBuffer((unsigned char*)callSig->sigInst.methInst,
1005 callSig->sigInst.methInstCount * 8); // porting issue
1006 value.callSig.args = (DWORDLONG)callSig->args;
1007 value.callSig.cbSig = (DWORD)callSig->cbSig;
1008 value.callSig.pSig_Index = (DWORD)RecordCallSite->AddBuffer((unsigned char*)callSig->pSig, callSig->cbSig);
1009 value.callSig.scope = (DWORDLONG)callSig->scope;
1010 value.callSig.token = (DWORD)callSig->token;
1011 }
1012 else
1013 {
1014 value.callSig.callConv = (DWORD)-1;
1015 value.callSig.retTypeClass = (DWORDLONG)-1;
1016 value.callSig.retTypeSigClass = (DWORDLONG)-1;
1017 value.callSig.retType = (DWORD)-1;
1018 value.callSig.flags = (DWORD)-1;
1019 value.callSig.numArgs = (DWORD)-1;
1020 value.callSig.sigInst_classInstCount = (DWORD)-1;
1021 value.callSig.sigInst_classInst_Index = (DWORD)-1;
1022 value.callSig.sigInst_methInstCount = (DWORD)-1;
1023 value.callSig.sigInst_methInst_Index = (DWORD)-1;
1024 value.callSig.args = (DWORDLONG)-1;
1025 value.callSig.cbSig = (DWORD)-1;
1026 value.callSig.pSig_Index = (DWORD)-1;
1027 value.callSig.scope = (DWORDLONG)-1;
1028 value.callSig.token = (DWORD)-1;
1029 }
1030
1031 value.methodHandle = (DWORDLONG)methodHandle;
1032
1033 RecordCallSite->Add(instrOffset, value);
1034}
1035
1036bool CompileResult::fndRecordCallSiteSigInfo(ULONG instrOffset, CORINFO_SIG_INFO* pCallSig)
1037{
1038 if (RecordCallSite == nullptr)
1039 return false;
1040
1041 if (RecordCallSite->GetIndex(instrOffset) == -1)
1042 return false;
1043
1044 Agnostic_RecordCallSite value = RecordCallSite->Get(instrOffset);
1045
1046 if (value.callSig.callConv == -1)
1047 return false;
1048
1049 pCallSig->callConv = (CorInfoCallConv)value.callSig.callConv;
1050 pCallSig->retTypeClass = (CORINFO_CLASS_HANDLE)value.callSig.retTypeClass;
1051 pCallSig->retTypeSigClass = (CORINFO_CLASS_HANDLE)value.callSig.retTypeSigClass;
1052 pCallSig->retType = (CorInfoType)value.callSig.retType;
1053 pCallSig->flags = (unsigned)value.callSig.flags;
1054 pCallSig->numArgs = (unsigned)value.callSig.numArgs;
1055 pCallSig->sigInst.classInstCount = (unsigned)value.callSig.sigInst_classInstCount;
1056 pCallSig->sigInst.classInst =
1057 (CORINFO_CLASS_HANDLE*)RecordCallSite->GetBuffer(value.callSig.sigInst_classInst_Index);
1058 pCallSig->sigInst.methInstCount = (unsigned)value.callSig.sigInst_methInstCount;
1059 pCallSig->sigInst.methInst = (CORINFO_CLASS_HANDLE*)RecordCallSite->GetBuffer(value.callSig.sigInst_methInst_Index);
1060 pCallSig->args = (CORINFO_ARG_LIST_HANDLE)value.callSig.args;
1061 pCallSig->cbSig = (unsigned int)value.callSig.cbSig;
1062 pCallSig->pSig = (PCCOR_SIGNATURE)RecordCallSite->GetBuffer(value.callSig.pSig_Index);
1063 pCallSig->scope = (CORINFO_MODULE_HANDLE)value.callSig.scope;
1064 pCallSig->token = (mdToken)value.callSig.token;
1065
1066 return true;
1067}
1068
1069bool CompileResult::fndRecordCallSiteMethodHandle(ULONG instrOffset, CORINFO_METHOD_HANDLE* pMethodHandle)
1070{
1071 if (RecordCallSite == nullptr)
1072 return false;
1073
1074 if (RecordCallSite->GetIndex(instrOffset) == -1)
1075 return false;
1076
1077 Agnostic_RecordCallSite value = RecordCallSite->Get(instrOffset);
1078 *pMethodHandle = (CORINFO_METHOD_HANDLE)value.methodHandle;
1079
1080 return true;
1081}
1082