1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7XX XX
8XX Utils.cpp XX
9XX XX
10XX Has miscellaneous utility functions XX
11XX XX
12XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
13XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
14*/
15
16#include "jitpch.h"
17#ifdef _MSC_VER
18#pragma hdrstop
19#endif
20
21#include "opcode.h"
22
23/*****************************************************************************/
24// Define the string platform name based on compilation #ifdefs. This is the
25// same code for all platforms, hence it is here instead of in the targetXXX.cpp
26// files.
27
28#ifdef _TARGET_UNIX_
29// Should we distinguish Mac? Can we?
30// Should we distinguish flavors of Unix? Can we?
31const char* Target::g_tgtPlatformName = "Unix";
32#else // !_TARGET_UNIX_
33const char* Target::g_tgtPlatformName = "Windows";
34#endif // !_TARGET_UNIX_
35
36/*****************************************************************************/
37
38#define DECLARE_DATA
39
40// clang-format off
41extern
42const signed char opcodeSizes[] =
43{
44 #define InlineNone_size 0
45 #define ShortInlineVar_size 1
46 #define InlineVar_size 2
47 #define ShortInlineI_size 1
48 #define InlineI_size 4
49 #define InlineI8_size 8
50 #define ShortInlineR_size 4
51 #define InlineR_size 8
52 #define ShortInlineBrTarget_size 1
53 #define InlineBrTarget_size 4
54 #define InlineMethod_size 4
55 #define InlineField_size 4
56 #define InlineType_size 4
57 #define InlineString_size 4
58 #define InlineSig_size 4
59 #define InlineRVA_size 4
60 #define InlineTok_size 4
61 #define InlineSwitch_size 0 // for now
62 #define InlinePhi_size 0 // for now
63 #define InlineVarTok_size 0 // remove
64
65 #define OPDEF(name,string,pop,push,oprType,opcType,l,s1,s2,ctrl) oprType ## _size ,
66 #include "opcode.def"
67 #undef OPDEF
68
69 #undef InlineNone_size
70 #undef ShortInlineVar_size
71 #undef InlineVar_size
72 #undef ShortInlineI_size
73 #undef InlineI_size
74 #undef InlineI8_size
75 #undef ShortInlineR_size
76 #undef InlineR_size
77 #undef ShortInlineBrTarget_size
78 #undef InlineBrTarget_size
79 #undef InlineMethod_size
80 #undef InlineField_size
81 #undef InlineType_size
82 #undef InlineString_size
83 #undef InlineSig_size
84 #undef InlineRVA_size
85 #undef InlineTok_size
86 #undef InlineSwitch_size
87 #undef InlinePhi_size
88};
89// clang-format on
90
91const BYTE varTypeClassification[] = {
92#define DEF_TP(tn, nm, jitType, verType, sz, sze, asze, st, al, tf, howUsed) tf,
93#include "typelist.h"
94#undef DEF_TP
95};
96
97/*****************************************************************************/
98/*****************************************************************************/
99#ifdef DEBUG
100extern const char* const opcodeNames[] = {
101#define OPDEF(name, string, pop, push, oprType, opcType, l, s1, s2, ctrl) string,
102#include "opcode.def"
103#undef OPDEF
104};
105
106extern const BYTE opcodeArgKinds[] = {
107#define OPDEF(name, string, pop, push, oprType, opcType, l, s1, s2, ctrl) (BYTE) oprType,
108#include "opcode.def"
109#undef OPDEF
110};
111#endif
112
113/*****************************************************************************/
114
115const char* varTypeName(var_types vt)
116{
117 static const char* const varTypeNames[] = {
118#define DEF_TP(tn, nm, jitType, verType, sz, sze, asze, st, al, tf, howUsed) nm,
119#include "typelist.h"
120#undef DEF_TP
121 };
122
123 assert((unsigned)vt < _countof(varTypeNames));
124
125 return varTypeNames[vt];
126}
127
128#if defined(DEBUG) || defined(LATE_DISASM)
129/*****************************************************************************
130 *
131 * Return the name of the given register.
132 */
133
134const char* getRegName(regNumber reg, bool isFloat)
135{
136 // Special-case REG_NA; it's not in the regNames array, but we might want to print it.
137 if (reg == REG_NA)
138 {
139 return "NA";
140 }
141
142#if defined(_TARGET_ARM64_)
143 static const char* const regNames[] = {
144#define REGDEF(name, rnum, mask, xname, wname) xname,
145#include "register.h"
146 };
147 assert(reg < ArrLen(regNames));
148 return regNames[reg];
149#else
150 static const char* const regNames[] = {
151#define REGDEF(name, rnum, mask, sname) sname,
152#include "register.h"
153 };
154 assert(reg < ArrLen(regNames));
155 return regNames[reg];
156#endif
157}
158
159const char* getRegName(unsigned reg,
160 bool isFloat) // this is for gcencode.cpp and disasm.cpp that dont use the regNumber type
161{
162 return getRegName((regNumber)reg, isFloat);
163}
164#endif // defined(DEBUG) || defined(LATE_DISASM)
165
166#if defined(DEBUG)
167
168const char* getRegNameFloat(regNumber reg, var_types type)
169{
170#ifdef _TARGET_ARM_
171 assert(genIsValidFloatReg(reg));
172 if (type == TYP_FLOAT)
173 return getRegName(reg);
174 else
175 {
176 const char* regName;
177
178 switch (reg)
179 {
180 default:
181 assert(!"Bad double register");
182 regName = "d??";
183 break;
184 case REG_F0:
185 regName = "d0";
186 break;
187 case REG_F2:
188 regName = "d2";
189 break;
190 case REG_F4:
191 regName = "d4";
192 break;
193 case REG_F6:
194 regName = "d6";
195 break;
196 case REG_F8:
197 regName = "d8";
198 break;
199 case REG_F10:
200 regName = "d10";
201 break;
202 case REG_F12:
203 regName = "d12";
204 break;
205 case REG_F14:
206 regName = "d14";
207 break;
208 case REG_F16:
209 regName = "d16";
210 break;
211 case REG_F18:
212 regName = "d18";
213 break;
214 case REG_F20:
215 regName = "d20";
216 break;
217 case REG_F22:
218 regName = "d22";
219 break;
220 case REG_F24:
221 regName = "d24";
222 break;
223 case REG_F26:
224 regName = "d26";
225 break;
226 case REG_F28:
227 regName = "d28";
228 break;
229 case REG_F30:
230 regName = "d30";
231 break;
232 }
233 return regName;
234 }
235
236#elif defined(_TARGET_ARM64_)
237
238 static const char* regNamesFloat[] = {
239#define REGDEF(name, rnum, mask, xname, wname) xname,
240#include "register.h"
241 };
242 assert((unsigned)reg < ArrLen(regNamesFloat));
243
244 return regNamesFloat[reg];
245
246#else
247 static const char* regNamesFloat[] = {
248#define REGDEF(name, rnum, mask, sname) "x" sname,
249#include "register.h"
250 };
251#ifdef FEATURE_SIMD
252 static const char* regNamesYMM[] = {
253#define REGDEF(name, rnum, mask, sname) "y" sname,
254#include "register.h"
255 };
256#endif // FEATURE_SIMD
257 assert((unsigned)reg < ArrLen(regNamesFloat));
258
259#ifdef FEATURE_SIMD
260 if (type == TYP_SIMD32)
261 {
262 return regNamesYMM[reg];
263 }
264#endif // FEATURE_SIMD
265
266 return regNamesFloat[reg];
267#endif
268}
269
270/*****************************************************************************
271 *
272 * Displays a register set.
273 * TODO-ARM64-Cleanup: don't allow ip0, ip1 as part of a range.
274 */
275
276void dspRegMask(regMaskTP regMask, size_t minSiz)
277{
278 const char* sep = "";
279
280 printf("[");
281
282 bool inRegRange = false;
283 regNumber regPrev = REG_NA;
284 regNumber regHead = REG_NA; // When we start a range, remember the first register of the range, so we don't use
285 // range notation if the range contains just a single register.
286 for (regNumber regNum = REG_INT_FIRST; regNum <= REG_INT_LAST; regNum = REG_NEXT(regNum))
287 {
288 regMaskTP regBit = genRegMask(regNum);
289
290 if ((regMask & regBit) != 0)
291 {
292 // We have a register to display. It gets displayed now if:
293 // 1. This is the first register to display of a new range of registers (possibly because
294 // no register has ever been displayed).
295 // 2. This is the last register of an acceptable range (either the last integer register,
296 // or the last of a range that is displayed with range notation).
297 if (!inRegRange)
298 {
299 // It's the first register of a potential range.
300 const char* nam = getRegName(regNum);
301 printf("%s%s", sep, nam);
302 minSiz -= strlen(sep) + strlen(nam);
303
304 // By default, we're not starting a potential register range.
305 sep = " ";
306
307 // What kind of separator should we use for this range (if it is indeed going to be a range)?
308 CLANG_FORMAT_COMMENT_ANCHOR;
309
310#if defined(_TARGET_AMD64_)
311 // For AMD64, create ranges for int registers R8 through R15, but not the "old" registers.
312 if (regNum >= REG_R8)
313 {
314 regHead = regNum;
315 inRegRange = true;
316 sep = "-";
317 }
318#elif defined(_TARGET_ARM64_)
319 // R17 and R28 can't be the start of a range, since the range would include TEB or FP
320 if ((regNum < REG_R17) || ((REG_R19 <= regNum) && (regNum < REG_R28)))
321 {
322 regHead = regNum;
323 inRegRange = true;
324 sep = "-";
325 }
326#elif defined(_TARGET_ARM_)
327 if (regNum < REG_R12)
328 {
329 regHead = regNum;
330 inRegRange = true;
331 sep = "-";
332 }
333#elif defined(_TARGET_X86_)
334// No register ranges
335#else // _TARGET_*
336#error Unsupported or unset target architecture
337#endif // _TARGET_*
338 }
339
340#if defined(_TARGET_ARM64_)
341 // We've already printed a register. Is this the end of a range?
342 else if ((regNum == REG_INT_LAST) || (regNum == REG_R17) // last register before TEB
343 || (regNum == REG_R28)) // last register before FP
344#else // _TARGET_ARM64_
345 // We've already printed a register. Is this the end of a range?
346 else if (regNum == REG_INT_LAST)
347#endif // _TARGET_ARM64_
348 {
349 const char* nam = getRegName(regNum);
350 printf("%s%s", sep, nam);
351 minSiz -= strlen(sep) + strlen(nam);
352 inRegRange = false; // No longer in the middle of a register range
353 regHead = REG_NA;
354 sep = " ";
355 }
356 }
357 else // ((regMask & regBit) == 0)
358 {
359 if (inRegRange)
360 {
361 assert(regHead != REG_NA);
362 if (regPrev != regHead)
363 {
364 // Close out the previous range, if it included more than one register.
365 const char* nam = getRegName(regPrev);
366 printf("%s%s", sep, nam);
367 minSiz -= strlen(sep) + strlen(nam);
368 }
369 sep = " ";
370 inRegRange = false;
371 regHead = REG_NA;
372 }
373 }
374
375 if (regBit > regMask)
376 {
377 break;
378 }
379
380 regPrev = regNum;
381 }
382
383 if (strlen(sep) > 0)
384 {
385 // We've already printed something.
386 sep = " ";
387 }
388 inRegRange = false;
389 regPrev = REG_NA;
390 regHead = REG_NA;
391 for (regNumber regNum = REG_FP_FIRST; regNum <= REG_FP_LAST; regNum = REG_NEXT(regNum))
392 {
393 regMaskTP regBit = genRegMask(regNum);
394
395 if (regMask & regBit)
396 {
397 if (!inRegRange || (regNum == REG_FP_LAST))
398 {
399 const char* nam = getRegName(regNum);
400 printf("%s%s", sep, nam);
401 minSiz -= strlen(sep) + strlen(nam);
402 sep = "-";
403 regHead = regNum;
404 }
405 inRegRange = true;
406 }
407 else
408 {
409 if (inRegRange)
410 {
411 if (regPrev != regHead)
412 {
413 const char* nam = getRegName(regPrev);
414 printf("%s%s", sep, nam);
415 minSiz -= (strlen(sep) + strlen(nam));
416 }
417 sep = " ";
418 }
419 inRegRange = false;
420 }
421
422 if (regBit > regMask)
423 {
424 break;
425 }
426
427 regPrev = regNum;
428 }
429
430 printf("]");
431
432 while ((int)minSiz > 0)
433 {
434 printf(" ");
435 minSiz--;
436 }
437}
438
439//------------------------------------------------------------------------
440// dumpILBytes: Helper for dumpSingleInstr() to dump hex bytes of an IL stream,
441// aligning up to a minimum alignment width.
442//
443// Arguments:
444// codeAddr - Pointer to IL byte stream to display.
445// codeSize - Number of bytes of IL byte stream to display.
446// alignSize - Pad out to this many characters, if fewer than this were written.
447//
448void dumpILBytes(const BYTE* const codeAddr,
449 unsigned codeSize,
450 unsigned alignSize) // number of characters to write, for alignment
451{
452 for (IL_OFFSET offs = 0; offs < codeSize; ++offs)
453 {
454 printf(" %02x", *(codeAddr + offs));
455 }
456
457 unsigned charsWritten = 3 * codeSize;
458 for (unsigned i = charsWritten; i < alignSize; i++)
459 {
460 printf(" ");
461 }
462}
463
464//------------------------------------------------------------------------
465// dumpSingleInstr: Display a single IL instruction.
466//
467// Arguments:
468// codeAddr - Base pointer to a stream of IL instructions.
469// offs - Offset from codeAddr of the IL instruction to display.
470// prefix - Optional string to prefix the IL instruction with (if nullptr, no prefix is output).
471//
472// Return Value:
473// Size of the displayed IL instruction in the instruction stream, in bytes. (Add this to 'offs' to
474// get to the next instruction.)
475//
476unsigned dumpSingleInstr(const BYTE* const codeAddr, IL_OFFSET offs, const char* prefix)
477{
478 const BYTE* opcodePtr = codeAddr + offs;
479 const BYTE* startOpcodePtr = opcodePtr;
480 const unsigned ALIGN_WIDTH = 3 * 6; // assume 3 characters * (1 byte opcode + 4 bytes data + 1 prefix byte) for
481 // most things
482
483 if (prefix != nullptr)
484 {
485 printf("%s", prefix);
486 }
487
488 OPCODE opcode = (OPCODE)getU1LittleEndian(opcodePtr);
489 opcodePtr += sizeof(__int8);
490
491DECODE_OPCODE:
492
493 if (opcode >= CEE_COUNT)
494 {
495 printf("\nIllegal opcode: %02X\n", (int)opcode);
496 return (IL_OFFSET)(opcodePtr - startOpcodePtr);
497 }
498
499 /* Get the size of additional parameters */
500
501 size_t sz = opcodeSizes[opcode];
502 unsigned argKind = opcodeArgKinds[opcode];
503
504 /* See what kind of an opcode we have, then */
505
506 switch (opcode)
507 {
508 case CEE_PREFIX1:
509 opcode = OPCODE(getU1LittleEndian(opcodePtr) + 256);
510 opcodePtr += sizeof(__int8);
511 goto DECODE_OPCODE;
512
513 default:
514 {
515 __int64 iOp;
516 double dOp;
517 int jOp;
518 DWORD jOp2;
519
520 switch (argKind)
521 {
522 case InlineNone:
523 dumpILBytes(startOpcodePtr, (unsigned)(opcodePtr - startOpcodePtr), ALIGN_WIDTH);
524 printf(" %-12s", opcodeNames[opcode]);
525 break;
526
527 case ShortInlineVar:
528 iOp = getU1LittleEndian(opcodePtr);
529 goto INT_OP;
530 case ShortInlineI:
531 iOp = getI1LittleEndian(opcodePtr);
532 goto INT_OP;
533 case InlineVar:
534 iOp = getU2LittleEndian(opcodePtr);
535 goto INT_OP;
536 case InlineTok:
537 case InlineMethod:
538 case InlineField:
539 case InlineType:
540 case InlineString:
541 case InlineSig:
542 case InlineI:
543 iOp = getI4LittleEndian(opcodePtr);
544 goto INT_OP;
545 case InlineI8:
546 iOp = getU4LittleEndian(opcodePtr);
547 iOp |= (__int64)getU4LittleEndian(opcodePtr + 4) << 32;
548 goto INT_OP;
549
550 INT_OP:
551 dumpILBytes(startOpcodePtr, (unsigned)((opcodePtr - startOpcodePtr) + sz), ALIGN_WIDTH);
552 printf(" %-12s 0x%X", opcodeNames[opcode], iOp);
553 break;
554
555 case ShortInlineR:
556 dOp = getR4LittleEndian(opcodePtr);
557 goto FLT_OP;
558 case InlineR:
559 dOp = getR8LittleEndian(opcodePtr);
560 goto FLT_OP;
561
562 FLT_OP:
563 dumpILBytes(startOpcodePtr, (unsigned)((opcodePtr - startOpcodePtr) + sz), ALIGN_WIDTH);
564 printf(" %-12s %f", opcodeNames[opcode], dOp);
565 break;
566
567 case ShortInlineBrTarget:
568 jOp = getI1LittleEndian(opcodePtr);
569 goto JMP_OP;
570 case InlineBrTarget:
571 jOp = getI4LittleEndian(opcodePtr);
572 goto JMP_OP;
573
574 JMP_OP:
575 dumpILBytes(startOpcodePtr, (unsigned)((opcodePtr - startOpcodePtr) + sz), ALIGN_WIDTH);
576 printf(" %-12s %d (IL_%04x)", opcodeNames[opcode], jOp, (int)(opcodePtr + sz - codeAddr) + jOp);
577 break;
578
579 case InlineSwitch:
580 jOp2 = getU4LittleEndian(opcodePtr);
581 opcodePtr += 4;
582 opcodePtr += jOp2 * 4; // Jump over the table
583 dumpILBytes(startOpcodePtr, (unsigned)(opcodePtr - startOpcodePtr), ALIGN_WIDTH);
584 printf(" %-12s", opcodeNames[opcode]);
585 break;
586
587 case InlinePhi:
588 jOp2 = getU1LittleEndian(opcodePtr);
589 opcodePtr += 1;
590 opcodePtr += jOp2 * 2; // Jump over the table
591 dumpILBytes(startOpcodePtr, (unsigned)(opcodePtr - startOpcodePtr), ALIGN_WIDTH);
592 printf(" %-12s", opcodeNames[opcode]);
593 break;
594
595 default:
596 assert(!"Bad argKind");
597 }
598
599 opcodePtr += sz;
600 break;
601 }
602 }
603
604 printf("\n");
605 return (IL_OFFSET)(opcodePtr - startOpcodePtr);
606}
607
608//------------------------------------------------------------------------
609// dumpILRange: Display a range of IL instructions from an IL instruction stream.
610//
611// Arguments:
612// codeAddr - Pointer to IL byte stream to display.
613// codeSize - Number of bytes of IL byte stream to display.
614//
615void dumpILRange(const BYTE* const codeAddr, unsigned codeSize) // in bytes
616{
617 for (IL_OFFSET offs = 0; offs < codeSize;)
618 {
619 char prefix[100];
620 sprintf_s(prefix, _countof(prefix), "IL_%04x ", offs);
621 unsigned codeBytesDumped = dumpSingleInstr(codeAddr, offs, prefix);
622 offs += codeBytesDumped;
623 }
624}
625
626/*****************************************************************************
627 *
628 * Display a variable set.
629 */
630const char* genES2str(BitVecTraits* traits, EXPSET_TP set)
631{
632 const int bufSize = 17;
633 static char num1[bufSize];
634
635 static char num2[bufSize];
636
637 static char* nump = num1;
638
639 char* temp = nump;
640
641 nump = (nump == num1) ? num2 : num1;
642
643 sprintf_s(temp, bufSize, "%s", BitVecOps::ToString(traits, set));
644
645 return temp;
646}
647
648const char* refCntWtd2str(unsigned refCntWtd)
649{
650 const int bufSize = 17;
651 static char num1[bufSize];
652
653 static char num2[bufSize];
654
655 static char* nump = num1;
656
657 char* temp = nump;
658
659 nump = (nump == num1) ? num2 : num1;
660
661 if (refCntWtd == BB_MAX_WEIGHT)
662 {
663 sprintf_s(temp, bufSize, "MAX ");
664 }
665 else
666 {
667 unsigned valueInt = refCntWtd / BB_UNITY_WEIGHT;
668 unsigned valueFrac = refCntWtd % BB_UNITY_WEIGHT;
669
670 if (valueFrac == 0)
671 {
672 sprintf_s(temp, bufSize, "%u ", valueInt);
673 }
674 else
675 {
676 sprintf_s(temp, bufSize, "%u.%02u", valueInt, (valueFrac * 100 / BB_UNITY_WEIGHT));
677 }
678 }
679 return temp;
680}
681
682#endif // DEBUG
683
684#if defined(DEBUG) || defined(INLINE_DATA)
685
686//------------------------------------------------------------------------
687// Contains: check if the range includes a particular method
688//
689// Arguments:
690// info -- jit interface pointer
691// method -- method handle for the method of interest
692
693bool ConfigMethodRange::Contains(ICorJitInfo* info, CORINFO_METHOD_HANDLE method)
694{
695 _ASSERT(m_inited == 1);
696
697 // No ranges specified means all methods included.
698 if (m_lastRange == 0)
699 {
700 return true;
701 }
702
703 // Check the hash. Note we can't use the cached hash here since
704 // we may not be asking about the method currently being jitted.
705 const unsigned hash = info->getMethodHash(method);
706
707 for (unsigned i = 0; i < m_lastRange; i++)
708 {
709 if ((m_ranges[i].m_low <= hash) && (hash <= m_ranges[i].m_high))
710 {
711 return true;
712 }
713 }
714
715 return false;
716}
717
718//------------------------------------------------------------------------
719// InitRanges: parse the range string and set up the range info
720//
721// Arguments:
722// rangeStr -- string to parse (may be nullptr)
723// capacity -- number ranges to allocate in the range array
724//
725// Notes:
726// Does some internal error checking; clients can use Error()
727// to determine if the range string couldn't be fully parsed
728// because of bad characters or too many entries, or had values
729// that were too large to represent.
730
731void ConfigMethodRange::InitRanges(const wchar_t* rangeStr, unsigned capacity)
732{
733 // Make sure that the memory was zero initialized
734 assert(m_inited == 0 || m_inited == 1);
735 assert(m_entries == 0);
736 assert(m_ranges == nullptr);
737 assert(m_lastRange == 0);
738
739 // Flag any crazy-looking requests
740 assert(capacity < 100000);
741
742 if (rangeStr == nullptr)
743 {
744 m_inited = 1;
745 return;
746 }
747
748 // Allocate some persistent memory
749 ICorJitHost* jitHost = g_jitHost;
750 m_ranges = (Range*)jitHost->allocateMemory(capacity * sizeof(Range));
751 m_entries = capacity;
752
753 const wchar_t* p = rangeStr;
754 unsigned lastRange = 0;
755 bool setHighPart = false;
756
757 while ((*p != 0) && (lastRange < m_entries))
758 {
759 while (*p == L' ')
760 {
761 p++;
762 }
763
764 int i = 0;
765
766 while (L'0' <= *p && *p <= L'9')
767 {
768 int j = 10 * i + ((*p++) - L'0');
769
770 // Check for overflow
771 if ((m_badChar != 0) && (j <= i))
772 {
773 m_badChar = (p - rangeStr) + 1;
774 }
775
776 i = j;
777 }
778
779 // Was this the high part of a low-high pair?
780 if (setHighPart)
781 {
782 // Yep, set it and move to the next range
783 m_ranges[lastRange].m_high = i;
784
785 // Sanity check that range is proper
786 if ((m_badChar != 0) && (m_ranges[lastRange].m_high < m_ranges[lastRange].m_low))
787 {
788 m_badChar = (p - rangeStr) + 1;
789 }
790
791 lastRange++;
792 setHighPart = false;
793 continue;
794 }
795
796 // Must have been looking for the low part of a range
797 m_ranges[lastRange].m_low = i;
798
799 while (*p == L' ')
800 {
801 p++;
802 }
803
804 // Was that the low part of a low-high pair?
805 if (*p == L'-')
806 {
807 // Yep, skip the dash and set high part next time around.
808 p++;
809 setHighPart = true;
810 continue;
811 }
812
813 // Else we have a point range, so set high = low
814 m_ranges[lastRange].m_high = i;
815 lastRange++;
816 }
817
818 // If we didn't parse the full range string, note index of the the
819 // first bad char.
820 if ((m_badChar != 0) && (*p != 0))
821 {
822 m_badChar = (p - rangeStr) + 1;
823 }
824
825 // Finish off any remaining open range
826 if (setHighPart)
827 {
828 m_ranges[lastRange].m_high = UINT_MAX;
829 lastRange++;
830 }
831
832 assert(lastRange <= m_entries);
833 m_lastRange = lastRange;
834 m_inited = 1;
835}
836
837#endif // defined(DEBUG) || defined(INLINE_DATA)
838
839#if CALL_ARG_STATS || COUNT_BASIC_BLOCKS || COUNT_LOOPS || EMITTER_STATS || MEASURE_NODE_SIZE || MEASURE_MEM_ALLOC
840
841/*****************************************************************************
842 * Histogram class.
843 */
844
845Histogram::Histogram(const unsigned* const sizeTable) : m_sizeTable(sizeTable)
846{
847 unsigned sizeCount = 0;
848 do
849 {
850 sizeCount++;
851 } while ((sizeTable[sizeCount] != 0) && (sizeCount < 1000));
852
853 assert(sizeCount < HISTOGRAM_MAX_SIZE_COUNT - 1);
854
855 m_sizeCount = sizeCount;
856
857 memset(m_counts, 0, (m_sizeCount + 1) * sizeof(*m_counts));
858}
859
860void Histogram::dump(FILE* output)
861{
862 unsigned t = 0;
863 for (unsigned i = 0; i < m_sizeCount; i++)
864 {
865 t += m_counts[i];
866 }
867
868 for (unsigned c = 0, i = 0; i <= m_sizeCount; i++)
869 {
870 if (i == m_sizeCount)
871 {
872 if (m_counts[i] == 0)
873 {
874 break;
875 }
876
877 fprintf(output, " > %7u", m_sizeTable[i - 1]);
878 }
879 else
880 {
881 if (i == 0)
882 {
883 fprintf(output, " <= ");
884 }
885 else
886 {
887 fprintf(output, "%7u .. ", m_sizeTable[i - 1] + 1);
888 }
889
890 fprintf(output, "%7u", m_sizeTable[i]);
891 }
892
893 c += m_counts[i];
894
895 fprintf(output, " ===> %7u count (%3u%% of total)\n", m_counts[i], (int)(100.0 * c / t));
896 }
897}
898
899void Histogram::record(unsigned size)
900{
901 unsigned i;
902 for (i = 0; i < m_sizeCount; i++)
903 {
904 if (m_sizeTable[i] >= size)
905 {
906 break;
907 }
908 }
909
910 m_counts[i]++;
911}
912
913#endif // CALL_ARG_STATS || COUNT_BASIC_BLOCKS || COUNT_LOOPS || EMITTER_STATS || MEASURE_NODE_SIZE
914
915/*****************************************************************************
916 * Fixed bit vector class
917 */
918
919// bitChunkSize() - Returns number of bits in a bitVect chunk
920inline UINT FixedBitVect::bitChunkSize()
921{
922 return sizeof(UINT) * 8;
923}
924
925// bitNumToBit() - Returns a bit mask of the given bit number
926inline UINT FixedBitVect::bitNumToBit(UINT bitNum)
927{
928 assert(bitNum < bitChunkSize());
929 assert(bitChunkSize() <= sizeof(int) * 8);
930
931 return 1 << bitNum;
932}
933
934// bitVectInit() - Initializes a bit vector of a given size
935FixedBitVect* FixedBitVect::bitVectInit(UINT size, Compiler* comp)
936{
937 UINT bitVectMemSize, numberOfChunks;
938 FixedBitVect* bv;
939
940 assert(size != 0);
941
942 numberOfChunks = (size - 1) / bitChunkSize() + 1;
943 bitVectMemSize = numberOfChunks * (bitChunkSize() / 8); // size in bytes
944
945 assert(bitVectMemSize * bitChunkSize() >= size);
946
947 bv = (FixedBitVect*)comp->getAllocator(CMK_FixedBitVect).allocate<char>(sizeof(FixedBitVect) + bitVectMemSize);
948 memset(bv->bitVect, 0, bitVectMemSize);
949
950 bv->bitVectSize = size;
951
952 return bv;
953}
954
955// bitVectSet() - Sets the given bit
956void FixedBitVect::bitVectSet(UINT bitNum)
957{
958 UINT index;
959
960 assert(bitNum <= bitVectSize);
961
962 index = bitNum / bitChunkSize();
963 bitNum -= index * bitChunkSize();
964
965 bitVect[index] |= bitNumToBit(bitNum);
966}
967
968// bitVectTest() - Tests the given bit
969bool FixedBitVect::bitVectTest(UINT bitNum)
970{
971 UINT index;
972
973 assert(bitNum <= bitVectSize);
974
975 index = bitNum / bitChunkSize();
976 bitNum -= index * bitChunkSize();
977
978 return (bitVect[index] & bitNumToBit(bitNum)) != 0;
979}
980
981// bitVectOr() - Or in the given bit vector
982void FixedBitVect::bitVectOr(FixedBitVect* bv)
983{
984 UINT bitChunkCnt = (bitVectSize - 1) / bitChunkSize() + 1;
985
986 assert(bitVectSize == bv->bitVectSize);
987
988 // Or each chunks
989 for (UINT i = 0; i < bitChunkCnt; i++)
990 {
991 bitVect[i] |= bv->bitVect[i];
992 }
993}
994
995// bitVectAnd() - And with passed in bit vector
996void FixedBitVect::bitVectAnd(FixedBitVect& bv)
997{
998 UINT bitChunkCnt = (bitVectSize - 1) / bitChunkSize() + 1;
999
1000 assert(bitVectSize == bv.bitVectSize);
1001
1002 // And each chunks
1003 for (UINT i = 0; i < bitChunkCnt; i++)
1004 {
1005 bitVect[i] &= bv.bitVect[i];
1006 }
1007}
1008
1009// bitVectGetFirst() - Find the first bit on and return bit num,
1010// Return -1 if no bits found.
1011UINT FixedBitVect::bitVectGetFirst()
1012{
1013 return bitVectGetNext((UINT)-1);
1014}
1015
1016// bitVectGetNext() - Find the next bit on given previous position and return bit num.
1017// Return -1 if no bits found.
1018UINT FixedBitVect::bitVectGetNext(UINT bitNumPrev)
1019{
1020 UINT bitNum = (UINT)-1;
1021 UINT index;
1022 UINT bitMask;
1023 UINT bitChunkCnt = (bitVectSize - 1) / bitChunkSize() + 1;
1024 UINT i;
1025
1026 if (bitNumPrev == (UINT)-1)
1027 {
1028 index = 0;
1029 bitMask = (UINT)-1;
1030 }
1031 else
1032 {
1033 UINT bit;
1034
1035 index = bitNumPrev / bitChunkSize();
1036 bitNumPrev -= index * bitChunkSize();
1037 bit = bitNumToBit(bitNumPrev);
1038 bitMask = ~(bit | (bit - 1));
1039 }
1040
1041 // Find first bit
1042 for (i = index; i < bitChunkCnt; i++)
1043 {
1044 UINT bitChunk = bitVect[i] & bitMask;
1045
1046 if (bitChunk != 0)
1047 {
1048 BitScanForward((ULONG*)&bitNum, bitChunk);
1049 break;
1050 }
1051
1052 bitMask = 0xFFFFFFFF;
1053 }
1054
1055 // Empty bit vector?
1056 if (bitNum == (UINT)-1)
1057 {
1058 return (UINT)-1;
1059 }
1060
1061 bitNum += i * bitChunkSize();
1062
1063 assert(bitNum <= bitVectSize);
1064
1065 return bitNum;
1066}
1067
1068// bitVectGetNextAndClear() - Find the first bit on, clear it and return it.
1069// Return -1 if no bits found.
1070UINT FixedBitVect::bitVectGetNextAndClear()
1071{
1072 UINT bitNum = (UINT)-1;
1073 UINT bitChunkCnt = (bitVectSize - 1) / bitChunkSize() + 1;
1074 UINT i;
1075
1076 // Find first bit
1077 for (i = 0; i < bitChunkCnt; i++)
1078 {
1079 if (bitVect[i] != 0)
1080 {
1081 BitScanForward((ULONG*)&bitNum, bitVect[i]);
1082 break;
1083 }
1084 }
1085
1086 // Empty bit vector?
1087 if (bitNum == (UINT)-1)
1088 {
1089 return (UINT)-1;
1090 }
1091
1092 // Clear the bit in the right chunk
1093 bitVect[i] &= ~bitNumToBit(bitNum);
1094
1095 bitNum += i * bitChunkSize();
1096
1097 assert(bitNum <= bitVectSize);
1098
1099 return bitNum;
1100}
1101
1102int SimpleSprintf_s(__in_ecount(cbBufSize - (pWriteStart - pBufStart)) char* pWriteStart,
1103 __in_ecount(cbBufSize) char* pBufStart,
1104 size_t cbBufSize,
1105 __in_z const char* fmt,
1106 ...)
1107{
1108 assert(fmt);
1109 assert(pBufStart);
1110 assert(pWriteStart);
1111 assert((size_t)pBufStart <= (size_t)pWriteStart);
1112 int ret;
1113
1114 // compute the space left in the buffer.
1115 if ((pBufStart + cbBufSize) < pWriteStart)
1116 {
1117 NO_WAY("pWriteStart is past end of buffer");
1118 }
1119 size_t cbSpaceLeft = (size_t)((pBufStart + cbBufSize) - pWriteStart);
1120 va_list args;
1121 va_start(args, fmt);
1122 ret = vsprintf_s(pWriteStart, cbSpaceLeft, const_cast<char*>(fmt), args);
1123 va_end(args);
1124 if (ret < 0)
1125 {
1126 NO_WAY("vsprintf_s failed.");
1127 }
1128 return ret;
1129}
1130
1131#ifdef DEBUG
1132
1133void hexDump(FILE* dmpf, const char* name, BYTE* addr, size_t size)
1134{
1135 if (!size)
1136 {
1137 return;
1138 }
1139
1140 assert(addr);
1141
1142 fprintf(dmpf, "Hex dump of %s:\n", name);
1143
1144 for (unsigned i = 0; i < size; i++)
1145 {
1146 if ((i % 16) == 0)
1147 {
1148 fprintf(dmpf, "\n %04X: ", i);
1149 }
1150
1151 fprintf(dmpf, "%02X ", *addr++);
1152 }
1153
1154 fprintf(dmpf, "\n\n");
1155}
1156
1157#endif // DEBUG
1158
1159void HelperCallProperties::init()
1160{
1161 for (CorInfoHelpFunc helper = CORINFO_HELP_UNDEF; // initialize helper
1162 (helper < CORINFO_HELP_COUNT); // test helper for loop exit
1163 helper = CorInfoHelpFunc(int(helper) + 1)) // update helper to next
1164 {
1165 // Generally you want initialize these to their most typical/safest result
1166 //
1167 bool isPure = false; // true if the result only depends upon input args and not any global state
1168 bool noThrow = false; // true if the helper will never throw
1169 bool nonNullReturn = false; // true if the result will never be null or zero
1170 bool isAllocator = false; // true if the result is usually a newly created heap item, or may throw OutOfMemory
1171 bool mutatesHeap = false; // true if any previous heap objects [are|can be] modified
1172 bool mayRunCctor = false; // true if the helper call may cause a static constructor to be run.
1173
1174 switch (helper)
1175 {
1176 // Arithmetic helpers that cannot throw
1177 case CORINFO_HELP_LLSH:
1178 case CORINFO_HELP_LRSH:
1179 case CORINFO_HELP_LRSZ:
1180 case CORINFO_HELP_LMUL:
1181 case CORINFO_HELP_LNG2DBL:
1182 case CORINFO_HELP_ULNG2DBL:
1183 case CORINFO_HELP_DBL2INT:
1184 case CORINFO_HELP_DBL2LNG:
1185 case CORINFO_HELP_DBL2UINT:
1186 case CORINFO_HELP_DBL2ULNG:
1187 case CORINFO_HELP_FLTREM:
1188 case CORINFO_HELP_DBLREM:
1189 case CORINFO_HELP_FLTROUND:
1190 case CORINFO_HELP_DBLROUND:
1191
1192 isPure = true;
1193 noThrow = true;
1194 break;
1195
1196 // Arithmetic helpers that *can* throw.
1197
1198 // This (or these) are not pure, in that they have "VM side effects"...but they don't mutate the heap.
1199 case CORINFO_HELP_ENDCATCH:
1200
1201 noThrow = true;
1202 break;
1203
1204 // Arithmetic helpers that may throw
1205 case CORINFO_HELP_LMOD: // Mods throw div-by zero, and signed mods have problems with the smallest integer
1206 // mod -1,
1207 case CORINFO_HELP_MOD: // which is not representable as a positive integer.
1208 case CORINFO_HELP_UMOD:
1209 case CORINFO_HELP_ULMOD:
1210
1211 case CORINFO_HELP_UDIV: // Divs throw divide-by-zero.
1212 case CORINFO_HELP_DIV:
1213 case CORINFO_HELP_LDIV:
1214 case CORINFO_HELP_ULDIV:
1215
1216 case CORINFO_HELP_LMUL_OVF:
1217 case CORINFO_HELP_ULMUL_OVF:
1218 case CORINFO_HELP_DBL2INT_OVF:
1219 case CORINFO_HELP_DBL2LNG_OVF:
1220 case CORINFO_HELP_DBL2UINT_OVF:
1221 case CORINFO_HELP_DBL2ULNG_OVF:
1222
1223 isPure = true;
1224 break;
1225
1226 // Heap Allocation helpers, these all never return null
1227 case CORINFO_HELP_NEWSFAST:
1228 case CORINFO_HELP_NEWSFAST_ALIGN8:
1229 case CORINFO_HELP_NEWSFAST_ALIGN8_VC:
1230 case CORINFO_HELP_NEW_CROSSCONTEXT:
1231 case CORINFO_HELP_NEWFAST:
1232 case CORINFO_HELP_NEWSFAST_FINALIZE:
1233 case CORINFO_HELP_NEWSFAST_ALIGN8_FINALIZE:
1234 case CORINFO_HELP_READYTORUN_NEW:
1235 case CORINFO_HELP_BOX:
1236
1237 isAllocator = true;
1238 nonNullReturn = true;
1239 noThrow = true; // only can throw OutOfMemory
1240 break;
1241
1242 // These allocation helpers do some checks on the size (and lower bound) inputs,
1243 // and can throw exceptions other than OOM.
1244 case CORINFO_HELP_NEWARR_1_VC:
1245 case CORINFO_HELP_NEWARR_1_ALIGN8:
1246 case CORINFO_HELP_NEW_MDARR:
1247 case CORINFO_HELP_NEWARR_1_DIRECT:
1248 case CORINFO_HELP_NEWARR_1_OBJ:
1249 case CORINFO_HELP_NEWARR_1_R2R_DIRECT:
1250 case CORINFO_HELP_READYTORUN_NEWARR_1:
1251
1252 isAllocator = true;
1253 nonNullReturn = true;
1254 break;
1255
1256 // Heap Allocation helpers that are also pure
1257 case CORINFO_HELP_STRCNS:
1258
1259 isPure = true;
1260 isAllocator = true;
1261 nonNullReturn = true;
1262 noThrow = true; // only can throw OutOfMemory
1263 break;
1264
1265 case CORINFO_HELP_BOX_NULLABLE:
1266 // Box Nullable is not a 'pure' function
1267 // It has a Byref argument that it reads the contents of.
1268 //
1269 // So two calls to Box Nullable that pass the same address (with the same Value Number)
1270 // will produce different results when the contents of the memory pointed to by the Byref changes
1271 //
1272 isAllocator = true;
1273 noThrow = true; // only can throw OutOfMemory
1274 break;
1275
1276 case CORINFO_HELP_RUNTIMEHANDLE_METHOD:
1277 case CORINFO_HELP_RUNTIMEHANDLE_CLASS:
1278 case CORINFO_HELP_RUNTIMEHANDLE_METHOD_LOG:
1279 case CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG:
1280 // logging helpers are not technically pure but can be optimized away
1281 isPure = true;
1282 noThrow = true;
1283 nonNullReturn = true;
1284 break;
1285
1286 // type casting helpers
1287 case CORINFO_HELP_ISINSTANCEOFINTERFACE:
1288 case CORINFO_HELP_ISINSTANCEOFARRAY:
1289 case CORINFO_HELP_ISINSTANCEOFCLASS:
1290 case CORINFO_HELP_ISINSTANCEOFANY:
1291 case CORINFO_HELP_READYTORUN_ISINSTANCEOF:
1292 case CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE:
1293 case CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE:
1294
1295 isPure = true;
1296 noThrow = true; // These return null for a failing cast
1297 break;
1298
1299 case CORINFO_HELP_ARE_TYPES_EQUIVALENT:
1300
1301 isPure = true;
1302 noThrow = true;
1303 break;
1304
1305 // type casting helpers that throw
1306 case CORINFO_HELP_CHKCASTINTERFACE:
1307 case CORINFO_HELP_CHKCASTARRAY:
1308 case CORINFO_HELP_CHKCASTCLASS:
1309 case CORINFO_HELP_CHKCASTANY:
1310 case CORINFO_HELP_CHKCASTCLASS_SPECIAL:
1311 case CORINFO_HELP_READYTORUN_CHKCAST:
1312
1313 // These throw for a failing cast
1314 // But if given a null input arg will return null
1315 isPure = true;
1316 break;
1317
1318 // helpers returning addresses, these can also throw
1319 case CORINFO_HELP_UNBOX:
1320 case CORINFO_HELP_GETREFANY:
1321 case CORINFO_HELP_LDELEMA_REF:
1322
1323 isPure = true;
1324 break;
1325
1326 // helpers that return internal handle
1327 case CORINFO_HELP_GETCLASSFROMMETHODPARAM:
1328 case CORINFO_HELP_GETSYNCFROMCLASSHANDLE:
1329
1330 isPure = true;
1331 noThrow = true;
1332 break;
1333
1334 // Helpers that load the base address for static variables.
1335 // We divide these between those that may and may not invoke
1336 // static class constructors.
1337 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE:
1338 case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE:
1339 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS:
1340 case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS:
1341 case CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE:
1342 case CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE:
1343 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE:
1344 case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE:
1345 case CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS:
1346 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS:
1347 case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS:
1348 case CORINFO_HELP_GETSTATICFIELDADDR_CONTEXT:
1349 case CORINFO_HELP_GETSTATICFIELDADDR_TLS:
1350 case CORINFO_HELP_GETGENERICS_GCSTATIC_BASE:
1351 case CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE:
1352 case CORINFO_HELP_READYTORUN_STATIC_BASE:
1353 case CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE:
1354
1355 // These may invoke static class constructors
1356 // These can throw InvalidProgram exception if the class can not be constructed
1357 //
1358 isPure = true;
1359 nonNullReturn = true;
1360 mayRunCctor = true;
1361 break;
1362
1363 case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR:
1364 case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR:
1365 case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR:
1366 case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR:
1367
1368 // These do not invoke static class constructors
1369 //
1370 isPure = true;
1371 noThrow = true;
1372 nonNullReturn = true;
1373 break;
1374
1375 // GC Write barrier support
1376 // TODO-ARM64-Bug?: Can these throw or not?
1377 case CORINFO_HELP_ASSIGN_REF:
1378 case CORINFO_HELP_CHECKED_ASSIGN_REF:
1379 case CORINFO_HELP_ASSIGN_REF_ENSURE_NONHEAP:
1380 case CORINFO_HELP_ASSIGN_BYREF:
1381 case CORINFO_HELP_ASSIGN_STRUCT:
1382
1383 mutatesHeap = true;
1384 break;
1385
1386 // Accessing fields (write)
1387 case CORINFO_HELP_SETFIELD32:
1388 case CORINFO_HELP_SETFIELD64:
1389 case CORINFO_HELP_SETFIELDOBJ:
1390 case CORINFO_HELP_SETFIELDSTRUCT:
1391 case CORINFO_HELP_SETFIELDFLOAT:
1392 case CORINFO_HELP_SETFIELDDOUBLE:
1393 case CORINFO_HELP_ARRADDR_ST:
1394
1395 mutatesHeap = true;
1396 break;
1397
1398 // These helper calls always throw an exception
1399 case CORINFO_HELP_OVERFLOW:
1400 case CORINFO_HELP_VERIFICATION:
1401 case CORINFO_HELP_RNGCHKFAIL:
1402 case CORINFO_HELP_THROWDIVZERO:
1403 case CORINFO_HELP_THROWNULLREF:
1404 case CORINFO_HELP_THROW:
1405 case CORINFO_HELP_RETHROW:
1406 case CORINFO_HELP_THROW_ARGUMENTEXCEPTION:
1407 case CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION:
1408 case CORINFO_HELP_THROW_NOT_IMPLEMENTED:
1409 case CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED:
1410 case CORINFO_HELP_THROW_TYPE_NOT_SUPPORTED:
1411
1412 break;
1413
1414 // These helper calls may throw an exception
1415 case CORINFO_HELP_METHOD_ACCESS_CHECK:
1416 case CORINFO_HELP_FIELD_ACCESS_CHECK:
1417 case CORINFO_HELP_CLASS_ACCESS_CHECK:
1418 case CORINFO_HELP_DELEGATE_SECURITY_CHECK:
1419 case CORINFO_HELP_MON_EXIT_STATIC:
1420
1421 break;
1422
1423 // This is a debugging aid; it simply returns a constant address.
1424 case CORINFO_HELP_LOOP_CLONE_CHOICE_ADDR:
1425 isPure = true;
1426 noThrow = true;
1427 break;
1428
1429 case CORINFO_HELP_DBG_IS_JUST_MY_CODE:
1430 case CORINFO_HELP_BBT_FCN_ENTER:
1431 case CORINFO_HELP_POLL_GC:
1432 case CORINFO_HELP_MON_ENTER:
1433 case CORINFO_HELP_MON_EXIT:
1434 case CORINFO_HELP_MON_ENTER_STATIC:
1435 case CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER:
1436 case CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT:
1437 case CORINFO_HELP_SECURITY_PROLOG:
1438 case CORINFO_HELP_SECURITY_PROLOG_FRAMED:
1439 case CORINFO_HELP_VERIFICATION_RUNTIME_CHECK:
1440 case CORINFO_HELP_GETFIELDADDR:
1441 case CORINFO_HELP_INIT_PINVOKE_FRAME:
1442 case CORINFO_HELP_JIT_PINVOKE_BEGIN:
1443 case CORINFO_HELP_JIT_PINVOKE_END:
1444 case CORINFO_HELP_GETCURRENTMANAGEDTHREADID:
1445
1446 noThrow = true;
1447 break;
1448
1449 // Not sure how to handle optimization involving the rest of these helpers
1450 default:
1451
1452 // The most pessimistic results are returned for these helpers
1453 mutatesHeap = true;
1454 break;
1455 }
1456
1457 m_isPure[helper] = isPure;
1458 m_noThrow[helper] = noThrow;
1459 m_nonNullReturn[helper] = nonNullReturn;
1460 m_isAllocator[helper] = isAllocator;
1461 m_mutatesHeap[helper] = mutatesHeap;
1462 m_mayRunCctor[helper] = mayRunCctor;
1463 }
1464}
1465
1466//=============================================================================
1467// AssemblyNamesList2
1468//=============================================================================
1469// The string should be of the form
1470// MyAssembly
1471// MyAssembly;mscorlib;System
1472// MyAssembly;mscorlib System
1473
1474AssemblyNamesList2::AssemblyNamesList2(const wchar_t* list, HostAllocator alloc) : m_alloc(alloc)
1475{
1476 WCHAR prevChar = '?'; // dummy
1477 LPWSTR nameStart = nullptr; // start of the name currently being processed. nullptr if no current name
1478 AssemblyName** ppPrevLink = &m_pNames;
1479
1480 for (LPWSTR listWalk = const_cast<LPWSTR>(list); prevChar != '\0'; prevChar = *listWalk, listWalk++)
1481 {
1482 WCHAR curChar = *listWalk;
1483
1484 if (iswspace(curChar) || curChar == W(';') || curChar == W('\0'))
1485 {
1486 //
1487 // Found white-space
1488 //
1489
1490 if (nameStart)
1491 {
1492 // Found the end of the current name; add a new assembly name to the list.
1493
1494 AssemblyName* newName = new (m_alloc) AssemblyName();
1495
1496 // Null out the current character so we can do zero-terminated string work; we'll restore it later.
1497 *listWalk = W('\0');
1498
1499 // How much space do we need?
1500 int convertedNameLenBytes =
1501 WszWideCharToMultiByte(CP_UTF8, 0, nameStart, -1, nullptr, 0, nullptr, nullptr);
1502 newName->m_assemblyName = new (m_alloc) char[convertedNameLenBytes]; // convertedNameLenBytes includes
1503 // the trailing null character
1504 if (WszWideCharToMultiByte(CP_UTF8, 0, nameStart, -1, newName->m_assemblyName, convertedNameLenBytes,
1505 nullptr, nullptr) != 0)
1506 {
1507 *ppPrevLink = newName;
1508 ppPrevLink = &newName->m_next;
1509 }
1510 else
1511 {
1512 // Failed to convert the string. Ignore this string (and leak the memory).
1513 }
1514
1515 nameStart = nullptr;
1516
1517 // Restore the current character.
1518 *listWalk = curChar;
1519 }
1520 }
1521 else if (!nameStart)
1522 {
1523 //
1524 // Found the start of a new name
1525 //
1526
1527 nameStart = listWalk;
1528 }
1529 }
1530
1531 assert(nameStart == nullptr); // cannot be in the middle of a name
1532 *ppPrevLink = nullptr; // Terminate the last element of the list.
1533}
1534
1535AssemblyNamesList2::~AssemblyNamesList2()
1536{
1537 for (AssemblyName* pName = m_pNames; pName != nullptr; /**/)
1538 {
1539 AssemblyName* cur = pName;
1540 pName = pName->m_next;
1541
1542 m_alloc.deallocate(cur->m_assemblyName);
1543 m_alloc.deallocate(cur);
1544 }
1545}
1546
1547bool AssemblyNamesList2::IsInList(const char* assemblyName)
1548{
1549 for (AssemblyName* pName = m_pNames; pName != nullptr; pName = pName->m_next)
1550 {
1551 if (_stricmp(pName->m_assemblyName, assemblyName) == 0)
1552 {
1553 return true;
1554 }
1555 }
1556
1557 return false;
1558}
1559
1560#ifdef FEATURE_JIT_METHOD_PERF
1561CycleCount::CycleCount() : cps(CycleTimer::CyclesPerSecond())
1562{
1563}
1564
1565bool CycleCount::GetCycles(unsigned __int64* time)
1566{
1567 return CycleTimer::GetThreadCyclesS(time);
1568}
1569
1570bool CycleCount::Start()
1571{
1572 return GetCycles(&beginCycles);
1573}
1574
1575double CycleCount::ElapsedTime()
1576{
1577 unsigned __int64 nowCycles;
1578 (void)GetCycles(&nowCycles);
1579 return ((double)(nowCycles - beginCycles) / cps) * 1000.0;
1580}
1581
1582bool PerfCounter::Start()
1583{
1584 bool result = QueryPerformanceFrequency(&beg) != 0;
1585 if (!result)
1586 {
1587 return result;
1588 }
1589 freq = (double)beg.QuadPart / 1000.0;
1590 (void)QueryPerformanceCounter(&beg);
1591 return result;
1592}
1593
1594// Return elapsed time from Start() in millis.
1595double PerfCounter::ElapsedTime()
1596{
1597 LARGE_INTEGER li;
1598 (void)QueryPerformanceCounter(&li);
1599 return (double)(li.QuadPart - beg.QuadPart) / freq;
1600}
1601
1602#endif
1603
1604#ifdef DEBUG
1605
1606/*****************************************************************************
1607 * Return the number of digits in a number of the given base (default base 10).
1608 * Used when outputting strings.
1609 */
1610unsigned CountDigits(unsigned num, unsigned base /* = 10 */)
1611{
1612 assert(2 <= base && base <= 16); // sanity check
1613 unsigned count = 1;
1614 while (num >= base)
1615 {
1616 num /= base;
1617 ++count;
1618 }
1619 return count;
1620}
1621
1622#endif // DEBUG
1623
1624double FloatingPointUtils::convertUInt64ToDouble(unsigned __int64 uIntVal)
1625{
1626 __int64 s64 = uIntVal;
1627 double d;
1628 if (s64 < 0)
1629 {
1630#if defined(_TARGET_XARCH_)
1631 // RyuJIT codegen and clang (or gcc) may produce different results for casting uint64 to
1632 // double, and the clang result is more accurate. For example,
1633 // 1) (double)0x84595161401484A0UL --> 43e08b2a2c280290 (RyuJIT codegen or VC++)
1634 // 2) (double)0x84595161401484A0UL --> 43e08b2a2c280291 (clang or gcc)
1635 // If the folding optimization below is implemented by simple casting of (double)uint64_val
1636 // and it is compiled by clang, casting result can be inconsistent, depending on whether
1637 // the folding optimization is triggered or the codegen generates instructions for casting. //
1638 // The current solution is to force the same math as the codegen does, so that casting
1639 // result is always consistent.
1640
1641 // d = (double)(int64_t)uint64 + 0x1p64
1642 uint64_t adjHex = 0x43F0000000000000UL;
1643 d = (double)s64 + *(double*)&adjHex;
1644#else
1645 d = (double)uIntVal;
1646#endif
1647 }
1648 else
1649 {
1650 d = (double)uIntVal;
1651 }
1652 return d;
1653}
1654
1655float FloatingPointUtils::convertUInt64ToFloat(unsigned __int64 u64)
1656{
1657 double d = convertUInt64ToDouble(u64);
1658 return (float)d;
1659}
1660
1661unsigned __int64 FloatingPointUtils::convertDoubleToUInt64(double d)
1662{
1663 unsigned __int64 u64;
1664 if (d >= 0.0)
1665 {
1666 // Work around a C++ issue where it doesn't properly convert large positive doubles
1667 const double two63 = 2147483648.0 * 4294967296.0;
1668 if (d < two63)
1669 {
1670 u64 = UINT64(d);
1671 }
1672 else
1673 {
1674 // subtract 0x8000000000000000, do the convert then add it back again
1675 u64 = INT64(d - two63) + I64(0x8000000000000000);
1676 }
1677 return u64;
1678 }
1679
1680#ifdef _TARGET_XARCH_
1681
1682 // While the Ecma spec does not specifically call this out,
1683 // the case of conversion from negative double to unsigned integer is
1684 // effectively an overflow and therefore the result is unspecified.
1685 // With MSVC for x86/x64, such a conversion results in the bit-equivalent
1686 // unsigned value of the conversion to integer. Other compilers convert
1687 // negative doubles to zero when the target is unsigned.
1688 // To make the behavior consistent across OS's on TARGET_XARCH,
1689 // this double cast is needed to conform MSVC behavior.
1690
1691 u64 = UINT64(INT64(d));
1692#else
1693 u64 = UINT64(d);
1694#endif // _TARGET_XARCH_
1695
1696 return u64;
1697}
1698
1699// Rounds a double-precision floating-point value to the nearest integer,
1700// and rounds midpoint values to the nearest even number.
1701double FloatingPointUtils::round(double x)
1702{
1703 // ************************************************************************************
1704 // IMPORTANT: Do not change this implementation without also updating Math.Round(double),
1705 // MathF.Round(float), and FloatingPointUtils::round(float)
1706 // ************************************************************************************
1707
1708 // If the number has no fractional part do nothing
1709 // This shortcut is necessary to workaround precision loss in borderline cases on some platforms
1710
1711 if (x == (double)((INT64)x))
1712 {
1713 return x;
1714 }
1715
1716 // We had a number that was equally close to 2 integers.
1717 // We need to return the even one.
1718
1719 double flrTempVal = floor(x + 0.5);
1720
1721 if ((x == (floor(x) + 0.5)) && (fmod(flrTempVal, 2.0) != 0))
1722 {
1723 flrTempVal -= 1.0;
1724 }
1725
1726 return _copysign(flrTempVal, x);
1727}
1728
1729// Windows x86 and Windows ARM/ARM64 may not define _copysignf() but they do define _copysign().
1730// We will redirect the macro to this other functions if the macro is not defined for the platform.
1731// This has the side effect of a possible implicit upcasting for arguments passed in and an explicit
1732// downcasting for the _copysign() call.
1733#if (defined(_TARGET_X86_) || defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)) && !defined(FEATURE_PAL)
1734
1735#if !defined(_copysignf)
1736#define _copysignf (float)_copysign
1737#endif
1738
1739#endif
1740
1741// Rounds a single-precision floating-point value to the nearest integer,
1742// and rounds midpoint values to the nearest even number.
1743float FloatingPointUtils::round(float x)
1744{
1745 // ************************************************************************************
1746 // IMPORTANT: Do not change this implementation without also updating MathF.Round(float),
1747 // Math.Round(double), and FloatingPointUtils::round(double)
1748 // ************************************************************************************
1749
1750 // If the number has no fractional part do nothing
1751 // This shortcut is necessary to workaround precision loss in borderline cases on some platforms
1752
1753 if (x == (float)((INT32)x))
1754 {
1755 return x;
1756 }
1757
1758 // We had a number that was equally close to 2 integers.
1759 // We need to return the even one.
1760
1761 float flrTempVal = floorf(x + 0.5f);
1762
1763 if ((x == (floorf(x) + 0.5f)) && (fmodf(flrTempVal, 2.0f) != 0))
1764 {
1765 flrTempVal -= 1.0f;
1766 }
1767
1768 return _copysignf(flrTempVal, x);
1769}
1770
1771namespace MagicDivide
1772{
1773template <int TableBase = 0, int TableSize, typename Magic>
1774static const Magic* TryGetMagic(const Magic (&table)[TableSize], typename Magic::DivisorType index)
1775{
1776 if ((index < TableBase) || (TableBase + TableSize <= index))
1777 {
1778 return nullptr;
1779 }
1780
1781 const Magic* p = &table[index - TableBase];
1782
1783 if (p->magic == 0)
1784 {
1785 return nullptr;
1786 }
1787
1788 return p;
1789};
1790
1791template <typename T>
1792struct UnsignedMagic
1793{
1794 typedef T DivisorType;
1795
1796 T magic;
1797 bool add;
1798 int shift;
1799};
1800
1801template <typename T>
1802const UnsignedMagic<T>* TryGetUnsignedMagic(T divisor)
1803{
1804 return nullptr;
1805}
1806
1807template <>
1808const UnsignedMagic<uint32_t>* TryGetUnsignedMagic(uint32_t divisor)
1809{
1810 static const UnsignedMagic<uint32_t> table[]{
1811 {0xaaaaaaab, false, 1}, // 3
1812 {},
1813 {0xcccccccd, false, 2}, // 5
1814 {0xaaaaaaab, false, 2}, // 6
1815 {0x24924925, true, 3}, // 7
1816 {},
1817 {0x38e38e39, false, 1}, // 9
1818 {0xcccccccd, false, 3}, // 10
1819 {0xba2e8ba3, false, 3}, // 11
1820 {0xaaaaaaab, false, 3}, // 12
1821 };
1822
1823 return TryGetMagic<3>(table, divisor);
1824}
1825
1826template <>
1827const UnsignedMagic<uint64_t>* TryGetUnsignedMagic(uint64_t divisor)
1828{
1829 static const UnsignedMagic<uint64_t> table[]{
1830 {0xaaaaaaaaaaaaaaab, false, 1}, // 3
1831 {},
1832 {0xcccccccccccccccd, false, 2}, // 5
1833 {0xaaaaaaaaaaaaaaab, false, 2}, // 6
1834 {0x2492492492492493, true, 3}, // 7
1835 {},
1836 {0xe38e38e38e38e38f, false, 3}, // 9
1837 {0xcccccccccccccccd, false, 3}, // 10
1838 {0x2e8ba2e8ba2e8ba3, false, 1}, // 11
1839 {0xaaaaaaaaaaaaaaab, false, 3}, // 12
1840 };
1841
1842 return TryGetMagic<3>(table, divisor);
1843}
1844
1845//------------------------------------------------------------------------
1846// GetUnsignedMagic: Generates a magic number and shift amount for the magic
1847// number unsigned division optimization.
1848//
1849// Arguments:
1850// d - The divisor
1851// add - Pointer to a flag indicating the kind of code to generate
1852// shift - Pointer to the shift value to be returned
1853//
1854// Returns:
1855// The magic number.
1856//
1857// Notes:
1858// This code is adapted from _The_PowerPC_Compiler_Writer's_Guide_, pages 57-58.
1859// The paper is based on "Division by invariant integers using multiplication"
1860// by Torbjorn Granlund and Peter L. Montgomery in PLDI 94
1861
1862template <typename T>
1863T GetUnsignedMagic(T d, bool* add /*out*/, int* shift /*out*/)
1864{
1865 assert((d >= 3) && !isPow2(d));
1866
1867 const UnsignedMagic<T>* magic = TryGetUnsignedMagic(d);
1868
1869 if (magic != nullptr)
1870 {
1871 *shift = magic->shift;
1872 *add = magic->add;
1873 return magic->magic;
1874 }
1875
1876 typedef typename jitstd::make_signed<T>::type ST;
1877
1878 const unsigned bits = sizeof(T) * 8;
1879 const unsigned bitsMinus1 = bits - 1;
1880 const T twoNMinus1 = T(1) << bitsMinus1;
1881
1882 *add = false;
1883 const T nc = -ST(1) - -ST(d) % ST(d);
1884 unsigned p = bitsMinus1;
1885 T q1 = twoNMinus1 / nc;
1886 T r1 = twoNMinus1 - (q1 * nc);
1887 T q2 = (twoNMinus1 - 1) / d;
1888 T r2 = (twoNMinus1 - 1) - (q2 * d);
1889 T delta;
1890
1891 do
1892 {
1893 p++;
1894
1895 if (r1 >= (nc - r1))
1896 {
1897 q1 = 2 * q1 + 1;
1898 r1 = 2 * r1 - nc;
1899 }
1900 else
1901 {
1902 q1 = 2 * q1;
1903 r1 = 2 * r1;
1904 }
1905
1906 if ((r2 + 1) >= (d - r2))
1907 {
1908 if (q2 >= (twoNMinus1 - 1))
1909 {
1910 *add = true;
1911 }
1912
1913 q2 = 2 * q2 + 1;
1914 r2 = 2 * r2 + 1 - d;
1915 }
1916 else
1917 {
1918 if (q2 >= twoNMinus1)
1919 {
1920 *add = true;
1921 }
1922
1923 q2 = 2 * q2;
1924 r2 = 2 * r2 + 1;
1925 }
1926
1927 delta = d - 1 - r2;
1928
1929 } while ((p < (bits * 2)) && ((q1 < delta) || ((q1 == delta) && (r1 == 0))));
1930
1931 *shift = p - bits; // resulting shift
1932 return q2 + 1; // resulting magic number
1933}
1934
1935uint32_t GetUnsigned32Magic(uint32_t d, bool* add /*out*/, int* shift /*out*/)
1936{
1937 return GetUnsignedMagic<uint32_t>(d, add, shift);
1938}
1939
1940#ifdef _TARGET_64BIT_
1941uint64_t GetUnsigned64Magic(uint64_t d, bool* add /*out*/, int* shift /*out*/)
1942{
1943 return GetUnsignedMagic<uint64_t>(d, add, shift);
1944}
1945#endif
1946
1947template <typename T>
1948struct SignedMagic
1949{
1950 typedef T DivisorType;
1951
1952 T magic;
1953 int shift;
1954};
1955
1956template <typename T>
1957const SignedMagic<T>* TryGetSignedMagic(T divisor)
1958{
1959 return nullptr;
1960}
1961
1962template <>
1963const SignedMagic<int32_t>* TryGetSignedMagic(int32_t divisor)
1964{
1965 static const SignedMagic<int32_t> table[]{
1966 {0x55555556, 0}, // 3
1967 {},
1968 {0x66666667, 1}, // 5
1969 {0x2aaaaaab, 0}, // 6
1970 {0x92492493, 2}, // 7
1971 {},
1972 {0x38e38e39, 1}, // 9
1973 {0x66666667, 2}, // 10
1974 {0x2e8ba2e9, 1}, // 11
1975 {0x2aaaaaab, 1}, // 12
1976 };
1977
1978 return TryGetMagic<3>(table, divisor);
1979}
1980
1981template <>
1982const SignedMagic<int64_t>* TryGetSignedMagic(int64_t divisor)
1983{
1984 static const SignedMagic<int64_t> table[]{
1985 {0x5555555555555556, 0}, // 3
1986 {},
1987 {0x6666666666666667, 1}, // 5
1988 {0x2aaaaaaaaaaaaaab, 0}, // 6
1989 {0x4924924924924925, 1}, // 7
1990 {},
1991 {0x1c71c71c71c71c72, 0}, // 9
1992 {0x6666666666666667, 2}, // 10
1993 {0x2e8ba2e8ba2e8ba3, 1}, // 11
1994 {0x2aaaaaaaaaaaaaab, 1}, // 12
1995 };
1996
1997 return TryGetMagic<3>(table, divisor);
1998}
1999
2000//------------------------------------------------------------------------
2001// GetSignedMagic: Generates a magic number and shift amount for
2002// the magic number division optimization.
2003//
2004// Arguments:
2005// denom - The denominator
2006// shift - Pointer to the shift value to be returned
2007//
2008// Returns:
2009// The magic number.
2010//
2011// Notes:
2012// This code is previously from UTC where it notes it was taken from
2013// _The_PowerPC_Compiler_Writer's_Guide_, pages 57-58. The paper is based on
2014// is "Division by invariant integers using multiplication" by Torbjorn Granlund
2015// and Peter L. Montgomery in PLDI 94
2016
2017template <typename T>
2018T GetSignedMagic(T denom, int* shift /*out*/)
2019{
2020 const SignedMagic<T>* magic = TryGetSignedMagic(denom);
2021
2022 if (magic != nullptr)
2023 {
2024 *shift = magic->shift;
2025 return magic->magic;
2026 }
2027
2028 const int bits = sizeof(T) * 8;
2029 const int bits_minus_1 = bits - 1;
2030
2031 typedef typename jitstd::make_unsigned<T>::type UT;
2032
2033 const UT two_nminus1 = UT(1) << bits_minus_1;
2034
2035 int p;
2036 UT absDenom;
2037 UT absNc;
2038 UT delta;
2039 UT q1;
2040 UT r1;
2041 UT r2;
2042 UT q2;
2043 UT t;
2044 T result_magic;
2045 int iters = 0;
2046
2047 absDenom = abs(denom);
2048 t = two_nminus1 + ((unsigned int)denom >> 31);
2049 absNc = t - 1 - (t % absDenom); // absolute value of nc
2050 p = bits_minus_1; // initialize p
2051 q1 = two_nminus1 / absNc; // initialize q1 = 2^p / abs(nc)
2052 r1 = two_nminus1 - (q1 * absNc); // initialize r1 = rem(2^p, abs(nc))
2053 q2 = two_nminus1 / absDenom; // initialize q1 = 2^p / abs(denom)
2054 r2 = two_nminus1 - (q2 * absDenom); // initialize r1 = rem(2^p, abs(denom))
2055
2056 do
2057 {
2058 iters++;
2059 p++;
2060 q1 *= 2; // update q1 = 2^p / abs(nc)
2061 r1 *= 2; // update r1 = rem(2^p / abs(nc))
2062
2063 if (r1 >= absNc)
2064 { // must be unsigned comparison
2065 q1++;
2066 r1 -= absNc;
2067 }
2068
2069 q2 *= 2; // update q2 = 2^p / abs(denom)
2070 r2 *= 2; // update r2 = rem(2^p / abs(denom))
2071
2072 if (r2 >= absDenom)
2073 { // must be unsigned comparison
2074 q2++;
2075 r2 -= absDenom;
2076 }
2077
2078 delta = absDenom - r2;
2079 } while (q1 < delta || (q1 == delta && r1 == 0));
2080
2081 result_magic = q2 + 1; // resulting magic number
2082 if (denom < 0)
2083 {
2084 result_magic = -result_magic;
2085 }
2086 *shift = p - bits; // resulting shift
2087
2088 return result_magic;
2089}
2090
2091int32_t GetSigned32Magic(int32_t d, int* shift /*out*/)
2092{
2093 return GetSignedMagic<int32_t>(d, shift);
2094}
2095
2096#ifdef _TARGET_64BIT_
2097int64_t GetSigned64Magic(int64_t d, int* shift /*out*/)
2098{
2099 return GetSignedMagic<int64_t>(d, shift);
2100}
2101#endif
2102}
2103