JavascriptNumber.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. namespace Js
  7. {
  8. class JavascriptNumber :
  9. #if !FLOATVAR
  10. public RecyclableObject,
  11. #endif
  12. public NumberConstants
  13. {
  14. private:
  15. double m_value;
  16. #if !FLOATVAR
  17. DEFINE_VTABLE_CTOR(JavascriptNumber, RecyclableObject);
  18. #endif
  19. public:
  20. JavascriptNumber(double value, StaticType*
  21. #if DBG
  22. , bool oopJIT = false
  23. #endif
  24. );
  25. static uint32 GetValueOffset()
  26. {
  27. return offsetof(JavascriptNumber, m_value);
  28. }
  29. static bool Is(Var aValue);
  30. static bool Is_NoTaggedIntCheck(Var aValue);
  31. static Var ToVarWithCheck(double value, ScriptContext* scriptContext);
  32. static Var ToVarNoCheck(double value, ScriptContext* scriptContext);
  33. static Var ToVarInPlace(double value, ScriptContext* scriptContext, JavascriptNumber *result);
  34. static Var ToVarMaybeInPlace(double value, ScriptContext* scriptContext, JavascriptNumber *result);
  35. static Var ToVarIntCheck(double value, ScriptContext* scriptContext);
  36. static Var ToVar(int32 nValue, ScriptContext* scriptContext);
  37. #ifdef ENABLE_TEST_HOOKS
  38. static Var ToVarFor32BitBytecode(int32 nValue, ScriptContext* scriptContext);
  39. #endif
  40. #if defined(__clang__) && defined(_M_IX86)
  41. static Var ToVar(intptr_t nValue, ScriptContext* scriptContext);
  42. #endif
  43. static Var ToVarInPlace(int32 nValue, ScriptContext* scriptContext, JavascriptNumber *result);
  44. static Var ToVarInPlace(int64 value, ScriptContext* scriptContext, JavascriptNumber *result);
  45. static Var ToVarInPlace(uint32 nValue, ScriptContext* scriptContext, JavascriptNumber *result);
  46. static Var ToVar(uint32 nValue, ScriptContext* scriptContext);
  47. static Var ToVar(int64 nValue, ScriptContext* scriptContext);
  48. static Var ToVar(uint64 nValue, ScriptContext* scriptContext);
  49. static double GetValue(Var aValue);
  50. static int32 DirectPowIntInt(bool*, int32, int32);
  51. static double DirectPowDoubleInt(double, int32);
  52. static double DirectPow(double, double);
  53. static bool TryToVarFast(int32 nValue, Var* result);
  54. static bool TryToVarFastWithCheck(double value, Var* result);
  55. inline static BOOL IsNan(double value) { return NumberUtilities::IsNan(value); }
  56. inline static BOOL IsNegative(double value) { return NumberUtilities::IsNegative(value); }
  57. static bool IsZero(double value);
  58. static BOOL IsNegZero(double value);
  59. static bool IsPosInf(double value);
  60. static bool IsNegInf(double value);
  61. template<bool acceptNegZero = false>
  62. static bool TryGetInt32Value(const double value, int32 *const int32Value)
  63. {
  64. Assert(int32Value);
  65. const int32 i = static_cast<int32>(value);
  66. if (static_cast<double>(i) != value || (!acceptNegZero && IsNegZero(value)))
  67. {
  68. return false;
  69. }
  70. *int32Value = i;
  71. return true;
  72. }
  73. static bool TryGetInt32OrUInt32Value(const double value, int32 *const int32Value, bool *const isInt32);
  74. static bool IsInt32(const double value);
  75. static bool IsInt32OrUInt32(const double value);
  76. static bool IsInt32_NoChecks(const Var number);
  77. static bool IsInt32OrUInt32_NoChecks(const Var number);
  78. static int32 GetNonzeroInt32Value_NoTaggedIntCheck(const Var object);
  79. static JavascriptString* ToString(double value, ScriptContext* scriptContext);
  80. class EntryInfo
  81. {
  82. public:
  83. static FunctionInfo NewInstance;
  84. // Number constructor built-ins:
  85. static FunctionInfo IsNaN;
  86. static FunctionInfo IsFinite;
  87. static FunctionInfo IsInteger;
  88. static FunctionInfo IsSafeInteger;
  89. // Number prototype built-ins:
  90. static FunctionInfo ToExponential;
  91. static FunctionInfo ToFixed;
  92. static FunctionInfo ToPrecision;
  93. static FunctionInfo ToLocaleString;
  94. static FunctionInfo ToString;
  95. static FunctionInfo ValueOf;
  96. };
  97. static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);
  98. // Number constructor built-ins:
  99. static Var EntryIsNaN(RecyclableObject* function, CallInfo callInfo, ...);
  100. static Var EntryIsFinite(RecyclableObject* function, CallInfo callInfo, ...);
  101. static Var EntryIsInteger(RecyclableObject* function, CallInfo callInfo, ...);
  102. static Var EntryIsSafeInteger(RecyclableObject* function, CallInfo callInfo, ...);
  103. // Number prototype built-ins:
  104. static Var EntryToExponential(RecyclableObject* function, CallInfo callInfo, ...);
  105. static Var EntryToFixed(RecyclableObject* function, CallInfo callInfo, ...);
  106. static Var EntryToPrecision(RecyclableObject* function, CallInfo callInfo, ...);
  107. static Var EntryToLocaleString(RecyclableObject* function, CallInfo callInfo, ...);
  108. static Var EntryToString(RecyclableObject* function, CallInfo callInfo, ...);
  109. static Var EntryValueOf(RecyclableObject* function, CallInfo callInfo, ...);
  110. static Var New(double value, ScriptContext* scriptContext);
  111. static Var NewWithCheck(double value, ScriptContext* scriptContext);
  112. static Var NewInlined(double value, ScriptContext* scriptContext);
  113. static JavascriptNumber* InPlaceNew(double value, ScriptContext* scriptContext, JavascriptNumber* result);
  114. #if ENABLE_NATIVE_CODEGEN
  115. #if FLOATVAR
  116. static Var NewCodeGenInstance(double value, ScriptContext* scriptContext);
  117. #else
  118. static Var NewCodeGenInstance(CodeGenNumberAllocator *alloc, double value, ScriptContext* scriptContext);
  119. #endif
  120. #endif
  121. inline static bool IsSpecial(double value, uint64 nSpecial) { return NumberUtilities::IsSpecial(value, nSpecial); }
  122. inline static uint64 ToSpecial(double value) { return NumberUtilities::ToSpecial(value); }
  123. static JavascriptString* ToStringNan(ScriptContext* scriptContext);
  124. static JavascriptString* ToStringRadix10(double dValue, ScriptContext* scriptContext);
  125. // when radix is 10, ToStringRadix10 should be used instead
  126. static JavascriptString* ToStringRadixHelper(double value, int radix, ScriptContext* scriptContext);
  127. static JavascriptString* ToLocaleString(double dValue, ScriptContext* scriptContext);
  128. static JavascriptString* ToLocaleStringIntl(ArgumentReader& args, CallInfo callInfo, ScriptContext* scriptContext);
  129. static JavascriptString* ToLocaleStringIntl(Var* values, CallInfo callInfo, ScriptContext* scriptContext);
  130. static Var CloneToScriptContext(Var aValue, ScriptContext* requestContext);
  131. #if !FLOATVAR
  132. static JavascriptNumber* NewUninitialized(Recycler * recycler);
  133. static Var BoxStackInstance(Var instance, ScriptContext* scriptContext);
  134. static Var BoxStackNumber(Var instance, ScriptContext* scriptContext);
  135. // This is needed to ensure JavascriptNumber has a VTABLE and JavascriptNumber::Is (which checks for the VTABLE value) works correctly.
  136. // This also prevents the vtable from being folded with other classes unexpectedly.
  137. virtual VTableValue DummyVirtualFunctionToHinderLinkerICF()
  138. {
  139. return VTableValue::VtableJavascriptNumber;
  140. }
  141. #endif
  142. #if FLOATVAR
  143. static Var ToVar(double value);
  144. #else
  145. static JavascriptNumber* FromVar(Var aValue);
  146. static JavascriptNumber* UnsafeFromVar(Var aValue);
  147. #endif
  148. private:
  149. void SetValue(double value)
  150. {
  151. m_value = value;
  152. }
  153. double GetValue() const
  154. {
  155. return m_value;
  156. }
  157. void SetSpecial(uint64 value)
  158. {
  159. uint64* pnOverwrite = reinterpret_cast<uint64 *>(&this->m_value);
  160. *pnOverwrite = value;
  161. }
  162. static JavascriptString* ToStringNanOrInfinite(double val, ScriptContext* scriptContext);
  163. static JavascriptString* ToStringNanOrInfiniteOrZero(double val, ScriptContext* scriptContext);
  164. static JavascriptString* ToLocaleStringNanOrInfinite(double val, ScriptContext* scriptContext);
  165. static Var FormatDoubleToString( double value, Js::NumberUtilities::FormatType formatType, int fractionDigits, ScriptContext* scriptContext );
  166. static BOOL GetThisValue(Var avalue, double* pDouble);
  167. };
  168. //
  169. // Implementations shared with diagnostics
  170. //
  171. #if FLOATVAR
  172. // Since RecyclableObject and Int32 in their Var representation have top 14 bits 0
  173. // and tagged float now has top 14 XOR'd with 1s - the value with 14 bits non zero is
  174. // a float.
  175. // A float can have all 14 bits 0 iff it was a NaN in the first place. Since
  176. // we can only produce NaNs with top 13 bits set (see k_Nan) - this cannot happen.
  177. inline bool JavascriptNumber::Is_NoTaggedIntCheck(Var aValue)
  178. {
  179. return ((uint64)aValue >> 50) != 0;
  180. }
  181. inline double JavascriptNumber::GetValue(Var aValue)
  182. {
  183. AssertMsg(Is(aValue), "Ensure var is actually a 'JavascriptNumber'");
  184. double result;
  185. (*(uint64*)(&result)) = (((uint64)aValue) ^ FloatTag_Value);
  186. return result;
  187. }
  188. #endif
  189. inline bool JavascriptNumber::IsZero(double value)
  190. {
  191. // succeeds for -0.0 as well
  192. return value == 0.0;
  193. }
  194. inline bool JavascriptNumber::IsPosInf(double value)
  195. {
  196. return IsSpecial(value, k_PosInf);
  197. }
  198. inline bool JavascriptNumber::IsNegInf(double value)
  199. {
  200. return IsSpecial(value, k_NegInf);
  201. }
  202. inline BOOL JavascriptNumber::IsNegZero(double value)
  203. {
  204. return IsSpecial(value, k_NegZero);
  205. }
  206. }
  207. #if defined(_M_IX86)
  208. #ifdef DBG
  209. #ifdef HEAP_ENUMERATION_VALIDATION
  210. // Heap enum has an extra field m_heapEnumValidationCookie, but it fills in the alignment
  211. // So the size is the same
  212. CompileAssert(sizeof(Js::JavascriptNumber) == 24);
  213. #else
  214. CompileAssert(sizeof(Js::JavascriptNumber) == 16);
  215. #endif
  216. #else
  217. CompileAssert(sizeof(Js::JavascriptNumber) == 16);
  218. #endif
  219. #endif