MathLibrary.cpp 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Copyright (c) ChakraCore Project Contributors. All rights reserved.
  4. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  5. //-------------------------------------------------------------------------------------------------------
  6. #include "RuntimeLibraryPch.h"
  7. #include "Language/JavascriptMathOperators.h"
  8. #include "Math/CrtSSE2Math.h"
  9. #include <math.h>
  10. const LPCWSTR UCrtC99MathApis::LibraryName = _u("api-ms-win-crt-math-l1-1-0.dll");
  11. void UCrtC99MathApis::Ensure()
  12. {
  13. if (m_isInit)
  14. {
  15. return;
  16. }
  17. DelayLoadLibrary::EnsureFromSystemDirOnly();
  18. if (IsAvailable())
  19. {
  20. m_pfnlog2 = (PFNMathFn)GetFunction("log2");
  21. m_pfnlog1p = (PFNMathFn)GetFunction("log1p");
  22. m_pfnexpm1 = (PFNMathFn)GetFunction("expm1");
  23. m_pfnacosh = (PFNMathFn)GetFunction("acosh");
  24. m_pfnasinh = (PFNMathFn)GetFunction("asinh");
  25. m_pfnatanh = (PFNMathFn)GetFunction("atanh");
  26. m_pfntrunc = (PFNMathFn)GetFunction("trunc");
  27. m_pfncbrt = (PFNMathFn)GetFunction("cbrt");
  28. if (m_pfnlog2 == nullptr ||
  29. m_pfnlog1p == nullptr ||
  30. m_pfnexpm1 == nullptr ||
  31. m_pfnacosh == nullptr ||
  32. m_pfnasinh == nullptr ||
  33. m_pfnatanh == nullptr ||
  34. m_pfntrunc == nullptr ||
  35. m_pfncbrt == nullptr)
  36. {
  37. // If any of the APIs fail to load then presume the entire module is bogus and free it
  38. FreeLibrary(m_hModule);
  39. m_hModule = nullptr;
  40. }
  41. }
  42. }
  43. namespace Js
  44. {
  45. const double Math::PI = 3.1415926535897931;
  46. const double Math::E = 2.7182818284590451;
  47. const double Math::LN10 = 2.3025850929940459;
  48. const double Math::LN2 = 0.69314718055994529;
  49. const double Math::LOG2E = 1.4426950408889634;
  50. const double Math::LOG10E = 0.43429448190325182;
  51. const double Math::SQRT1_2 = 0.70710678118654757;
  52. const double Math::SQRT2 = 1.4142135623730951;
  53. const double Math::EPSILON = 2.2204460492503130808472633361816e-16;
  54. const double Math::MAX_SAFE_INTEGER = 9007199254740991.0;
  55. const double Math::MIN_SAFE_INTEGER = -9007199254740991.0;
  56. ///----------------------------------------------------------------------------
  57. /// Abs() returns the absolute value of the given number, as described in
  58. /// (ES5.0: S15.8.2.1).
  59. ///----------------------------------------------------------------------------
  60. Var Math::Abs(RecyclableObject* function, CallInfo callInfo, ...)
  61. {
  62. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  63. ARGUMENTS(args, callInfo);
  64. ScriptContext* scriptContext = function->GetScriptContext();
  65. Assert(!(callInfo.Flags & CallFlags_New));
  66. if (args.Info.Count >= 2)
  67. {
  68. Var arg = args[1];
  69. if (TaggedInt::Is(arg))
  70. {
  71. #if defined(TARGET_64)
  72. __int64 result = ::_abs64(TaggedInt::ToInt32(arg));
  73. #else
  74. __int32 result = ::abs(TaggedInt::ToInt32(arg));
  75. #endif
  76. return JavascriptNumber::ToVar(result, scriptContext);
  77. }
  78. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  79. double result = Math::Abs(x);
  80. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  81. }
  82. else
  83. {
  84. return scriptContext->GetLibrary()->GetNaN();
  85. }
  86. }
  87. double Math::Abs(double x)
  88. {
  89. // ::fabs if linked from UCRT changes FPU ctrl word for NaN input
  90. if (NumberUtilities::IsNan(x))
  91. {
  92. // canonicalize to 0xFFF8000..., so we can tag correctly on x64.
  93. return NumberConstants::NaN;
  94. }
  95. return ::fabs(x);
  96. }
  97. ///----------------------------------------------------------------------------
  98. /// Acos() returns the arc-cosine of the given angle in radians, as described
  99. /// in (ES5.0: S15.8.2.2).
  100. ///----------------------------------------------------------------------------
  101. Var Math::Acos(RecyclableObject* function, CallInfo callInfo, ...)
  102. {
  103. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  104. ARGUMENTS(args, callInfo);
  105. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  106. ScriptContext* scriptContext = function->GetScriptContext();
  107. Assert(!(callInfo.Flags & CallFlags_New));
  108. if (args.Info.Count >= 2)
  109. {
  110. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  111. double result = Math::Acos(x);
  112. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  113. }
  114. else
  115. {
  116. return scriptContext->GetLibrary()->GetNaN();
  117. }
  118. }
  119. double Math::Acos(double x)
  120. {
  121. double result;
  122. #if defined(_M_IX86) && defined(_WIN32)
  123. // This is for perf, not for functionality
  124. // If non Win32 CRT implementation already support SSE2,
  125. // then we get most of the perf already.
  126. if (AutoSystemInfo::Data.SSE2Available())
  127. {
  128. _asm {
  129. movsd xmm0, x
  130. call dword ptr [__libm_sse2_acos]
  131. movsd result, xmm0
  132. }
  133. }
  134. else
  135. #endif
  136. {
  137. result = ::acos(x);
  138. }
  139. return result;
  140. }
  141. ///----------------------------------------------------------------------------
  142. /// Asin() returns the arc-sine of the given angle in radians, as described in
  143. /// (ES5.0: S15.8.2.3).
  144. ///----------------------------------------------------------------------------
  145. Var Math::Asin(RecyclableObject* function, CallInfo callInfo, ...)
  146. {
  147. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  148. ARGUMENTS(args, callInfo);
  149. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  150. ScriptContext* scriptContext = function->GetScriptContext();
  151. Assert(!(callInfo.Flags & CallFlags_New));
  152. if (args.Info.Count >= 2)
  153. {
  154. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  155. double result = Math::Asin(x);
  156. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  157. }
  158. else
  159. {
  160. return scriptContext->GetLibrary()->GetNaN();
  161. }
  162. }
  163. double Math::Asin(double x)
  164. {
  165. double result;
  166. #if defined(_M_IX86) && defined(_WIN32)
  167. // This is for perf, not for functionality
  168. // If non Win32 CRT implementation already support SSE2,
  169. // then we get most of the perf already.
  170. if (AutoSystemInfo::Data.SSE2Available())
  171. {
  172. _asm {
  173. movsd xmm0, x
  174. call dword ptr [__libm_sse2_asin]
  175. movsd result, xmm0
  176. }
  177. }
  178. else
  179. #endif
  180. {
  181. result = ::asin(x);
  182. }
  183. return result;
  184. }
  185. ///----------------------------------------------------------------------------
  186. /// Atan() returns the arc-tangent of the given angle in radians, as described
  187. /// in (ES5.0: S15.8.2.4).
  188. ///----------------------------------------------------------------------------
  189. Var Math::Atan(RecyclableObject* function, CallInfo callInfo, ...)
  190. {
  191. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  192. ARGUMENTS(args, callInfo);
  193. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  194. ScriptContext* scriptContext = function->GetScriptContext();
  195. Assert(!(callInfo.Flags & CallFlags_New));
  196. if (args.Info.Count >= 2)
  197. {
  198. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  199. double result = Math::Atan(x);
  200. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  201. }
  202. else
  203. {
  204. return scriptContext->GetLibrary()->GetNaN();
  205. }
  206. }
  207. double Math::Atan(double x)
  208. {
  209. double result;
  210. #if defined(_M_IX86) && defined(_WIN32)
  211. // This is for perf, not for functionality
  212. // If non Win32 CRT implementation already support SSE2,
  213. // then we get most of the perf already.
  214. if (AutoSystemInfo::Data.SSE2Available())
  215. {
  216. _asm {
  217. movsd xmm0, x
  218. call dword ptr [__libm_sse2_atan]
  219. movsd result, xmm0
  220. }
  221. }
  222. else
  223. #endif
  224. {
  225. result = ::atan(x);
  226. }
  227. return result;
  228. }
  229. ///----------------------------------------------------------------------------
  230. /// Atan2() returns the arc-tangent of the angle described by the given x and y
  231. /// lengths, as described in (ES5.0: S15.8.2.5).
  232. ///----------------------------------------------------------------------------
  233. Var Math::Atan2(RecyclableObject* function, CallInfo callInfo, ...)
  234. {
  235. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  236. ARGUMENTS(args, callInfo);
  237. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  238. ScriptContext* scriptContext = function->GetScriptContext();
  239. Assert(!(callInfo.Flags & CallFlags_New));
  240. if (args.Info.Count >= 3)
  241. {
  242. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  243. double y = JavascriptConversion::ToNumber(args[2], scriptContext);
  244. double result = Math::Atan2(x,y);
  245. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  246. }
  247. else
  248. {
  249. return scriptContext->GetLibrary()->GetNaN();
  250. }
  251. }
  252. double Math::Atan2( double x, double y )
  253. {
  254. double result;
  255. #if defined(_M_IX86) && defined(_WIN32)
  256. // This is for perf, not for functionality
  257. // If non Win32 CRT implementation already support SSE2,
  258. // then we get most of the perf already.
  259. if (AutoSystemInfo::Data.SSE2Available())
  260. {
  261. _asm
  262. {
  263. movsd xmm0, x
  264. movsd xmm1, y
  265. call dword ptr[__libm_sse2_atan2]
  266. movsd result, xmm0
  267. }
  268. }
  269. else
  270. #endif
  271. {
  272. result = ::atan2(x, y);
  273. }
  274. return result;
  275. }
  276. ///----------------------------------------------------------------------------
  277. /// Ceil() returns the smallest (closest to -Inf) number value that is not less
  278. /// than x and is equal to an integer, as described in (ES5.0: S15.8.2.6).
  279. ///----------------------------------------------------------------------------
  280. #pragma warning(push)
  281. #pragma warning(disable:4700) // uninitialized local variable 'output' used, for call to _mm_ceil_sd
  282. Var Math::Ceil(RecyclableObject* function, CallInfo callInfo, ...)
  283. {
  284. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  285. ARGUMENTS(args, callInfo);
  286. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  287. ScriptContext* scriptContext = function->GetScriptContext();
  288. Assert(!(callInfo.Flags & CallFlags_New));
  289. if (args.Info.Count >= 2)
  290. {
  291. Var inputArg = args[1];
  292. if (TaggedInt::Is(inputArg))
  293. {
  294. return inputArg;
  295. }
  296. double x = JavascriptConversion::ToNumber(inputArg, scriptContext);
  297. #if defined(_M_ARM32_OR_ARM64)
  298. if (Js::JavascriptNumber::IsNan(x))
  299. {
  300. return scriptContext->GetLibrary()->GetNaN();
  301. }
  302. #endif
  303. #if (defined(_M_IX86) || defined(_M_X64)) \
  304. && (__SSE4_1__ || _WIN32) // _mm_ceil_sd needs this
  305. if (AutoSystemInfo::Data.SSE4_1Available())
  306. {
  307. __m128d input, output;
  308. input = _mm_load_sd(&x);
  309. output = _mm_ceil_sd(input, input);
  310. int intResult = _mm_cvtsd_si32(output);
  311. if (TaggedInt::IsOverflow(intResult) || intResult == 0 || intResult == 0x80000000)
  312. {
  313. double dblResult;
  314. _mm_store_sd(&dblResult, output);
  315. if (intResult == 0 && !JavascriptNumber::IsNegZero(dblResult))
  316. {
  317. return JavascriptNumber::ToVar(0, scriptContext);
  318. }
  319. Assert(dblResult == ::ceil(x) || Js::JavascriptNumber::IsNan(dblResult));
  320. return JavascriptNumber::ToVarNoCheck(dblResult, scriptContext);
  321. }
  322. else
  323. {
  324. return JavascriptNumber::ToVar(intResult, scriptContext);
  325. }
  326. }
  327. else
  328. #endif
  329. {
  330. double result = ::ceil(x);
  331. intptr_t intResult = (intptr_t)result;
  332. if (TaggedInt::IsOverflow(intResult) || JavascriptNumber::IsNegZero(result))
  333. {
  334. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  335. }
  336. else
  337. {
  338. return JavascriptNumber::ToVar(intResult, scriptContext);
  339. }
  340. }
  341. }
  342. else
  343. {
  344. return scriptContext->GetLibrary()->GetNaN();
  345. }
  346. }
  347. #pragma warning(pop)
  348. ///----------------------------------------------------------------------------
  349. /// Cos() returns the cosine of the given angle in radians, as described in
  350. /// (ES5.0: S15.8.2.7).
  351. ///----------------------------------------------------------------------------
  352. Var Math::Cos(RecyclableObject* function, CallInfo callInfo, ...)
  353. {
  354. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  355. ARGUMENTS(args, callInfo);
  356. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  357. ScriptContext* scriptContext = function->GetScriptContext();
  358. Assert(!(callInfo.Flags & CallFlags_New));
  359. if (args.Info.Count >= 2)
  360. {
  361. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  362. double result = Math::Cos(x);
  363. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  364. }
  365. else
  366. {
  367. return scriptContext->GetLibrary()->GetNaN();
  368. }
  369. }
  370. double Math::Cos(double x)
  371. {
  372. double result;
  373. #if defined(_M_IX86) && defined(_WIN32)
  374. // This is for perf, not for functionality
  375. // If non Win32 CRT implementation already support SSE2,
  376. // then we get most of the perf already.
  377. if (AutoSystemInfo::Data.SSE2Available())
  378. {
  379. _asm {
  380. movsd xmm0, x
  381. call dword ptr [__libm_sse2_cos]
  382. movsd result, xmm0
  383. }
  384. }
  385. else
  386. #endif
  387. {
  388. result = ::cos(x);
  389. }
  390. return result;
  391. }
  392. ///----------------------------------------------------------------------------
  393. /// Exp() returns e^x, as described in (ES5.0: S15.8.2.8).
  394. ///----------------------------------------------------------------------------
  395. Var Math::Exp(RecyclableObject* function, CallInfo callInfo, ...)
  396. {
  397. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  398. ARGUMENTS(args, callInfo);
  399. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  400. ScriptContext* scriptContext = function->GetScriptContext();
  401. Assert(!(callInfo.Flags & CallFlags_New));
  402. if (args.Info.Count >= 2)
  403. {
  404. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  405. double result = Math::Exp(x);
  406. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  407. }
  408. else
  409. {
  410. return scriptContext->GetLibrary()->GetNaN();
  411. }
  412. }
  413. double Math::Exp(double x)
  414. {
  415. double result;
  416. #if defined(_M_IX86) && defined(_WIN32)
  417. // This is for perf, not for functionality
  418. // If non Win32 CRT implementation already support SSE2,
  419. // then we get most of the perf already.
  420. if (AutoSystemInfo::Data.SSE2Available())
  421. {
  422. _asm {
  423. movsd xmm0, x
  424. call dword ptr [__libm_sse2_exp]
  425. movsd result, xmm0
  426. }
  427. }
  428. else
  429. #endif
  430. {
  431. result = ::exp(x);
  432. }
  433. return result;
  434. }
  435. ///----------------------------------------------------------------------------
  436. /// Floor() returns the greatest (closest to +Inf) number value that is not
  437. /// greater than x and is equal to an integer, as described in
  438. /// (ES5.0: S15.8.2.9).
  439. ///----------------------------------------------------------------------------
  440. Var Math::Floor(RecyclableObject* function, CallInfo callInfo, ...)
  441. {
  442. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  443. ARGUMENTS(args, callInfo);
  444. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  445. ScriptContext* scriptContext = function->GetScriptContext();
  446. Assert(!(callInfo.Flags & CallFlags_New));
  447. if (args.Info.Count >= 2)
  448. {
  449. Var input = args[1];
  450. if (TaggedInt::Is(input))
  451. {
  452. return input;
  453. }
  454. double x = JavascriptConversion::ToNumber(input, scriptContext);
  455. #if defined(_M_ARM32_OR_ARM64)
  456. if (Js::JavascriptNumber::IsNan(x))
  457. {
  458. return scriptContext->GetLibrary()->GetNaN();
  459. }
  460. #endif
  461. return Math::FloorDouble(x, scriptContext);
  462. }
  463. else
  464. {
  465. return scriptContext->GetLibrary()->GetNaN();
  466. }
  467. }
  468. #pragma warning(push)
  469. #pragma warning(disable:4700) // // uninitialized local variable 'output' used, for call to _mm_floor_sd
  470. Var inline Math::FloorDouble(double d, ScriptContext *scriptContext)
  471. {
  472. // xplat-todo: use intrinsics here on linux
  473. #ifdef _MSC_VER
  474. #if defined(_M_IX86) || defined(_M_X64)
  475. if (AutoSystemInfo::Data.SSE4_1Available())
  476. {
  477. __m128d input, output;
  478. int intResult;
  479. input = _mm_load_sd(&d);
  480. if (d >= 0.0)
  481. {
  482. output = input;
  483. }
  484. else
  485. {
  486. output = _mm_floor_sd(input, input);
  487. }
  488. intResult = _mm_cvttsd_si32(output);
  489. if (TaggedInt::IsOverflow(intResult) || intResult == 0x80000000 || JavascriptNumber::IsNegZero(d))
  490. {
  491. double dblResult;
  492. if (d >= 0.0)
  493. {
  494. output = _mm_floor_sd(output, input);
  495. }
  496. _mm_store_sd(&dblResult, output);
  497. Assert(dblResult == ::floor(d) || Js::JavascriptNumber::IsNan(dblResult));
  498. return JavascriptNumber::ToVarNoCheck(dblResult, scriptContext);
  499. }
  500. else
  501. {
  502. Assert(intResult == (int)::floor(d));
  503. return JavascriptNumber::ToVar(intResult, scriptContext);
  504. }
  505. }
  506. else
  507. #endif
  508. #endif
  509. {
  510. intptr_t intResult;
  511. if (d >= 0.0)
  512. {
  513. intResult = (intptr_t)d;
  514. }
  515. else
  516. {
  517. d = ::floor(d);
  518. intResult = (intptr_t)d;
  519. }
  520. if (TaggedInt::IsOverflow(intResult) || JavascriptNumber::IsNegZero(d))
  521. {
  522. return JavascriptNumber::ToVarNoCheck(::floor(d), scriptContext);
  523. }
  524. else
  525. {
  526. return JavascriptNumber::ToVar(intResult, scriptContext);
  527. }
  528. }
  529. }
  530. #pragma warning(pop)
  531. ///----------------------------------------------------------------------------
  532. /// Log() returns the natural logarithm of x, as described in
  533. /// (ES5.0: S15.8.2.10).
  534. ///----------------------------------------------------------------------------
  535. Var Math::Log(RecyclableObject* function, CallInfo callInfo, ...)
  536. {
  537. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  538. ARGUMENTS(args, callInfo);
  539. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  540. ScriptContext* scriptContext = function->GetScriptContext();
  541. Assert(!(callInfo.Flags & CallFlags_New));
  542. if (args.Info.Count >= 2)
  543. {
  544. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  545. double result = Math::Log(x);
  546. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  547. }
  548. else
  549. {
  550. return scriptContext->GetLibrary()->GetNaN();
  551. }
  552. }
  553. double Math::Log(double x)
  554. {
  555. double result;
  556. #if defined(_M_IX86) && defined(_WIN32)
  557. // This is for perf, not for functionality
  558. // If non Win32 CRT implementation already support SSE2,
  559. // then we get most of the perf already.
  560. if (AutoSystemInfo::Data.SSE2Available())
  561. {
  562. _asm {
  563. movsd xmm0, x
  564. call dword ptr [__libm_sse2_log]
  565. movsd result, xmm0
  566. }
  567. }
  568. else
  569. #endif
  570. {
  571. result = ::log(x);
  572. }
  573. return result;
  574. }
  575. ///----------------------------------------------------------------------------
  576. /// Max() returns the maximum of a series of numbers, as described in
  577. /// (ES5.0: S15.8.2.11):
  578. /// - Arg:0 = "this"
  579. /// - Arg:1-n = Values to compare
  580. ///----------------------------------------------------------------------------
  581. Var Math::Max(RecyclableObject* function, CallInfo callInfo, ...)
  582. {
  583. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  584. ARGUMENTS(args, callInfo);
  585. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  586. ScriptContext* scriptContext = function->GetScriptContext();
  587. bool hasOnlyIntegerArgs = false;
  588. Assert(!(callInfo.Flags & CallFlags_New));
  589. if (args.Info.Count <= 1)
  590. {
  591. return scriptContext->GetLibrary()->GetNegativeInfinite();
  592. }
  593. else if (args.Info.Count == 2)
  594. {
  595. double result = JavascriptConversion::ToNumber(args[1], scriptContext);
  596. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  597. }
  598. else
  599. {
  600. hasOnlyIntegerArgs = TaggedInt::OnlyContainsTaggedInt(args);
  601. if (hasOnlyIntegerArgs && args.Info.Count == 3)
  602. {
  603. return TaggedInt::ToVarUnchecked(max(TaggedInt::ToInt32(args[1]), TaggedInt::ToInt32(args[2])));
  604. }
  605. }
  606. if (hasOnlyIntegerArgs)
  607. {
  608. int32 current = TaggedInt::ToInt32(args[1]);
  609. for (uint idxArg = 2; idxArg < args.Info.Count; idxArg++)
  610. {
  611. int32 compare = TaggedInt::ToInt32(args[idxArg]);
  612. if (current < compare)
  613. {
  614. current = compare;
  615. }
  616. }
  617. return TaggedInt::ToVarUnchecked(current);
  618. }
  619. else
  620. {
  621. double current = JavascriptConversion::ToNumber(args[1], scriptContext);
  622. bool returnNaN = false;
  623. if (JavascriptNumber::IsNan(current))
  624. {
  625. returnNaN = true;
  626. }
  627. for (uint idxArg = 2; idxArg < args.Info.Count; idxArg++)
  628. {
  629. double compare = JavascriptConversion::ToNumber(args[idxArg], scriptContext);
  630. if (JavascriptNumber::IsNan(compare) || returnNaN) // Call ToNumber for all args
  631. {
  632. returnNaN = true;
  633. }
  634. // In C++, -0.0f == 0.0f; however, in ES, -0.0f < 0.0f. Thus, use additional library
  635. // call to test this comparison.
  636. else if ((compare == 0 && JavascriptNumber::IsNegZero(current)) ||
  637. current < compare)
  638. {
  639. current = compare;
  640. }
  641. }
  642. if (returnNaN)
  643. {
  644. return scriptContext->GetLibrary()->GetNaN();
  645. }
  646. return JavascriptNumber::ToVarNoCheck(current, scriptContext);
  647. }
  648. }
  649. ///----------------------------------------------------------------------------
  650. /// Min() returns the minimum of a series of numbers, as described in
  651. /// (ES5.0: S15.8.2.12):
  652. /// - Arg:0 = "this"
  653. /// - Arg:1-n = Values to compare
  654. ///----------------------------------------------------------------------------
  655. Var Math::Min(RecyclableObject* function, CallInfo callInfo, ...)
  656. {
  657. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  658. ARGUMENTS(args, callInfo);
  659. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  660. ScriptContext* scriptContext = function->GetScriptContext();
  661. bool hasOnlyIntegerArgs = false;
  662. Assert(!(callInfo.Flags & CallFlags_New));
  663. if (args.Info.Count <= 1)
  664. {
  665. return scriptContext->GetLibrary()->GetPositiveInfinite();
  666. }
  667. else if (args.Info.Count == 2)
  668. {
  669. double result = JavascriptConversion::ToNumber(args[1], scriptContext);
  670. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  671. }
  672. else
  673. {
  674. hasOnlyIntegerArgs = TaggedInt::OnlyContainsTaggedInt(args);
  675. if (hasOnlyIntegerArgs && args.Info.Count == 3)
  676. {
  677. return TaggedInt::ToVarUnchecked(min(TaggedInt::ToInt32(args[1]), TaggedInt::ToInt32(args[2])));
  678. }
  679. }
  680. if (hasOnlyIntegerArgs)
  681. {
  682. int32 current = TaggedInt::ToInt32(args[1]);
  683. for (uint idxArg = 2; idxArg < args.Info.Count; idxArg++)
  684. {
  685. int32 compare = TaggedInt::ToInt32(args[idxArg]);
  686. if (current > compare)
  687. {
  688. current = compare;
  689. }
  690. }
  691. return TaggedInt::ToVarUnchecked(current);
  692. }
  693. else
  694. {
  695. double current = JavascriptConversion::ToNumber(args[1], scriptContext);
  696. bool returnNaN = false;
  697. if (JavascriptNumber::IsNan(current))
  698. {
  699. returnNaN = true;
  700. }
  701. for (uint idxArg = 2; idxArg < args.Info.Count; idxArg++)
  702. {
  703. double compare = JavascriptConversion::ToNumber(args[idxArg], scriptContext);
  704. if (JavascriptNumber::IsNan(compare) || returnNaN) // Call ToNumber for all args
  705. {
  706. returnNaN = true;
  707. }
  708. // In C++, -0.0f == 0.0f; however, in ES, -0.0f < 0.0f. Thus, use additional library
  709. // call to test this comparison.
  710. else if ((current == 0 && JavascriptNumber::IsNegZero(compare)) ||
  711. current > compare)
  712. {
  713. current = compare;
  714. }
  715. }
  716. if (returnNaN)
  717. {
  718. return scriptContext->GetLibrary()->GetNaN();
  719. }
  720. return JavascriptNumber::ToVarNoCheck(current, scriptContext);
  721. }
  722. }
  723. ///----------------------------------------------------------------------------
  724. /// Pow() returns x ^ y, as described in (ES5.0: S15.8.2.13).
  725. ///----------------------------------------------------------------------------
  726. Var Math::Pow(RecyclableObject* function, CallInfo callInfo, ...)
  727. {
  728. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  729. ARGUMENTS(args, callInfo);
  730. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  731. ScriptContext* scriptContext = function->GetScriptContext();
  732. Assert(!(callInfo.Flags & CallFlags_New));
  733. if (args.Info.Count >= 3)
  734. {
  735. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  736. double y = JavascriptConversion::ToNumber(args[2], scriptContext);
  737. double result = Math::Pow( x, y );
  738. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  739. }
  740. else
  741. {
  742. return scriptContext->GetLibrary()->GetNaN();
  743. }
  744. }
  745. double Math::Pow( double x, double y )
  746. {
  747. double result = 0;
  748. #if defined(_M_IX86) && defined(_WIN32) // TODO: xplat support
  749. // We can't just use "if (0 == y)" because NaN compares
  750. // equal to 0 according to our compilers.
  751. if( 0 == NumberUtilities::LuLoDbl( y ) && 0 == ( NumberUtilities::LuHiDbl( y ) & 0x7FFFFFFF ) )
  752. {
  753. // Result is 1 even if x is NaN.
  754. result = 1;
  755. }
  756. else if( 1.0 == Math::Abs( x ) && !NumberUtilities::IsFinite( y ) )
  757. {
  758. result = JavascriptNumber::NaN;
  759. }
  760. else
  761. {
  762. int32 intY;
  763. // range [-8, 8] is from JavascriptNumber::DirectPowDoubleInt
  764. if (JavascriptNumber::TryGetInt32Value(y, &intY) && intY >= -8 && intY <= 8)
  765. {
  766. result = JavascriptNumber::DirectPowDoubleInt(x, intY);
  767. }
  768. else if( AutoSystemInfo::Data.SSE2Available() )
  769. {
  770. _asm {
  771. movsd xmm0, x
  772. movsd xmm1, y
  773. call dword ptr[__libm_sse2_pow]
  774. movsd result, xmm0
  775. }
  776. }
  777. else
  778. {
  779. result = ::pow( x, y );
  780. }
  781. }
  782. #else
  783. result = JavascriptNumber::DirectPow( x, y );
  784. #endif
  785. return result;
  786. }
  787. ///----------------------------------------------------------------------------
  788. /// Random() returns a random number 0 <= n < 1.0, as described in
  789. /// (ES5.0: S15.8.2.14).
  790. ///----------------------------------------------------------------------------
  791. Var Math::Random(RecyclableObject* function, CallInfo callInfo, ...)
  792. {
  793. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  794. AssertMsg(callInfo.Count > 0, "Should always have implicit 'this'");
  795. ScriptContext* scriptContext = function->GetScriptContext();
  796. Assert(!(callInfo.Flags & CallFlags_New));
  797. double res = JavascriptMath::Random(scriptContext);
  798. return JavascriptNumber::ToVarNoCheck(res, scriptContext);
  799. }
  800. ///----------------------------------------------------------------------------
  801. /// Round() returns the number value that is closest to x and is equal to an
  802. /// integer, as described in (ES5.0: S15.8.2.15).
  803. ///----------------------------------------------------------------------------
  804. Var Math::Round(RecyclableObject* function, CallInfo callInfo, ...)
  805. {
  806. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  807. ARGUMENTS(args, callInfo);
  808. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  809. ScriptContext* scriptContext = function->GetScriptContext();
  810. Assert(!(callInfo.Flags & CallFlags_New));
  811. if (args.Info.Count >= 2)
  812. {
  813. Var input = args[1];
  814. if (TaggedInt::Is(input))
  815. {
  816. return input;
  817. }
  818. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  819. if(JavascriptNumber::IsNan(x))
  820. {
  821. return scriptContext->GetLibrary()->GetNaN();
  822. }
  823. // for doubles, if x >= 2^52 or <= -2^52, x must be an integer, and adding 0.5 will overflow the
  824. // integer to the next one. Therefore, we directly return x.
  825. if (x == 0.0 || !NumberUtilities::IsFinite(x) || x >= 4503599627370496.0 || x <= -4503599627370496.0)
  826. {
  827. // 0.0 catches the -0 case...
  828. return JavascriptNumber::ToVarNoCheck(x, scriptContext);
  829. }
  830. if (x > 0 && x < 0.5) {
  831. return JavascriptNumber::ToVarNoCheck((double)Js::JavascriptNumber::k_Zero, scriptContext);
  832. }
  833. if(x < 0 && x >= -0.5)
  834. {
  835. return scriptContext->GetLibrary()->GetNegativeZero();
  836. }
  837. return Math::FloorDouble(x+0.5, scriptContext);
  838. }
  839. else
  840. {
  841. return scriptContext->GetLibrary()->GetNaN();
  842. }
  843. }
  844. ///----------------------------------------------------------------------------
  845. /// Sin() returns the sine of the given angle in radians, as described in
  846. /// (ES5.0: S15.8.2.16).
  847. ///----------------------------------------------------------------------------
  848. Var Math::Sin(RecyclableObject* function, CallInfo callInfo, ...)
  849. {
  850. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  851. ARGUMENTS(args, callInfo);
  852. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  853. ScriptContext* scriptContext = function->GetScriptContext();
  854. Assert(!(callInfo.Flags & CallFlags_New));
  855. if (args.Info.Count >= 2)
  856. {
  857. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  858. double result = Math::Sin(x);
  859. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  860. }
  861. else
  862. {
  863. return scriptContext->GetLibrary()->GetNaN();
  864. }
  865. }
  866. double Math::Sin(double x)
  867. {
  868. double result;
  869. #if defined(_M_IX86) && defined(_WIN32)
  870. // This is for perf, not for functionality
  871. // If non Win32 CRT implementation already support SSE2,
  872. // then we get most of the perf already.
  873. if (AutoSystemInfo::Data.SSE2Available())
  874. {
  875. _asm {
  876. movsd xmm0, x
  877. call dword ptr [__libm_sse2_sin]
  878. movsd result, xmm0
  879. }
  880. }
  881. else
  882. #endif
  883. {
  884. result = ::sin(x);
  885. }
  886. return result;
  887. }
  888. ///----------------------------------------------------------------------------
  889. /// Sqrt() returns the square-root of the given number, as described in
  890. /// (ES5.0: S15.8.2.17).
  891. ///----------------------------------------------------------------------------
  892. Var Math::Sqrt(RecyclableObject* function, CallInfo callInfo, ...)
  893. {
  894. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  895. ARGUMENTS(args, callInfo);
  896. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  897. ScriptContext* scriptContext = function->GetScriptContext();
  898. Assert(!(callInfo.Flags & CallFlags_New));
  899. if (args.Info.Count >= 2)
  900. {
  901. Var arg = args[1];
  902. double x = JavascriptConversion::ToNumber(arg, scriptContext);
  903. double result = ::sqrt(x);
  904. if (TaggedInt::Is(arg))
  905. {
  906. return JavascriptNumber::ToVarIntCheck(result, scriptContext);
  907. }
  908. else
  909. {
  910. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  911. }
  912. }
  913. else
  914. {
  915. return scriptContext->GetLibrary()->GetNaN();
  916. }
  917. }
  918. ///----------------------------------------------------------------------------
  919. /// Tan() returns the tangent of the given angle, in radians, as described in
  920. /// (ES5.0: S15.8.2.18).
  921. ///----------------------------------------------------------------------------
  922. Var Math::Tan(RecyclableObject* function, CallInfo callInfo, ...)
  923. {
  924. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  925. ARGUMENTS(args, callInfo);
  926. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  927. ScriptContext* scriptContext = function->GetScriptContext();
  928. Assert(!(callInfo.Flags & CallFlags_New));
  929. if (args.Info.Count >= 2)
  930. {
  931. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  932. double result = Math::Tan( x );
  933. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  934. }
  935. else
  936. {
  937. return scriptContext->GetLibrary()->GetNaN();
  938. }
  939. }
  940. double Math::Tan( double x )
  941. {
  942. double result = 0;
  943. #if defined(_M_IX86) && defined(_WIN32)
  944. // This is for perf, not for functionality
  945. // If non Win32 CRT implementation already support SSE2,
  946. // then we get most of the perf already.
  947. if( AutoSystemInfo::Data.SSE2Available() )
  948. {
  949. _asm {
  950. movsd xmm0, x
  951. call dword ptr[__libm_sse2_tan]
  952. movsd result, xmm0
  953. }
  954. }
  955. else
  956. #endif
  957. {
  958. result = ::tan( x );
  959. }
  960. return result;
  961. }
  962. ///----------------------------------------------------------------------------
  963. /// Log10() returns the base 10 logarithm of the given number, as described in
  964. /// (ES6.0: S20.2.2.21).
  965. ///----------------------------------------------------------------------------
  966. Var Math::Log10(RecyclableObject* function, CallInfo callInfo, ...)
  967. {
  968. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  969. ARGUMENTS(args, callInfo);
  970. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  971. ScriptContext* scriptContext = function->GetScriptContext();
  972. Assert(!(callInfo.Flags & CallFlags_New));
  973. CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(Math_Constructor_log10);
  974. if (args.Info.Count >= 2)
  975. {
  976. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  977. double result = Math::Log10(x);
  978. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  979. }
  980. else
  981. {
  982. return scriptContext->GetLibrary()->GetNaN();
  983. }
  984. }
  985. double Math::Log10(double x)
  986. {
  987. double result;
  988. #if defined(_M_IX86) && defined(_WIN32)
  989. // This is for perf, not for functionality
  990. // If non Win32 CRT implementation already support SSE2,
  991. // then we get most of the perf already.
  992. if (AutoSystemInfo::Data.SSE2Available())
  993. {
  994. _asm {
  995. movsd xmm0, x
  996. call dword ptr [__libm_sse2_log10]
  997. movsd result, xmm0
  998. }
  999. }
  1000. else
  1001. #endif
  1002. {
  1003. result = ::log10(x);
  1004. }
  1005. return result;
  1006. }
  1007. ///----------------------------------------------------------------------------
  1008. /// Log2() returns the base 2 logarithm of the given number, as described in
  1009. /// (ES6.0: S20.2.2.22).
  1010. ///----------------------------------------------------------------------------
  1011. Var Math::Log2(RecyclableObject* function, CallInfo callInfo, ...)
  1012. {
  1013. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1014. ARGUMENTS(args, callInfo);
  1015. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1016. ScriptContext* scriptContext = function->GetScriptContext();
  1017. Assert(!(callInfo.Flags & CallFlags_New));
  1018. CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(Math_Constructor_log2);
  1019. if (args.Info.Count >= 2)
  1020. {
  1021. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  1022. double result = Math::Log2(x, scriptContext);
  1023. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  1024. }
  1025. else
  1026. {
  1027. return scriptContext->GetLibrary()->GetNaN();
  1028. }
  1029. }
  1030. double Math::Log2(double x, ScriptContext* scriptContext)
  1031. {
  1032. #if defined(WHEN_UCRT_IS_LINKED_IN_BUILD) || !defined(_WIN32)
  1033. return ::log2( x );
  1034. #else
  1035. // TODO: THE FALLBACK IS NOT ACCURATE; Universal CRT is available on Threshold so we should never fallback but ideally we would link at build time to these APIs instead of loading them at runtime
  1036. UCrtC99MathApis* ucrtC99MathApis = scriptContext->GetThreadContext()->GetUCrtC99MathApis();
  1037. return ucrtC99MathApis->IsAvailable() ?
  1038. ucrtC99MathApis->log2(x) :
  1039. Math::Log( x ) / Math::LN2;
  1040. #endif
  1041. }
  1042. ///----------------------------------------------------------------------------
  1043. /// Log1p() returns the natural logarithm of one plus the given number, as
  1044. /// described in (ES6.0: S20.2.2.20).
  1045. ///----------------------------------------------------------------------------
  1046. Var Math::Log1p(RecyclableObject* function, CallInfo callInfo, ...)
  1047. {
  1048. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1049. ARGUMENTS(args, callInfo);
  1050. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1051. ScriptContext* scriptContext = function->GetScriptContext();
  1052. Assert(!(callInfo.Flags & CallFlags_New));
  1053. CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(Math_Constructor_log1p);
  1054. if (args.Info.Count >= 2)
  1055. {
  1056. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  1057. #if defined(WHEN_UCRT_IS_LINKED_IN_BUILD) || !defined(_WIN32)
  1058. double result = ::log1p(x);
  1059. #else
  1060. // TODO: THE FALLBACK IS NOT ACCURATE; Universal CRT is available on Threshold so we should never fallback but ideally we would link at build time to these APIs instead of loading them at runtime
  1061. UCrtC99MathApis* ucrtC99MathApis = scriptContext->GetThreadContext()->GetUCrtC99MathApis();
  1062. double result = ucrtC99MathApis->IsAvailable() ?
  1063. ucrtC99MathApis->log1p(x):
  1064. (JavascriptNumber::IsNegZero(x)) ? x : Math::Log(1.0 + x);
  1065. #endif
  1066. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  1067. }
  1068. else
  1069. {
  1070. return scriptContext->GetLibrary()->GetNaN();
  1071. }
  1072. }
  1073. ///----------------------------------------------------------------------------
  1074. /// Expm1() returns the result of subtracting one from the exponential
  1075. /// function of the given number, as described in (ES6.0: S20.2.2.14).
  1076. ///----------------------------------------------------------------------------
  1077. Var Math::Expm1(RecyclableObject* function, CallInfo callInfo, ...)
  1078. {
  1079. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1080. ARGUMENTS(args, callInfo);
  1081. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1082. ScriptContext* scriptContext = function->GetScriptContext();
  1083. Assert(!(callInfo.Flags & CallFlags_New));
  1084. CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(Math_Constructor_expm1);
  1085. if (args.Info.Count >= 2)
  1086. {
  1087. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  1088. #if defined(WHEN_UCRT_IS_LINKED_IN_BUILD) || !defined(_WIN32)
  1089. double result = ::expm1(x);
  1090. #else
  1091. // TODO: THE FALLBACK IS NOT ACCURATE; Universal CRT is available on Threshold so we should never fallback but ideally we would link at build time to these APIs instead of loading them at runtime
  1092. UCrtC99MathApis* ucrtC99MathApis = scriptContext->GetThreadContext()->GetUCrtC99MathApis();
  1093. double result = ucrtC99MathApis->IsAvailable() ?
  1094. ucrtC99MathApis->expm1(x) :
  1095. (JavascriptNumber::IsNegZero(x)) ? x : Math::Exp(x) - 1.0;
  1096. #endif
  1097. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  1098. }
  1099. else
  1100. {
  1101. return scriptContext->GetLibrary()->GetNaN();
  1102. }
  1103. }
  1104. ///----------------------------------------------------------------------------
  1105. /// Cosh() returns the hyperbolic cosine of the given number, as described in
  1106. /// (ES6.0: S20.2.2.12).
  1107. ///----------------------------------------------------------------------------
  1108. Var Math::Cosh(RecyclableObject* function, CallInfo callInfo, ...)
  1109. {
  1110. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1111. ARGUMENTS(args, callInfo);
  1112. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1113. ScriptContext* scriptContext = function->GetScriptContext();
  1114. Assert(!(callInfo.Flags & CallFlags_New));
  1115. CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(Math_Constructor_cosh);
  1116. if (args.Info.Count >= 2)
  1117. {
  1118. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  1119. double result = ::cosh(x);
  1120. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  1121. }
  1122. else
  1123. {
  1124. return scriptContext->GetLibrary()->GetNaN();
  1125. }
  1126. }
  1127. ///----------------------------------------------------------------------------
  1128. /// Sinh() returns the hyperbolic sine of the given number, as described in
  1129. /// (ES6.0: S20.2.2.30).
  1130. ///----------------------------------------------------------------------------
  1131. Var Math::Sinh(RecyclableObject* function, CallInfo callInfo, ...)
  1132. {
  1133. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1134. ARGUMENTS(args, callInfo);
  1135. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1136. ScriptContext* scriptContext = function->GetScriptContext();
  1137. Assert(!(callInfo.Flags & CallFlags_New));
  1138. CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(Math_Constructor_sinh);
  1139. if (args.Info.Count >= 2)
  1140. {
  1141. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  1142. double result = ::sinh(x);
  1143. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  1144. }
  1145. else
  1146. {
  1147. return scriptContext->GetLibrary()->GetNaN();
  1148. }
  1149. }
  1150. ///----------------------------------------------------------------------------
  1151. /// Tanh() returns the hyperbolic tangent of the given number, as described in
  1152. /// (ES6.0: S20.2.2.33).
  1153. ///----------------------------------------------------------------------------
  1154. Var Math::Tanh(RecyclableObject* function, CallInfo callInfo, ...)
  1155. {
  1156. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1157. ARGUMENTS(args, callInfo);
  1158. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1159. ScriptContext* scriptContext = function->GetScriptContext();
  1160. Assert(!(callInfo.Flags & CallFlags_New));
  1161. CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(Math_Constructor_tanh);
  1162. if (args.Info.Count >= 2)
  1163. {
  1164. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  1165. double result = ::tanh(x);
  1166. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  1167. }
  1168. else
  1169. {
  1170. return scriptContext->GetLibrary()->GetNaN();
  1171. }
  1172. }
  1173. ///----------------------------------------------------------------------------
  1174. /// Acosh() returns the inverse hyperbolic cosine of the given number, as
  1175. /// described in (ES6.0: S20.2.2.3).
  1176. ///----------------------------------------------------------------------------
  1177. Var Math::Acosh(RecyclableObject* function, CallInfo callInfo, ...)
  1178. {
  1179. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1180. ARGUMENTS(args, callInfo);
  1181. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1182. ScriptContext* scriptContext = function->GetScriptContext();
  1183. Assert(!(callInfo.Flags & CallFlags_New));
  1184. CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(Math_Constructor_acosh);
  1185. if (args.Info.Count >= 2)
  1186. {
  1187. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  1188. #if defined(WHEN_UCRT_IS_LINKED_IN_BUILD) || !defined(_WIN32)
  1189. double result = ::acosh(x);
  1190. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  1191. #else
  1192. // TODO: THE FALLBACK IS NOT ACCURATE; Universal CRT is available on Threshold so we should never fallback but ideally we would link at build time to these APIs instead of loading them at runtime
  1193. UCrtC99MathApis* ucrtC99MathApis = scriptContext->GetThreadContext()->GetUCrtC99MathApis();
  1194. if (ucrtC99MathApis->IsAvailable())
  1195. {
  1196. return JavascriptNumber::ToVarNoCheck(ucrtC99MathApis->acosh(x), scriptContext);
  1197. }
  1198. else if (x >= 1.0)
  1199. {
  1200. // Can be smarter about large values of x, e.g. as x -> Infinity, sqrt(x^2 - 1) -> x
  1201. // Therefore for large x, log(x+x) is sufficient, but how to decide what a large x is?
  1202. // Also ln(x+x) = ln 2x = ln 2 + ln x
  1203. double result = (x == 1.0) ? 0.0 : Math::Log(x + ::sqrt(x*x - 1.0));
  1204. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  1205. }
  1206. else
  1207. {
  1208. return scriptContext->GetLibrary()->GetNaN();
  1209. }
  1210. #endif
  1211. }
  1212. else
  1213. {
  1214. return scriptContext->GetLibrary()->GetNaN();
  1215. }
  1216. }
  1217. ///----------------------------------------------------------------------------
  1218. /// Asinh() returns the inverse hyperbolic sine of the given number, as
  1219. /// described in (ES6.0: S20.2.2.5).
  1220. ///----------------------------------------------------------------------------
  1221. Var Math::Asinh(RecyclableObject* function, CallInfo callInfo, ...)
  1222. {
  1223. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1224. ARGUMENTS(args, callInfo);
  1225. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1226. ScriptContext* scriptContext = function->GetScriptContext();
  1227. Assert(!(callInfo.Flags & CallFlags_New));
  1228. CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(Math_Constructor_asinh);
  1229. if (args.Info.Count >= 2)
  1230. {
  1231. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  1232. #if defined(WHEN_UCRT_IS_LINKED_IN_BUILD) || !defined(_WIN32)
  1233. double result = ::asinh(x);
  1234. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  1235. #else
  1236. // TODO: THE FALLBACK IS NOT ACCURATE; Universal CRT is available on Threshold so we should never fallback but ideally we would link at build time to these APIs instead of loading them at runtime
  1237. UCrtC99MathApis* ucrtC99MathApis = scriptContext->GetThreadContext()->GetUCrtC99MathApis();
  1238. if (ucrtC99MathApis->IsAvailable())
  1239. {
  1240. return JavascriptNumber::ToVarNoCheck(ucrtC99MathApis->asinh(x), scriptContext);
  1241. }
  1242. else
  1243. {
  1244. double result = JavascriptNumber::IsNegZero(x) ? x :
  1245. JavascriptNumber::IsPosInf(x) ? JavascriptNumber::POSITIVE_INFINITY :
  1246. JavascriptNumber::IsNegInf(x) ? JavascriptNumber::NEGATIVE_INFINITY :
  1247. Math::Log(x + ::sqrt(x*x + 1.0));
  1248. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  1249. }
  1250. #endif
  1251. }
  1252. else
  1253. {
  1254. return scriptContext->GetLibrary()->GetNaN();
  1255. }
  1256. }
  1257. ///----------------------------------------------------------------------------
  1258. /// Atanh() returns the inverse hyperbolic tangent of the given number, as
  1259. /// described in (ES6.0: S20.2.2.7).
  1260. ///----------------------------------------------------------------------------
  1261. Var Math::Atanh(RecyclableObject* function, CallInfo callInfo, ...)
  1262. {
  1263. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1264. ARGUMENTS(args, callInfo);
  1265. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1266. ScriptContext* scriptContext = function->GetScriptContext();
  1267. Assert(!(callInfo.Flags & CallFlags_New));
  1268. CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(Math_Constructor_atanh);
  1269. if (args.Info.Count >= 2)
  1270. {
  1271. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  1272. #if defined(WHEN_UCRT_IS_LINKED_IN_BUILD) || !defined(_WIN32)
  1273. double result = ::atanh(x);
  1274. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  1275. #else
  1276. // TODO: THE FALLBACK IS NOT ACCURATE; Universal CRT is available on Threshold so we should never fallback but ideally we would link at build time to these APIs instead of loading them at runtime
  1277. UCrtC99MathApis* ucrtC99MathApis = scriptContext->GetThreadContext()->GetUCrtC99MathApis();
  1278. if (ucrtC99MathApis->IsAvailable())
  1279. {
  1280. return JavascriptNumber::ToVarNoCheck(ucrtC99MathApis->atanh(x), scriptContext);
  1281. }
  1282. else if (Math::Abs(x) < 1.0)
  1283. {
  1284. double result = (JavascriptNumber::IsNegZero(x)) ? x : Math::Log((1.0 + x) / (1.0 - x)) / 2.0;
  1285. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  1286. }
  1287. else
  1288. {
  1289. if (x == -1.0)
  1290. {
  1291. return scriptContext->GetLibrary()->GetNegativeInfinite();
  1292. }
  1293. else if (x == 1.0)
  1294. {
  1295. return scriptContext->GetLibrary()->GetPositiveInfinite();
  1296. }
  1297. return scriptContext->GetLibrary()->GetNaN();
  1298. }
  1299. #endif
  1300. }
  1301. else
  1302. {
  1303. return scriptContext->GetLibrary()->GetNaN();
  1304. }
  1305. }
  1306. ///----------------------------------------------------------------------------
  1307. /// Hypot() returns the square root of the sum of squares of the two or three
  1308. /// given numbers, as described in (ES6.0: S20.2.2.17).
  1309. ///----------------------------------------------------------------------------
  1310. Var Math::Hypot(RecyclableObject* function, CallInfo callInfo, ...)
  1311. {
  1312. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1313. ARGUMENTS(args, callInfo);
  1314. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1315. ScriptContext* scriptContext = function->GetScriptContext();
  1316. Assert(!(callInfo.Flags & CallFlags_New));
  1317. CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(Math_Constructor_hypot);
  1318. // ES6 20.2.2.18 Math.hypot(value1, value2, ...values)
  1319. // If no arguments are passed, the result is +0.
  1320. // If any argument is +Infinity, the result is +Infinity.
  1321. // If any argument is -Infinity, the result is +Infinity.
  1322. // If no argument is +Infinity or -Infinity, and any argument is NaN, the result is NaN.
  1323. // If all arguments are either +0 or -0, the result is +0.
  1324. double result = JavascriptNumber::k_Zero; // If there are no arguments return value is positive zero.
  1325. if (args.Info.Count == 2)
  1326. {
  1327. // Special case for one argument
  1328. double x1 = JavascriptConversion::ToNumber(args[1], scriptContext);
  1329. if (JavascriptNumber::IsPosInf(x1) || JavascriptNumber::IsNegInf(x1))
  1330. {
  1331. result = JavascriptNumber::POSITIVE_INFINITY;
  1332. }
  1333. else
  1334. {
  1335. result = Math::Abs(x1);
  1336. }
  1337. }
  1338. else if (args.Info.Count == 3)
  1339. {
  1340. // CRT hypot call
  1341. double x1 = JavascriptConversion::ToNumber(args[1], scriptContext);
  1342. double x2 = JavascriptConversion::ToNumber(args[2], scriptContext);
  1343. if (JavascriptNumber::IsPosInf(x1) || JavascriptNumber::IsNegInf(x1) ||
  1344. JavascriptNumber::IsPosInf(x2) || JavascriptNumber::IsNegInf(x2))
  1345. {
  1346. result = JavascriptNumber::POSITIVE_INFINITY;
  1347. }
  1348. else if (JavascriptNumber::IsNan(x1) || JavascriptNumber::IsNan(x2))
  1349. {
  1350. result = JavascriptNumber::NaN;
  1351. }
  1352. else
  1353. {
  1354. result = ::hypot(x1, x2);
  1355. }
  1356. }
  1357. else if (args.Info.Count > 3)
  1358. {
  1359. // Uncommon case of more than 2 arguments for hypot
  1360. result = Math::HypotHelper(args, scriptContext);
  1361. }
  1362. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  1363. }
  1364. double Math::HypotHelper(Arguments args, ScriptContext *scriptContext)
  1365. {
  1366. // CRT does not have a multiple version of hypot, so we implement it here ourselves.
  1367. bool foundNaN = false;
  1368. double scale = 0;
  1369. double sum = 0;
  1370. //Ignore first argument which is this pointer
  1371. for (uint counter = 1; counter < args.Info.Count; counter++)
  1372. {
  1373. double doubleVal = JavascriptConversion::ToNumber(args[counter], scriptContext);
  1374. if (JavascriptNumber::IsPosInf(doubleVal) || JavascriptNumber::IsNegInf(doubleVal))
  1375. {
  1376. return JavascriptNumber::POSITIVE_INFINITY;
  1377. }
  1378. if (!foundNaN)
  1379. {
  1380. if (JavascriptNumber::IsNan(doubleVal))
  1381. {
  1382. //Even though we found NaN, we still need to validate none of the other arguments are +Infinity or -Infinity
  1383. foundNaN = true;
  1384. }
  1385. else
  1386. {
  1387. doubleVal = Math::Abs(doubleVal);
  1388. if (scale < doubleVal)
  1389. {
  1390. sum = sum * (scale / doubleVal) * (scale / doubleVal) + 1; /* scale/scale === 1*/
  1391. //change the scale to new max value
  1392. scale = doubleVal;
  1393. }
  1394. else if (scale != 0)
  1395. {
  1396. sum += (doubleVal / scale) * (doubleVal / scale);
  1397. }
  1398. }
  1399. }
  1400. }
  1401. if (foundNaN)
  1402. {
  1403. return JavascriptNumber::NaN;
  1404. }
  1405. return scale * ::sqrt(sum);
  1406. }
  1407. ///----------------------------------------------------------------------------
  1408. /// Trunc() returns the integral part of the given number, removing any
  1409. /// fractional digits, as described in (ES6.0: S20.2.2.34).
  1410. ///----------------------------------------------------------------------------
  1411. Var Math::Trunc(RecyclableObject* function, CallInfo callInfo, ...)
  1412. {
  1413. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1414. ARGUMENTS(args, callInfo);
  1415. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1416. ScriptContext* scriptContext = function->GetScriptContext();
  1417. Assert(!(callInfo.Flags & CallFlags_New));
  1418. CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(Math_Constructor_trunc);
  1419. if (args.Info.Count >= 2)
  1420. {
  1421. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  1422. #if defined(WHEN_UCRT_IS_LINKED_IN_BUILD) || !defined(_WIN32)
  1423. double result = ::trunc(x);
  1424. #else
  1425. // TODO: THE FALLBACK IS NOT ACCURATE; Universal CRT is available on Threshold so we should never fallback but ideally we would link at build time to these APIs instead of loading them at runtime
  1426. UCrtC99MathApis* ucrtC99MathApis = scriptContext->GetThreadContext()->GetUCrtC99MathApis();
  1427. double result = ucrtC99MathApis->IsAvailable() ?
  1428. ucrtC99MathApis->trunc(x) :
  1429. (x < 0.0) ? ::ceil(x) : ::floor(x);
  1430. #endif
  1431. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  1432. }
  1433. else
  1434. {
  1435. return scriptContext->GetLibrary()->GetNaN();
  1436. }
  1437. }
  1438. ///----------------------------------------------------------------------------
  1439. /// Sign() returns the sign of the given number, indicating whether it is
  1440. /// positive, negative, or zero, as described in (ES6.0: S20.2.2.28).
  1441. ///----------------------------------------------------------------------------
  1442. Var Math::Sign(RecyclableObject* function, CallInfo callInfo, ...)
  1443. {
  1444. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1445. ARGUMENTS(args, callInfo);
  1446. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1447. ScriptContext* scriptContext = function->GetScriptContext();
  1448. Assert(!(callInfo.Flags & CallFlags_New));
  1449. CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(Math_Constructor_sign);
  1450. if (args.Info.Count >= 2)
  1451. {
  1452. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  1453. if (JavascriptNumber::IsNan(x))
  1454. {
  1455. return scriptContext->GetLibrary()->GetNaN();
  1456. }
  1457. else if (JavascriptNumber::IsNegZero(x))
  1458. {
  1459. return scriptContext->GetLibrary()->GetNegativeZero();
  1460. }
  1461. else
  1462. {
  1463. return TaggedInt::ToVarUnchecked(x == 0.0 ? 0 : x < 0.0 ? -1 : 1);
  1464. }
  1465. }
  1466. else
  1467. {
  1468. return scriptContext->GetLibrary()->GetNaN();
  1469. }
  1470. }
  1471. ///----------------------------------------------------------------------------
  1472. /// Cbrt() returns the cube root of the given number, as described in
  1473. /// (ES6.0: S20.2.2.9).
  1474. ///----------------------------------------------------------------------------
  1475. Var Math::Cbrt(RecyclableObject* function, CallInfo callInfo, ...)
  1476. {
  1477. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1478. ARGUMENTS(args, callInfo);
  1479. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1480. ScriptContext* scriptContext = function->GetScriptContext();
  1481. Assert(!(callInfo.Flags & CallFlags_New));
  1482. CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(Math_Constructor_cbrt);
  1483. if (args.Info.Count >= 2)
  1484. {
  1485. double x = JavascriptConversion::ToNumber(args[1], scriptContext);
  1486. #if defined(WHEN_UCRT_IS_LINKED_IN_BUILD) || !defined(_WIN32)
  1487. double result = ::cbrt(x);
  1488. #else
  1489. // TODO: THE FALLBACK IS NOT ACCURATE; Universal CRT is available on Threshold so we should never fallback but ideally we would link at build time to these APIs instead of loading them at runtime
  1490. UCrtC99MathApis* ucrtC99MathApis = scriptContext->GetThreadContext()->GetUCrtC99MathApis();
  1491. if (ucrtC99MathApis->IsAvailable())
  1492. {
  1493. return JavascriptNumber::ToVarNoCheck(ucrtC99MathApis->cbrt(x), scriptContext);
  1494. }
  1495. bool isNeg = x < 0.0;
  1496. if (isNeg)
  1497. {
  1498. x = -x;
  1499. }
  1500. double result = (x == 0.0) ? x : Math::Exp(Math::Log(x) / 3.0);
  1501. if (isNeg)
  1502. {
  1503. result = -result;
  1504. }
  1505. #endif
  1506. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  1507. }
  1508. else
  1509. {
  1510. return scriptContext->GetLibrary()->GetNaN();
  1511. }
  1512. }
  1513. ///----------------------------------------------------------------------------
  1514. /// Imul() returns the 32-bit integer multiplication of two given numbers, as
  1515. /// described in (ES6.0: S20.2.2.18).
  1516. ///----------------------------------------------------------------------------
  1517. Var Math::Imul(RecyclableObject* function, CallInfo callInfo, ...)
  1518. {
  1519. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1520. ARGUMENTS(args, callInfo);
  1521. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1522. ScriptContext* scriptContext = function->GetScriptContext();
  1523. Assert(!(callInfo.Flags & CallFlags_New));
  1524. CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(Math_Constructor_imul);
  1525. if (args.Info.Count >= 3)
  1526. {
  1527. int32 x = JavascriptConversion::ToInt32(args[1], scriptContext);
  1528. int32 y = JavascriptConversion::ToInt32(args[2], scriptContext);
  1529. int64 int64Result = (int64)x * (int64)y;
  1530. int32 result = (int32)int64Result;
  1531. return JavascriptNumber::ToVar(result, scriptContext);
  1532. }
  1533. else
  1534. {
  1535. // The arguments, if left unspecified default to undefined, and ToUint32(undefined) produces +0.
  1536. // Therefore we return +0, not NaN here like the other Math functions.
  1537. return TaggedInt::ToVarUnchecked(0);
  1538. }
  1539. }
  1540. ///----------------------------------------------------------------------------
  1541. /// Clz32() returns the leading number of zero bits of ToUint32(x), as
  1542. /// described in (ES6.0: S20.2.2.11).
  1543. ///----------------------------------------------------------------------------
  1544. Var Math::Clz32(RecyclableObject* function, CallInfo callInfo, ...)
  1545. {
  1546. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1547. ARGUMENTS(args, callInfo);
  1548. ScriptContext* scriptContext = function->GetScriptContext();
  1549. Var value = args.Info.Count > 1 ? args[1] : scriptContext->GetLibrary()->GetUndefined();
  1550. Assert(!(callInfo.Flags & CallFlags_New));
  1551. CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(Math_Constructor_clz32);
  1552. uint32 uint32value = JavascriptConversion::ToUInt32(value, scriptContext);
  1553. DWORD index;
  1554. if (!_BitScanReverse(&index, uint32value))
  1555. {
  1556. return TaggedInt::ToVarUnchecked(32);
  1557. }
  1558. return TaggedInt::ToVarUnchecked(31 - index);
  1559. }
  1560. Var Math::Fround(RecyclableObject* function, CallInfo callInfo, ...)
  1561. {
  1562. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1563. ARGUMENTS(args, callInfo);
  1564. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1565. ScriptContext* scriptContext = function->GetScriptContext();
  1566. Assert(!(callInfo.Flags & CallFlags_New));
  1567. CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(Math_Constructor_fround);
  1568. if (args.Info.Count >= 2)
  1569. {
  1570. float x = (float) JavascriptConversion::ToNumber(args[1], scriptContext);
  1571. return JavascriptNumber::ToVarNoCheck((double) x, scriptContext);
  1572. }
  1573. else
  1574. {
  1575. return scriptContext->GetLibrary()->GetNaN();
  1576. }
  1577. }
  1578. } // namespace Js