JavascriptNumber.h 10 KB

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