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.
5 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10 XX Has miscellaneous utility functions XX
12 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
13 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
19 #include "iallocator.h"
20 #include "hostallocator.h"
21 #include "cycletimer.h"
23 // Needed for unreached()
27 #define BitScanForwardPtr BitScanForward64
29 #define BitScanForwardPtr BitScanForward
32 template <typename T, int size>
33 unsigned ArrLen(T (&)[size])
38 // return true if arg is a power of 2
40 inline bool isPow2(T i)
42 return (i > 0 && ((i - 1) & i) == 0);
45 // Adapter for iterators to a type that is compatible with C++11
46 // range-based for loops.
47 template <typename TIterator>
54 IteratorPair(TIterator begin, TIterator end) : m_begin(begin), m_end(end)
58 inline TIterator begin()
63 inline TIterator end()
69 template <typename TIterator>
70 inline IteratorPair<TIterator> MakeIteratorPair(TIterator begin, TIterator end)
72 return IteratorPair<TIterator>(begin, end);
75 // Recursive template definition to calculate the base-2 logarithm
76 // of a constant value.
77 template <unsigned val, unsigned acc = 0>
82 value = ConstLog2<val / 2, acc + 1>::value
86 template <unsigned acc>
87 struct ConstLog2<0, acc>
95 template <unsigned acc>
96 struct ConstLog2<1, acc>
104 inline const char* dspBool(bool b)
106 return (b) ? "true" : "false";
109 #ifdef FEATURE_CORECLR
110 #ifdef _CRT_ABS_DEFINED
111 // we don't have the full standard library
112 inline int64_t abs(int64_t t)
114 return t > 0 ? t : -t;
117 #endif // FEATURE_CORECLR
119 template <typename T>
136 #if defined(DEBUG) || defined(INLINE_DATA)
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.
142 // Note method hash codes are not necessarily unique. For instance
143 // many IL stubs may have the same hash.
145 // If range string is null or just whitespace, range includes all
148 // Parses values as decimal numbers.
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
157 class ConfigMethodRange
164 DEFAULT_CAPACITY = 50
167 // Does the range include this method's hash?
168 bool Contains(class ICorJitInfo* info, CORINFO_METHOD_HANDLE method);
170 // Ensure the range string has been parsed.
171 void EnsureInit(const wchar_t* rangeStr, unsigned capacity = DEFAULT_CAPACITY)
173 // Make sure that the memory was zero initialized
174 assert(m_inited == 0 || m_inited == 1);
178 InitRanges(rangeStr, capacity);
179 assert(m_inited == 1);
186 return m_badChar != 0;
188 size_t BadCharIndex() const
190 return m_badChar - 1;
200 void InitRanges(const wchar_t* rangeStr, unsigned capacity);
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
209 #endif // defined(DEBUG) || defined(INLINE_DATA)
213 /*****************************************************************************
214 * Fixed bit vector class
222 // bitChunkSize() - Returns number of bits in a bitVect chunk
223 static UINT bitChunkSize();
225 // bitNumToBit() - Returns a bit mask of the given bit number
226 static UINT bitNumToBit(UINT bitNum);
229 // bitVectInit() - Initializes a bit vector of a given size
230 static FixedBitVect* bitVectInit(UINT size, Compiler* comp);
232 // bitVectSet() - Sets the given bit
233 void bitVectSet(UINT bitNum);
235 // bitVectTest() - Tests the given bit
236 bool bitVectTest(UINT bitNum);
238 // bitVectOr() - Or in the given bit vector
239 void bitVectOr(FixedBitVect* bv);
241 // bitVectAnd() - And with passed in bit vector
242 void bitVectAnd(FixedBitVect& bv);
244 // bitVectGetFirst() - Find the first bit on and return the bit num.
245 // Return -1 if no bits found.
246 UINT bitVectGetFirst();
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);
252 // bitVectGetNextAndClear() - Find the first bit on, clear it and return it.
253 // Return -1 if no bits found.
254 UINT bitVectGetNextAndClear();
257 /******************************************************************************
258 * A specialized version of sprintf_s to simplify conversion to SecureCRT
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
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
267 * fmt -> The format string
270 * returns -> number of bytes successfully written, not including the null
271 * terminator. Calls NO_WAY on error.
273 int SimpleSprintf_s(__in_ecount(cbBufSize - (pWriteStart - pBufStart)) char* pWriteStart,
274 __in_ecount(cbBufSize) char* pBufStart,
276 __in_z const char* fmt,
280 void hexDump(FILE* dmpf, const char* name, BYTE* addr, size_t size);
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);
291 template <typename T>
292 class ScopedSetVariable
295 ScopedSetVariable(T* pVariable, T value) : m_pVariable(pVariable)
297 m_oldValue = *m_pVariable;
298 *m_pVariable = value;
299 INDEBUG(m_value = value;)
304 assert(*m_pVariable == m_value); // Assert that the value didn't change between ctor and dtor
305 *m_pVariable = m_oldValue;
310 T m_value; // The value we set the variable to (used for assert).
312 T m_oldValue; // The old value, to restore the variable to.
313 T* m_pVariable; // Address of the variable to change
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.
327 template <typename T>
333 : m_initialized(false), m_writePhase(true)
341 , m_initialized(true)
350 m_initialized = false;
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.
362 assert(m_initialized);
363 (const_cast<PhasedVar*>(this))->m_writePhase = false;
368 // Mark the value as read only; explicitly change the variable to the "read" phase.
369 void MarkAsReadOnly() const
372 assert(m_initialized);
373 (const_cast<PhasedVar*>(this))->m_writePhase = false;
377 // Functions/operators to write the value. Must be in the write phase.
379 PhasedVar& operator=(const T& value)
382 #ifndef LEGACY_BACKEND
383 assert(m_writePhase);
384 #endif // !LEGACY_BACKEND
385 m_initialized = true;
391 PhasedVar& operator&=(const T& value)
394 #ifndef LEGACY_BACKEND
395 assert(m_writePhase);
396 #endif // !LEGACY_BACKEND
397 m_initialized = true;
403 // Note: if you need more <op>= functions, you can define them here, like operator&=
405 // Assign a value, but don't assert if we're not in the write phase, and
406 // don't change the phase (if we're actually in the read phase, we'll stay
407 // in the read phase). This is a dangerous function, and overrides the main
408 // benefit of this class. Use it wisely!
409 void OverrideAssign(const T& value)
412 m_initialized = true;
417 // We've decided that this variable can go back to write phase, even if it has been
418 // written. This can be used, for example, for variables set and read during frame
419 // layout calculation, as long as it is before final layout, such that anything
420 // being calculated is just an estimate anyway. Obviously, it must be used carefully,
421 // since it overrides the main benefit of this class.
422 void ResetWritePhase()
430 // Don't allow a copy constructor. (This could be allowed, but only add it once it is actually needed.)
432 PhasedVar(const PhasedVar& o)
439 bool m_initialized; // true once the variable has been initialized, that is, written once.
440 bool m_writePhase; // true if we are in the (initial) "write" phase. Once the value is read, this changes to false,
441 // and can't be changed back.
445 class HelperCallProperties
448 bool m_isPure[CORINFO_HELP_COUNT];
449 bool m_noThrow[CORINFO_HELP_COUNT];
450 bool m_nonNullReturn[CORINFO_HELP_COUNT];
451 bool m_isAllocator[CORINFO_HELP_COUNT];
452 bool m_mutatesHeap[CORINFO_HELP_COUNT];
453 bool m_mayRunCctor[CORINFO_HELP_COUNT];
454 bool m_mayFinalize[CORINFO_HELP_COUNT];
459 HelperCallProperties()
464 bool IsPure(CorInfoHelpFunc helperId)
466 assert(helperId > CORINFO_HELP_UNDEF);
467 assert(helperId < CORINFO_HELP_COUNT);
468 return m_isPure[helperId];
471 bool NoThrow(CorInfoHelpFunc helperId)
473 assert(helperId > CORINFO_HELP_UNDEF);
474 assert(helperId < CORINFO_HELP_COUNT);
475 return m_noThrow[helperId];
478 bool NonNullReturn(CorInfoHelpFunc helperId)
480 assert(helperId > CORINFO_HELP_UNDEF);
481 assert(helperId < CORINFO_HELP_COUNT);
482 return m_nonNullReturn[helperId];
485 bool IsAllocator(CorInfoHelpFunc helperId)
487 assert(helperId > CORINFO_HELP_UNDEF);
488 assert(helperId < CORINFO_HELP_COUNT);
489 return m_isAllocator[helperId];
492 bool MutatesHeap(CorInfoHelpFunc helperId)
494 assert(helperId > CORINFO_HELP_UNDEF);
495 assert(helperId < CORINFO_HELP_COUNT);
496 return m_mutatesHeap[helperId];
499 bool MayRunCctor(CorInfoHelpFunc helperId)
501 assert(helperId > CORINFO_HELP_UNDEF);
502 assert(helperId < CORINFO_HELP_COUNT);
503 return m_mayRunCctor[helperId];
506 bool MayFinalize(CorInfoHelpFunc helperId)
508 assert(helperId > CORINFO_HELP_UNDEF);
509 assert(helperId < CORINFO_HELP_COUNT);
510 return m_mayFinalize[helperId];
514 //*****************************************************************************
515 // AssemblyNamesList2: Parses and stores a list of Assembly names, and provides
516 // a function for determining whether a given assembly name is part of the list.
518 // This is a clone of the AssemblyNamesList class that exists in the VM's utilcode,
519 // modified to use the JIT's memory allocator and throw on out of memory behavior.
520 // It is named AssemblyNamesList2 to avoid a name conflict with the VM version.
521 // It might be preferable to adapt the VM's code to be more flexible (for example,
522 // by using an IAllocator), but the string handling code there is heavily macroized,
523 // and for the small usage we have of this class, investing in genericizing the VM
524 // implementation didn't seem worth it.
525 //*****************************************************************************
527 class AssemblyNamesList2
531 char* m_assemblyName;
532 AssemblyName* m_next;
535 AssemblyName* m_pNames; // List of names
536 HostAllocator* m_alloc; // HostAllocator to use in this class
539 // Take a Unicode string list of assembly names, parse it, and store it.
540 AssemblyNamesList2(const wchar_t* list, __in HostAllocator* alloc);
542 ~AssemblyNamesList2();
544 // Return 'true' if 'assemblyName' (in UTF-8 format) is in the stored list of assembly names.
545 bool IsInList(const char* assemblyName);
547 // Return 'true' if the assembly name list is empty.
550 return m_pNames == nullptr;
554 #ifdef FEATURE_JIT_METHOD_PERF
555 // When Start() is called time is noted and when ElapsedTime
556 // is called we know how much time was spent in msecs.
561 double cps; // cycles per second
562 unsigned __int64 beginCycles; // cycles at stop watch construction
566 // Kick off the counter, and if re-entrant will use the latest cycles as starting point.
567 // If the method returns false, any other query yield unpredictable results.
570 // Return time elapsed in msecs, if Start returned true.
571 double ElapsedTime();
574 // Return true if successful.
575 bool GetCycles(unsigned __int64* time);
578 // Uses win API QueryPerformanceCounter/QueryPerformanceFrequency.
585 // If the method returns false, any other query yield unpredictable results.
588 // Return time elapsed from start in millis, if Start returned true.
589 double ElapsedTime();
592 #endif // FEATURE_JIT_METHOD_PERF
596 /*****************************************************************************
597 * Return the number of digits in a number of the given base (default base 10).
598 * Used when outputting strings.
600 unsigned CountDigits(unsigned num, unsigned base = 10);
604 /*****************************************************************************
605 * Floating point utility class
607 class FloatingPointUtils
610 static double convertUInt64ToDouble(unsigned __int64 u64);
612 static float convertUInt64ToFloat(unsigned __int64 u64);
614 static unsigned __int64 convertDoubleToUInt64(double d);
616 static double round(double x);
618 static float round(float x);
621 // The CLR requires that critical section locks be initialized via its ClrCreateCriticalSection API...but
622 // that can't be called until the CLR is initialized. If we have static data that we'd like to protect by a
623 // lock, and we have a statically allocated lock to protect that data, there's an issue in how to initialize
624 // that lock. We could insert an initialize call in the startup path, but one might prefer to keep the code
625 // more local. For such situations, CritSecObject solves the initialization problem, via a level of
626 // indirection. A pointer to the lock is initially null, and when we query for the lock pointer via "Val()".
627 // If the lock has not yet been allocated, this allocates one (here a leaf lock), and uses a
628 // CompareAndExchange-based lazy-initialization to update the field. If this fails, the allocated lock is
629 // destroyed. This will work as long as the first locking attempt occurs after enough CLR initialization has
630 // happened to make ClrCreateCriticalSection calls legal.
642 if (m_pCs == nullptr)
644 // CompareExchange-based lazy init.
645 CRITSEC_COOKIE newCs = ClrCreateCriticalSection(CrstLeafLock, CRST_DEFAULT);
646 CRITSEC_COOKIE observed = InterlockedCompareExchangeT(&m_pCs, newCs, NULL);
647 if (observed != nullptr)
649 ClrDeleteCriticalSection(newCs);
656 // CRITSEC_COOKIE is an opaque pointer type.
657 CRITSEC_COOKIE m_pCs;
659 // No copying or assignment allowed.
660 CritSecObject(const CritSecObject&) = delete;
661 CritSecObject& operator=(const CritSecObject&) = delete;
664 // Stack-based holder for a critial section lock.
665 // Ensures lock is released.
670 CritSecHolder(CritSecObject& critSec) : m_CritSec(critSec)
672 ClrEnterCriticalSection(m_CritSec.Val());
677 ClrLeaveCriticalSection(m_CritSec.Val());
681 CritSecObject& m_CritSec;
683 // No copying or assignment allowed.
684 CritSecHolder(const CritSecHolder&) = delete;
685 CritSecHolder& operator=(const CritSecHolder&) = delete;
688 namespace MagicDivide
690 uint32_t GetUnsigned32Magic(uint32_t d, bool* add /*out*/, int* shift /*out*/);
691 #ifdef _TARGET_64BIT_
692 uint64_t GetUnsigned64Magic(uint64_t d, bool* add /*out*/, int* shift /*out*/);
694 int32_t GetSigned32Magic(int32_t d, int* shift /*out*/);
695 #ifdef _TARGET_64BIT_
696 int64_t GetSigned64Magic(int64_t d, int* shift /*out*/);