JavascriptMath.cpp 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152
  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. namespace Js
  6. {
  7. Var JavascriptMath::Negate_Full(Var aRight, ScriptContext* scriptContext)
  8. {
  9. // Special case for zero. Must return -0
  10. if( aRight == TaggedInt::ToVarUnchecked(0) )
  11. {
  12. return scriptContext->GetLibrary()->GetNegativeZero();
  13. }
  14. double value = Negate_Helper(aRight, scriptContext);
  15. return JavascriptNumber::ToVarNoCheck(value, scriptContext);
  16. }
  17. Var JavascriptMath::Negate_InPlace(Var aRight, ScriptContext* scriptContext, JavascriptNumber* result)
  18. {
  19. // Special case for zero. Must return -0
  20. if( aRight == TaggedInt::ToVarUnchecked(0) )
  21. {
  22. return scriptContext->GetLibrary()->GetNegativeZero();
  23. }
  24. double value = Negate_Helper(aRight, scriptContext);
  25. return JavascriptNumber::InPlaceNew(value, scriptContext, result);
  26. }
  27. Var JavascriptMath::Not_Full(Var aRight, ScriptContext* scriptContext)
  28. {
  29. #if _M_IX86
  30. AssertMsg(!TaggedInt::Is(aRight), "Should be detected");
  31. #endif
  32. int nValue = JavascriptConversion::ToInt32(aRight, scriptContext);
  33. return JavascriptNumber::ToVar(~nValue, scriptContext);
  34. }
  35. Var JavascriptMath::Not_InPlace(Var aRight, ScriptContext* scriptContext, JavascriptNumber* result)
  36. {
  37. AssertMsg(!TaggedInt::Is(aRight), "Should be detected");
  38. int nValue = JavascriptConversion::ToInt32(aRight, scriptContext);
  39. return JavascriptNumber::ToVarInPlace(~nValue, scriptContext, result);
  40. }
  41. Var JavascriptMath::Increment_InPlace(Var aRight, ScriptContext* scriptContext, JavascriptNumber* result)
  42. {
  43. if (TaggedInt::Is(aRight))
  44. {
  45. return TaggedInt::Increment(aRight, scriptContext);
  46. }
  47. double inc = Increment_Helper(aRight, scriptContext);
  48. return JavascriptNumber::InPlaceNew(inc, scriptContext, result);
  49. }
  50. Var JavascriptMath::Increment_Full(Var aRight, ScriptContext* scriptContext)
  51. {
  52. if (TaggedInt::Is(aRight))
  53. {
  54. return TaggedInt::Increment(aRight, scriptContext);
  55. }
  56. double inc = Increment_Helper(aRight, scriptContext);
  57. return JavascriptNumber::ToVarNoCheck(inc, scriptContext);
  58. }
  59. Var JavascriptMath::Decrement_InPlace(Var aRight, ScriptContext* scriptContext, JavascriptNumber* result)
  60. {
  61. if (TaggedInt::Is(aRight))
  62. {
  63. return TaggedInt::Decrement(aRight, scriptContext);
  64. }
  65. double dec = Decrement_Helper(aRight,scriptContext);
  66. return JavascriptNumber::InPlaceNew(dec, scriptContext, result);
  67. }
  68. Var JavascriptMath::Decrement_Full(Var aRight, ScriptContext* scriptContext)
  69. {
  70. if (TaggedInt::Is(aRight))
  71. {
  72. return TaggedInt::Decrement(aRight, scriptContext);
  73. }
  74. double dec = Decrement_Helper(aRight,scriptContext);
  75. return JavascriptNumber::ToVarNoCheck(dec, scriptContext);
  76. }
  77. Var JavascriptMath::And_Full(Var aLeft, Var aRight, ScriptContext* scriptContext)
  78. {
  79. int32 value = And_Helper(aLeft, aRight, scriptContext);
  80. return JavascriptNumber::ToVar(value, scriptContext);
  81. }
  82. Var JavascriptMath::And_InPlace(Var aLeft, Var aRight, ScriptContext* scriptContext, JavascriptNumber* result)
  83. {
  84. int32 value = And_Helper(aLeft, aRight, scriptContext);
  85. return JavascriptNumber::ToVarInPlace(value, scriptContext, result);
  86. }
  87. Var JavascriptMath::Or_Full(Var aLeft, Var aRight, ScriptContext* scriptContext)
  88. {
  89. int32 value = Or_Helper(aLeft, aRight, scriptContext);
  90. return JavascriptNumber::ToVar(value, scriptContext);
  91. }
  92. Var JavascriptMath::Or_InPlace(Var aLeft, Var aRight, ScriptContext* scriptContext, JavascriptNumber* result)
  93. {
  94. int32 value = Or_Helper(aLeft, aRight, scriptContext);
  95. return JavascriptNumber::ToVarInPlace(value, scriptContext, result);
  96. }
  97. Var JavascriptMath::Xor_Full(Var aLeft, Var aRight, ScriptContext* scriptContext)
  98. {
  99. int32 nLeft = TaggedInt::Is(aLeft) ? TaggedInt::ToInt32(aLeft) : JavascriptConversion::ToInt32(aLeft, scriptContext);
  100. int32 nRight = TaggedInt::Is(aRight) ? TaggedInt::ToInt32(aRight) : JavascriptConversion::ToInt32(aRight, scriptContext);
  101. return JavascriptNumber::ToVar(nLeft ^ nRight,scriptContext);
  102. }
  103. Var JavascriptMath::Xor_InPlace(Var aLeft, Var aRight, ScriptContext* scriptContext, JavascriptNumber* result)
  104. {
  105. int32 nLeft = TaggedInt::Is(aLeft) ? TaggedInt::ToInt32(aLeft) : JavascriptConversion::ToInt32(aLeft, scriptContext);
  106. int32 nRight = TaggedInt::Is(aRight) ? TaggedInt::ToInt32(aRight) : JavascriptConversion::ToInt32(aRight, scriptContext);
  107. return JavascriptNumber::ToVarInPlace(nLeft ^ nRight, scriptContext, result);
  108. }
  109. Var JavascriptMath::ShiftLeft_Full(Var aLeft, Var aRight, ScriptContext* scriptContext)
  110. {
  111. int32 nValue = JavascriptConversion::ToInt32(aLeft, scriptContext);
  112. uint32 nShift = JavascriptConversion::ToUInt32(aRight, scriptContext);
  113. int32 nResult = nValue << (nShift & 0x1F);
  114. return JavascriptNumber::ToVar(nResult,scriptContext);
  115. }
  116. Var JavascriptMath::ShiftRight_Full(Var aLeft, Var aRight, ScriptContext* scriptContext)
  117. {
  118. int32 nValue = JavascriptConversion::ToInt32(aLeft, scriptContext);
  119. uint32 nShift = JavascriptConversion::ToUInt32(aRight, scriptContext);
  120. int32 nResult = nValue >> (nShift & 0x1F);
  121. return JavascriptNumber::ToVar(nResult,scriptContext);
  122. }
  123. Var JavascriptMath::ShiftRightU_Full(Var aLeft, Var aRight, ScriptContext* scriptContext)
  124. {
  125. uint32 nValue = JavascriptConversion::ToUInt32(aLeft, scriptContext);
  126. uint32 nShift = JavascriptConversion::ToUInt32(aRight, scriptContext);
  127. uint32 nResult = nValue >> (nShift & 0x1F);
  128. return JavascriptNumber::ToVar(nResult,scriptContext);
  129. }
  130. #if FLOATVAR
  131. Var JavascriptMath::Add_Full(Var aLeft, Var aRight, ScriptContext* scriptContext)
  132. {
  133. Assert(aLeft != nullptr);
  134. Assert(aRight != nullptr);
  135. Assert(scriptContext != nullptr);
  136. Js::TypeId typeLeft = JavascriptOperators::GetTypeId(aLeft);
  137. Js::TypeId typeRight = JavascriptOperators::GetTypeId(aRight);
  138. if (typeRight == typeLeft)
  139. {
  140. // If both sides are numbers/string, then we can do the addition directly
  141. if(typeLeft == TypeIds_Number)
  142. {
  143. double sum = JavascriptNumber::GetValue(aLeft) + JavascriptNumber::GetValue(aRight);
  144. return JavascriptNumber::ToVarNoCheck(sum, scriptContext);
  145. }
  146. else if (typeLeft == TypeIds_Integer)
  147. {
  148. __int64 sum = TaggedInt::ToInt64(aLeft) + TaggedInt::ToInt64(aRight);
  149. return JavascriptNumber::ToVar(sum, scriptContext);
  150. }
  151. else if (typeLeft == TypeIds_String)
  152. {
  153. return JavascriptString::Concat(JavascriptString::UnsafeFromVar(aLeft), JavascriptString::UnsafeFromVar(aRight));
  154. }
  155. }
  156. else if(typeLeft == TypeIds_Number && typeRight == TypeIds_Integer)
  157. {
  158. double sum = JavascriptNumber::GetValue(aLeft) + TaggedInt::ToDouble(aRight);
  159. return JavascriptNumber::ToVarNoCheck(sum, scriptContext);
  160. }
  161. else if(typeLeft == TypeIds_Integer && typeRight == TypeIds_Number)
  162. {
  163. double sum = TaggedInt::ToDouble(aLeft) + JavascriptNumber::GetValue(aRight);
  164. return JavascriptNumber::ToVarNoCheck(sum, scriptContext);
  165. }
  166. return Add_FullHelper_Wrapper(aLeft, aRight, scriptContext, nullptr, false);
  167. }
  168. #else
  169. Var JavascriptMath::Add_Full(Var aLeft, Var aRight, ScriptContext* scriptContext)
  170. {
  171. Assert(aLeft != nullptr);
  172. Assert(aRight != nullptr);
  173. Assert(scriptContext != nullptr);
  174. Js::TypeId typeLeft = JavascriptOperators::GetTypeId(aLeft);
  175. Js::TypeId typeRight = JavascriptOperators::GetTypeId(aRight);
  176. // Handle combinations of TaggedInt and Number or String pairs directly,
  177. // otherwise call the helper.
  178. switch( typeLeft )
  179. {
  180. case TypeIds_Integer:
  181. {
  182. switch( typeRight )
  183. {
  184. case TypeIds_Integer:
  185. {
  186. // Compute the sum using integer addition, then convert to double.
  187. // That way there's only one int->float conversion.
  188. #if INT32VAR
  189. int64 sum = TaggedInt::ToInt64(aLeft) + TaggedInt::ToInt64(aRight);
  190. #else
  191. int32 sum = TaggedInt::ToInt32(aLeft) + TaggedInt::ToInt32(aRight);
  192. #endif
  193. return JavascriptNumber::ToVar(sum, scriptContext );
  194. }
  195. case TypeIds_Number:
  196. {
  197. double sum = TaggedInt::ToDouble(aLeft) + JavascriptNumber::GetValue(aRight);
  198. return JavascriptNumber::NewInlined( sum, scriptContext );
  199. }
  200. }
  201. break;
  202. }
  203. case TypeIds_Number:
  204. {
  205. switch( typeRight )
  206. {
  207. case TypeIds_Integer:
  208. {
  209. double sum = JavascriptNumber::GetValue(aLeft) + TaggedInt::ToDouble(aRight);
  210. return JavascriptNumber::NewInlined( sum, scriptContext );
  211. }
  212. case TypeIds_Number:
  213. {
  214. double sum = JavascriptNumber::GetValue(aLeft) + JavascriptNumber::GetValue(aRight);
  215. return JavascriptNumber::NewInlined( sum, scriptContext );
  216. }
  217. }
  218. break;
  219. }
  220. case TypeIds_String:
  221. {
  222. if( typeRight == TypeIds_String )
  223. {
  224. JavascriptString* leftString = JavascriptString::UnsafeFromVar(aLeft);
  225. JavascriptString* rightString = JavascriptString::UnsafeFromVar(aRight);
  226. return JavascriptString::Concat(leftString, rightString);
  227. }
  228. break;
  229. }
  230. }
  231. return Add_FullHelper_Wrapper(aLeft, aRight, scriptContext, nullptr, false);
  232. }
  233. #endif
  234. Var JavascriptMath::Add_InPlace(Var aLeft, Var aRight, ScriptContext* scriptContext, JavascriptNumber* result)
  235. {
  236. Assert(aLeft != nullptr);
  237. Assert(aRight != nullptr);
  238. Assert(scriptContext != nullptr);
  239. Assert(result != nullptr);
  240. // If both sides are numbers, then we can do the addition directly, otherwise
  241. // we need to call the helper.
  242. if( TaggedInt::Is(aLeft) )
  243. {
  244. if( TaggedInt::Is(aRight) )
  245. {
  246. // Compute the sum using integer addition, then convert to double.
  247. // That way there's only one int->float conversion.
  248. #if INT32VAR
  249. int64 sum = TaggedInt::ToInt64(aLeft) + TaggedInt::ToInt64(aRight);
  250. #else
  251. int32 sum = TaggedInt::ToInt32(aLeft) + TaggedInt::ToInt32(aRight);
  252. #endif
  253. return JavascriptNumber::ToVarInPlace(sum, scriptContext, result);
  254. }
  255. else if( JavascriptNumber::Is_NoTaggedIntCheck(aRight) )
  256. {
  257. double sum = TaggedInt::ToDouble(aLeft) + JavascriptNumber::GetValue(aRight);
  258. return JavascriptNumber::InPlaceNew( sum, scriptContext, result );
  259. }
  260. }
  261. else if( TaggedInt::Is(aRight) )
  262. {
  263. if( JavascriptNumber::Is_NoTaggedIntCheck(aLeft) )
  264. {
  265. double sum = JavascriptNumber::GetValue(aLeft) + TaggedInt::ToDouble(aRight);
  266. return JavascriptNumber::InPlaceNew( sum, scriptContext, result );
  267. }
  268. }
  269. else if( JavascriptNumber::Is_NoTaggedIntCheck(aLeft) && JavascriptNumber::Is_NoTaggedIntCheck(aRight) )
  270. {
  271. double sum = JavascriptNumber::GetValue(aLeft) + JavascriptNumber::GetValue(aRight);
  272. return JavascriptNumber::InPlaceNew( sum, scriptContext, result );
  273. }
  274. return Add_FullHelper_Wrapper(aLeft, aRight, scriptContext, result, false);
  275. }
  276. Var JavascriptMath::AddLeftDead(Var aLeft, Var aRight, ScriptContext* scriptContext, JavascriptNumber *result)
  277. {
  278. if (JavascriptOperators::GetTypeId(aLeft) == TypeIds_String)
  279. {
  280. JavascriptString* leftString = JavascriptString::UnsafeFromVar(aLeft);
  281. JavascriptString* rightString;
  282. TypeId rightType = JavascriptOperators::GetTypeId(aRight);
  283. switch(rightType)
  284. {
  285. case TypeIds_String:
  286. rightString = JavascriptString::UnsafeFromVar(aRight);
  287. StringCommon:
  288. return leftString->ConcatDestructive(rightString);
  289. case TypeIds_Integer:
  290. rightString = scriptContext->GetIntegerString(aRight);
  291. goto StringCommon;
  292. case TypeIds_Number:
  293. rightString = JavascriptNumber::ToStringRadix10(JavascriptNumber::GetValue(aRight), scriptContext);
  294. goto StringCommon;
  295. }
  296. }
  297. if (TaggedInt::Is(aLeft))
  298. {
  299. if (TaggedInt::Is(aRight))
  300. {
  301. return TaggedInt::Add(aLeft, aRight, scriptContext);
  302. }
  303. else if (JavascriptNumber::Is_NoTaggedIntCheck(aRight))
  304. {
  305. return JavascriptNumber::ToVarMaybeInPlace(TaggedInt::ToDouble(aLeft) + JavascriptNumber::GetValue(aRight), scriptContext, result);
  306. }
  307. }
  308. else if (TaggedInt::Is(aRight))
  309. {
  310. if (JavascriptNumber::Is_NoTaggedIntCheck(aLeft))
  311. {
  312. return JavascriptNumber::ToVarMaybeInPlace(JavascriptNumber::GetValue(aLeft) + TaggedInt::ToDouble(aRight), scriptContext, result);
  313. }
  314. }
  315. else if (JavascriptNumber::Is_NoTaggedIntCheck(aLeft) && JavascriptNumber::Is_NoTaggedIntCheck(aRight))
  316. {
  317. return JavascriptNumber::ToVarMaybeInPlace(JavascriptNumber::GetValue(aLeft) + JavascriptNumber::GetValue(aRight), scriptContext, result);
  318. }
  319. return Add_FullHelper_Wrapper(aLeft, aRight, scriptContext, result, true);
  320. }
  321. Var JavascriptMath::Add_FullHelper_Wrapper(Var aLeft, Var aRight, ScriptContext* scriptContext, JavascriptNumber* result, bool leftIsDead)
  322. {
  323. Var aLeftToPrim = JavascriptConversion::ToPrimitive<JavascriptHint::None>(aLeft, scriptContext);
  324. Var aRightToPrim = JavascriptConversion::ToPrimitive<JavascriptHint::None>(aRight, scriptContext);
  325. return Add_FullHelper(aLeftToPrim, aRightToPrim, scriptContext, result, leftIsDead);
  326. }
  327. Var JavascriptMath::Add_FullHelper(Var primLeft, Var primRight, ScriptContext* scriptContext, JavascriptNumber *result, bool leftIsDead)
  328. {
  329. // If either side is a string, then the result is also a string
  330. if (JavascriptOperators::GetTypeId(primLeft) == TypeIds_String)
  331. {
  332. JavascriptString* stringLeft = JavascriptString::UnsafeFromVar(primLeft);
  333. JavascriptString* stringRight = nullptr;
  334. if (JavascriptOperators::GetTypeId(primRight) == TypeIds_String)
  335. {
  336. stringRight = JavascriptString::UnsafeFromVar(primRight);
  337. }
  338. else
  339. {
  340. stringRight = JavascriptConversion::ToString(primRight, scriptContext);
  341. }
  342. if(leftIsDead)
  343. {
  344. return stringLeft->ConcatDestructive(stringRight);
  345. }
  346. return JavascriptString::Concat(stringLeft, stringRight);
  347. }
  348. if (JavascriptOperators::GetTypeId(primRight) == TypeIds_String)
  349. {
  350. JavascriptString* stringLeft = JavascriptConversion::ToString(primLeft, scriptContext);
  351. JavascriptString* stringRight = JavascriptString::UnsafeFromVar(primRight);
  352. if(leftIsDead)
  353. {
  354. return stringLeft->ConcatDestructive(stringRight);
  355. }
  356. return JavascriptString::Concat(stringLeft, stringRight);
  357. }
  358. double sum = Add_Helper(primLeft, primRight, scriptContext);
  359. return JavascriptNumber::ToVarMaybeInPlace(sum, scriptContext, result);
  360. }
  361. Var JavascriptMath::MulAddLeft(Var mulLeft, Var mulRight, Var addLeft, ScriptContext* scriptContext, JavascriptNumber* result)
  362. {
  363. if(TaggedInt::Is(mulLeft))
  364. {
  365. if(TaggedInt::Is(mulRight))
  366. {
  367. // Compute the sum using integer addition, then convert to double.
  368. // That way there's only one int->float conversion.
  369. JavascriptNumber mulTemp(0, scriptContext->GetLibrary()->GetNumberTypeStatic());
  370. Var mulResult = TaggedInt::MultiplyInPlace(mulLeft, mulRight, scriptContext, &mulTemp);
  371. if (result)
  372. {
  373. return JavascriptMath::Add_InPlace(addLeft, mulResult, scriptContext, result);
  374. }
  375. else
  376. {
  377. return JavascriptMath::Add_Full(addLeft, mulResult, scriptContext);
  378. }
  379. }
  380. else if(JavascriptNumber::Is_NoTaggedIntCheck(mulRight))
  381. {
  382. double mulResult = TaggedInt::ToDouble(mulLeft) * JavascriptNumber::GetValue(mulRight);
  383. return JavascriptMath::Add_DoubleHelper(addLeft, mulResult, scriptContext, result);
  384. }
  385. }
  386. else if(TaggedInt::Is(mulRight))
  387. {
  388. if(JavascriptNumber::Is_NoTaggedIntCheck(mulLeft))
  389. {
  390. double mulResult = JavascriptNumber::GetValue(mulLeft) * TaggedInt::ToDouble(mulRight);
  391. return JavascriptMath::Add_DoubleHelper(addLeft, mulResult, scriptContext, result);
  392. }
  393. }
  394. else if(JavascriptNumber::Is_NoTaggedIntCheck(mulLeft) && JavascriptNumber::Is_NoTaggedIntCheck(mulRight))
  395. {
  396. double mulResult = JavascriptNumber::GetValue(mulLeft) * JavascriptNumber::GetValue(mulRight);
  397. return JavascriptMath::Add_DoubleHelper(addLeft, mulResult, scriptContext, result);
  398. }
  399. Var aMul;
  400. JavascriptNumber mulTemp(0, scriptContext->GetLibrary()->GetNumberTypeStatic());
  401. aMul = JavascriptMath::Multiply_InPlace(mulLeft, mulRight, scriptContext, &mulTemp);
  402. if (result)
  403. {
  404. return JavascriptMath::Add_InPlace(addLeft, aMul, scriptContext, result);
  405. }
  406. else
  407. {
  408. return JavascriptMath::Add_Full(addLeft, aMul, scriptContext);
  409. }
  410. }
  411. Var JavascriptMath::MulAddRight(Var mulLeft, Var mulRight, Var addRight, ScriptContext* scriptContext, JavascriptNumber* result)
  412. {
  413. if(TaggedInt::Is(mulLeft))
  414. {
  415. if(TaggedInt::Is(mulRight))
  416. {
  417. // Compute the sum using integer addition, then convert to double.
  418. // That way there's only one int->float conversion.
  419. JavascriptNumber mulTemp(0, scriptContext->GetLibrary()->GetNumberTypeStatic());
  420. Var mulResult = TaggedInt::MultiplyInPlace(mulLeft, mulRight, scriptContext, &mulTemp);
  421. if (result)
  422. {
  423. return JavascriptMath::Add_InPlace(mulResult, addRight, scriptContext, result);
  424. }
  425. else
  426. {
  427. return JavascriptMath::Add_Full(mulResult, addRight, scriptContext);
  428. }
  429. }
  430. else if(JavascriptNumber::Is_NoTaggedIntCheck(mulRight))
  431. {
  432. double mulResult = TaggedInt::ToDouble(mulLeft) * JavascriptNumber::GetValue(mulRight);
  433. return JavascriptMath::Add_DoubleHelper(mulResult, addRight, scriptContext, result);
  434. }
  435. }
  436. else if(TaggedInt::Is(mulRight))
  437. {
  438. if(JavascriptNumber::Is_NoTaggedIntCheck(mulLeft))
  439. {
  440. double mulResult = JavascriptNumber::GetValue(mulLeft) * TaggedInt::ToDouble(mulRight);
  441. return JavascriptMath::Add_DoubleHelper(mulResult, addRight, scriptContext, result);
  442. }
  443. }
  444. else if(JavascriptNumber::Is_NoTaggedIntCheck(mulLeft) && JavascriptNumber::Is_NoTaggedIntCheck(mulRight))
  445. {
  446. double mulResult = JavascriptNumber::GetValue(mulLeft) * JavascriptNumber::GetValue(mulRight);
  447. return JavascriptMath::Add_DoubleHelper(mulResult, addRight, scriptContext, result);
  448. }
  449. Var aMul;
  450. JavascriptNumber mulTemp(0, scriptContext->GetLibrary()->GetNumberTypeStatic());
  451. aMul = JavascriptMath::Multiply_InPlace(mulLeft, mulRight, scriptContext, &mulTemp);
  452. if (result)
  453. {
  454. return JavascriptMath::Add_InPlace(aMul, addRight, scriptContext, result);
  455. }
  456. else
  457. {
  458. return JavascriptMath::Add_Full(aMul, addRight, scriptContext);
  459. }
  460. }
  461. Var JavascriptMath::MulSubLeft(Var mulLeft, Var mulRight, Var subLeft, ScriptContext* scriptContext, JavascriptNumber* result)
  462. {
  463. if(TaggedInt::Is(mulLeft))
  464. {
  465. if(TaggedInt::Is(mulRight))
  466. {
  467. // Compute the sum using integer addition, then convert to double.
  468. // That way there's only one int->float conversion.
  469. JavascriptNumber mulTemp(0, scriptContext->GetLibrary()->GetNumberTypeStatic());
  470. Var mulResult = TaggedInt::MultiplyInPlace(mulLeft, mulRight, scriptContext, &mulTemp);
  471. if (result)
  472. {
  473. return JavascriptMath::Subtract_InPlace(subLeft, mulResult, scriptContext, result);
  474. }
  475. else
  476. {
  477. return JavascriptMath::Subtract_Full(subLeft, mulResult, scriptContext);
  478. }
  479. }
  480. else if(JavascriptNumber::Is_NoTaggedIntCheck(mulRight))
  481. {
  482. double mulResult = TaggedInt::ToDouble(mulLeft) * JavascriptNumber::GetValue(mulRight);
  483. return JavascriptMath::Subtract_DoubleHelper(subLeft, mulResult, scriptContext, result);
  484. }
  485. }
  486. else if(TaggedInt::Is(mulRight))
  487. {
  488. if(JavascriptNumber::Is_NoTaggedIntCheck(mulLeft))
  489. {
  490. double mulResult = JavascriptNumber::GetValue(mulLeft) * TaggedInt::ToDouble(mulRight);
  491. return JavascriptMath::Subtract_DoubleHelper(subLeft, mulResult, scriptContext, result);
  492. }
  493. }
  494. else if(JavascriptNumber::Is_NoTaggedIntCheck(mulLeft) && JavascriptNumber::Is_NoTaggedIntCheck(mulRight))
  495. {
  496. double mulResult = JavascriptNumber::GetValue(mulLeft) * JavascriptNumber::GetValue(mulRight);
  497. return JavascriptMath::Subtract_DoubleHelper(subLeft, mulResult, scriptContext, result);
  498. }
  499. Var aMul;
  500. JavascriptNumber mulTemp(0, scriptContext->GetLibrary()->GetNumberTypeStatic());
  501. aMul = JavascriptMath::Multiply_InPlace(mulLeft, mulRight, scriptContext, &mulTemp);
  502. if (result)
  503. {
  504. return JavascriptMath::Subtract_InPlace(subLeft, aMul, scriptContext, result);
  505. }
  506. else
  507. {
  508. return JavascriptMath::Subtract_Full(subLeft, aMul, scriptContext);
  509. }
  510. }
  511. Var JavascriptMath::MulSubRight(Var mulLeft, Var mulRight, Var subRight, ScriptContext* scriptContext, JavascriptNumber* result)
  512. {
  513. if(TaggedInt::Is(mulLeft))
  514. {
  515. if(TaggedInt::Is(mulRight))
  516. {
  517. // Compute the sum using integer addition, then convert to double.
  518. // That way there's only one int->float conversion.
  519. JavascriptNumber mulTemp(0, scriptContext->GetLibrary()->GetNumberTypeStatic());
  520. Var mulResult = TaggedInt::MultiplyInPlace(mulLeft, mulRight, scriptContext, &mulTemp);
  521. if (result)
  522. {
  523. return JavascriptMath::Subtract_InPlace(mulResult, subRight, scriptContext, result);
  524. }
  525. else
  526. {
  527. return JavascriptMath::Subtract_Full(mulResult, subRight, scriptContext);
  528. }
  529. }
  530. else if(JavascriptNumber::Is_NoTaggedIntCheck(mulRight))
  531. {
  532. double mulResult = TaggedInt::ToDouble(mulLeft) * JavascriptNumber::GetValue(mulRight);
  533. return JavascriptMath::Subtract_DoubleHelper(mulResult, subRight, scriptContext, result);
  534. }
  535. }
  536. else if(TaggedInt::Is(mulRight))
  537. {
  538. if(JavascriptNumber::Is_NoTaggedIntCheck(mulLeft))
  539. {
  540. double mulResult = JavascriptNumber::GetValue(mulLeft) * TaggedInt::ToDouble(mulRight);
  541. return JavascriptMath::Subtract_DoubleHelper(mulResult, subRight, scriptContext, result);
  542. }
  543. }
  544. else if(JavascriptNumber::Is_NoTaggedIntCheck(mulLeft) && JavascriptNumber::Is_NoTaggedIntCheck(mulRight))
  545. {
  546. double mulResult = JavascriptNumber::GetValue(mulLeft) * JavascriptNumber::GetValue(mulRight);
  547. return JavascriptMath::Subtract_DoubleHelper(mulResult, subRight, scriptContext, result);
  548. }
  549. Var aMul;
  550. JavascriptNumber mulTemp(0, scriptContext->GetLibrary()->GetNumberTypeStatic());
  551. aMul = JavascriptMath::Multiply_InPlace(mulLeft, mulRight, scriptContext, &mulTemp);
  552. if (result)
  553. {
  554. return JavascriptMath::Subtract_InPlace(aMul, subRight, scriptContext, result);
  555. }
  556. else
  557. {
  558. return JavascriptMath::Subtract_Full(aMul, subRight, scriptContext);
  559. }
  560. }
  561. Var inline JavascriptMath::Add_DoubleHelper(double dblLeft, Var addRight, ScriptContext* scriptContext, JavascriptNumber*result)
  562. {
  563. if (TaggedInt::Is(addRight))
  564. {
  565. double sum = dblLeft + TaggedInt::ToDouble(addRight);
  566. return JavascriptNumber::ToVarMaybeInPlace(sum, scriptContext, result);
  567. }
  568. else if (JavascriptNumber::Is_NoTaggedIntCheck(addRight))
  569. {
  570. double sum = dblLeft + JavascriptNumber::GetValue(addRight);
  571. return JavascriptNumber::ToVarMaybeInPlace(sum, scriptContext, result);
  572. }
  573. else
  574. {
  575. Var aLeft = JavascriptNumber::ToVarMaybeInPlace(dblLeft, scriptContext, result);
  576. return Add_Full(aLeft, addRight, scriptContext);
  577. }
  578. }
  579. Var inline JavascriptMath::Add_DoubleHelper(Var addLeft, double dblRight, ScriptContext* scriptContext, JavascriptNumber*result)
  580. {
  581. if (TaggedInt::Is(addLeft))
  582. {
  583. double sum = TaggedInt::ToDouble(addLeft) + dblRight;
  584. return JavascriptNumber::ToVarMaybeInPlace(sum, scriptContext, result);
  585. }
  586. else if (JavascriptNumber::Is_NoTaggedIntCheck(addLeft))
  587. {
  588. double sum = JavascriptNumber::GetValue(addLeft) + dblRight;
  589. return JavascriptNumber::ToVarMaybeInPlace(sum, scriptContext, result);
  590. }
  591. else
  592. {
  593. Var aRight = JavascriptNumber::ToVarMaybeInPlace(dblRight, scriptContext, result);
  594. return Add_Full(addLeft, aRight, scriptContext);
  595. }
  596. }
  597. Var inline JavascriptMath::Subtract_DoubleHelper(double dblLeft, Var subRight, ScriptContext* scriptContext, JavascriptNumber* result)
  598. {
  599. if (TaggedInt::Is(subRight))
  600. {
  601. double sum = dblLeft - TaggedInt::ToDouble(subRight);
  602. return JavascriptNumber::ToVarMaybeInPlace(sum, scriptContext, result);
  603. }
  604. else if (JavascriptNumber::Is_NoTaggedIntCheck(subRight))
  605. {
  606. double sum = dblLeft - JavascriptNumber::GetValue(subRight);
  607. return JavascriptNumber::ToVarMaybeInPlace(sum, scriptContext, result);
  608. }
  609. else
  610. {
  611. Var aLeft = JavascriptNumber::ToVarMaybeInPlace(dblLeft, scriptContext, result);
  612. return Subtract_Full(aLeft, subRight, scriptContext);
  613. }
  614. }
  615. Var inline JavascriptMath::Subtract_DoubleHelper(Var subLeft, double dblRight, ScriptContext* scriptContext, JavascriptNumber*result)
  616. {
  617. if (TaggedInt::Is(subLeft))
  618. {
  619. double sum = TaggedInt::ToDouble(subLeft) - dblRight;
  620. return JavascriptNumber::ToVarMaybeInPlace(sum, scriptContext, result);
  621. }
  622. else if (JavascriptNumber::Is_NoTaggedIntCheck(subLeft))
  623. {
  624. double sum = JavascriptNumber::GetValue(subLeft) - dblRight;
  625. return JavascriptNumber::ToVarMaybeInPlace(sum, scriptContext, result);
  626. }
  627. else
  628. {
  629. Var aRight = JavascriptNumber::ToVarMaybeInPlace(dblRight, scriptContext, result);
  630. return Subtract_Full(subLeft, aRight, scriptContext);
  631. }
  632. }
  633. Var JavascriptMath::Subtract_Full(Var aLeft, Var aRight, ScriptContext* scriptContext)
  634. {
  635. double difference = Subtract_Helper(aLeft, aRight, scriptContext);
  636. return JavascriptNumber::ToVarNoCheck(difference, scriptContext);
  637. }
  638. Var JavascriptMath::Subtract_InPlace(Var aLeft, Var aRight, ScriptContext* scriptContext, JavascriptNumber* result)
  639. {
  640. double difference = Subtract_Helper(aLeft, aRight, scriptContext);
  641. return JavascriptNumber::InPlaceNew(difference, scriptContext, result);
  642. }
  643. Var JavascriptMath::Divide_Full(Var aLeft,Var aRight, ScriptContext* scriptContext)
  644. {
  645. // If both arguments are TaggedInt, then try to do integer division
  646. // This case is not handled by the lowerer.
  647. if (TaggedInt::IsPair(aLeft, aRight))
  648. {
  649. return TaggedInt::Divide(aLeft, aRight, scriptContext);
  650. }
  651. return JavascriptNumber::NewInlined( Divide_Helper(aLeft, aRight, scriptContext), scriptContext );
  652. }
  653. Var JavascriptMath::Exponentiation_Full(Var aLeft, Var aRight, ScriptContext *scriptContext)
  654. {
  655. double x = JavascriptConversion::ToNumber(aLeft, scriptContext);
  656. double y = JavascriptConversion::ToNumber(aRight, scriptContext);
  657. return JavascriptNumber::ToVarNoCheck(Math::Pow(x, y), scriptContext);
  658. }
  659. Var JavascriptMath::Exponentiation_InPlace(Var aLeft, Var aRight, ScriptContext* scriptContext, JavascriptNumber* result)
  660. {
  661. // The IEEE 754 floating point spec ensures that NaNs are preserved in all operations
  662. double dblLeft = JavascriptConversion::ToNumber(aLeft, scriptContext);
  663. double dblRight = JavascriptConversion::ToNumber(aRight, scriptContext);
  664. return JavascriptNumber::InPlaceNew(Math::Pow(dblLeft, dblRight), scriptContext, result);
  665. }
  666. Var JavascriptMath::Multiply_Full(Var aLeft, Var aRight, ScriptContext* scriptContext)
  667. {
  668. Assert(aLeft != nullptr);
  669. Assert(aRight != nullptr);
  670. Assert(scriptContext != nullptr);
  671. if(JavascriptNumber::Is(aLeft))
  672. {
  673. if(JavascriptNumber::Is(aRight))
  674. {
  675. double product = JavascriptNumber::GetValue(aLeft) * JavascriptNumber::GetValue(aRight);
  676. return JavascriptNumber::ToVarNoCheck(product, scriptContext);
  677. }
  678. else if(TaggedInt::Is(aRight))
  679. {
  680. double product = TaggedInt::ToDouble(aRight) * JavascriptNumber::GetValue(aLeft);
  681. return JavascriptNumber::ToVarNoCheck(product, scriptContext);
  682. }
  683. }
  684. else if(JavascriptNumber::Is(aRight))
  685. {
  686. if(TaggedInt::Is(aLeft))
  687. {
  688. double product = TaggedInt::ToDouble(aLeft) * JavascriptNumber::GetValue(aRight);
  689. return JavascriptNumber::ToVarNoCheck(product, scriptContext);
  690. }
  691. }
  692. else if(TaggedInt::IsPair(aLeft, aRight))
  693. {
  694. return TaggedInt::Multiply(aLeft, aRight, scriptContext);
  695. }
  696. double product = Multiply_Helper(aLeft, aRight, scriptContext);
  697. return JavascriptNumber::ToVarNoCheck(product, scriptContext);
  698. }
  699. Var JavascriptMath::Multiply_InPlace(Var aLeft, Var aRight, ScriptContext* scriptContext, JavascriptNumber* result)
  700. {
  701. if(JavascriptNumber::Is(aLeft))
  702. {
  703. if(JavascriptNumber::Is(aRight))
  704. {
  705. return JavascriptNumber::ToVarInPlace(
  706. JavascriptNumber::GetValue(aLeft) * JavascriptNumber::GetValue(aRight), scriptContext, result);
  707. }
  708. else if (TaggedInt::Is(aRight))
  709. {
  710. return JavascriptNumber::ToVarInPlace(
  711. JavascriptNumber::GetValue(aLeft) * TaggedInt::ToDouble(aRight), scriptContext, result);
  712. }
  713. }
  714. else if(JavascriptNumber::Is(aRight))
  715. {
  716. if(TaggedInt::Is(aLeft))
  717. {
  718. return JavascriptNumber::ToVarInPlace(
  719. TaggedInt::ToDouble(aLeft) * JavascriptNumber::GetValue(aRight), scriptContext, result);
  720. }
  721. }
  722. else if(TaggedInt::IsPair(aLeft, aRight))
  723. {
  724. return TaggedInt::MultiplyInPlace(aLeft, aRight, scriptContext, result);
  725. }
  726. double product = Multiply_Helper(aLeft, aRight, scriptContext);
  727. return JavascriptNumber::InPlaceNew(product, scriptContext, result);
  728. }
  729. Var JavascriptMath::Divide_InPlace(Var aLeft, Var aRight, ScriptContext* scriptContext, JavascriptNumber* result)
  730. {
  731. // If both arguments are TaggedInt, then try to do integer division
  732. // This case is not handled by the lowerer.
  733. if (TaggedInt::IsPair(aLeft, aRight))
  734. {
  735. return TaggedInt::DivideInPlace(aLeft, aRight, scriptContext, result);
  736. }
  737. double quotient = Divide_Helper(aLeft, aRight, scriptContext);
  738. return JavascriptNumber::InPlaceNew(quotient, scriptContext, result);
  739. }
  740. Var JavascriptMath::Modulus_Full(Var aLeft, Var aRight, ScriptContext* scriptContext)
  741. {
  742. // If both arguments are TaggedInt, then try to do integer modulus.
  743. // This case is not handled by the lowerer.
  744. if (TaggedInt::IsPair(aLeft, aRight))
  745. {
  746. return TaggedInt::Modulus(aLeft, aRight, scriptContext);
  747. }
  748. double remainder = Modulus_Helper(aLeft, aRight, scriptContext);
  749. return JavascriptNumber::ToVarNoCheck(remainder, scriptContext);
  750. }
  751. Var JavascriptMath::Modulus_InPlace(Var aLeft, Var aRight, ScriptContext* scriptContext, JavascriptNumber* result)
  752. {
  753. Assert(aLeft != nullptr);
  754. Assert(aRight != nullptr);
  755. Assert(scriptContext != nullptr);
  756. // If both arguments are TaggedInt, then try to do integer division
  757. // This case is not handled by the lowerer.
  758. if (TaggedInt::IsPair(aLeft, aRight))
  759. {
  760. return TaggedInt::Modulus(aLeft, aRight, scriptContext);
  761. }
  762. double remainder = Modulus_Helper(aLeft, aRight, scriptContext);
  763. return JavascriptNumber::InPlaceNew(remainder, scriptContext, result);
  764. }
  765. Var JavascriptMath::FinishOddDivByPow2(int32 value, ScriptContext *scriptContext)
  766. {
  767. return JavascriptNumber::New((double)(value + 0.5), scriptContext);
  768. }
  769. Var JavascriptMath::FinishOddDivByPow2_InPlace(int32 value, ScriptContext *scriptContext, JavascriptNumber* result)
  770. {
  771. return JavascriptNumber::InPlaceNew((double)(value + 0.5), scriptContext, result);
  772. }
  773. Var JavascriptMath::MaxInAnArray(RecyclableObject * function, CallInfo callInfo, ...)
  774. {
  775. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  776. ARGUMENTS(args, callInfo);
  777. Assert(args.Info.Count == 2);
  778. Var thisArg = args[0];
  779. Var arrayArg = args[1];
  780. ScriptContext * scriptContext = function->GetScriptContext();
  781. TypeId typeId = JavascriptOperators::GetTypeId(arrayArg);
  782. if (!JavascriptNativeArray::Is(typeId) && !(TypedArrayBase::Is(typeId) && typeId != TypeIds_CharArray && typeId != TypeIds_BoolArray))
  783. {
  784. if (JavascriptArray::IsVarArray(typeId) && JavascriptArray::UnsafeFromVar(arrayArg)->GetLength() == 0)
  785. {
  786. return scriptContext->GetLibrary()->GetNegativeInfinite();
  787. }
  788. return JavascriptFunction::CalloutHelper<false>(function, thisArg, /* overridingNewTarget = */nullptr, arrayArg, scriptContext);
  789. }
  790. if (JavascriptNativeArray::Is(typeId))
  791. {
  792. #if ENABLE_COPYONACCESS_ARRAY
  793. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(arrayArg);
  794. #endif
  795. JavascriptNativeArray * argsArray = JavascriptNativeArray::UnsafeFromVar(arrayArg);
  796. uint len = argsArray->GetLength();
  797. if (len == 0)
  798. {
  799. return scriptContext->GetLibrary()->GetNegativeInfinite();
  800. }
  801. if (argsArray->GetHead()->next != nullptr || !argsArray->HasNoMissingValues() ||
  802. argsArray->GetHead()->length != len)
  803. {
  804. return JavascriptFunction::CalloutHelper<false>(function, thisArg, /* overridingNewTarget = */nullptr, arrayArg, scriptContext);
  805. }
  806. return argsArray->FindMinOrMax(scriptContext, true /*findMax*/);
  807. }
  808. else
  809. {
  810. TypedArrayBase * argsArray = TypedArrayBase::UnsafeFromVar(arrayArg);
  811. uint len = argsArray->GetLength();
  812. if (len == 0)
  813. {
  814. return scriptContext->GetLibrary()->GetNegativeInfinite();
  815. }
  816. Var max = argsArray->FindMinOrMax(scriptContext, typeId, true /*findMax*/);
  817. if (max == nullptr)
  818. {
  819. return JavascriptFunction::CalloutHelper<false>(function, thisArg, /* overridingNewTarget = */nullptr, arrayArg, scriptContext);
  820. }
  821. return max;
  822. }
  823. }
  824. Var JavascriptMath::MinInAnArray(RecyclableObject * function, CallInfo callInfo, ...)
  825. {
  826. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  827. ARGUMENTS(args, callInfo);
  828. Assert(args.Info.Count == 2);
  829. Var thisArg = args[0];
  830. Var arrayArg = args[1];
  831. ScriptContext * scriptContext = function->GetScriptContext();
  832. TypeId typeId = JavascriptOperators::GetTypeId(arrayArg);
  833. if (!JavascriptNativeArray::Is(typeId) && !(TypedArrayBase::Is(typeId) && typeId != TypeIds_CharArray && typeId != TypeIds_BoolArray))
  834. {
  835. if (JavascriptArray::Is(typeId) && JavascriptArray::UnsafeFromVar(arrayArg)->GetLength() == 0)
  836. {
  837. return scriptContext->GetLibrary()->GetPositiveInfinite();
  838. }
  839. return JavascriptFunction::CalloutHelper<false>(function, thisArg, /* overridingNewTarget = */nullptr, arrayArg, scriptContext);
  840. }
  841. if (JavascriptNativeArray::Is(typeId))
  842. {
  843. #if ENABLE_COPYONACCESS_ARRAY
  844. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(arrayArg);
  845. #endif
  846. JavascriptNativeArray * argsArray = JavascriptNativeArray::UnsafeFromVar(arrayArg);
  847. uint len = argsArray->GetLength();
  848. if (len == 0)
  849. {
  850. return scriptContext->GetLibrary()->GetPositiveInfinite();
  851. }
  852. if (argsArray->GetHead()->next != nullptr || !argsArray->HasNoMissingValues() ||
  853. argsArray->GetHead()->length != len)
  854. {
  855. return JavascriptFunction::CalloutHelper<false>(function, thisArg, /* overridingNewTarget = */nullptr, arrayArg, scriptContext);
  856. }
  857. return argsArray->FindMinOrMax(scriptContext, false /*findMax*/);
  858. }
  859. else
  860. {
  861. TypedArrayBase * argsArray = TypedArrayBase::UnsafeFromVar(arrayArg);
  862. uint len = argsArray->GetLength();
  863. if (len == 0)
  864. {
  865. return scriptContext->GetLibrary()->GetPositiveInfinite();
  866. }
  867. Var min = argsArray->FindMinOrMax(scriptContext, typeId, false /*findMax*/);
  868. if (min == nullptr)
  869. {
  870. return JavascriptFunction::CalloutHelper<false>(function, thisArg, /* overridingNewTarget = */nullptr, arrayArg, scriptContext);
  871. }
  872. return min;
  873. }
  874. }
  875. void InitializeRandomSeeds(uint64 *seed0, uint64 *seed1, ScriptContext *scriptContext)
  876. {
  877. #if DBG
  878. if (CONFIG_FLAG(PRNGSeed0) && CONFIG_FLAG(PRNGSeed1))
  879. {
  880. *seed0 = CONFIG_FLAG(PRNGSeed0);
  881. *seed1 = CONFIG_FLAG(PRNGSeed1);
  882. }
  883. else
  884. #endif
  885. {
  886. LARGE_INTEGER s0;
  887. LARGE_INTEGER s1;
  888. if (!rand_s(reinterpret_cast<unsigned int*>(&s0.LowPart)) &&
  889. !rand_s(reinterpret_cast<unsigned int*>(&s0.HighPart)) &&
  890. !rand_s(reinterpret_cast<unsigned int*>(&s1.LowPart)) &&
  891. !rand_s(reinterpret_cast<unsigned int*>(&s1.HighPart)))
  892. {
  893. *seed0 = s0.QuadPart;
  894. *seed1 = s1.QuadPart;
  895. }
  896. else
  897. {
  898. AssertMsg(false, "Unable to initialize PRNG seeds with rand_s. Revert to using entropy.");
  899. #ifdef ENABLE_CUSTOM_ENTROPY
  900. ThreadContext *threadContext = scriptContext->GetThreadContext();
  901. threadContext->GetEntropy().AddThreadCycleTime();
  902. threadContext->GetEntropy().AddIoCounters();
  903. *seed0 = threadContext->GetEntropy().GetRand();
  904. threadContext->GetEntropy().AddThreadCycleTime();
  905. threadContext->GetEntropy().AddIoCounters();
  906. *seed1 = threadContext->GetEntropy().GetRand();
  907. #endif
  908. }
  909. }
  910. }
  911. double ConvertRandomSeedsToDouble(const uint64 seed0, const uint64 seed1)
  912. {
  913. const uint64 mExp = 0x3FF0000000000000;
  914. const uint64 mMant = 0x000FFFFFFFFFFFFF;
  915. // Take lower 52 bits of the sum of two seeds to make a double
  916. // Subtract 1.0 to negate the implicit integer bit of 1. Final range: [0.0, 1.0)
  917. // See IEEE754 Double-precision floating-point format for details
  918. // https://en.wikipedia.org/wiki/Double-precision_floating-point_format
  919. uint64 resplusone_ui64 = ((seed0 + seed1) & mMant) | mExp;
  920. double res = *(reinterpret_cast<double*>(&resplusone_ui64)) - 1.0;
  921. return res;
  922. }
  923. void Xorshift128plus(uint64 *seed0, uint64 *seed1)
  924. {
  925. uint64 s1 = *seed0;
  926. uint64 s0 = *seed1;
  927. *seed0 = s0;
  928. s1 ^= s1 << 23;
  929. s1 ^= s1 >> 17;
  930. s1 ^= s0;
  931. s1 ^= s0 >> 26;
  932. *seed1 = s1;
  933. }
  934. double JavascriptMath::Random(ScriptContext *scriptContext)
  935. {
  936. uint64 seed0;
  937. uint64 seed1;
  938. if (!scriptContext->GetLibrary()->IsPRNGSeeded())
  939. {
  940. InitializeRandomSeeds(&seed0, &seed1, scriptContext);
  941. #if DBG_DUMP
  942. OUTPUT_TRACE(Js::PRNGPhase, _u("[PRNG:%x] INIT %I64x %I64x\n"), scriptContext, seed0, seed1);
  943. #endif
  944. scriptContext->GetLibrary()->SetIsPRNGSeeded(true);
  945. #if ENABLE_TTD
  946. if(scriptContext->ShouldPerformReplayAction())
  947. {
  948. scriptContext->GetThreadContext()->TTDLog->ReplayExternalEntropyRandomEvent(&seed0, &seed1);
  949. }
  950. else if(scriptContext->ShouldPerformRecordAction())
  951. {
  952. scriptContext->GetThreadContext()->TTDLog->RecordExternalEntropyRandomEvent(seed0, seed1);
  953. }
  954. else
  955. {
  956. ;
  957. }
  958. #endif
  959. }
  960. else
  961. {
  962. seed0 = scriptContext->GetLibrary()->GetRandSeed0();
  963. seed1 = scriptContext->GetLibrary()->GetRandSeed1();
  964. }
  965. #if DBG_DUMP
  966. OUTPUT_TRACE(Js::PRNGPhase, _u("[PRNG:%x] SEED %I64x %I64x\n"), scriptContext, seed0, seed1);
  967. #endif
  968. Xorshift128plus(&seed0, &seed1);
  969. //update the seeds in script context
  970. scriptContext->GetLibrary()->SetRandSeed0(seed0);
  971. scriptContext->GetLibrary()->SetRandSeed1(seed1);
  972. double res = ConvertRandomSeedsToDouble(seed0, seed1);
  973. #if DBG_DUMP
  974. OUTPUT_TRACE(Js::PRNGPhase, _u("[PRNG:%x] RAND %I64x\n"), scriptContext, *((uint64 *)&res));
  975. #endif
  976. return res;
  977. }
  978. uint32 JavascriptMath::ToUInt32(double T1)
  979. {
  980. // Same as doing ToInt32 and reinterpret the bits as uint32
  981. return (uint32)ToInt32Core(T1);
  982. }
  983. int32 JavascriptMath::ToInt32(double T1)
  984. {
  985. return JavascriptMath::ToInt32Core(T1);
  986. }
  987. int32 JavascriptMath::ToInt32_Full(Var aValue, ScriptContext* scriptContext)
  988. {
  989. AssertMsg(!TaggedInt::Is(aValue), "Should be detected");
  990. // This is used when TaggedInt's overflow but remain under int32
  991. // so Number is our most critical case:
  992. TypeId typeId = JavascriptOperators::GetTypeId(aValue);
  993. if (typeId == TypeIds_Number)
  994. {
  995. return JavascriptMath::ToInt32Core(JavascriptNumber::GetValue(aValue));
  996. }
  997. return JavascriptConversion::ToInt32_Full(aValue, scriptContext);
  998. }
  999. }