JavascriptConversion.cpp 68 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687
  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. #include "RuntimeLanguagePch.h"
  6. #include "RuntimeMathPch.h"
  7. #include "Library/JavascriptNumberObject.h"
  8. #include "Library/JavascriptStringObject.h"
  9. #include "Library/JavascriptSimdObject.h"
  10. #include "Library/DateImplementation.h"
  11. #include "Library/JavascriptDate.h"
  12. namespace Js
  13. {
  14. static const double k_2to16 = 65536.0;
  15. static const double k_2to31 = 2147483648.0;
  16. static const double k_2to32 = 4294967296.0;
  17. // ES5 9.10 indicates that this method should throw a TypeError if the supplied value is Undefined or Null.
  18. // Our implementation returns FALSE in this scenario, expecting the caller to throw the TypeError.
  19. // This allows the caller to provide more context in the error message without having to unnecessarily
  20. // construct the message string before knowing whether or not the object is coercible.
  21. BOOL JavascriptConversion::CheckObjectCoercible(Var aValue, ScriptContext* scriptContext)
  22. {
  23. TypeId typeId = JavascriptOperators::GetTypeId(aValue);
  24. if (typeId == TypeIds_Null || typeId == TypeIds_Undefined)
  25. {
  26. return FALSE;
  27. }
  28. return TRUE;
  29. }
  30. //ES5 9.11 Undefined, Null, Boolean, Number, String - return false
  31. //If Object has a [[Call]] internal method, then return true, otherwise return false
  32. bool JavascriptConversion::IsCallable(Var aValue)
  33. {
  34. if (!RecyclableObject::Is(aValue))
  35. {
  36. return false;
  37. }
  38. JavascriptMethod entryPoint = RecyclableObject::FromVar(aValue)->GetEntryPoint();
  39. return RecyclableObject::DefaultEntryPoint != entryPoint;
  40. }
  41. //----------------------------------------------------------------------------
  42. // ES5 9.12 SameValue algorithm implementation.
  43. // 1. If Type(x) is different from Type(y), return false.
  44. // 2. If Type(x) is Undefined, return true.
  45. // 3. If Type(x) is Null, return true.
  46. // 4. If Type(x) is Number, then.
  47. // a. If x is NaN and y is NaN, return true.
  48. // b. If x is +0 and y is -0, return false.
  49. // c. If x is -0 and y is +0, return false.
  50. // d. If x is the same number value as y, return true.
  51. // e. Return false.
  52. // 5. If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions); otherwise, return false.
  53. // 6. If Type(x) is Boolean, return true if x and y are both true or both false; otherwise, return false.
  54. // 7. Return true if x and y refer to the same object. Otherwise, return false.
  55. //----------------------------------------------------------------------------
  56. template<bool zero>
  57. bool JavascriptConversion::SameValueCommon(Var aLeft, Var aRight)
  58. {
  59. TypeId leftType = JavascriptOperators::GetTypeId(aLeft);
  60. TypeId rightType = JavascriptOperators::GetTypeId(aRight);
  61. //Check for undefined and null type;
  62. if (leftType == TypeIds_Undefined )
  63. {
  64. return rightType == TypeIds_Undefined;
  65. }
  66. if (leftType == TypeIds_Null)
  67. {
  68. return rightType == TypeIds_Null;
  69. }
  70. double dblLeft, dblRight;
  71. switch (leftType)
  72. {
  73. case TypeIds_Integer:
  74. switch (rightType)
  75. {
  76. case TypeIds_Integer:
  77. return aLeft == aRight;
  78. case TypeIds_Number:
  79. dblLeft = TaggedInt::ToDouble(aLeft);
  80. dblRight = JavascriptNumber::GetValue(aRight);
  81. goto CommonNumber;
  82. case TypeIds_Int64Number:
  83. {
  84. int leftValue = TaggedInt::ToInt32(aLeft);
  85. __int64 rightValue = JavascriptInt64Number::FromVar(aRight)->GetValue();
  86. return leftValue == rightValue;
  87. }
  88. case TypeIds_UInt64Number:
  89. {
  90. int leftValue = TaggedInt::ToInt32(aLeft);
  91. unsigned __int64 rightValue = JavascriptInt64Number::FromVar(aRight)->GetValue();
  92. return leftValue == rightValue;
  93. }
  94. }
  95. break;
  96. case TypeIds_Int64Number:
  97. switch (rightType)
  98. {
  99. case TypeIds_Integer:
  100. {
  101. __int64 leftValue = JavascriptInt64Number::FromVar(aLeft)->GetValue();
  102. int rightValue = TaggedInt::ToInt32(aRight);
  103. return leftValue == rightValue;
  104. }
  105. case TypeIds_Number:
  106. dblLeft = (double)JavascriptInt64Number::FromVar(aLeft)->GetValue();
  107. dblRight = JavascriptNumber::GetValue(aRight);
  108. goto CommonNumber;
  109. case TypeIds_Int64Number:
  110. {
  111. __int64 leftValue = JavascriptInt64Number::FromVar(aLeft)->GetValue();
  112. __int64 rightValue = JavascriptInt64Number::FromVar(aRight)->GetValue();
  113. return leftValue == rightValue;
  114. }
  115. case TypeIds_UInt64Number:
  116. {
  117. __int64 leftValue = JavascriptInt64Number::FromVar(aLeft)->GetValue();
  118. unsigned __int64 rightValue = JavascriptInt64Number::FromVar(aRight)->GetValue();
  119. return ((unsigned __int64)leftValue == rightValue);
  120. }
  121. }
  122. break;
  123. case TypeIds_UInt64Number:
  124. switch (rightType)
  125. {
  126. case TypeIds_Integer:
  127. {
  128. unsigned __int64 leftValue = JavascriptUInt64Number::FromVar(aLeft)->GetValue();
  129. __int64 rightValue = TaggedInt::ToInt32(aRight);
  130. return (leftValue == (unsigned __int64)rightValue);
  131. }
  132. case TypeIds_Number:
  133. dblLeft = (double)JavascriptUInt64Number::FromVar(aLeft)->GetValue();
  134. dblRight = JavascriptNumber::GetValue(aRight);
  135. goto CommonNumber;
  136. case TypeIds_Int64Number:
  137. {
  138. unsigned __int64 leftValue = JavascriptUInt64Number::FromVar(aLeft)->GetValue();
  139. __int64 rightValue = JavascriptInt64Number::FromVar(aRight)->GetValue();
  140. return (leftValue == (unsigned __int64)rightValue);
  141. }
  142. case TypeIds_UInt64Number:
  143. {
  144. unsigned __int64 leftValue = JavascriptUInt64Number::FromVar(aLeft)->GetValue();
  145. unsigned __int64 rightValue = JavascriptInt64Number::FromVar(aRight)->GetValue();
  146. return leftValue == rightValue;
  147. }
  148. }
  149. break;
  150. case TypeIds_Number:
  151. switch (rightType)
  152. {
  153. case TypeIds_Integer:
  154. dblLeft = JavascriptNumber::GetValue(aLeft);
  155. dblRight = TaggedInt::ToDouble(aRight);
  156. goto CommonNumber;
  157. case TypeIds_Int64Number:
  158. dblLeft = JavascriptNumber::GetValue(aLeft);
  159. dblRight = (double)JavascriptInt64Number::FromVar(aRight)->GetValue();
  160. goto CommonNumber;
  161. case TypeIds_UInt64Number:
  162. dblLeft = JavascriptNumber::GetValue(aLeft);
  163. dblRight = (double)JavascriptUInt64Number::FromVar(aRight)->GetValue();
  164. goto CommonNumber;
  165. case TypeIds_Number:
  166. dblLeft = JavascriptNumber::GetValue(aLeft);
  167. dblRight = JavascriptNumber::GetValue(aRight);
  168. CommonNumber:
  169. if (JavascriptNumber::IsNan(dblLeft) && JavascriptNumber::IsNan(dblRight))
  170. {
  171. return true;
  172. }
  173. if (zero)
  174. {
  175. // SameValueZero(+0,-0) returns true;
  176. return dblLeft == dblRight;
  177. }
  178. else
  179. {
  180. // SameValue(+0,-0) returns false;
  181. return (NumberUtilities::LuLoDbl(dblLeft) == NumberUtilities::LuLoDbl(dblRight) &&
  182. NumberUtilities::LuHiDbl(dblLeft) == NumberUtilities::LuHiDbl(dblRight));
  183. }
  184. }
  185. break;
  186. case TypeIds_Boolean:
  187. switch (rightType)
  188. {
  189. case TypeIds_Boolean:
  190. return aLeft == aRight;
  191. }
  192. break;
  193. case TypeIds_String:
  194. switch (rightType)
  195. {
  196. case TypeIds_String:
  197. return JavascriptString::Equals(aLeft, aRight);
  198. }
  199. break;
  200. case TypeIds_Symbol:
  201. switch (rightType)
  202. {
  203. case TypeIds_Symbol:
  204. {
  205. JavascriptSymbol* leftSymbol = JavascriptSymbol::FromVar(aLeft);
  206. JavascriptSymbol* rightSymbol = JavascriptSymbol::FromVar(aRight);
  207. return leftSymbol->GetValue() == rightSymbol->GetValue();
  208. }
  209. }
  210. return false;
  211. default:
  212. break;
  213. }
  214. return aLeft == aRight;
  215. }
  216. template bool JavascriptConversion::SameValueCommon<false>(Var aLeft, Var aRight);
  217. template bool JavascriptConversion::SameValueCommon<true>(Var aLeft, Var aRight);
  218. //----------------------------------------------------------------------------
  219. // ToObject() takes a value and converts it to an Object type
  220. // Implementation of ES5 9.9
  221. // The spec indicates that this method should throw a TypeError if the supplied value is Undefined or Null.
  222. // Our implementation returns FALSE in this scenario, expecting the caller to throw the TypeError.
  223. // This allows the caller to provide more context in the error message without having to unnecessarily
  224. // construct the message string before knowing whether or not the value can be converted to an object.
  225. //
  226. // Undefined Return FALSE.
  227. // Null Return FALSE.
  228. // Boolean Create a new Boolean object whose [[PrimitiveValue]]
  229. // internal property is set to the value of the boolean.
  230. // See 15.6 for a description of Boolean objects.
  231. // Return TRUE.
  232. // Number Create a new Number object whose [[PrimitiveValue]]
  233. // internal property is set to the value of the number.
  234. // See 15.7 for a description of Number objects.
  235. // Return TRUE.
  236. // String Create a new String object whose [[PrimitiveValue]]
  237. // internal property is set to the value of the string.
  238. // See 15.5 for a description of String objects.
  239. // Return TRUE.
  240. // Object The result is the input argument (no conversion).
  241. // Return TRUE.
  242. //----------------------------------------------------------------------------
  243. BOOL JavascriptConversion::ToObject(Var aValue, ScriptContext* scriptContext, RecyclableObject** object)
  244. {
  245. Assert(object);
  246. switch (JavascriptOperators::GetTypeId(aValue))
  247. {
  248. case TypeIds_Undefined:
  249. case TypeIds_Null:
  250. return FALSE;
  251. case TypeIds_Number:
  252. case TypeIds_Integer:
  253. *object = scriptContext->GetLibrary()->CreateNumberObject(aValue);
  254. return TRUE;
  255. default:
  256. {
  257. #ifdef ENABLE_SIMDJS
  258. if (SIMDUtils::IsSimdType(aValue))
  259. {
  260. *object = scriptContext->GetLibrary()->CreateSIMDObject(aValue, JavascriptOperators::GetTypeId(aValue));
  261. }
  262. else
  263. #endif
  264. {
  265. *object = RecyclableObject::FromVar(aValue)->ToObject(scriptContext);
  266. }
  267. return TRUE;
  268. }
  269. }
  270. }
  271. //----------------------------------------------------------------------------
  272. // ToPropertyKey() takes a value and converts it to a property key
  273. // Implementation of ES6 7.1.14
  274. //----------------------------------------------------------------------------
  275. void JavascriptConversion::ToPropertyKey(Var argument, ScriptContext* scriptContext, const PropertyRecord** propertyRecord)
  276. {
  277. Var key = JavascriptConversion::ToPrimitive(argument, JavascriptHint::HintString, scriptContext);
  278. if (JavascriptSymbol::Is(key))
  279. {
  280. // If we are looking up a property keyed by a symbol, we already have the PropertyId in the symbol
  281. *propertyRecord = JavascriptSymbol::FromVar(key)->GetValue();
  282. }
  283. else
  284. {
  285. // For all other types, convert the key into a string and use that as the property name
  286. JavascriptString * propName = JavascriptConversion::ToString(key, scriptContext);
  287. if (VirtualTableInfo<Js::PropertyString>::HasVirtualTable(propName))
  288. {
  289. PropertyString * propertyString = (PropertyString *)propName;
  290. *propertyRecord = propertyString->GetPropertyRecord();
  291. }
  292. else if (VirtualTableInfo<Js::LiteralStringWithPropertyStringPtr>::HasVirtualTable(propName))
  293. {
  294. LiteralStringWithPropertyStringPtr * str = (LiteralStringWithPropertyStringPtr *)propName;
  295. if (str->GetPropertyString())
  296. {
  297. *propertyRecord = str->GetPropertyString()->GetPropertyRecord();
  298. }
  299. else
  300. {
  301. scriptContext->GetOrAddPropertyRecord(propName->GetString(), propName->GetLength(), propertyRecord);
  302. PropertyString * propStr = scriptContext->GetPropertyString((*propertyRecord)->GetPropertyId());
  303. str->SetPropertyString(propStr);
  304. }
  305. }
  306. else
  307. {
  308. scriptContext->GetOrAddPropertyRecord(propName->GetString(), propName->GetLength(), propertyRecord);
  309. }
  310. }
  311. }
  312. //----------------------------------------------------------------------------
  313. // ToPrimitive() takes a value and an optional argument and converts it to a non Object type
  314. // Implementation of ES5 9.1
  315. //
  316. // Undefined:The result equals the input argument (no conversion).
  317. // Null: The result equals the input argument (no conversion).
  318. // Boolean: The result equals the input argument (no conversion).
  319. // Number: The result equals the input argument (no conversion).
  320. // String: The result equals the input argument (no conversion).
  321. // VariantDate:Returns the value for variant date by calling ToPrimitve directly.
  322. // Object: Return a default value for the Object.
  323. // The default value of an object is retrieved by calling the [[DefaultValue]]
  324. // internal method of the object, passing the optional hint PreferredType.
  325. // The behavior of the [[DefaultValue]] internal method is defined by this specification
  326. // for all native ECMAScript objects (8.12.9).
  327. //----------------------------------------------------------------------------
  328. Var JavascriptConversion::ToPrimitive(Var aValue, JavascriptHint hint, ScriptContext * requestContext)
  329. {
  330. switch (JavascriptOperators::GetTypeId(aValue))
  331. {
  332. case TypeIds_Undefined:
  333. case TypeIds_Null:
  334. case TypeIds_Integer:
  335. case TypeIds_Boolean:
  336. case TypeIds_Number:
  337. case TypeIds_String:
  338. case TypeIds_Symbol:
  339. return aValue;
  340. case TypeIds_VariantDate:
  341. {
  342. Var result = nullptr;
  343. if (JavascriptVariantDate::FromVar(aValue)->ToPrimitive(hint, &result, requestContext) != TRUE)
  344. {
  345. result = nullptr;
  346. }
  347. return result;
  348. }
  349. case TypeIds_StringObject:
  350. {
  351. JavascriptStringObject * stringObject = JavascriptStringObject::FromVar(aValue);
  352. ScriptContext * objectScriptContext = stringObject->GetScriptContext();
  353. if (objectScriptContext->optimizationOverrides.GetSideEffects() & (hint == JavascriptHint::HintString ? SideEffects_ToString : SideEffects_ValueOf))
  354. {
  355. return MethodCallToPrimitive(aValue, hint, requestContext);
  356. }
  357. return CrossSite::MarshalVar(requestContext, stringObject->Unwrap(), objectScriptContext);
  358. }
  359. case TypeIds_NumberObject:
  360. {
  361. JavascriptNumberObject * numberObject = JavascriptNumberObject::FromVar(aValue);
  362. ScriptContext * objectScriptContext = numberObject->GetScriptContext();
  363. if (hint == JavascriptHint::HintString)
  364. {
  365. if (objectScriptContext->optimizationOverrides.GetSideEffects() & SideEffects_ToString)
  366. {
  367. return MethodCallToPrimitive(aValue, hint, requestContext);
  368. }
  369. return JavascriptNumber::ToStringRadix10(numberObject->GetValue(), requestContext);
  370. }
  371. else
  372. {
  373. if (objectScriptContext->optimizationOverrides.GetSideEffects() & SideEffects_ValueOf)
  374. {
  375. return MethodCallToPrimitive(aValue, hint, requestContext);
  376. }
  377. return CrossSite::MarshalVar(requestContext, numberObject->Unwrap(), objectScriptContext);
  378. }
  379. }
  380. case TypeIds_SymbolObject:
  381. {
  382. JavascriptSymbolObject* symbolObject = JavascriptSymbolObject::FromVar(aValue);
  383. return requestContext->GetLibrary()->CreateSymbol(symbolObject->GetValue());
  384. }
  385. case TypeIds_Date:
  386. case TypeIds_WinRTDate:
  387. {
  388. JavascriptDate* dateObject = JavascriptDate::FromVar(aValue);
  389. if(hint == JavascriptHint::HintNumber)
  390. {
  391. if (dateObject->GetScriptContext()->optimizationOverrides.GetSideEffects() & SideEffects_ValueOf)
  392. {
  393. // if no Method exists this function falls back to OrdinaryToPrimitive
  394. // if IsES6ToPrimitiveEnabled flag is off we also fall back to OrdinaryToPrimitive
  395. return MethodCallToPrimitive(aValue, hint, requestContext);
  396. }
  397. return JavascriptNumber::ToVarNoCheck(dateObject->GetTime(), requestContext);
  398. }
  399. else
  400. {
  401. if (dateObject->GetScriptContext()->optimizationOverrides.GetSideEffects() & SideEffects_ToString)
  402. {
  403. // if no Method exists this function falls back to OrdinaryToPrimitive
  404. // if IsES6ToPrimitiveEnabled flag is off we also fall back to OrdinaryToPrimitive
  405. return MethodCallToPrimitive(aValue, hint, requestContext);
  406. }
  407. return JavascriptDate::ToString(dateObject, requestContext);
  408. }
  409. }
  410. // convert to JavascriptNumber
  411. case TypeIds_Int64Number:
  412. return JavascriptInt64Number::FromVar(aValue)->ToJavascriptNumber();
  413. case TypeIds_UInt64Number:
  414. return JavascriptUInt64Number::FromVar(aValue)->ToJavascriptNumber();
  415. default:
  416. #ifdef ENABLE_SIMDJS
  417. if (SIMDUtils::IsSimdType(aValue))
  418. {
  419. return aValue;
  420. }
  421. else
  422. #endif
  423. {
  424. // if no Method exists this function falls back to OrdinaryToPrimitive
  425. // if IsES6ToPrimitiveEnabled flag is off we also fall back to OrdinaryToPrimitive
  426. return MethodCallToPrimitive(aValue, hint, requestContext);
  427. }
  428. }
  429. }
  430. //----------------------------------------------------------------------------
  431. //https://tc39.github.io/ecma262/#sec-canonicalnumericindexstring
  432. //1. Assert : Type(argument) is String.
  433. //2. If argument is "-0", then return -0.
  434. //3. Let n be ToNumber(argument).
  435. //4. If SameValue(ToString(n), argument) is false, then return undefined.
  436. //5. Return n.
  437. //----------------------------------------------------------------------------
  438. BOOL JavascriptConversion::CanonicalNumericIndexString(JavascriptString *aValue, double *indexValue, ScriptContext * scriptContext)
  439. {
  440. if (JavascriptString::IsNegZero(aValue))
  441. {
  442. *indexValue = -0;
  443. return TRUE;
  444. }
  445. double indexDoubleValue = aValue->ToDouble();
  446. if (JavascriptString::Equals(JavascriptNumber::ToStringRadix10(indexDoubleValue, scriptContext), aValue))
  447. {
  448. *indexValue = indexDoubleValue;
  449. return TRUE;
  450. }
  451. return FALSE;
  452. }
  453. Var JavascriptConversion::MethodCallToPrimitive(Var aValue, JavascriptHint hint, ScriptContext * requestContext)
  454. {
  455. Var result = nullptr;
  456. RecyclableObject *const recyclableObject = RecyclableObject::FromVar(aValue);
  457. ScriptContext *const scriptContext = recyclableObject->GetScriptContext();
  458. //7.3.9 GetMethod(V, P)
  459. // The abstract operation GetMethod is used to get the value of a specific property of an ECMAScript language value when the value of the
  460. // property is expected to be a function. The operation is called with arguments V and P where V is the ECMAScript language value, P is the
  461. // property key. This abstract operation performs the following steps:
  462. // 1. Assert: IsPropertyKey(P) is true.
  463. // 2. Let func be ? GetV(V, P).
  464. // 3. If func is either undefined or null, return undefined.
  465. // 4. If IsCallable(func) is false, throw a TypeError exception.
  466. // 5. Return func.
  467. Var varMethod = nullptr;
  468. if (!(requestContext->GetConfig()->IsES6ToPrimitiveEnabled()
  469. && JavascriptOperators::GetPropertyReference(recyclableObject, PropertyIds::_symbolToPrimitive, &varMethod, requestContext)
  470. && !JavascriptOperators::IsUndefinedOrNull(varMethod)))
  471. {
  472. return OrdinaryToPrimitive(aValue, hint, requestContext);
  473. }
  474. if (!JavascriptFunction::Is(varMethod))
  475. {
  476. // Don't error if we disabled implicit calls
  477. JavascriptError::TryThrowTypeError(scriptContext, requestContext, JSERR_Property_NeedFunction, requestContext->GetPropertyName(PropertyIds::_symbolToPrimitive)->GetBuffer());
  478. return requestContext->GetLibrary()->GetNull();
  479. }
  480. // Let exoticToPrim be GetMethod(input, @@toPrimitive).
  481. JavascriptFunction* exoticToPrim = JavascriptFunction::FromVar(varMethod);
  482. JavascriptString* hintString = nullptr;
  483. if (hint == JavascriptHint::HintString)
  484. {
  485. hintString = requestContext->GetLibrary()->GetStringTypeDisplayString();
  486. }
  487. else if (hint == JavascriptHint::HintNumber)
  488. {
  489. hintString = requestContext->GetLibrary()->GetNumberTypeDisplayString();
  490. }
  491. else
  492. {
  493. hintString = requestContext->GetPropertyString(PropertyIds::default_);
  494. }
  495. // If exoticToPrim is not undefined, then
  496. if (nullptr != exoticToPrim)
  497. {
  498. ThreadContext * threadContext = requestContext->GetThreadContext();
  499. result = threadContext->ExecuteImplicitCall(exoticToPrim, ImplicitCall_ToPrimitive, [=]()->Js::Var
  500. {
  501. // Stack object should have a pre-op bail on implicit call. We shouldn't see them here.
  502. Assert(!ThreadContext::IsOnStack(recyclableObject));
  503. // Let result be the result of calling the[[Call]] internal method of exoticToPrim, with input as thisArgument and(hint) as argumentsList.
  504. return CALL_FUNCTION(threadContext, exoticToPrim, CallInfo(CallFlags_Value, 2), recyclableObject, hintString);
  505. });
  506. if (!result)
  507. {
  508. // There was an implicit call and implicit calls are disabled. This would typically cause a bailout.
  509. Assert(threadContext->IsDisableImplicitCall());
  510. return requestContext->GetLibrary()->GetNull();
  511. }
  512. Assert(!CrossSite::NeedMarshalVar(result, requestContext));
  513. }
  514. // If result is an ECMAScript language value and Type(result) is not Object, then return result.
  515. if (TaggedInt::Is(result) || !JavascriptOperators::IsObjectType(JavascriptOperators::GetTypeId(result)))
  516. {
  517. return result;
  518. }
  519. // Else, throw a TypeError exception.
  520. else
  521. {
  522. // Don't error if we disabled implicit calls
  523. JavascriptError::TryThrowTypeError(scriptContext, requestContext, JSERR_FunctionArgument_Invalid, _u("[Symbol.toPrimitive]"));
  524. return requestContext->GetLibrary()->GetNull();
  525. }
  526. }
  527. Var JavascriptConversion::OrdinaryToPrimitive(Var aValue, JavascriptHint hint, ScriptContext * requestContext)
  528. {
  529. Var result;
  530. RecyclableObject *const recyclableObject = RecyclableObject::FromVar(aValue);
  531. if (!recyclableObject->ToPrimitive(hint, &result, requestContext))
  532. {
  533. ScriptContext *const scriptContext = recyclableObject->GetScriptContext();
  534. int32 hCode;
  535. switch (hint)
  536. {
  537. case JavascriptHint::HintNumber:
  538. hCode = JSERR_NeedNumber;
  539. break;
  540. case JavascriptHint::HintString:
  541. hCode = JSERR_NeedString;
  542. break;
  543. default:
  544. hCode = VBSERR_OLENoPropOrMethod;
  545. break;
  546. }
  547. JavascriptError::TryThrowTypeError(scriptContext, scriptContext, hCode);
  548. return requestContext->GetLibrary()->GetNull();
  549. }
  550. return result;
  551. }
  552. JavascriptString *JavascriptConversion::CoerseString(Var aValue, ScriptContext* scriptContext, const char16* apiNameForErrorMsg)
  553. {
  554. if (!JavascriptConversion::CheckObjectCoercible(aValue, scriptContext))
  555. {
  556. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NullOrUndefined, apiNameForErrorMsg);
  557. }
  558. return ToString(aValue, scriptContext);
  559. }
  560. //----------------------------------------------------------------------------
  561. // ToString - abstract operation
  562. // ES5 9.8
  563. //Input Type Result
  564. // Undefined
  565. // "undefined"
  566. // Null
  567. // "null"
  568. // Boolean
  569. // If the argument is true, then the result is "true". If the argument is false, then the result is "false".
  570. // Number
  571. // See 9.8.1 below.
  572. // String
  573. // Return the input argument (no conversion)
  574. // Object
  575. // Apply the following steps:
  576. // 1. Let primValue be ToPrimitive(input argument, hint String).
  577. // 2. Return ToString(primValue).
  578. //----------------------------------------------------------------------------
  579. JavascriptString *JavascriptConversion::ToString(Var aValue, ScriptContext* scriptContext)
  580. {
  581. Assert(scriptContext->GetThreadContext()->IsScriptActive());
  582. BOOL fPrimitiveOnly = false;
  583. while(true)
  584. {
  585. switch (JavascriptOperators::GetTypeId(aValue))
  586. {
  587. case TypeIds_Undefined:
  588. return scriptContext->GetLibrary()->GetUndefinedDisplayString();
  589. case TypeIds_Null:
  590. return scriptContext->GetLibrary()->GetNullDisplayString();
  591. case TypeIds_Integer:
  592. return scriptContext->GetIntegerString(aValue);
  593. case TypeIds_Boolean:
  594. return JavascriptBoolean::FromVar(aValue)->GetValue() ? scriptContext->GetLibrary()->GetTrueDisplayString() : scriptContext->GetLibrary()->GetFalseDisplayString();
  595. case TypeIds_Number:
  596. return JavascriptNumber::ToStringRadix10(JavascriptNumber::GetValue(aValue), scriptContext);
  597. case TypeIds_Int64Number:
  598. {
  599. __int64 value = JavascriptInt64Number::FromVar(aValue)->GetValue();
  600. if (!TaggedInt::IsOverflow(value))
  601. {
  602. return scriptContext->GetIntegerString((int)value);
  603. }
  604. else
  605. {
  606. return JavascriptInt64Number::ToString(aValue, scriptContext);
  607. }
  608. }
  609. case TypeIds_UInt64Number:
  610. {
  611. unsigned __int64 value = JavascriptUInt64Number::FromVar(aValue)->GetValue();
  612. if (!TaggedInt::IsOverflow(value))
  613. {
  614. return scriptContext->GetIntegerString((uint)value);
  615. }
  616. else
  617. {
  618. return JavascriptUInt64Number::ToString(aValue, scriptContext);
  619. }
  620. }
  621. case TypeIds_String:
  622. {
  623. ScriptContext* aValueScriptContext = Js::RecyclableObject::FromVar(aValue)->GetScriptContext();
  624. return JavascriptString::FromVar(CrossSite::MarshalVar(scriptContext,
  625. aValue, aValueScriptContext));
  626. }
  627. case TypeIds_VariantDate:
  628. return JavascriptVariantDate::FromVar(aValue)->GetValueString(scriptContext);
  629. case TypeIds_Symbol:
  630. return JavascriptSymbol::FromVar(aValue)->ToString(scriptContext);
  631. case TypeIds_SymbolObject:
  632. return JavascriptSymbol::ToString(JavascriptSymbolObject::FromVar(aValue)->GetValue(), scriptContext);
  633. #ifdef ENABLE_SIMDJS
  634. case TypeIds_SIMDBool8x16:
  635. case TypeIds_SIMDBool16x8:
  636. case TypeIds_SIMDBool32x4:
  637. case TypeIds_SIMDInt8x16:
  638. case TypeIds_SIMDInt16x8:
  639. case TypeIds_SIMDInt32x4:
  640. case TypeIds_SIMDUint8x16:
  641. case TypeIds_SIMDUint16x8:
  642. case TypeIds_SIMDUint32x4:
  643. case TypeIds_SIMDFloat32x4:
  644. {
  645. Assert(aValue);
  646. RecyclableObject *obj = nullptr;
  647. if (!JavascriptConversion::ToObject(aValue, scriptContext, &obj))
  648. {
  649. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedSimd, _u("SIMDType.toString"));
  650. }
  651. JavascriptSIMDObject* simdObject = static_cast<JavascriptSIMDObject*>(obj);
  652. return JavascriptString::FromVar(simdObject->ToString(scriptContext));
  653. }
  654. #endif
  655. case TypeIds_GlobalObject:
  656. aValue = static_cast<Js::GlobalObject*>(aValue)->ToThis();
  657. // fall through
  658. default:
  659. {
  660. AssertMsg(JavascriptOperators::IsObject(aValue), "bad type object in conversion ToString");
  661. if(fPrimitiveOnly)
  662. {
  663. AssertMsg(FALSE, "wrong call in ToString, no dynamic objects should get here");
  664. JavascriptError::ThrowError(scriptContext, VBSERR_InternalError);
  665. }
  666. fPrimitiveOnly = true;
  667. aValue = ToPrimitive(aValue, JavascriptHint::HintString, scriptContext);
  668. }
  669. }
  670. }
  671. }
  672. JavascriptString *JavascriptConversion::ToLocaleString(Var aValue, ScriptContext* scriptContext)
  673. {
  674. switch (JavascriptOperators::GetTypeId(aValue))
  675. {
  676. case TypeIds_Undefined:
  677. return scriptContext->GetLibrary()->GetUndefinedDisplayString();
  678. case TypeIds_Null:
  679. return scriptContext->GetLibrary()->GetNullDisplayString();
  680. case TypeIds_Integer:
  681. return JavascriptNumber::ToLocaleString(TaggedInt::ToInt32(aValue), scriptContext);
  682. case TypeIds_Boolean:
  683. return JavascriptBoolean::FromVar(aValue)->GetValue() ? scriptContext->GetLibrary()->GetTrueDisplayString() : scriptContext->GetLibrary()->GetFalseDisplayString();
  684. case TypeIds_Int64Number:
  685. return JavascriptNumber::ToLocaleString((double)JavascriptInt64Number::FromVar(aValue)->GetValue(), scriptContext);
  686. case TypeIds_UInt64Number:
  687. return JavascriptNumber::ToLocaleString((double)JavascriptUInt64Number::FromVar(aValue)->GetValue(), scriptContext);
  688. case TypeIds_Number:
  689. return JavascriptNumber::ToLocaleString(JavascriptNumber::GetValue(aValue), scriptContext);
  690. case TypeIds_String:
  691. return JavascriptString::FromVar(aValue);
  692. case TypeIds_VariantDate:
  693. // Legacy behavior was to create an empty object and call toLocaleString on it, which would result in this value
  694. return scriptContext->GetLibrary()->GetObjectDisplayString();
  695. case TypeIds_Symbol:
  696. return JavascriptSymbol::FromVar(aValue)->ToString(scriptContext);
  697. default:
  698. {
  699. RecyclableObject* object = RecyclableObject::FromVar(aValue);
  700. Var value = JavascriptOperators::GetProperty(object, PropertyIds::toLocaleString, scriptContext, NULL);
  701. if (JavascriptConversion::IsCallable(value))
  702. {
  703. RecyclableObject* toLocaleStringFunction = RecyclableObject::FromVar(value);
  704. Var aResult = CALL_FUNCTION(scriptContext->GetThreadContext(), toLocaleStringFunction, CallInfo(1), aValue);
  705. if (JavascriptString::Is(aResult))
  706. {
  707. return JavascriptString::FromVar(aResult);
  708. }
  709. else
  710. {
  711. return JavascriptConversion::ToString(aResult, scriptContext);
  712. }
  713. }
  714. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_NeedFunction, scriptContext->GetPropertyName(PropertyIds::toLocaleString)->GetBuffer());
  715. }
  716. }
  717. }
  718. //----------------------------------------------------------------------------
  719. // ToBoolean_Full:
  720. // (ES3.0: S9.2):
  721. //
  722. // Input Output
  723. // ----- ------
  724. // 'undefined' 'false'
  725. // 'null' 'false'
  726. // Boolean Value
  727. // Number 'false' if +0, -0, or Nan
  728. // 'true' otherwise
  729. // String 'false' if argument is ""
  730. // 'true' otherwise
  731. // Object 'true'
  732. // Falsy Object 'false'
  733. //----------------------------------------------------------------------------
  734. BOOL JavascriptConversion::ToBoolean_Full(Var aValue, ScriptContext* scriptContext)
  735. {
  736. AssertMsg(!TaggedInt::Is(aValue), "Should be detected");
  737. AssertMsg(RecyclableObject::Is(aValue), "Should be handled already");
  738. auto type = RecyclableObject::FromVar(aValue)->GetType();
  739. switch (type->GetTypeId())
  740. {
  741. case TypeIds_Undefined:
  742. case TypeIds_Null:
  743. case TypeIds_VariantDate:
  744. return false;
  745. case TypeIds_Symbol:
  746. return true;
  747. case TypeIds_Boolean:
  748. return JavascriptBoolean::FromVar(aValue)->GetValue();
  749. #if !FLOATVAR
  750. case TypeIds_Number:
  751. {
  752. double value = JavascriptNumber::GetValue(aValue);
  753. return (!JavascriptNumber::IsNan(value)) && (!JavascriptNumber::IsZero(value));
  754. }
  755. #endif
  756. case TypeIds_Int64Number:
  757. {
  758. __int64 value = JavascriptInt64Number::FromVar(aValue)->GetValue();
  759. return value != 0;
  760. }
  761. case TypeIds_UInt64Number:
  762. {
  763. unsigned __int64 value = JavascriptUInt64Number::FromVar(aValue)->GetValue();
  764. return value != 0;
  765. }
  766. case TypeIds_String:
  767. {
  768. JavascriptString * pstValue = JavascriptString::FromVar(aValue);
  769. return pstValue->GetLength() > 0;
  770. }
  771. #ifdef ENABLE_SIMDJS
  772. case TypeIds_SIMDFloat32x4:
  773. case TypeIds_SIMDFloat64x2:
  774. case TypeIds_SIMDInt32x4:
  775. case TypeIds_SIMDInt16x8:
  776. case TypeIds_SIMDInt8x16:
  777. case TypeIds_SIMDBool32x4:
  778. case TypeIds_SIMDBool16x8:
  779. case TypeIds_SIMDBool8x16:
  780. case TypeIds_SIMDUint32x4:
  781. case TypeIds_SIMDUint16x8:
  782. case TypeIds_SIMDUint8x16:
  783. {
  784. return true;
  785. }
  786. #endif
  787. default:
  788. {
  789. AssertMsg(JavascriptOperators::IsObject(aValue), "bad type object in conversion ToBoolean");
  790. // Falsy objects evaluate to false when converted to Boolean.
  791. return !type->IsFalsy();
  792. }
  793. }
  794. }
  795. void JavascriptConversion::ToFloat_Helper(Var aValue, float *pResult, ScriptContext* scriptContext)
  796. {
  797. *pResult = (float)ToNumber_Full(aValue, scriptContext);
  798. }
  799. void JavascriptConversion::ToNumber_Helper(Var aValue, double *pResult, ScriptContext* scriptContext)
  800. {
  801. Assert(Js::JavascriptStackWalker::ValidateTopJitFrame(scriptContext));
  802. *pResult = ToNumber_Full(aValue, scriptContext);
  803. }
  804. // Used for the JIT's float type specialization
  805. // Convert aValue to double, but only allow primitives. Return false otherwise.
  806. BOOL JavascriptConversion::ToNumber_FromPrimitive(Var aValue, double *pResult, BOOL allowUndefined, ScriptContext* scriptContext)
  807. {
  808. Assert(Js::JavascriptStackWalker::ValidateTopJitFrame(scriptContext));
  809. Assert(!TaggedNumber::Is(aValue));
  810. RecyclableObject *obj = RecyclableObject::FromVar(aValue);
  811. // NOTE: Don't allow strings, otherwise JIT's float type specialization has to worry about concats
  812. if (obj->GetTypeId() >= TypeIds_String)
  813. {
  814. return false;
  815. }
  816. if (!allowUndefined && obj->GetTypeId() == TypeIds_Undefined)
  817. {
  818. return false;
  819. }
  820. *pResult = ToNumber_Full(aValue, scriptContext);
  821. return true;
  822. }
  823. //----------------------------------------------------------------------------
  824. // ToNumber_Full:
  825. // Implements ES6 Draft Rev 26 July 18, 2014
  826. //
  827. // Undefined: NaN
  828. // Null: 0
  829. // boolean: v==true ? 1 : 0 ;
  830. // number: v (original number)
  831. // String: conversion by spec algorithm
  832. // object: ToNumber(PrimitiveValue(v, hint_number))
  833. // Symbol: TypeError
  834. //----------------------------------------------------------------------------
  835. double JavascriptConversion::ToNumber_Full(Var aValue,ScriptContext* scriptContext)
  836. {
  837. AssertMsg(!TaggedInt::Is(aValue), "Should be detected");
  838. ScriptContext * objectScriptContext = RecyclableObject::Is(aValue) ? RecyclableObject::FromVar(aValue)->GetScriptContext() : nullptr;
  839. BOOL fPrimitiveOnly = false;
  840. while(true)
  841. {
  842. switch (JavascriptOperators::GetTypeId(aValue))
  843. {
  844. case TypeIds_Symbol:
  845. JavascriptError::TryThrowTypeError(objectScriptContext, scriptContext, JSERR_NeedNumber);
  846. // Fallthrough to return NaN if exceptions are disabled
  847. case TypeIds_Undefined:
  848. return JavascriptNumber::GetValue(scriptContext->GetLibrary()->GetNaN());
  849. case TypeIds_Null:
  850. return 0;
  851. case TypeIds_Integer:
  852. return TaggedInt::ToDouble(aValue);
  853. case TypeIds_Boolean:
  854. return JavascriptBoolean::FromVar(aValue)->GetValue() ? 1 : +0;
  855. case TypeIds_Number:
  856. return JavascriptNumber::GetValue(aValue);
  857. case TypeIds_Int64Number:
  858. return (double)JavascriptInt64Number::FromVar(aValue)->GetValue();
  859. case TypeIds_UInt64Number:
  860. return (double)JavascriptUInt64Number::FromVar(aValue)->GetValue();
  861. case TypeIds_String:
  862. return JavascriptString::FromVar(aValue)->ToDouble();
  863. case TypeIds_VariantDate:
  864. return Js::DateImplementation::GetTvUtc(Js::DateImplementation::JsLocalTimeFromVarDate(JavascriptVariantDate::FromVar(aValue)->GetValue()), scriptContext);
  865. #ifdef ENABLE_SIMDJS
  866. case TypeIds_SIMDFloat32x4:
  867. case TypeIds_SIMDInt32x4:
  868. case TypeIds_SIMDInt16x8:
  869. case TypeIds_SIMDInt8x16:
  870. case TypeIds_SIMDFloat64x2:
  871. case TypeIds_SIMDBool32x4:
  872. case TypeIds_SIMDBool16x8:
  873. case TypeIds_SIMDBool8x16:
  874. case TypeIds_SIMDUint32x4:
  875. case TypeIds_SIMDUint16x8:
  876. case TypeIds_SIMDUint8x16:
  877. JavascriptError::ThrowError(scriptContext, JSERR_NeedNumber);
  878. #endif
  879. default:
  880. {
  881. AssertMsg(JavascriptOperators::IsObject(aValue), "bad type object in conversion ToInteger");
  882. if(fPrimitiveOnly)
  883. {
  884. JavascriptError::ThrowError(scriptContext, VBSERR_OLENoPropOrMethod);
  885. }
  886. fPrimitiveOnly = true;
  887. aValue = ToPrimitive(aValue, JavascriptHint::HintNumber, scriptContext);
  888. }
  889. }
  890. }
  891. }
  892. //----------------------------------------------------------------------------
  893. // second part of the ToInteger() implementation.(ES5.0: S9.4).
  894. //----------------------------------------------------------------------------
  895. double JavascriptConversion::ToInteger_Full(Var aValue,ScriptContext* scriptContext)
  896. {
  897. AssertMsg(!TaggedInt::Is(aValue), "Should be detected");
  898. ScriptContext * objectScriptContext = RecyclableObject::Is(aValue) ? RecyclableObject::FromVar(aValue)->GetScriptContext() : nullptr;
  899. BOOL fPrimitiveOnly = false;
  900. while(true)
  901. {
  902. switch (JavascriptOperators::GetTypeId(aValue))
  903. {
  904. case TypeIds_Symbol:
  905. JavascriptError::TryThrowTypeError(objectScriptContext, scriptContext, JSERR_NeedNumber);
  906. // Fallthrough to return 0 if exceptions are disabled
  907. case TypeIds_Undefined:
  908. case TypeIds_Null:
  909. return 0;
  910. case TypeIds_Integer:
  911. return TaggedInt::ToInt32(aValue);
  912. case TypeIds_Boolean:
  913. return JavascriptBoolean::FromVar(aValue)->GetValue() ? 1 : +0;
  914. case TypeIds_Number:
  915. return ToInteger(JavascriptNumber::GetValue(aValue));
  916. case TypeIds_Int64Number:
  917. return ToInteger((double)JavascriptInt64Number::FromVar(aValue)->GetValue());
  918. case TypeIds_UInt64Number:
  919. return ToInteger((double)JavascriptUInt64Number::FromVar(aValue)->GetValue());
  920. case TypeIds_String:
  921. return ToInteger(JavascriptString::FromVar(aValue)->ToDouble());
  922. case TypeIds_VariantDate:
  923. return ToInteger(ToNumber_Full(aValue, scriptContext));
  924. #ifdef ENABLE_SIMDJS
  925. case TypeIds_SIMDFloat32x4:
  926. case TypeIds_SIMDFloat64x2:
  927. case TypeIds_SIMDInt32x4:
  928. case TypeIds_SIMDInt16x8:
  929. case TypeIds_SIMDInt8x16:
  930. case TypeIds_SIMDBool32x4:
  931. case TypeIds_SIMDBool16x8:
  932. case TypeIds_SIMDBool8x16:
  933. case TypeIds_SIMDUint32x4:
  934. case TypeIds_SIMDUint16x8:
  935. case TypeIds_SIMDUint8x16:
  936. JavascriptError::ThrowError(scriptContext, JSERR_NeedNumber);
  937. #endif
  938. default:
  939. {
  940. AssertMsg(JavascriptOperators::IsObject(aValue), "bad type object in conversion ToInteger");
  941. if(fPrimitiveOnly)
  942. {
  943. AssertMsg(FALSE, "wrong call in ToInteger_Full, no dynamic objects should get here");
  944. JavascriptError::ThrowError(scriptContext, VBSERR_OLENoPropOrMethod);
  945. }
  946. fPrimitiveOnly = true;
  947. aValue = ToPrimitive(aValue, JavascriptHint::HintNumber, scriptContext);
  948. }
  949. }
  950. }
  951. }
  952. double JavascriptConversion::ToInteger(double val)
  953. {
  954. if(JavascriptNumber::IsNan(val))
  955. return 0;
  956. if(JavascriptNumber::IsPosInf(val) || JavascriptNumber::IsNegInf(val) ||
  957. JavascriptNumber::IsZero(val))
  958. {
  959. return val;
  960. }
  961. return ( ((val < 0) ? -1 : 1 ) * floor(fabs(val)));
  962. }
  963. //----------------------------------------------------------------------------
  964. // ToInt32() converts the given Var to an Int32 value, as described in
  965. // (ES3.0: S9.5).
  966. //----------------------------------------------------------------------------
  967. int32 JavascriptConversion::ToInt32_Full(Var aValue, ScriptContext* scriptContext)
  968. {
  969. Assert(Js::JavascriptStackWalker::ValidateTopJitFrame(scriptContext));
  970. AssertMsg(!TaggedInt::Is(aValue), "Should be detected");
  971. ScriptContext * objectScriptContext = RecyclableObject::Is(aValue) ? RecyclableObject::FromVar(aValue)->GetScriptContext() : nullptr;
  972. // This is used when TaggedInt's overflow but remain under int32
  973. // so Number is our most critical case:
  974. TypeId typeId = JavascriptOperators::GetTypeId(aValue);
  975. if (typeId == TypeIds_Number)
  976. {
  977. return JavascriptMath::ToInt32Core(JavascriptNumber::GetValue(aValue));
  978. }
  979. switch (typeId)
  980. {
  981. case TypeIds_Symbol:
  982. JavascriptError::TryThrowTypeError(objectScriptContext, scriptContext, JSERR_NeedNumber);
  983. // Fallthrough to return 0 if exceptions are disabled
  984. case TypeIds_Undefined:
  985. case TypeIds_Null:
  986. return 0;
  987. case TypeIds_Integer:
  988. return TaggedInt::ToInt32(aValue);
  989. case TypeIds_Boolean:
  990. return JavascriptBoolean::FromVar(aValue)->GetValue() ? 1 : +0;
  991. case TypeIds_Int64Number:
  992. // we won't lose precision if the int64 is within 32bit boundary; otherwise we need to
  993. // treat it as double anyhow.
  994. return JavascriptMath::ToInt32Core((double)JavascriptInt64Number::FromVar(aValue)->GetValue());
  995. case TypeIds_UInt64Number:
  996. // we won't lose precision if the int64 is within 32bit boundary; otherwise we need to
  997. // treat it as double anyhow.
  998. return JavascriptMath::ToInt32Core((double)JavascriptUInt64Number::FromVar(aValue)->GetValue());
  999. case TypeIds_String:
  1000. {
  1001. double result;
  1002. if (JavascriptString::FromVar(aValue)->ToDouble(&result))
  1003. {
  1004. return JavascriptMath::ToInt32Core(result);
  1005. }
  1006. // If the string isn't a valid number, ToDouble returns NaN, and ToInt32 of that is 0
  1007. return 0;
  1008. }
  1009. case TypeIds_VariantDate:
  1010. return ToInt32(ToNumber_Full(aValue, scriptContext));
  1011. #ifdef ENABLE_SIMDJS
  1012. case TypeIds_SIMDFloat32x4:
  1013. case TypeIds_SIMDFloat64x2:
  1014. case TypeIds_SIMDInt32x4:
  1015. case TypeIds_SIMDInt16x8:
  1016. case TypeIds_SIMDInt8x16:
  1017. case TypeIds_SIMDBool32x4:
  1018. case TypeIds_SIMDBool16x8:
  1019. case TypeIds_SIMDBool8x16:
  1020. case TypeIds_SIMDUint32x4:
  1021. case TypeIds_SIMDUint16x8:
  1022. case TypeIds_SIMDUint8x16:
  1023. JavascriptError::ThrowError(scriptContext, JSERR_NeedNumber);
  1024. #endif
  1025. default:
  1026. AssertMsg(JavascriptOperators::IsObject(aValue), "bad type object in conversion ToInteger32");
  1027. aValue = ToPrimitive(aValue, JavascriptHint::HintNumber, scriptContext);
  1028. }
  1029. switch (JavascriptOperators::GetTypeId(aValue))
  1030. {
  1031. case TypeIds_Symbol:
  1032. JavascriptError::TryThrowTypeError(objectScriptContext, scriptContext, JSERR_NeedNumber);
  1033. // Fallthrough to return 0 if exceptions are disabled
  1034. case TypeIds_Undefined:
  1035. case TypeIds_Null:
  1036. return 0;
  1037. case TypeIds_Integer:
  1038. return TaggedInt::ToInt32(aValue);
  1039. case TypeIds_Boolean:
  1040. return JavascriptBoolean::FromVar(aValue)->GetValue() ? 1 : +0;
  1041. case TypeIds_Number:
  1042. return ToInt32(JavascriptNumber::GetValue(aValue));
  1043. case TypeIds_Int64Number:
  1044. // we won't lose precision if the int64 is within 32bit boundary; otherwise we need to
  1045. // treat it as double anyhow.
  1046. return JavascriptMath::ToInt32Core((double)JavascriptInt64Number::FromVar(aValue)->GetValue());
  1047. case TypeIds_UInt64Number:
  1048. // we won't lose precision if the int64 is within 32bit boundary; otherwise we need to
  1049. // treat it as double anyhow.
  1050. return JavascriptMath::ToInt32Core((double)JavascriptUInt64Number::FromVar(aValue)->GetValue());
  1051. case TypeIds_String:
  1052. {
  1053. double result;
  1054. if (JavascriptString::FromVar(aValue)->ToDouble(&result))
  1055. {
  1056. return ToInt32(result);
  1057. }
  1058. // If the string isn't a valid number, ToDouble returns NaN, and ToInt32 of that is 0
  1059. return 0;
  1060. }
  1061. case TypeIds_VariantDate:
  1062. return ToInt32(ToNumber_Full(aValue, scriptContext));
  1063. default:
  1064. AssertMsg(FALSE, "wrong call in ToInteger32_Full, no dynamic objects should get here.");
  1065. JavascriptError::ThrowError(scriptContext, VBSERR_OLENoPropOrMethod);
  1066. }
  1067. }
  1068. // a strict version of ToInt32 conversion that returns false for non int32 values like, inf, NaN, undef
  1069. BOOL JavascriptConversion::ToInt32Finite(Var aValue, ScriptContext* scriptContext, int32* result)
  1070. {
  1071. ScriptContext * objectScriptContext = RecyclableObject::Is(aValue) ? RecyclableObject::FromVar(aValue)->GetScriptContext() : nullptr;
  1072. BOOL fPrimitiveOnly = false;
  1073. while(true)
  1074. {
  1075. switch (JavascriptOperators::GetTypeId(aValue))
  1076. {
  1077. case TypeIds_Symbol:
  1078. JavascriptError::TryThrowTypeError(objectScriptContext, scriptContext, JSERR_NeedNumber);
  1079. // Fallthrough to return false and set result to 0 if exceptions are disabled
  1080. case TypeIds_Undefined:
  1081. *result = 0;
  1082. return false;
  1083. case TypeIds_Null:
  1084. *result = 0;
  1085. return true;
  1086. case TypeIds_Integer:
  1087. *result = TaggedInt::ToInt32(aValue);
  1088. return true;
  1089. case TypeIds_Boolean:
  1090. *result = JavascriptBoolean::FromVar(aValue)->GetValue() ? 1 : +0;
  1091. return true;
  1092. case TypeIds_Number:
  1093. return ToInt32Finite(JavascriptNumber::GetValue(aValue), result);
  1094. case TypeIds_Int64Number:
  1095. // we won't lose precision if the int64 is within 32bit boundary; otherwise we need to
  1096. // treat it as double anyhow.
  1097. return ToInt32Finite((double)JavascriptInt64Number::FromVar(aValue)->GetValue(), result);
  1098. case TypeIds_UInt64Number:
  1099. // we won't lose precision if the int64 is within 32bit boundary; otherwise we need to
  1100. // treat it as double anyhow.
  1101. return ToInt32Finite((double)JavascriptUInt64Number::FromVar(aValue)->GetValue(), result);
  1102. case TypeIds_String:
  1103. return ToInt32Finite(JavascriptString::FromVar(aValue)->ToDouble(), result);
  1104. case TypeIds_VariantDate:
  1105. return ToInt32Finite(ToNumber_Full(aValue, scriptContext), result);
  1106. #ifdef ENABLE_SIMDJS
  1107. case TypeIds_SIMDFloat32x4:
  1108. case TypeIds_SIMDFloat64x2:
  1109. case TypeIds_SIMDInt32x4:
  1110. case TypeIds_SIMDInt16x8:
  1111. case TypeIds_SIMDInt8x16:
  1112. case TypeIds_SIMDBool32x4:
  1113. case TypeIds_SIMDBool16x8:
  1114. case TypeIds_SIMDBool8x16:
  1115. case TypeIds_SIMDUint32x4:
  1116. case TypeIds_SIMDUint16x8:
  1117. case TypeIds_SIMDUint8x16:
  1118. JavascriptError::ThrowError(scriptContext, JSERR_NeedNumber);
  1119. #endif
  1120. default:
  1121. {
  1122. AssertMsg(JavascriptOperators::IsObject(aValue), "bad type object in conversion ToInteger32");
  1123. if(fPrimitiveOnly)
  1124. {
  1125. AssertMsg(FALSE, "wrong call in ToInteger32_Full, no dynamic objects should get here");
  1126. JavascriptError::ThrowError(scriptContext, VBSERR_OLENoPropOrMethod);
  1127. }
  1128. fPrimitiveOnly = true;
  1129. aValue = ToPrimitive(aValue, JavascriptHint::HintNumber, scriptContext);
  1130. }
  1131. }
  1132. }
  1133. }
  1134. int32 JavascriptConversion::ToInt32(double T1)
  1135. {
  1136. return JavascriptMath::ToInt32Core(T1);
  1137. }
  1138. __int64 JavascriptConversion::ToInt64(Var aValue, ScriptContext* scriptContext)
  1139. {
  1140. switch (JavascriptOperators::GetTypeId(aValue))
  1141. {
  1142. case TypeIds_Integer:
  1143. {
  1144. return TaggedInt::ToInt32(aValue);
  1145. }
  1146. case TypeIds_Int64Number:
  1147. {
  1148. JavascriptInt64Number* int64Number = JavascriptInt64Number::FromVar(aValue);
  1149. return int64Number->GetValue();
  1150. }
  1151. case TypeIds_UInt64Number:
  1152. {
  1153. JavascriptUInt64Number* uint64Number = JavascriptUInt64Number::FromVar(aValue);
  1154. return (__int64)uint64Number->GetValue();
  1155. }
  1156. case TypeIds_Number:
  1157. return JavascriptMath::TryToInt64(JavascriptNumber::GetValue(aValue));
  1158. default:
  1159. return (unsigned __int64)JavascriptConversion::ToInt32_Full(aValue, scriptContext);
  1160. }
  1161. }
  1162. unsigned __int64 JavascriptConversion::ToUInt64(Var aValue, ScriptContext* scriptContext)
  1163. {
  1164. switch (JavascriptOperators::GetTypeId(aValue))
  1165. {
  1166. case TypeIds_Integer:
  1167. {
  1168. return (unsigned __int64)TaggedInt::ToInt32(aValue);
  1169. }
  1170. case TypeIds_Int64Number:
  1171. {
  1172. JavascriptInt64Number* int64Number = JavascriptInt64Number::FromVar(aValue);
  1173. return (unsigned __int64)int64Number->GetValue();
  1174. }
  1175. case TypeIds_UInt64Number:
  1176. {
  1177. JavascriptUInt64Number* uint64Number = JavascriptUInt64Number::FromVar(aValue);
  1178. return uint64Number->GetValue();
  1179. }
  1180. case TypeIds_Number:
  1181. return static_cast<unsigned __int64>(JavascriptMath::TryToInt64(JavascriptNumber::GetValue(aValue)));
  1182. default:
  1183. return (unsigned __int64)JavascriptConversion::ToInt32_Full(aValue, scriptContext);
  1184. }
  1185. }
  1186. BOOL JavascriptConversion::ToInt32Finite(double value, int32* result)
  1187. {
  1188. if((!NumberUtilities::IsFinite(value)) || JavascriptNumber::IsNan(value))
  1189. {
  1190. *result = 0;
  1191. return false;
  1192. }
  1193. else
  1194. {
  1195. *result = JavascriptMath::ToInt32Core(value);
  1196. return true;
  1197. }
  1198. }
  1199. //----------------------------------------------------------------------------
  1200. // (ES3.0: S9.6).
  1201. //----------------------------------------------------------------------------
  1202. uint32 JavascriptConversion::ToUInt32_Full(Var aValue, ScriptContext* scriptContext)
  1203. {
  1204. AssertMsg(!TaggedInt::Is(aValue), "Should be detected");
  1205. ScriptContext * objectScriptContext = RecyclableObject::Is(aValue) ? RecyclableObject::FromVar(aValue)->GetScriptContext() : nullptr;
  1206. BOOL fPrimitiveOnly = false;
  1207. while(true)
  1208. {
  1209. switch (JavascriptOperators::GetTypeId(aValue))
  1210. {
  1211. case TypeIds_Symbol:
  1212. JavascriptError::TryThrowTypeError(objectScriptContext, scriptContext, JSERR_NeedNumber);
  1213. // Fallthrough to return 0 if exceptions are disabled
  1214. case TypeIds_Undefined:
  1215. case TypeIds_Null:
  1216. return 0;
  1217. case TypeIds_Integer:
  1218. return TaggedInt::ToUInt32(aValue);
  1219. case TypeIds_Boolean:
  1220. return JavascriptBoolean::FromVar(aValue)->GetValue() ? 1 : +0;
  1221. case TypeIds_Number:
  1222. return JavascriptMath::ToUInt32(JavascriptNumber::GetValue(aValue));
  1223. case TypeIds_Int64Number:
  1224. // we won't lose precision if the int64 is within 32bit boundary; otherwise we need to
  1225. // treat it as double anyhow.
  1226. return JavascriptMath::ToUInt32((double)JavascriptInt64Number::FromVar(aValue)->GetValue());
  1227. case TypeIds_UInt64Number:
  1228. // we won't lose precision if the int64 is within 32bit boundary; otherwise we need to
  1229. // treat it as double anyhow.
  1230. return JavascriptMath::ToUInt32((double)JavascriptUInt64Number::FromVar(aValue)->GetValue());
  1231. case TypeIds_String:
  1232. {
  1233. double result;
  1234. if (JavascriptString::FromVar(aValue)->ToDouble(&result))
  1235. {
  1236. return JavascriptMath::ToUInt32(result);
  1237. }
  1238. // If the string isn't a valid number, ToDouble returns NaN, and ToUInt32 of that is 0
  1239. return 0;
  1240. }
  1241. case TypeIds_VariantDate:
  1242. return JavascriptMath::ToUInt32(ToNumber_Full(aValue, scriptContext));
  1243. #ifdef ENABLE_SIMDJS
  1244. case TypeIds_SIMDFloat32x4:
  1245. case TypeIds_SIMDFloat64x2:
  1246. case TypeIds_SIMDInt32x4:
  1247. case TypeIds_SIMDInt16x8:
  1248. case TypeIds_SIMDInt8x16:
  1249. case TypeIds_SIMDBool32x4:
  1250. case TypeIds_SIMDBool16x8:
  1251. case TypeIds_SIMDBool8x16:
  1252. case TypeIds_SIMDUint32x4:
  1253. case TypeIds_SIMDUint16x8:
  1254. case TypeIds_SIMDUint8x16:
  1255. JavascriptError::ThrowError(scriptContext, JSERR_NeedNumber);
  1256. #endif
  1257. default:
  1258. {
  1259. AssertMsg(JavascriptOperators::IsObject(aValue), "bad type object in conversion ToUInt32");
  1260. if(fPrimitiveOnly)
  1261. {
  1262. AssertMsg(FALSE, "wrong call in ToUInt32_Full, no dynamic objects should get here");
  1263. JavascriptError::ThrowError(scriptContext, VBSERR_OLENoPropOrMethod);
  1264. }
  1265. fPrimitiveOnly = true;
  1266. aValue = ToPrimitive(aValue, JavascriptHint::HintNumber, scriptContext);
  1267. }
  1268. }
  1269. }
  1270. }
  1271. uint32 JavascriptConversion::ToUInt32(double T1)
  1272. {
  1273. // Same as doing ToInt32 and reinterpret the bits as uint32
  1274. return (uint32)JavascriptMath::ToInt32Core(T1);
  1275. }
  1276. //----------------------------------------------------------------------------
  1277. // ToUInt16() converts the given Var to a UInt16 value, as described in
  1278. // (ES3.0: S9.6).
  1279. //----------------------------------------------------------------------------
  1280. uint16 JavascriptConversion::ToUInt16_Full(IN Var aValue, ScriptContext* scriptContext)
  1281. {
  1282. AssertMsg(!TaggedInt::Is(aValue), "Should be detected");
  1283. ScriptContext * objectScriptContext = RecyclableObject::Is(aValue) ? RecyclableObject::FromVar(aValue)->GetScriptContext() : nullptr;
  1284. BOOL fPrimitiveOnly = false;
  1285. while(true)
  1286. {
  1287. switch (JavascriptOperators::GetTypeId(aValue))
  1288. {
  1289. case TypeIds_Symbol:
  1290. JavascriptError::TryThrowTypeError(objectScriptContext, scriptContext, JSERR_NeedNumber);
  1291. // Fallthrough to return 0 if exceptions are disabled
  1292. case TypeIds_Undefined:
  1293. case TypeIds_Null:
  1294. return 0;
  1295. case TypeIds_Integer:
  1296. return TaggedInt::ToUInt16(aValue);
  1297. case TypeIds_Boolean:
  1298. return JavascriptBoolean::FromVar(aValue)->GetValue() ? 1 : +0;
  1299. case TypeIds_Number:
  1300. return ToUInt16(JavascriptNumber::GetValue(aValue));
  1301. case TypeIds_Int64Number:
  1302. // we won't lose precision if the int64 is within 16bit boundary; otherwise we need to
  1303. // treat it as double anyhow.
  1304. return ToUInt16((double)JavascriptInt64Number::FromVar(aValue)->GetValue());
  1305. case TypeIds_UInt64Number:
  1306. // we won't lose precision if the int64 is within 16bit boundary; otherwise we need to
  1307. // treat it as double anyhow.
  1308. return ToUInt16((double)JavascriptUInt64Number::FromVar(aValue)->GetValue());
  1309. case TypeIds_String:
  1310. {
  1311. double result;
  1312. if (JavascriptString::FromVar(aValue)->ToDouble(&result))
  1313. {
  1314. return ToUInt16(result);
  1315. }
  1316. // If the string isn't a valid number, ToDouble is NaN, and ToUInt16 of that is 0
  1317. return 0;
  1318. }
  1319. case TypeIds_VariantDate:
  1320. return ToUInt16(ToNumber_Full(aValue, scriptContext));
  1321. #ifdef ENABLE_SIMDJS
  1322. case TypeIds_SIMDFloat32x4:
  1323. case TypeIds_SIMDFloat64x2:
  1324. case TypeIds_SIMDInt32x4:
  1325. case TypeIds_SIMDInt16x8:
  1326. case TypeIds_SIMDInt8x16:
  1327. case TypeIds_SIMDBool32x4:
  1328. case TypeIds_SIMDBool16x8:
  1329. case TypeIds_SIMDBool8x16:
  1330. case TypeIds_SIMDUint32x4:
  1331. case TypeIds_SIMDUint16x8:
  1332. case TypeIds_SIMDUint8x16:
  1333. JavascriptError::ThrowError(scriptContext, JSERR_NeedNumber);
  1334. #endif
  1335. default:
  1336. {
  1337. AssertMsg(JavascriptOperators::IsObject(aValue), "bad type object in conversion ToUIn16");
  1338. if(fPrimitiveOnly)
  1339. {
  1340. AssertMsg(FALSE, "wrong call in ToUInt16, no dynamic objects should get here");
  1341. JavascriptError::ThrowError(scriptContext, VBSERR_OLENoPropOrMethod);
  1342. }
  1343. fPrimitiveOnly = true;
  1344. aValue = ToPrimitive(aValue, JavascriptHint::HintNumber, scriptContext);
  1345. }
  1346. }
  1347. }
  1348. }
  1349. inline uint16 JavascriptConversion::ToUInt16(double T1)
  1350. {
  1351. //
  1352. // VC does the right thing here, if we first convert to uint32 and then to uint16
  1353. // Spec says mod should be done.
  1354. //
  1355. uint32 result = JavascriptConversion::ToUInt32(T1);
  1356. #if defined(_M_IX86) && _MSC_FULL_VER < 160030329
  1357. // Well VC doesn't actually do the right thing... It takes (uint16)(uint32)double and removes the
  1358. // middle uint32 cast to (uint16)double, which isn't the same thing. Somehow, it only seems to be a
  1359. // problem for x86. Forcing a store to uint32 prevents the incorrect optimization.
  1360. //
  1361. // A bug has been filled in the Dev11 database: TF bug id #901495
  1362. // Fixed in compiler 16.00.30329.00
  1363. volatile uint32 volResult = result;
  1364. #endif
  1365. return (uint16) result;
  1366. }
  1367. JavascriptString * JavascriptConversion::ToPrimitiveString(Var aValue, ScriptContext * scriptContext)
  1368. {
  1369. return ToString(ToPrimitive(aValue, JavascriptHint::None, scriptContext), scriptContext);
  1370. }
  1371. double JavascriptConversion::LongToDouble(__int64 aValue)
  1372. {
  1373. return static_cast<double>(aValue);
  1374. }
  1375. // Windows x64 version implemented in masm to work around precision limitation
  1376. #if !defined(_WIN32 ) || !defined(_M_X64)
  1377. double JavascriptConversion::ULongToDouble(unsigned __int64 aValue)
  1378. {
  1379. return static_cast<double>(aValue);
  1380. }
  1381. #endif
  1382. float JavascriptConversion::LongToFloat(__int64 aValue)
  1383. {
  1384. return static_cast<float>(aValue);
  1385. }
  1386. float JavascriptConversion::ULongToFloat (unsigned __int64 aValue)
  1387. {
  1388. return static_cast<float>(aValue);
  1389. }
  1390. int32 JavascriptConversion::F32TOI32(float src, ScriptContext * ctx)
  1391. {
  1392. if (Wasm::WasmMath::isInRange<float, uint32, NumberConstants::k_Float32TwoTo31, NumberConstants::k_Float32NegZero, NumberConstants::k_Float32NegTwoTo31,
  1393. &Wasm::WasmMath::LessThan<uint32>, &Wasm::WasmMath::LessOrEqual<uint32>>(src) &&
  1394. !Wasm::WasmMath::isNaN<float>(src))
  1395. {
  1396. return (int32)src;
  1397. }
  1398. JavascriptError::ThrowWebAssemblyRuntimeError(ctx, VBSERR_Overflow);
  1399. }
  1400. uint32 JavascriptConversion::F32TOU32(float src, ScriptContext * ctx)
  1401. {
  1402. if (Wasm::WasmMath::isInRange<float, uint32, NumberConstants::k_Float32TwoTo32, NumberConstants::k_Float32NegZero, NumberConstants::k_Float32NegOne,
  1403. &Wasm::WasmMath::LessThan<uint32>, &Wasm::WasmMath::LessThan<uint32>>(src) &&
  1404. !Wasm::WasmMath::isNaN<float>(src))
  1405. {
  1406. return (uint32)src;
  1407. }
  1408. JavascriptError::ThrowWebAssemblyRuntimeError(ctx, VBSERR_Overflow);
  1409. }
  1410. int32 JavascriptConversion::F64TOI32(double src, ScriptContext * ctx)
  1411. {
  1412. if (Wasm::WasmMath::isInRange<double, uint64, NumberConstants::k_TwoTo31, NumberConstants::k_NegZero, NumberConstants::k_NegTwoTo31,
  1413. &Wasm::WasmMath::LessOrEqual<uint64>, &Wasm::WasmMath::LessOrEqual<uint64>>(src) &&
  1414. !Wasm::WasmMath::isNaN<double>(src))
  1415. {
  1416. return (int32)src;
  1417. }
  1418. JavascriptError::ThrowWebAssemblyRuntimeError(ctx, VBSERR_Overflow);
  1419. }
  1420. uint32 JavascriptConversion::F64TOU32(double src, ScriptContext * ctx)
  1421. {
  1422. if (Wasm::WasmMath::isInRange<double, uint64, NumberConstants::k_TwoTo32, NumberConstants::k_NegZero, NumberConstants::k_NegOne,
  1423. &Wasm::WasmMath::LessOrEqual<uint64>, &Wasm::WasmMath::LessThan<uint64>>(src)
  1424. && !Wasm::WasmMath::isNaN<double>(src))
  1425. {
  1426. return (uint32)src;
  1427. }
  1428. JavascriptError::ThrowWebAssemblyRuntimeError(ctx, VBSERR_Overflow);
  1429. }
  1430. int64 JavascriptConversion::F32TOI64(float src, ScriptContext * ctx)
  1431. {
  1432. if (Wasm::WasmMath::isInRange<float, uint32, NumberConstants::k_Float32TwoTo63, NumberConstants::k_Float32NegZero, NumberConstants::k_Float32NegTwoTo63,
  1433. &Wasm::WasmMath::LessThan<uint32>, &Wasm::WasmMath::LessOrEqual<uint32>>(src) &&
  1434. !Wasm::WasmMath::isNaN<float>(src))
  1435. {
  1436. return (int64)src;
  1437. }
  1438. JavascriptError::ThrowWebAssemblyRuntimeError(ctx, VBSERR_Overflow);
  1439. }
  1440. uint64 JavascriptConversion::F32TOU64(float src, ScriptContext * ctx)
  1441. {
  1442. if (Wasm::WasmMath::isInRange<float, uint32, NumberConstants::k_Float32TwoTo64, NumberConstants::k_Float32NegZero, NumberConstants::k_Float32NegOne,
  1443. &Wasm::WasmMath::LessThan<uint32>, &Wasm::WasmMath::LessThan<uint32>>(src) &&
  1444. !Wasm::WasmMath::isNaN<float>(src))
  1445. {
  1446. return (uint64)src;
  1447. }
  1448. JavascriptError::ThrowWebAssemblyRuntimeError(ctx, VBSERR_Overflow);
  1449. }
  1450. int64 JavascriptConversion::F64TOI64(double src, ScriptContext * ctx)
  1451. {
  1452. if (Wasm::WasmMath::isInRange<double, uint64, NumberConstants::k_TwoTo63, NumberConstants::k_NegZero, NumberConstants::k_NegTwoTo63,
  1453. &Wasm::WasmMath::LessThan<uint64>, &Wasm::WasmMath::LessOrEqual<uint64>>(src) &&
  1454. !Wasm::WasmMath::isNaN<double>(src))
  1455. {
  1456. return (int64)src;
  1457. }
  1458. JavascriptError::ThrowWebAssemblyRuntimeError(ctx, VBSERR_Overflow);
  1459. }
  1460. uint64 JavascriptConversion::F64TOU64(double src, ScriptContext * ctx)
  1461. {
  1462. if (Wasm::WasmMath::isInRange<double, uint64, NumberConstants::k_TwoTo64, NumberConstants::k_NegZero, NumberConstants::k_NegOne,
  1463. &Wasm::WasmMath::LessThan<uint64>, &Wasm::WasmMath::LessThan<uint64>>(src) &&
  1464. !Wasm::WasmMath::isNaN<double>(src))
  1465. {
  1466. return (uint64)src;
  1467. }
  1468. JavascriptError::ThrowWebAssemblyRuntimeError(ctx, VBSERR_Overflow);
  1469. }
  1470. int64 JavascriptConversion::ToLength(Var aValue, ScriptContext* scriptContext)
  1471. {
  1472. if (TaggedInt::Is(aValue))
  1473. {
  1474. int64 length = TaggedInt::ToInt64(aValue);
  1475. return (length < 0) ? 0 : length;
  1476. }
  1477. double length = JavascriptConversion::ToInteger(aValue, scriptContext);
  1478. if (length < 0.0 || JavascriptNumber::IsNegZero(length))
  1479. {
  1480. length = 0.0;
  1481. }
  1482. else if (length > Math::MAX_SAFE_INTEGER)
  1483. {
  1484. length = Math::MAX_SAFE_INTEGER;
  1485. }
  1486. return NumberUtilities::TryToInt64(length);
  1487. }
  1488. } // namespace Js