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.h XX
9XX XX
10XX Has miscellaneous utility functions XX
11XX XX
12XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
13XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
14*/
15
16#ifndef _UTILS_H_
17#define _UTILS_H_
18
19#include "iallocator.h"
20#include "hostallocator.h"
21#include "cycletimer.h"
22
23// Needed for unreached()
24#include "error.h"
25
26#ifdef _TARGET_64BIT_
27#define BitScanForwardPtr BitScanForward64
28#else
29#define BitScanForwardPtr BitScanForward
30#endif
31
32template <typename T, int size>
33unsigned ArrLen(T (&)[size])
34{
35 return size;
36}
37
38// return true if arg is a power of 2
39template <typename T>
40inline bool isPow2(T i)
41{
42 return (i > 0 && ((i - 1) & i) == 0);
43}
44
45// Adapter for iterators to a type that is compatible with C++11
46// range-based for loops.
47template <typename TIterator>
48class IteratorPair
49{
50 TIterator m_begin;
51 TIterator m_end;
52
53public:
54 IteratorPair(TIterator begin, TIterator end) : m_begin(begin), m_end(end)
55 {
56 }
57
58 inline TIterator begin()
59 {
60 return m_begin;
61 }
62
63 inline TIterator end()
64 {
65 return m_end;
66 }
67};
68
69template <typename TIterator>
70inline IteratorPair<TIterator> MakeIteratorPair(TIterator begin, TIterator end)
71{
72 return IteratorPair<TIterator>(begin, end);
73}
74
75// Recursive template definition to calculate the base-2 logarithm
76// of a constant value.
77template <unsigned val, unsigned acc = 0>
78struct ConstLog2
79{
80 enum
81 {
82 value = ConstLog2<val / 2, acc + 1>::value
83 };
84};
85
86template <unsigned acc>
87struct ConstLog2<0, acc>
88{
89 enum
90 {
91 value = acc
92 };
93};
94
95template <unsigned acc>
96struct ConstLog2<1, acc>
97{
98 enum
99 {
100 value = acc
101 };
102};
103
104inline const char* dspBool(bool b)
105{
106 return (b) ? "true" : "false";
107}
108
109#ifdef FEATURE_CORECLR
110#ifdef _CRT_ABS_DEFINED
111// we don't have the full standard library
112inline int64_t abs(int64_t t)
113{
114 return t > 0 ? t : -t;
115}
116#endif
117#endif // FEATURE_CORECLR
118
119template <typename T>
120int signum(T val)
121{
122 if (val < T(0))
123 {
124 return -1;
125 }
126 else if (val > T(0))
127 {
128 return 1;
129 }
130 else
131 {
132 return 0;
133 }
134}
135
136#if defined(DEBUG) || defined(INLINE_DATA)
137
138// ConfigMethodRange describes a set of methods, specified via their
139// hash codes. This can be used for binary search and/or specifying an
140// explicit method set.
141//
142// Note method hash codes are not necessarily unique. For instance
143// many IL stubs may have the same hash.
144//
145// If range string is null or just whitespace, range includes all
146// methods.
147//
148// Parses values as decimal numbers.
149//
150// Examples:
151//
152// [string with just spaces] : all methods
153// 12345678 : a single method
154// 12345678-23456789 : a range of methods
155// 99998888 12345678-23456789 : a range of methods plus a single method
156
157class ConfigMethodRange
158{
159
160public:
161 // Default capacity
162 enum
163 {
164 DEFAULT_CAPACITY = 50
165 };
166
167 // Does the range include this method's hash?
168 bool Contains(class ICorJitInfo* info, CORINFO_METHOD_HANDLE method);
169
170 // Ensure the range string has been parsed.
171 void EnsureInit(const wchar_t* rangeStr, unsigned capacity = DEFAULT_CAPACITY)
172 {
173 // Make sure that the memory was zero initialized
174 assert(m_inited == 0 || m_inited == 1);
175
176 if (!m_inited)
177 {
178 InitRanges(rangeStr, capacity);
179 assert(m_inited == 1);
180 }
181 }
182
183 // Error checks
184 bool Error() const
185 {
186 return m_badChar != 0;
187 }
188 size_t BadCharIndex() const
189 {
190 return m_badChar - 1;
191 }
192
193private:
194 struct Range
195 {
196 unsigned m_low;
197 unsigned m_high;
198 };
199
200 void InitRanges(const wchar_t* rangeStr, unsigned capacity);
201
202 unsigned m_entries; // number of entries in the range array
203 unsigned m_lastRange; // count of low-high pairs
204 unsigned m_inited; // 1 if range string has been parsed
205 size_t m_badChar; // index + 1 of any bad character in range string
206 Range* m_ranges; // ranges of functions to include
207};
208
209#endif // defined(DEBUG) || defined(INLINE_DATA)
210
211class Compiler;
212
213/*****************************************************************************
214 * Fixed bit vector class
215 */
216class FixedBitVect
217{
218private:
219 UINT bitVectSize;
220 UINT bitVect[];
221
222 // bitChunkSize() - Returns number of bits in a bitVect chunk
223 static UINT bitChunkSize();
224
225 // bitNumToBit() - Returns a bit mask of the given bit number
226 static UINT bitNumToBit(UINT bitNum);
227
228public:
229 // bitVectInit() - Initializes a bit vector of a given size
230 static FixedBitVect* bitVectInit(UINT size, Compiler* comp);
231
232 // bitVectSet() - Sets the given bit
233 void bitVectSet(UINT bitNum);
234
235 // bitVectTest() - Tests the given bit
236 bool bitVectTest(UINT bitNum);
237
238 // bitVectOr() - Or in the given bit vector
239 void bitVectOr(FixedBitVect* bv);
240
241 // bitVectAnd() - And with passed in bit vector
242 void bitVectAnd(FixedBitVect& bv);
243
244 // bitVectGetFirst() - Find the first bit on and return the bit num.
245 // Return -1 if no bits found.
246 UINT bitVectGetFirst();
247
248 // bitVectGetNext() - Find the next bit on given previous bit and return bit num.
249 // Return -1 if no bits found.
250 UINT bitVectGetNext(UINT bitNumPrev);
251
252 // bitVectGetNextAndClear() - Find the first bit on, clear it and return it.
253 // Return -1 if no bits found.
254 UINT bitVectGetNextAndClear();
255};
256
257/******************************************************************************
258 * A specialized version of sprintf_s to simplify conversion to SecureCRT
259 *
260 * pWriteStart -> A pointer to the first byte to which data is written.
261 * pBufStart -> the start of the buffer into which the data is written. If
262 * composing a complex string with multiple calls to sprintf, this
263 * should not change.
264 * cbBufSize -> The size of the overall buffer (i.e. the size of the buffer
265 * pointed to by pBufStart). For subsequent calls, this does not
266 * change.
267 * fmt -> The format string
268 * ... -> Arguments.
269 *
270 * returns -> number of bytes successfully written, not including the null
271 * terminator. Calls NO_WAY on error.
272 */
273int SimpleSprintf_s(__in_ecount(cbBufSize - (pWriteStart - pBufStart)) char* pWriteStart,
274 __in_ecount(cbBufSize) char* pBufStart,
275 size_t cbBufSize,
276 __in_z const char* fmt,
277 ...);
278
279#ifdef DEBUG
280void hexDump(FILE* dmpf, const char* name, BYTE* addr, size_t size);
281#endif // DEBUG
282
283/******************************************************************************
284 * ScopedSetVariable: A simple class to set and restore a variable within a scope.
285 * For example, it can be used to set a 'bool' flag to 'true' at the beginning of a
286 * function and automatically back to 'false' either at the end the function, or at
287 * any other return location. The variable should not be changed during the scope:
288 * the destructor asserts that the value at destruction time is the same one we set.
289 * Usage: ScopedSetVariable<bool> _unused_name(&variable, true);
290 */
291template <typename T>
292class ScopedSetVariable
293{
294public:
295 ScopedSetVariable(T* pVariable, T value) : m_pVariable(pVariable)
296 {
297 m_oldValue = *m_pVariable;
298 *m_pVariable = value;
299 INDEBUG(m_value = value;)
300 }
301
302 ~ScopedSetVariable()
303 {
304 assert(*m_pVariable == m_value); // Assert that the value didn't change between ctor and dtor
305 *m_pVariable = m_oldValue;
306 }
307
308private:
309#ifdef DEBUG
310 T m_value; // The value we set the variable to (used for assert).
311#endif // DEBUG
312 T m_oldValue; // The old value, to restore the variable to.
313 T* m_pVariable; // Address of the variable to change
314};
315
316/******************************************************************************
317 * PhasedVar: A class to represent a variable that has phases, in particular,
318 * a write phase where the variable is computed, and a read phase where the
319 * variable is used. Once the variable has been read, it can no longer be changed.
320 * Reading the variable essentially commits everyone to using that value forever,
321 * and it is assumed that subsequent changes to the variable would invalidate
322 * whatever assumptions were made by the previous readers, leading to bad generated code.
323 * These assumptions are asserted in DEBUG builds.
324 * The phase ordering is clean for AMD64, but not for x86/ARM. So don't do the phase
325 * ordering asserts for those platforms.
326 */
327template <typename T>
328class PhasedVar
329{
330public:
331 PhasedVar()
332#ifdef DEBUG
333 : m_initialized(false), m_writePhase(true)
334#endif // DEBUG
335 {
336 }
337
338 PhasedVar(T value)
339 : m_value(value)
340#ifdef DEBUG
341 , m_initialized(true)
342 , m_writePhase(true)
343#endif // DEBUG
344 {
345 }
346
347 ~PhasedVar()
348 {
349#ifdef DEBUG
350 m_initialized = false;
351 m_writePhase = true;
352#endif // DEBUG
353 }
354
355 // Read the value. Change to the read phase.
356 // Marked 'const' because we don't change the encapsulated value, even though
357 // we do change the write phase, which is only for debugging asserts.
358
359 operator T() const
360 {
361#ifdef DEBUG
362 assert(m_initialized);
363 (const_cast<PhasedVar*>(this))->m_writePhase = false;
364#endif // DEBUG
365 return m_value;
366 }
367
368 // Mark the value as read only; explicitly change the variable to the "read" phase.
369 void MarkAsReadOnly() const
370 {
371#ifdef DEBUG
372 assert(m_initialized);
373 (const_cast<PhasedVar*>(this))->m_writePhase = false;
374#endif // DEBUG
375 }
376
377 // When dumping stuff we could try to read a PhasedVariable
378 // This method tells us whether we should read the PhasedVariable
379 bool HasFinalValue() const
380 {
381#ifdef DEBUG
382 return (const_cast<PhasedVar*>(this))->m_writePhase == false;
383#else
384 return true;
385#endif // DEBUG
386 }
387
388 // Functions/operators to write the value. Must be in the write phase.
389
390 PhasedVar& operator=(const T& value)
391 {
392#ifdef DEBUG
393 assert(m_writePhase);
394 m_initialized = true;
395#endif // DEBUG
396 m_value = value;
397 return *this;
398 }
399
400 PhasedVar& operator&=(const T& value)
401 {
402#ifdef DEBUG
403 assert(m_writePhase);
404 m_initialized = true;
405#endif // DEBUG
406 m_value &= value;
407 return *this;
408 }
409
410 // Note: if you need more <op>= functions, you can define them here, like operator&=
411
412 // Assign a value, but don't assert if we're not in the write phase, and
413 // don't change the phase (if we're actually in the read phase, we'll stay
414 // in the read phase). This is a dangerous function, and overrides the main
415 // benefit of this class. Use it wisely!
416 void OverrideAssign(const T& value)
417 {
418#ifdef DEBUG
419 m_initialized = true;
420#endif // DEBUG
421 m_value = value;
422 }
423
424 // We've decided that this variable can go back to write phase, even if it has been
425 // written. This can be used, for example, for variables set and read during frame
426 // layout calculation, as long as it is before final layout, such that anything
427 // being calculated is just an estimate anyway. Obviously, it must be used carefully,
428 // since it overrides the main benefit of this class.
429 void ResetWritePhase()
430 {
431#ifdef DEBUG
432 m_writePhase = true;
433#endif // DEBUG
434 }
435
436private:
437 // Don't allow a copy constructor. (This could be allowed, but only add it once it is actually needed.)
438
439 PhasedVar(const PhasedVar& o)
440 {
441 unreached();
442 }
443
444 T m_value;
445#ifdef DEBUG
446 bool m_initialized; // true once the variable has been initialized, that is, written once.
447 bool m_writePhase; // true if we are in the (initial) "write" phase. Once the value is read, this changes to false,
448 // and can't be changed back.
449#endif // DEBUG
450};
451
452class HelperCallProperties
453{
454private:
455 bool m_isPure[CORINFO_HELP_COUNT];
456 bool m_noThrow[CORINFO_HELP_COUNT];
457 bool m_nonNullReturn[CORINFO_HELP_COUNT];
458 bool m_isAllocator[CORINFO_HELP_COUNT];
459 bool m_mutatesHeap[CORINFO_HELP_COUNT];
460 bool m_mayRunCctor[CORINFO_HELP_COUNT];
461
462 void init();
463
464public:
465 HelperCallProperties()
466 {
467 init();
468 }
469
470 bool IsPure(CorInfoHelpFunc helperId)
471 {
472 assert(helperId > CORINFO_HELP_UNDEF);
473 assert(helperId < CORINFO_HELP_COUNT);
474 return m_isPure[helperId];
475 }
476
477 bool NoThrow(CorInfoHelpFunc helperId)
478 {
479 assert(helperId > CORINFO_HELP_UNDEF);
480 assert(helperId < CORINFO_HELP_COUNT);
481 return m_noThrow[helperId];
482 }
483
484 bool NonNullReturn(CorInfoHelpFunc helperId)
485 {
486 assert(helperId > CORINFO_HELP_UNDEF);
487 assert(helperId < CORINFO_HELP_COUNT);
488 return m_nonNullReturn[helperId];
489 }
490
491 bool IsAllocator(CorInfoHelpFunc helperId)
492 {
493 assert(helperId > CORINFO_HELP_UNDEF);
494 assert(helperId < CORINFO_HELP_COUNT);
495 return m_isAllocator[helperId];
496 }
497
498 bool MutatesHeap(CorInfoHelpFunc helperId)
499 {
500 assert(helperId > CORINFO_HELP_UNDEF);
501 assert(helperId < CORINFO_HELP_COUNT);
502 return m_mutatesHeap[helperId];
503 }
504
505 bool MayRunCctor(CorInfoHelpFunc helperId)
506 {
507 assert(helperId > CORINFO_HELP_UNDEF);
508 assert(helperId < CORINFO_HELP_COUNT);
509 return m_mayRunCctor[helperId];
510 }
511};
512
513//*****************************************************************************
514// AssemblyNamesList2: Parses and stores a list of Assembly names, and provides
515// a function for determining whether a given assembly name is part of the list.
516//
517// This is a clone of the AssemblyNamesList class that exists in the VM's utilcode,
518// modified to use the JIT's memory allocator and throw on out of memory behavior.
519// It is named AssemblyNamesList2 to avoid a name conflict with the VM version.
520// It might be preferable to adapt the VM's code to be more flexible (for example,
521// by using an IAllocator), but the string handling code there is heavily macroized,
522// and for the small usage we have of this class, investing in genericizing the VM
523// implementation didn't seem worth it.
524//*****************************************************************************
525
526class AssemblyNamesList2
527{
528 struct AssemblyName
529 {
530 char* m_assemblyName;
531 AssemblyName* m_next;
532 };
533
534 AssemblyName* m_pNames; // List of names
535 HostAllocator m_alloc; // HostAllocator to use in this class
536
537public:
538 // Take a Unicode string list of assembly names, parse it, and store it.
539 AssemblyNamesList2(const wchar_t* list, HostAllocator alloc);
540
541 ~AssemblyNamesList2();
542
543 // Return 'true' if 'assemblyName' (in UTF-8 format) is in the stored list of assembly names.
544 bool IsInList(const char* assemblyName);
545
546 // Return 'true' if the assembly name list is empty.
547 bool IsEmpty()
548 {
549 return m_pNames == nullptr;
550 }
551};
552
553#ifdef FEATURE_JIT_METHOD_PERF
554// When Start() is called time is noted and when ElapsedTime
555// is called we know how much time was spent in msecs.
556//
557class CycleCount
558{
559private:
560 double cps; // cycles per second
561 unsigned __int64 beginCycles; // cycles at stop watch construction
562public:
563 CycleCount();
564
565 // Kick off the counter, and if re-entrant will use the latest cycles as starting point.
566 // If the method returns false, any other query yield unpredictable results.
567 bool Start();
568
569 // Return time elapsed in msecs, if Start returned true.
570 double ElapsedTime();
571
572private:
573 // Return true if successful.
574 bool GetCycles(unsigned __int64* time);
575};
576
577// Uses win API QueryPerformanceCounter/QueryPerformanceFrequency.
578class PerfCounter
579{
580 LARGE_INTEGER beg;
581 double freq;
582
583public:
584 // If the method returns false, any other query yield unpredictable results.
585 bool Start();
586
587 // Return time elapsed from start in millis, if Start returned true.
588 double ElapsedTime();
589};
590
591#endif // FEATURE_JIT_METHOD_PERF
592
593#ifdef DEBUG
594
595/*****************************************************************************
596 * Return the number of digits in a number of the given base (default base 10).
597 * Used when outputting strings.
598 */
599unsigned CountDigits(unsigned num, unsigned base = 10);
600
601#endif // DEBUG
602
603/*****************************************************************************
604* Floating point utility class
605*/
606class FloatingPointUtils
607{
608public:
609 static double convertUInt64ToDouble(unsigned __int64 u64);
610
611 static float convertUInt64ToFloat(unsigned __int64 u64);
612
613 static unsigned __int64 convertDoubleToUInt64(double d);
614
615 static double round(double x);
616
617 static float round(float x);
618};
619
620// The CLR requires that critical section locks be initialized via its ClrCreateCriticalSection API...but
621// that can't be called until the CLR is initialized. If we have static data that we'd like to protect by a
622// lock, and we have a statically allocated lock to protect that data, there's an issue in how to initialize
623// that lock. We could insert an initialize call in the startup path, but one might prefer to keep the code
624// more local. For such situations, CritSecObject solves the initialization problem, via a level of
625// indirection. A pointer to the lock is initially null, and when we query for the lock pointer via "Val()".
626// If the lock has not yet been allocated, this allocates one (here a leaf lock), and uses a
627// CompareAndExchange-based lazy-initialization to update the field. If this fails, the allocated lock is
628// destroyed. This will work as long as the first locking attempt occurs after enough CLR initialization has
629// happened to make ClrCreateCriticalSection calls legal.
630
631class CritSecObject
632{
633public:
634 CritSecObject()
635 {
636 m_pCs = nullptr;
637 }
638
639 CRITSEC_COOKIE Val()
640 {
641 if (m_pCs == nullptr)
642 {
643 // CompareExchange-based lazy init.
644 CRITSEC_COOKIE newCs = ClrCreateCriticalSection(CrstLeafLock, CRST_DEFAULT);
645 CRITSEC_COOKIE observed = InterlockedCompareExchangeT(&m_pCs, newCs, NULL);
646 if (observed != nullptr)
647 {
648 ClrDeleteCriticalSection(newCs);
649 }
650 }
651 return m_pCs;
652 }
653
654private:
655 // CRITSEC_COOKIE is an opaque pointer type.
656 CRITSEC_COOKIE m_pCs;
657
658 // No copying or assignment allowed.
659 CritSecObject(const CritSecObject&) = delete;
660 CritSecObject& operator=(const CritSecObject&) = delete;
661};
662
663// Stack-based holder for a critial section lock.
664// Ensures lock is released.
665
666class CritSecHolder
667{
668public:
669 CritSecHolder(CritSecObject& critSec) : m_CritSec(critSec)
670 {
671 ClrEnterCriticalSection(m_CritSec.Val());
672 }
673
674 ~CritSecHolder()
675 {
676 ClrLeaveCriticalSection(m_CritSec.Val());
677 }
678
679private:
680 CritSecObject& m_CritSec;
681
682 // No copying or assignment allowed.
683 CritSecHolder(const CritSecHolder&) = delete;
684 CritSecHolder& operator=(const CritSecHolder&) = delete;
685};
686
687namespace MagicDivide
688{
689uint32_t GetUnsigned32Magic(uint32_t d, bool* add /*out*/, int* shift /*out*/);
690#ifdef _TARGET_64BIT_
691uint64_t GetUnsigned64Magic(uint64_t d, bool* add /*out*/, int* shift /*out*/);
692#endif
693int32_t GetSigned32Magic(int32_t d, int* shift /*out*/);
694#ifdef _TARGET_64BIT_
695int64_t GetSigned64Magic(int64_t d, int* shift /*out*/);
696#endif
697}
698
699#endif // _UTILS_H_
700