JavascriptConversion.inl 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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. #if defined(_M_IX86) || defined(_M_X64)
  7. #ifdef _WIN32
  8. #include <emmintrin.h>
  9. #endif
  10. #endif
  11. namespace Js {
  12. inline BOOL JavascriptConversion::ToBoolean(Var aValue,ScriptContext* scriptContext)
  13. {
  14. if (TaggedInt::Is(aValue))
  15. {
  16. return aValue != reinterpret_cast<Var>(AtomTag_IntPtr);
  17. }
  18. #if FLOATVAR
  19. else if (JavascriptNumber::Is_NoTaggedIntCheck(aValue))
  20. {
  21. double value = JavascriptNumber::GetValue(aValue);
  22. return (!JavascriptNumber::IsNan(value)) && (!JavascriptNumber::IsZero(value));
  23. }
  24. #endif
  25. else
  26. {
  27. return ToBoolean_Full(aValue, scriptContext);
  28. }
  29. }
  30. inline bool JavascriptConversion::ToBool(Var aValue,ScriptContext* scriptContext)
  31. {
  32. return !!JavascriptConversion::ToBoolean(aValue, scriptContext);
  33. }
  34. /// ToNumber() returns an integer value, as described in (ES3.0: S9.3).
  35. inline double JavascriptConversion::ToNumber(Var aValue, ScriptContext* scriptContext)
  36. {
  37. // Optimize for TaggedInt and double before falling back to ToNumber_Full
  38. if( TaggedInt::Is(aValue) )
  39. {
  40. return TaggedInt::ToDouble(aValue);
  41. }
  42. if( JavascriptNumber::Is_NoTaggedIntCheck(aValue) )
  43. {
  44. return JavascriptNumber::GetValue(aValue);
  45. }
  46. return ToNumber_Full(aValue, scriptContext);
  47. }
  48. inline double JavascriptConversion::ToInteger(Var aValue, ScriptContext* scriptContext)
  49. {
  50. return
  51. TaggedInt::Is(aValue) ?
  52. TaggedInt::ToDouble(aValue) :
  53. ToInteger_Full(aValue, scriptContext);
  54. }
  55. inline int32 JavascriptConversion::ToInt32(Var aValue, ScriptContext* scriptContext)
  56. {
  57. return
  58. TaggedInt::Is(aValue) ?
  59. TaggedInt::ToInt32(aValue) :
  60. ToInt32_Full(aValue, scriptContext);
  61. }
  62. inline uint32 JavascriptConversion::ToUInt32(Var aValue, ScriptContext* scriptContext)
  63. {
  64. return
  65. TaggedInt::Is(aValue) ?
  66. TaggedInt::ToUInt32(aValue) :
  67. ToUInt32_Full(aValue, scriptContext);
  68. }
  69. inline uint16 JavascriptConversion::ToUInt16(Var aValue, ScriptContext* scriptContext)
  70. {
  71. return
  72. TaggedInt::Is(aValue) ?
  73. (uint16) TaggedInt::ToUInt32(aValue) :
  74. ToUInt16_Full(aValue, scriptContext);
  75. }
  76. inline int8 JavascriptConversion::ToInt8(Var aValue, ScriptContext* scriptContext)
  77. {
  78. return TaggedInt::Is(aValue) ?
  79. (int8) TaggedInt::ToInt32(aValue) :
  80. (int8) ToInt32(aValue, scriptContext);
  81. }
  82. inline uint8 JavascriptConversion::ToUInt8(Var aValue, ScriptContext* scriptContext)
  83. {
  84. return TaggedInt::Is(aValue) ?
  85. (uint8) TaggedInt::ToInt32(aValue) :
  86. (uint8) ToUInt32(aValue, scriptContext);
  87. }
  88. inline uint8 JavascriptConversion::ToUInt8Clamped(Var aValue, ScriptContext* scriptContext)
  89. {
  90. double dval;
  91. if (TaggedInt::Is(aValue))
  92. {
  93. int32 val = Js::TaggedInt::ToInt32(aValue);
  94. // Values larger than 0xff should be clamped to 0xff
  95. if (val > UINT8_MAX)
  96. {
  97. return UINT8_MAX;
  98. }
  99. // Negative values should be clamped to 0
  100. if (val < 0)
  101. {
  102. return 0;
  103. }
  104. return (uint8) val;
  105. }
  106. else if (JavascriptOperators::GetTypeId(aValue) == TypeIds_Number)
  107. {
  108. dval = JavascriptNumber::GetValue(aValue);
  109. }
  110. else
  111. {
  112. dval = JavascriptConversion::ToNumber_Full(aValue, scriptContext);
  113. }
  114. // This will also cover positive infinity
  115. // Note: This is strictly greater-than check because 254.5 rounds to 254
  116. if (dval > 254.5)
  117. {
  118. return UINT8_MAX;
  119. }
  120. // This will also cover negative infinity, and anything less than INT_MIN
  121. if (dval < 0)
  122. {
  123. return 0;
  124. }
  125. // We now have a double value which is between 0 and 255 and just need to convert it
  126. // to an integer following IEEE 754 rounding rules which round ties to the nearest
  127. // even integer.
  128. #if defined(_M_IX86) || defined(_M_X64)
  129. if (AutoSystemInfo::Data.SSE2Available())
  130. {
  131. // On x86 we have a convenient CVTSD2SI intrinsic function to handle this.
  132. __m128d t = _mm_load_sd(&dval);
  133. return (uint8)_mm_cvtsd_si32(t);
  134. }
  135. else
  136. #endif
  137. {
  138. // On ARM, there is not a convenient intrinsic (for VCVTRS32F64).
  139. // Once DevDiv TFS item 656383 is complete, we should replace the below with the intrinsic.
  140. // 1. Calculate the fractional part of the double value
  141. // 2. Round up or down as usual if the fractional part is <> 0.5
  142. // 3. If the fractional part == 0.5, round to nearest even integer:
  143. // Divide by 2, add 0.5, cast to integer, multiply by 2 again.
  144. uint8 u8 = (uint8)dval;
  145. double frac = dval - u8;
  146. if (frac > 0.5)
  147. {
  148. return (uint8)(dval + 0.5);
  149. }
  150. else if (frac < 0.5)
  151. {
  152. return u8;
  153. }
  154. else
  155. {
  156. return ((uint8)(dval / 2.0 + 0.5)) * 2;
  157. }
  158. }
  159. }
  160. inline int16 JavascriptConversion::ToInt16(Var aValue, ScriptContext* scriptContext)
  161. {
  162. return TaggedInt::Is(aValue) ?
  163. (int16) TaggedInt::ToInt32(aValue) :
  164. (int16) ToUInt32(aValue, scriptContext);
  165. }
  166. inline float JavascriptConversion::ToFloat(Var aValue, ScriptContext* scriptContext)
  167. {
  168. return (float)ToNumber(aValue, scriptContext);
  169. }
  170. inline bool JavascriptConversion::SameValue(Var aValue, Var bValue)
  171. {
  172. return SameValueCommon<false>(aValue, bValue);
  173. }
  174. inline bool JavascriptConversion::SameValueZero(Var aValue, Var bValue)
  175. {
  176. return SameValueCommon<true>(aValue, bValue);
  177. }
  178. } // namespace Js