JavascriptConversion.inl 6.3 KB

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