1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
4 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9 XX Has miscellaneous utility functions XX
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
18 #include "iallocator.h"
19 #include "hostallocator.h"
20 #include "cycletimer.h"
22 // Needed for unreached()
26 #define BitScanForwardPtr BitScanForward64
28 #define BitScanForwardPtr BitScanForward
31 template <typename T, int size>
32 unsigned ArrLen(T (&)[size])
37 // return true if arg is a power of 2
39 inline bool isPow2(T i)
41 return (i > 0 && ((i - 1) & i) == 0);
44 // Adapter for iterators to a type that is compatible with C++11
45 // range-based for loops.
46 template <typename TIterator>
53 IteratorPair(TIterator begin, TIterator end) : m_begin(begin), m_end(end)
57 inline TIterator begin()
62 inline TIterator end()
68 template <typename TIterator>
69 inline IteratorPair<TIterator> MakeIteratorPair(TIterator begin, TIterator end)
71 return IteratorPair<TIterator>(begin, end);
74 // Recursive template definition to calculate the base-2 logarithm
75 // of a constant value.
76 template <unsigned val, unsigned acc = 0>
81 value = ConstLog2<val / 2, acc + 1>::value
85 template <unsigned acc>
86 struct ConstLog2<0, acc>
94 template <unsigned acc>
95 struct ConstLog2<1, acc>
103 inline const char* dspBool(bool b)
105 return (b) ? "true" : "false";
108 template <typename T>
125 #if defined(DEBUG) || defined(INLINE_DATA)
127 // ConfigMethodRange describes a set of methods, specified via their
128 // hash codes. This can be used for binary search and/or specifying an
129 // explicit method set.
131 // Note method hash codes are not necessarily unique. For instance
132 // many IL stubs may have the same hash.
134 // If range string is null or just whitespace, range includes all
137 // Parses values as decimal numbers.
141 // [string with just spaces] : all methods
142 // 12345678 : a single method
143 // 12345678-23456789 : a range of methods
144 // 99998888 12345678-23456789 : a range of methods plus a single method
146 class ConfigMethodRange
153 DEFAULT_CAPACITY = 50
156 // Does the range include this hash?
157 bool Contains(unsigned hash);
159 // Ensure the range string has been parsed.
160 void EnsureInit(const WCHAR* rangeStr, unsigned capacity = DEFAULT_CAPACITY)
162 // Make sure that the memory was zero initialized
163 assert(m_inited == 0 || m_inited == 1);
167 InitRanges(rangeStr, capacity);
168 assert(m_inited == 1);
174 return m_lastRange == 0;
180 return m_badChar != 0;
183 size_t BadCharIndex() const
185 return m_badChar - 1;
197 void InitRanges(const WCHAR* rangeStr, unsigned capacity);
199 unsigned m_entries; // number of entries in the range array
200 unsigned m_lastRange; // count of low-high pairs
201 unsigned m_inited; // 1 if range string has been parsed
202 size_t m_badChar; // index + 1 of any bad character in range string
203 Range* m_ranges; // ranges of functions to include
206 #endif // defined(DEBUG) || defined(INLINE_DATA)
210 /*****************************************************************************
211 * Fixed bit vector class
219 // bitChunkSize() - Returns number of bits in a bitVect chunk
220 static UINT bitChunkSize();
222 // bitNumToBit() - Returns a bit mask of the given bit number
223 static UINT bitNumToBit(UINT bitNum);
226 // bitVectInit() - Initializes a bit vector of a given size
227 static FixedBitVect* bitVectInit(UINT size, Compiler* comp);
229 // bitVectSet() - Sets the given bit
230 void bitVectSet(UINT bitNum);
232 // bitVectTest() - Tests the given bit
233 bool bitVectTest(UINT bitNum);
235 // bitVectOr() - Or in the given bit vector
236 void bitVectOr(FixedBitVect* bv);
238 // bitVectAnd() - And with passed in bit vector
239 void bitVectAnd(FixedBitVect& bv);
241 // bitVectGetFirst() - Find the first bit on and return the bit num.
242 // Return -1 if no bits found.
243 UINT bitVectGetFirst();
245 // bitVectGetNext() - Find the next bit on given previous bit and return bit num.
246 // Return -1 if no bits found.
247 UINT bitVectGetNext(UINT bitNumPrev);
249 // bitVectGetNextAndClear() - Find the first bit on, clear it and return it.
250 // Return -1 if no bits found.
251 UINT bitVectGetNextAndClear();
254 /******************************************************************************
255 * A specialized version of sprintf_s to simplify conversion to SecureCRT
257 * pWriteStart -> A pointer to the first byte to which data is written.
258 * pBufStart -> the start of the buffer into which the data is written. If
259 * composing a complex string with multiple calls to sprintf, this
261 * cbBufSize -> The size of the overall buffer (i.e. the size of the buffer
262 * pointed to by pBufStart). For subsequent calls, this does not
264 * fmt -> The format string
267 * returns -> number of bytes successfully written, not including the null
268 * terminator. Calls NO_WAY on error.
270 int SimpleSprintf_s(__in_ecount(cbBufSize - (pWriteStart - pBufStart)) char* pWriteStart,
271 __in_ecount(cbBufSize) char* pBufStart,
273 __in_z const char* fmt,
277 void hexDump(FILE* dmpf, const char* name, BYTE* addr, size_t size);
280 /******************************************************************************
281 * ScopedSetVariable: A simple class to set and restore a variable within a scope.
282 * For example, it can be used to set a 'bool' flag to 'true' at the beginning of a
283 * function and automatically back to 'false' either at the end the function, or at
284 * any other return location. The variable should not be changed during the scope:
285 * the destructor asserts that the value at destruction time is the same one we set.
286 * Usage: ScopedSetVariable<bool> _unused_name(&variable, true);
288 template <typename T>
289 class ScopedSetVariable
292 ScopedSetVariable(T* pVariable, T value) : m_pVariable(pVariable)
294 m_oldValue = *m_pVariable;
295 *m_pVariable = value;
296 INDEBUG(m_value = value;)
301 assert(*m_pVariable == m_value); // Assert that the value didn't change between ctor and dtor
302 *m_pVariable = m_oldValue;
307 T m_value; // The value we set the variable to (used for assert).
309 T m_oldValue; // The old value, to restore the variable to.
310 T* m_pVariable; // Address of the variable to change
313 /******************************************************************************
314 * PhasedVar: A class to represent a variable that has phases, in particular,
315 * a write phase where the variable is computed, and a read phase where the
316 * variable is used. Once the variable has been read, it can no longer be changed.
317 * Reading the variable essentially commits everyone to using that value forever,
318 * and it is assumed that subsequent changes to the variable would invalidate
319 * whatever assumptions were made by the previous readers, leading to bad generated code.
320 * These assumptions are asserted in DEBUG builds.
321 * The phase ordering is clean for AMD64, but not for x86/ARM. So don't do the phase
322 * ordering asserts for those platforms.
324 template <typename T>
330 : m_initialized(false), m_writePhase(true)
338 , m_initialized(true)
347 m_initialized = false;
352 // Read the value. Change to the read phase.
353 // Marked 'const' because we don't change the encapsulated value, even though
354 // we do change the write phase, which is only for debugging asserts.
359 assert(m_initialized);
360 (const_cast<PhasedVar*>(this))->m_writePhase = false;
365 // Mark the value as read only; explicitly change the variable to the "read" phase.
366 void MarkAsReadOnly() const
369 assert(m_initialized);
370 (const_cast<PhasedVar*>(this))->m_writePhase = false;
374 // When dumping stuff we could try to read a PhasedVariable
375 // This method tells us whether we should read the PhasedVariable
376 bool HasFinalValue() const
379 return (const_cast<PhasedVar*>(this))->m_writePhase == false;
385 // Functions/operators to write the value. Must be in the write phase.
387 PhasedVar& operator=(const T& value)
390 assert(m_writePhase);
391 m_initialized = true;
397 PhasedVar& operator&=(const T& value)
400 assert(m_writePhase);
401 m_initialized = true;
407 // Note: if you need more <op>= functions, you can define them here, like operator&=
409 // Assign a value, but don't assert if we're not in the write phase, and
410 // don't change the phase (if we're actually in the read phase, we'll stay
411 // in the read phase). This is a dangerous function, and overrides the main
412 // benefit of this class. Use it wisely!
413 void OverrideAssign(const T& value)
416 m_initialized = true;
421 // We've decided that this variable can go back to write phase, even if it has been
422 // written. This can be used, for example, for variables set and read during frame
423 // layout calculation, as long as it is before final layout, such that anything
424 // being calculated is just an estimate anyway. Obviously, it must be used carefully,
425 // since it overrides the main benefit of this class.
426 void ResetWritePhase()
434 // Don't allow a copy constructor. (This could be allowed, but only add it once it is actually needed.)
436 PhasedVar(const PhasedVar& o)
443 bool m_initialized; // true once the variable has been initialized, that is, written once.
444 bool m_writePhase; // true if we are in the (initial) "write" phase. Once the value is read, this changes to false,
445 // and can't be changed back.
449 class HelperCallProperties
452 bool m_isPure[CORINFO_HELP_COUNT];
453 bool m_noThrow[CORINFO_HELP_COUNT];
454 bool m_alwaysThrow[CORINFO_HELP_COUNT];
455 bool m_nonNullReturn[CORINFO_HELP_COUNT];
456 bool m_isAllocator[CORINFO_HELP_COUNT];
457 bool m_mutatesHeap[CORINFO_HELP_COUNT];
458 bool m_mayRunCctor[CORINFO_HELP_COUNT];
463 HelperCallProperties()
468 bool IsPure(CorInfoHelpFunc helperId)
470 assert(helperId > CORINFO_HELP_UNDEF);
471 assert(helperId < CORINFO_HELP_COUNT);
472 return m_isPure[helperId];
475 bool NoThrow(CorInfoHelpFunc helperId)
477 assert(helperId > CORINFO_HELP_UNDEF);
478 assert(helperId < CORINFO_HELP_COUNT);
479 return m_noThrow[helperId];
482 bool AlwaysThrow(CorInfoHelpFunc helperId)
484 assert(helperId > CORINFO_HELP_UNDEF);
485 assert(helperId < CORINFO_HELP_COUNT);
486 return m_alwaysThrow[helperId];
489 bool NonNullReturn(CorInfoHelpFunc helperId)
491 assert(helperId > CORINFO_HELP_UNDEF);
492 assert(helperId < CORINFO_HELP_COUNT);
493 return m_nonNullReturn[helperId];
496 bool IsAllocator(CorInfoHelpFunc helperId)
498 assert(helperId > CORINFO_HELP_UNDEF);
499 assert(helperId < CORINFO_HELP_COUNT);
500 return m_isAllocator[helperId];
503 bool MutatesHeap(CorInfoHelpFunc helperId)
505 assert(helperId > CORINFO_HELP_UNDEF);
506 assert(helperId < CORINFO_HELP_COUNT);
507 return m_mutatesHeap[helperId];
510 bool MayRunCctor(CorInfoHelpFunc helperId)
512 assert(helperId > CORINFO_HELP_UNDEF);
513 assert(helperId < CORINFO_HELP_COUNT);
514 return m_mayRunCctor[helperId];
518 //*****************************************************************************
519 // AssemblyNamesList2: Parses and stores a list of Assembly names, and provides
520 // a function for determining whether a given assembly name is part of the list.
522 // This is a clone of the AssemblyNamesList class that exists in the VM's utilcode,
523 // modified to use the JIT's memory allocator and throw on out of memory behavior.
524 // It is named AssemblyNamesList2 to avoid a name conflict with the VM version.
525 // It might be preferable to adapt the VM's code to be more flexible (for example,
526 // by using an IAllocator), but the string handling code there is heavily macroized,
527 // and for the small usage we have of this class, investing in genericizing the VM
528 // implementation didn't seem worth it.
529 //*****************************************************************************
531 class AssemblyNamesList2
535 char* m_assemblyName;
536 AssemblyName* m_next;
539 AssemblyName* m_pNames; // List of names
540 HostAllocator m_alloc; // HostAllocator to use in this class
543 // Take a Unicode string list of assembly names, parse it, and store it.
544 AssemblyNamesList2(const WCHAR* list, HostAllocator alloc);
546 ~AssemblyNamesList2();
548 // Return 'true' if 'assemblyName' (in UTF-8 format) is in the stored list of assembly names.
549 bool IsInList(const char* assemblyName);
551 // Return 'true' if the assembly name list is empty.
554 return m_pNames == nullptr;
558 // MethodSet: Manage a list of methods that is read from a file.
560 // Methods are approximately in the format output by JitFunctionTrace, e.g.:
562 // System.CLRConfig:GetBoolValue(ref,byref):bool (MethodHash=3c54d35e)
563 // -- use the MethodHash, not the method name
565 // System.CLRConfig:GetBoolValue(ref,byref):bool
566 // -- use just the name
568 // Method names should not have any leading whitespace.
570 // TODO: Should this be more related to JitConfigValues::MethodSet?
574 // TODO: use a hash table? or two: one on hash value, one on function name
581 MethodInfo(char* methodName, int methodHash)
582 : m_MethodName(methodName), m_MethodHash(methodHash), m_next(nullptr)
587 MethodInfo* m_pInfos; // List of function info
588 HostAllocator m_alloc; // HostAllocator to use in this class
591 // Take a Unicode string with the filename containing a list of function names, parse it, and store it.
592 MethodSet(const WCHAR* filename, HostAllocator alloc);
596 // Return 'true' if 'functionName' (in UTF-8 format) is in the stored set of assembly names.
597 bool IsInSet(const char* functionName);
599 // Return 'true' if 'functionHash' (in UTF-8 format) is in the stored set of assembly names.
600 bool IsInSet(int functionHash);
602 // Return 'true' if this method is active. Prefer non-zero methodHash for check over (non-null) methodName.
603 bool IsActiveMethod(const char* methodName, int methodHash);
605 // Return 'true' if the assembly name set is empty.
608 return m_pInfos == nullptr;
612 #ifdef FEATURE_JIT_METHOD_PERF
613 // When Start() is called time is noted and when ElapsedTime
614 // is called we know how much time was spent in msecs.
619 double cps; // cycles per second
620 unsigned __int64 beginCycles; // cycles at stop watch construction
624 // Kick off the counter, and if re-entrant will use the latest cycles as starting point.
625 // If the method returns false, any other query yield unpredictable results.
628 // Return time elapsed in msecs, if Start returned true.
629 double ElapsedTime();
632 // Return true if successful.
633 bool GetCycles(unsigned __int64* time);
636 // Uses win API QueryPerformanceCounter/QueryPerformanceFrequency.
643 // If the method returns false, any other query yield unpredictable results.
646 // Return time elapsed from start in millis, if Start returned true.
647 double ElapsedTime();
650 #endif // FEATURE_JIT_METHOD_PERF
654 /*****************************************************************************
655 * Return the number of digits in a number of the given base (default base 10).
656 * Used when outputting strings.
658 unsigned CountDigits(unsigned num, unsigned base = 10);
659 unsigned CountDigits(float num, unsigned base = 10);
663 /*****************************************************************************
664 * Floating point utility class
666 class FloatingPointUtils
669 static double convertUInt64ToDouble(unsigned __int64 u64);
671 static float convertUInt64ToFloat(unsigned __int64 u64);
673 static unsigned __int64 convertDoubleToUInt64(double d);
675 static double round(double x);
677 static float round(float x);
679 static bool isNormal(double x);
681 static bool isNormal(float x);
683 static bool hasPreciseReciprocal(double x);
685 static bool hasPreciseReciprocal(float x);
687 static float infinite_float();
690 // The CLR requires that critical section locks be initialized via its ClrCreateCriticalSection API...but
691 // that can't be called until the CLR is initialized. If we have static data that we'd like to protect by a
692 // lock, and we have a statically allocated lock to protect that data, there's an issue in how to initialize
693 // that lock. We could insert an initialize call in the startup path, but one might prefer to keep the code
694 // more local. For such situations, CritSecObject solves the initialization problem, via a level of
695 // indirection. A pointer to the lock is initially null, and when we query for the lock pointer via "Val()".
696 // If the lock has not yet been allocated, this allocates one (here a leaf lock), and uses a
697 // CompareAndExchange-based lazy-initialization to update the field. If this fails, the allocated lock is
698 // destroyed. This will work as long as the first locking attempt occurs after enough CLR initialization has
699 // happened to make ClrCreateCriticalSection calls legal.
711 if (m_pCs == nullptr)
713 // CompareExchange-based lazy init.
714 CRITSEC_COOKIE newCs = ClrCreateCriticalSection(CrstLeafLock, CRST_DEFAULT);
715 CRITSEC_COOKIE observed = InterlockedCompareExchangeT(&m_pCs, newCs, NULL);
716 if (observed != nullptr)
718 ClrDeleteCriticalSection(newCs);
725 // CRITSEC_COOKIE is an opaque pointer type.
726 CRITSEC_COOKIE m_pCs;
728 // No copying or assignment allowed.
729 CritSecObject(const CritSecObject&) = delete;
730 CritSecObject& operator=(const CritSecObject&) = delete;
733 // Stack-based holder for a critial section lock.
734 // Ensures lock is released.
739 CritSecHolder(CritSecObject& critSec) : m_CritSec(critSec)
741 ClrEnterCriticalSection(m_CritSec.Val());
746 ClrLeaveCriticalSection(m_CritSec.Val());
750 CritSecObject& m_CritSec;
752 // No copying or assignment allowed.
753 CritSecHolder(const CritSecHolder&) = delete;
754 CritSecHolder& operator=(const CritSecHolder&) = delete;
757 namespace MagicDivide
759 uint32_t GetUnsigned32Magic(uint32_t d, bool* add /*out*/, int* shift /*out*/);
761 uint64_t GetUnsigned64Magic(uint64_t d, bool* add /*out*/, int* shift /*out*/);
763 int32_t GetSigned32Magic(int32_t d, int* shift /*out*/);
765 int64_t GetSigned64Magic(int64_t d, int* shift /*out*/);
773 double CachedCyclesPerSecond();