JavascriptConversion.cpp 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683
  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. if (stringObject->GetScriptContext()->optimizationOverrides.GetSideEffects() & (hint == JavascriptHint::HintString ? SideEffects_ToString : SideEffects_ValueOf))
  353. {
  354. return MethodCallToPrimitive(aValue, hint, requestContext);
  355. }
  356. return CrossSite::MarshalVar(requestContext, stringObject->Unwrap());
  357. }
  358. case TypeIds_NumberObject:
  359. {
  360. JavascriptNumberObject * numberObject = JavascriptNumberObject::FromVar(aValue);
  361. if (hint == JavascriptHint::HintString)
  362. {
  363. if (numberObject->GetScriptContext()->optimizationOverrides.GetSideEffects() & SideEffects_ToString)
  364. {
  365. return MethodCallToPrimitive(aValue, hint, requestContext);
  366. }
  367. return JavascriptNumber::ToStringRadix10(numberObject->GetValue(), requestContext);
  368. }
  369. else
  370. {
  371. if (numberObject->GetScriptContext()->optimizationOverrides.GetSideEffects() & SideEffects_ValueOf)
  372. {
  373. return MethodCallToPrimitive(aValue, hint, requestContext);
  374. }
  375. return CrossSite::MarshalVar(requestContext, numberObject->Unwrap());
  376. }
  377. }
  378. case TypeIds_SymbolObject:
  379. {
  380. JavascriptSymbolObject* symbolObject = JavascriptSymbolObject::FromVar(aValue);
  381. return requestContext->GetLibrary()->CreateSymbol(symbolObject->GetValue());
  382. }
  383. case TypeIds_Date:
  384. case TypeIds_WinRTDate:
  385. {
  386. JavascriptDate* dateObject = JavascriptDate::FromVar(aValue);
  387. if(hint == JavascriptHint::HintNumber)
  388. {
  389. if (dateObject->GetScriptContext()->optimizationOverrides.GetSideEffects() & SideEffects_ValueOf)
  390. {
  391. // if no Method exists this function falls back to OrdinaryToPrimitive
  392. // if IsES6ToPrimitiveEnabled flag is off we also fall back to OrdinaryToPrimitive
  393. return MethodCallToPrimitive(aValue, hint, requestContext);
  394. }
  395. return JavascriptNumber::ToVarNoCheck(dateObject->GetTime(), requestContext);
  396. }
  397. else
  398. {
  399. if (dateObject->GetScriptContext()->optimizationOverrides.GetSideEffects() & SideEffects_ToString)
  400. {
  401. // if no Method exists this function falls back to OrdinaryToPrimitive
  402. // if IsES6ToPrimitiveEnabled flag is off we also fall back to OrdinaryToPrimitive
  403. return MethodCallToPrimitive(aValue, hint, requestContext);
  404. }
  405. return JavascriptDate::ToString(dateObject, requestContext);
  406. }
  407. }
  408. // convert to JavascriptNumber
  409. case TypeIds_Int64Number:
  410. return JavascriptInt64Number::FromVar(aValue)->ToJavascriptNumber();
  411. case TypeIds_UInt64Number:
  412. return JavascriptUInt64Number::FromVar(aValue)->ToJavascriptNumber();
  413. default:
  414. #ifdef ENABLE_SIMDJS
  415. if (SIMDUtils::IsSimdType(aValue))
  416. {
  417. return aValue;
  418. }
  419. else
  420. #endif
  421. {
  422. // if no Method exists this function falls back to OrdinaryToPrimitive
  423. // if IsES6ToPrimitiveEnabled flag is off we also fall back to OrdinaryToPrimitive
  424. return MethodCallToPrimitive(aValue, hint, requestContext);
  425. }
  426. }
  427. }
  428. //----------------------------------------------------------------------------
  429. //https://tc39.github.io/ecma262/#sec-canonicalnumericindexstring
  430. //1. Assert : Type(argument) is String.
  431. //2. If argument is "-0", then return -0.
  432. //3. Let n be ToNumber(argument).
  433. //4. If SameValue(ToString(n), argument) is false, then return undefined.
  434. //5. Return n.
  435. //----------------------------------------------------------------------------
  436. BOOL JavascriptConversion::CanonicalNumericIndexString(JavascriptString *aValue, double *indexValue, ScriptContext * scriptContext)
  437. {
  438. if (JavascriptString::IsNegZero(aValue))
  439. {
  440. *indexValue = -0;
  441. return TRUE;
  442. }
  443. double indexDoubleValue = aValue->ToDouble();
  444. if (JavascriptString::Equals(JavascriptNumber::ToStringRadix10(indexDoubleValue, scriptContext), aValue))
  445. {
  446. *indexValue = indexDoubleValue;
  447. return TRUE;
  448. }
  449. return FALSE;
  450. }
  451. Var JavascriptConversion::MethodCallToPrimitive(Var aValue, JavascriptHint hint, ScriptContext * requestContext)
  452. {
  453. Var result = nullptr;
  454. RecyclableObject *const recyclableObject = RecyclableObject::FromVar(aValue);
  455. ScriptContext *const scriptContext = recyclableObject->GetScriptContext();
  456. //7.3.9 GetMethod(V, P)
  457. // The abstract operation GetMethod is used to get the value of a specific property of an ECMAScript language value when the value of the
  458. // 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
  459. // property key. This abstract operation performs the following steps:
  460. // 1. Assert: IsPropertyKey(P) is true.
  461. // 2. Let func be ? GetV(V, P).
  462. // 3. If func is either undefined or null, return undefined.
  463. // 4. If IsCallable(func) is false, throw a TypeError exception.
  464. // 5. Return func.
  465. Var varMethod = nullptr;
  466. if (!(requestContext->GetConfig()->IsES6ToPrimitiveEnabled()
  467. && JavascriptOperators::GetPropertyReference(recyclableObject, PropertyIds::_symbolToPrimitive, &varMethod, requestContext)
  468. && !JavascriptOperators::IsUndefinedOrNull(varMethod)))
  469. {
  470. return OrdinaryToPrimitive(aValue, hint, requestContext);
  471. }
  472. if (!JavascriptFunction::Is(varMethod))
  473. {
  474. // Don't error if we disabled implicit calls
  475. JavascriptError::TryThrowTypeError(scriptContext, requestContext, JSERR_Property_NeedFunction, requestContext->GetPropertyName(PropertyIds::_symbolToPrimitive)->GetBuffer());
  476. return requestContext->GetLibrary()->GetNull();
  477. }
  478. // Let exoticToPrim be GetMethod(input, @@toPrimitive).
  479. JavascriptFunction* exoticToPrim = JavascriptFunction::FromVar(varMethod);
  480. JavascriptString* hintString = nullptr;
  481. if (hint == JavascriptHint::HintString)
  482. {
  483. hintString = requestContext->GetLibrary()->GetStringTypeDisplayString();
  484. }
  485. else if (hint == JavascriptHint::HintNumber)
  486. {
  487. hintString = requestContext->GetLibrary()->GetNumberTypeDisplayString();
  488. }
  489. else
  490. {
  491. hintString = requestContext->GetPropertyString(PropertyIds::default_);
  492. }
  493. // If exoticToPrim is not undefined, then
  494. if (nullptr != exoticToPrim)
  495. {
  496. ThreadContext * threadContext = requestContext->GetThreadContext();
  497. result = threadContext->ExecuteImplicitCall(exoticToPrim, ImplicitCall_ToPrimitive, [=]()->Js::Var
  498. {
  499. // Stack object should have a pre-op bail on implicit call. We shouldn't see them here.
  500. Assert(!ThreadContext::IsOnStack(recyclableObject));
  501. // Let result be the result of calling the[[Call]] internal method of exoticToPrim, with input as thisArgument and(hint) as argumentsList.
  502. return CALL_FUNCTION(threadContext, exoticToPrim, CallInfo(CallFlags_Value, 2), recyclableObject, hintString);
  503. });
  504. if (!result)
  505. {
  506. // There was an implicit call and implicit calls are disabled. This would typically cause a bailout.
  507. Assert(threadContext->IsDisableImplicitCall());
  508. return requestContext->GetLibrary()->GetNull();
  509. }
  510. Assert(!CrossSite::NeedMarshalVar(result, requestContext));
  511. }
  512. // If result is an ECMAScript language value and Type(result) is not Object, then return result.
  513. if (TaggedInt::Is(result) || !JavascriptOperators::IsObjectType(JavascriptOperators::GetTypeId(result)))
  514. {
  515. return result;
  516. }
  517. // Else, throw a TypeError exception.
  518. else
  519. {
  520. // Don't error if we disabled implicit calls
  521. JavascriptError::TryThrowTypeError(scriptContext, requestContext, JSERR_FunctionArgument_Invalid, _u("[Symbol.toPrimitive]"));
  522. return requestContext->GetLibrary()->GetNull();
  523. }
  524. }
  525. Var JavascriptConversion::OrdinaryToPrimitive(Var aValue, JavascriptHint hint, ScriptContext * requestContext)
  526. {
  527. Var result;
  528. RecyclableObject *const recyclableObject = RecyclableObject::FromVar(aValue);
  529. if (!recyclableObject->ToPrimitive(hint, &result, requestContext))
  530. {
  531. ScriptContext *const scriptContext = recyclableObject->GetScriptContext();
  532. int32 hCode;
  533. switch (hint)
  534. {
  535. case JavascriptHint::HintNumber:
  536. hCode = JSERR_NeedNumber;
  537. break;
  538. case JavascriptHint::HintString:
  539. hCode = JSERR_NeedString;
  540. break;
  541. default:
  542. hCode = VBSERR_OLENoPropOrMethod;
  543. break;
  544. }
  545. JavascriptError::TryThrowTypeError(scriptContext, scriptContext, hCode);
  546. return requestContext->GetLibrary()->GetNull();
  547. }
  548. return result;
  549. }
  550. JavascriptString *JavascriptConversion::CoerseString(Var aValue, ScriptContext* scriptContext, const char16* apiNameForErrorMsg)
  551. {
  552. if (!JavascriptConversion::CheckObjectCoercible(aValue, scriptContext))
  553. {
  554. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NullOrUndefined, apiNameForErrorMsg);
  555. }
  556. return ToString(aValue, scriptContext);
  557. }
  558. //----------------------------------------------------------------------------
  559. // ToString - abstract operation
  560. // ES5 9.8
  561. //Input Type Result
  562. // Undefined
  563. // "undefined"
  564. // Null
  565. // "null"
  566. // Boolean
  567. // If the argument is true, then the result is "true". If the argument is false, then the result is "false".
  568. // Number
  569. // See 9.8.1 below.
  570. // String
  571. // Return the input argument (no conversion)
  572. // Object
  573. // Apply the following steps:
  574. // 1. Let primValue be ToPrimitive(input argument, hint String).
  575. // 2. Return ToString(primValue).
  576. //----------------------------------------------------------------------------
  577. JavascriptString *JavascriptConversion::ToString(Var aValue, ScriptContext* scriptContext)
  578. {
  579. Assert(scriptContext->GetThreadContext()->IsScriptActive());
  580. BOOL fPrimitiveOnly = false;
  581. while(true)
  582. {
  583. switch (JavascriptOperators::GetTypeId(aValue))
  584. {
  585. case TypeIds_Undefined:
  586. return scriptContext->GetLibrary()->GetUndefinedDisplayString();
  587. case TypeIds_Null:
  588. return scriptContext->GetLibrary()->GetNullDisplayString();
  589. case TypeIds_Integer:
  590. return scriptContext->GetIntegerString(aValue);
  591. case TypeIds_Boolean:
  592. return JavascriptBoolean::FromVar(aValue)->GetValue() ? scriptContext->GetLibrary()->GetTrueDisplayString() : scriptContext->GetLibrary()->GetFalseDisplayString();
  593. case TypeIds_Number:
  594. return JavascriptNumber::ToStringRadix10(JavascriptNumber::GetValue(aValue), scriptContext);
  595. case TypeIds_Int64Number:
  596. {
  597. __int64 value = JavascriptInt64Number::FromVar(aValue)->GetValue();
  598. if (!TaggedInt::IsOverflow(value))
  599. {
  600. return scriptContext->GetIntegerString((int)value);
  601. }
  602. else
  603. {
  604. return JavascriptInt64Number::ToString(aValue, scriptContext);
  605. }
  606. }
  607. case TypeIds_UInt64Number:
  608. {
  609. unsigned __int64 value = JavascriptUInt64Number::FromVar(aValue)->GetValue();
  610. if (!TaggedInt::IsOverflow(value))
  611. {
  612. return scriptContext->GetIntegerString((uint)value);
  613. }
  614. else
  615. {
  616. return JavascriptUInt64Number::ToString(aValue, scriptContext);
  617. }
  618. }
  619. case TypeIds_String:
  620. return JavascriptString::FromVar(CrossSite::MarshalVar(scriptContext, aValue));
  621. case TypeIds_VariantDate:
  622. return JavascriptVariantDate::FromVar(aValue)->GetValueString(scriptContext);
  623. case TypeIds_Symbol:
  624. return JavascriptSymbol::FromVar(aValue)->ToString(scriptContext);
  625. case TypeIds_SymbolObject:
  626. return JavascriptSymbol::ToString(JavascriptSymbolObject::FromVar(aValue)->GetValue(), scriptContext);
  627. #ifdef ENABLE_SIMDJS
  628. case TypeIds_SIMDBool8x16:
  629. case TypeIds_SIMDBool16x8:
  630. case TypeIds_SIMDBool32x4:
  631. case TypeIds_SIMDInt8x16:
  632. case TypeIds_SIMDInt16x8:
  633. case TypeIds_SIMDInt32x4:
  634. case TypeIds_SIMDUint8x16:
  635. case TypeIds_SIMDUint16x8:
  636. case TypeIds_SIMDUint32x4:
  637. case TypeIds_SIMDFloat32x4:
  638. {
  639. Assert(aValue);
  640. RecyclableObject *obj = nullptr;
  641. if (!JavascriptConversion::ToObject(aValue, scriptContext, &obj))
  642. {
  643. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedSimd, _u("SIMDType.toString"));
  644. }
  645. JavascriptSIMDObject* simdObject = static_cast<JavascriptSIMDObject*>(obj);
  646. return JavascriptString::FromVar(simdObject->ToString(scriptContext));
  647. }
  648. #endif
  649. case TypeIds_GlobalObject:
  650. aValue = static_cast<Js::GlobalObject*>(aValue)->ToThis();
  651. // fall through
  652. default:
  653. {
  654. AssertMsg(JavascriptOperators::IsObject(aValue), "bad type object in conversion ToString");
  655. if(fPrimitiveOnly)
  656. {
  657. AssertMsg(FALSE, "wrong call in ToString, no dynamic objects should get here");
  658. JavascriptError::ThrowError(scriptContext, VBSERR_InternalError);
  659. }
  660. fPrimitiveOnly = true;
  661. aValue = ToPrimitive(aValue, JavascriptHint::HintString, scriptContext);
  662. }
  663. }
  664. }
  665. }
  666. JavascriptString *JavascriptConversion::ToLocaleString(Var aValue, ScriptContext* scriptContext)
  667. {
  668. switch (JavascriptOperators::GetTypeId(aValue))
  669. {
  670. case TypeIds_Undefined:
  671. return scriptContext->GetLibrary()->GetUndefinedDisplayString();
  672. case TypeIds_Null:
  673. return scriptContext->GetLibrary()->GetNullDisplayString();
  674. case TypeIds_Integer:
  675. return JavascriptNumber::ToLocaleString(TaggedInt::ToInt32(aValue), scriptContext);
  676. case TypeIds_Boolean:
  677. return JavascriptBoolean::FromVar(aValue)->GetValue() ? scriptContext->GetLibrary()->GetTrueDisplayString() : scriptContext->GetLibrary()->GetFalseDisplayString();
  678. case TypeIds_Int64Number:
  679. return JavascriptNumber::ToLocaleString((double)JavascriptInt64Number::FromVar(aValue)->GetValue(), scriptContext);
  680. case TypeIds_UInt64Number:
  681. return JavascriptNumber::ToLocaleString((double)JavascriptUInt64Number::FromVar(aValue)->GetValue(), scriptContext);
  682. case TypeIds_Number:
  683. return JavascriptNumber::ToLocaleString(JavascriptNumber::GetValue(aValue), scriptContext);
  684. case TypeIds_String:
  685. return JavascriptString::FromVar(aValue);
  686. case TypeIds_VariantDate:
  687. // Legacy behavior was to create an empty object and call toLocaleString on it, which would result in this value
  688. return scriptContext->GetLibrary()->GetObjectDisplayString();
  689. case TypeIds_Symbol:
  690. return JavascriptSymbol::FromVar(aValue)->ToString(scriptContext);
  691. default:
  692. {
  693. RecyclableObject* object = RecyclableObject::FromVar(aValue);
  694. Var value = JavascriptOperators::GetProperty(object, PropertyIds::toLocaleString, scriptContext, NULL);
  695. if (JavascriptConversion::IsCallable(value))
  696. {
  697. RecyclableObject* toLocaleStringFunction = RecyclableObject::FromVar(value);
  698. Var aResult = CALL_FUNCTION(scriptContext->GetThreadContext(), toLocaleStringFunction, CallInfo(1), aValue);
  699. if (JavascriptString::Is(aResult))
  700. {
  701. return JavascriptString::FromVar(aResult);
  702. }
  703. else
  704. {
  705. return JavascriptConversion::ToString(aResult, scriptContext);
  706. }
  707. }
  708. JavascriptError::ThrowTypeError(scriptContext, JSERR_Property_NeedFunction, scriptContext->GetPropertyName(PropertyIds::toLocaleString)->GetBuffer());
  709. }
  710. }
  711. }
  712. //----------------------------------------------------------------------------
  713. // ToBoolean_Full:
  714. // (ES3.0: S9.2):
  715. //
  716. // Input Output
  717. // ----- ------
  718. // 'undefined' 'false'
  719. // 'null' 'false'
  720. // Boolean Value
  721. // Number 'false' if +0, -0, or Nan
  722. // 'true' otherwise
  723. // String 'false' if argument is ""
  724. // 'true' otherwise
  725. // Object 'true'
  726. // Falsy Object 'false'
  727. //----------------------------------------------------------------------------
  728. BOOL JavascriptConversion::ToBoolean_Full(Var aValue, ScriptContext* scriptContext)
  729. {
  730. AssertMsg(!TaggedInt::Is(aValue), "Should be detected");
  731. AssertMsg(RecyclableObject::Is(aValue), "Should be handled already");
  732. auto type = RecyclableObject::FromVar(aValue)->GetType();
  733. switch (type->GetTypeId())
  734. {
  735. case TypeIds_Undefined:
  736. case TypeIds_Null:
  737. case TypeIds_VariantDate:
  738. return false;
  739. case TypeIds_Symbol:
  740. return true;
  741. case TypeIds_Boolean:
  742. return JavascriptBoolean::FromVar(aValue)->GetValue();
  743. #if !FLOATVAR
  744. case TypeIds_Number:
  745. {
  746. double value = JavascriptNumber::GetValue(aValue);
  747. return (!JavascriptNumber::IsNan(value)) && (!JavascriptNumber::IsZero(value));
  748. }
  749. #endif
  750. case TypeIds_Int64Number:
  751. {
  752. __int64 value = JavascriptInt64Number::FromVar(aValue)->GetValue();
  753. return value != 0;
  754. }
  755. case TypeIds_UInt64Number:
  756. {
  757. unsigned __int64 value = JavascriptUInt64Number::FromVar(aValue)->GetValue();
  758. return value != 0;
  759. }
  760. case TypeIds_String:
  761. {
  762. JavascriptString * pstValue = JavascriptString::FromVar(aValue);
  763. return pstValue->GetLength() > 0;
  764. }
  765. #ifdef ENABLE_SIMDJS
  766. case TypeIds_SIMDFloat32x4:
  767. case TypeIds_SIMDFloat64x2:
  768. case TypeIds_SIMDInt32x4:
  769. case TypeIds_SIMDInt16x8:
  770. case TypeIds_SIMDInt8x16:
  771. case TypeIds_SIMDBool32x4:
  772. case TypeIds_SIMDBool16x8:
  773. case TypeIds_SIMDBool8x16:
  774. case TypeIds_SIMDUint32x4:
  775. case TypeIds_SIMDUint16x8:
  776. case TypeIds_SIMDUint8x16:
  777. {
  778. return true;
  779. }
  780. #endif
  781. default:
  782. {
  783. AssertMsg(JavascriptOperators::IsObject(aValue), "bad type object in conversion ToBoolean");
  784. // Falsy objects evaluate to false when converted to Boolean.
  785. return !type->IsFalsy();
  786. }
  787. }
  788. }
  789. void JavascriptConversion::ToFloat_Helper(Var aValue, float *pResult, ScriptContext* scriptContext)
  790. {
  791. *pResult = (float)ToNumber_Full(aValue, scriptContext);
  792. }
  793. void JavascriptConversion::ToNumber_Helper(Var aValue, double *pResult, ScriptContext* scriptContext)
  794. {
  795. Assert(Js::JavascriptStackWalker::ValidateTopJitFrame(scriptContext));
  796. *pResult = ToNumber_Full(aValue, scriptContext);
  797. }
  798. // Used for the JIT's float type specialization
  799. // Convert aValue to double, but only allow primitives. Return false otherwise.
  800. BOOL JavascriptConversion::ToNumber_FromPrimitive(Var aValue, double *pResult, BOOL allowUndefined, ScriptContext* scriptContext)
  801. {
  802. Assert(Js::JavascriptStackWalker::ValidateTopJitFrame(scriptContext));
  803. Assert(!TaggedNumber::Is(aValue));
  804. RecyclableObject *obj = RecyclableObject::FromVar(aValue);
  805. // NOTE: Don't allow strings, otherwise JIT's float type specialization has to worry about concats
  806. if (obj->GetTypeId() >= TypeIds_String)
  807. {
  808. return false;
  809. }
  810. if (!allowUndefined && obj->GetTypeId() == TypeIds_Undefined)
  811. {
  812. return false;
  813. }
  814. *pResult = ToNumber_Full(aValue, scriptContext);
  815. return true;
  816. }
  817. //----------------------------------------------------------------------------
  818. // ToNumber_Full:
  819. // Implements ES6 Draft Rev 26 July 18, 2014
  820. //
  821. // Undefined: NaN
  822. // Null: 0
  823. // boolean: v==true ? 1 : 0 ;
  824. // number: v (original number)
  825. // String: conversion by spec algorithm
  826. // object: ToNumber(PrimitiveValue(v, hint_number))
  827. // Symbol: TypeError
  828. //----------------------------------------------------------------------------
  829. double JavascriptConversion::ToNumber_Full(Var aValue,ScriptContext* scriptContext)
  830. {
  831. AssertMsg(!TaggedInt::Is(aValue), "Should be detected");
  832. ScriptContext * objectScriptContext = RecyclableObject::Is(aValue) ? RecyclableObject::FromVar(aValue)->GetScriptContext() : nullptr;
  833. BOOL fPrimitiveOnly = false;
  834. while(true)
  835. {
  836. switch (JavascriptOperators::GetTypeId(aValue))
  837. {
  838. case TypeIds_Symbol:
  839. JavascriptError::TryThrowTypeError(objectScriptContext, scriptContext, JSERR_NeedNumber);
  840. // Fallthrough to return NaN if exceptions are disabled
  841. case TypeIds_Undefined:
  842. return JavascriptNumber::GetValue(scriptContext->GetLibrary()->GetNaN());
  843. case TypeIds_Null:
  844. return 0;
  845. case TypeIds_Integer:
  846. return TaggedInt::ToDouble(aValue);
  847. case TypeIds_Boolean:
  848. return JavascriptBoolean::FromVar(aValue)->GetValue() ? 1 : +0;
  849. case TypeIds_Number:
  850. return JavascriptNumber::GetValue(aValue);
  851. case TypeIds_Int64Number:
  852. return (double)JavascriptInt64Number::FromVar(aValue)->GetValue();
  853. case TypeIds_UInt64Number:
  854. return (double)JavascriptUInt64Number::FromVar(aValue)->GetValue();
  855. case TypeIds_String:
  856. return JavascriptString::FromVar(aValue)->ToDouble();
  857. case TypeIds_VariantDate:
  858. return Js::DateImplementation::GetTvUtc(Js::DateImplementation::JsLocalTimeFromVarDate(JavascriptVariantDate::FromVar(aValue)->GetValue()), scriptContext);
  859. #ifdef ENABLE_SIMDJS
  860. case TypeIds_SIMDFloat32x4:
  861. case TypeIds_SIMDInt32x4:
  862. case TypeIds_SIMDInt16x8:
  863. case TypeIds_SIMDInt8x16:
  864. case TypeIds_SIMDFloat64x2:
  865. case TypeIds_SIMDBool32x4:
  866. case TypeIds_SIMDBool16x8:
  867. case TypeIds_SIMDBool8x16:
  868. case TypeIds_SIMDUint32x4:
  869. case TypeIds_SIMDUint16x8:
  870. case TypeIds_SIMDUint8x16:
  871. JavascriptError::ThrowError(scriptContext, JSERR_NeedNumber);
  872. #endif
  873. default:
  874. {
  875. AssertMsg(JavascriptOperators::IsObject(aValue), "bad type object in conversion ToInteger");
  876. if(fPrimitiveOnly)
  877. {
  878. JavascriptError::ThrowError(scriptContext, VBSERR_OLENoPropOrMethod);
  879. }
  880. fPrimitiveOnly = true;
  881. aValue = ToPrimitive(aValue, JavascriptHint::HintNumber, scriptContext);
  882. }
  883. }
  884. }
  885. }
  886. //----------------------------------------------------------------------------
  887. // second part of the ToInteger() implementation.(ES5.0: S9.4).
  888. //----------------------------------------------------------------------------
  889. double JavascriptConversion::ToInteger_Full(Var aValue,ScriptContext* scriptContext)
  890. {
  891. AssertMsg(!TaggedInt::Is(aValue), "Should be detected");
  892. ScriptContext * objectScriptContext = RecyclableObject::Is(aValue) ? RecyclableObject::FromVar(aValue)->GetScriptContext() : nullptr;
  893. BOOL fPrimitiveOnly = false;
  894. while(true)
  895. {
  896. switch (JavascriptOperators::GetTypeId(aValue))
  897. {
  898. case TypeIds_Symbol:
  899. JavascriptError::TryThrowTypeError(objectScriptContext, scriptContext, JSERR_NeedNumber);
  900. // Fallthrough to return 0 if exceptions are disabled
  901. case TypeIds_Undefined:
  902. case TypeIds_Null:
  903. return 0;
  904. case TypeIds_Integer:
  905. return TaggedInt::ToInt32(aValue);
  906. case TypeIds_Boolean:
  907. return JavascriptBoolean::FromVar(aValue)->GetValue() ? 1 : +0;
  908. case TypeIds_Number:
  909. return ToInteger(JavascriptNumber::GetValue(aValue));
  910. case TypeIds_Int64Number:
  911. return ToInteger((double)JavascriptInt64Number::FromVar(aValue)->GetValue());
  912. case TypeIds_UInt64Number:
  913. return ToInteger((double)JavascriptUInt64Number::FromVar(aValue)->GetValue());
  914. case TypeIds_String:
  915. return ToInteger(JavascriptString::FromVar(aValue)->ToDouble());
  916. case TypeIds_VariantDate:
  917. return ToInteger(ToNumber_Full(aValue, scriptContext));
  918. #ifdef ENABLE_SIMDJS
  919. case TypeIds_SIMDFloat32x4:
  920. case TypeIds_SIMDFloat64x2:
  921. case TypeIds_SIMDInt32x4:
  922. case TypeIds_SIMDInt16x8:
  923. case TypeIds_SIMDInt8x16:
  924. case TypeIds_SIMDBool32x4:
  925. case TypeIds_SIMDBool16x8:
  926. case TypeIds_SIMDBool8x16:
  927. case TypeIds_SIMDUint32x4:
  928. case TypeIds_SIMDUint16x8:
  929. case TypeIds_SIMDUint8x16:
  930. JavascriptError::ThrowError(scriptContext, JSERR_NeedNumber);
  931. #endif
  932. default:
  933. {
  934. AssertMsg(JavascriptOperators::IsObject(aValue), "bad type object in conversion ToInteger");
  935. if(fPrimitiveOnly)
  936. {
  937. AssertMsg(FALSE, "wrong call in ToInteger_Full, no dynamic objects should get here");
  938. JavascriptError::ThrowError(scriptContext, VBSERR_OLENoPropOrMethod);
  939. }
  940. fPrimitiveOnly = true;
  941. aValue = ToPrimitive(aValue, JavascriptHint::HintNumber, scriptContext);
  942. }
  943. }
  944. }
  945. }
  946. double JavascriptConversion::ToInteger(double val)
  947. {
  948. if(JavascriptNumber::IsNan(val))
  949. return 0;
  950. if(JavascriptNumber::IsPosInf(val) || JavascriptNumber::IsNegInf(val) ||
  951. JavascriptNumber::IsZero(val))
  952. {
  953. return val;
  954. }
  955. return ( ((val < 0) ? -1 : 1 ) * floor(fabs(val)));
  956. }
  957. //----------------------------------------------------------------------------
  958. // ToInt32() converts the given Var to an Int32 value, as described in
  959. // (ES3.0: S9.5).
  960. //----------------------------------------------------------------------------
  961. int32 JavascriptConversion::ToInt32_Full(Var aValue, ScriptContext* scriptContext)
  962. {
  963. Assert(Js::JavascriptStackWalker::ValidateTopJitFrame(scriptContext));
  964. AssertMsg(!TaggedInt::Is(aValue), "Should be detected");
  965. ScriptContext * objectScriptContext = RecyclableObject::Is(aValue) ? RecyclableObject::FromVar(aValue)->GetScriptContext() : nullptr;
  966. // This is used when TaggedInt's overflow but remain under int32
  967. // so Number is our most critical case:
  968. TypeId typeId = JavascriptOperators::GetTypeId(aValue);
  969. if (typeId == TypeIds_Number)
  970. {
  971. return JavascriptMath::ToInt32Core(JavascriptNumber::GetValue(aValue));
  972. }
  973. switch (typeId)
  974. {
  975. case TypeIds_Symbol:
  976. JavascriptError::TryThrowTypeError(objectScriptContext, scriptContext, JSERR_NeedNumber);
  977. // Fallthrough to return 0 if exceptions are disabled
  978. case TypeIds_Undefined:
  979. case TypeIds_Null:
  980. return 0;
  981. case TypeIds_Integer:
  982. return TaggedInt::ToInt32(aValue);
  983. case TypeIds_Boolean:
  984. return JavascriptBoolean::FromVar(aValue)->GetValue() ? 1 : +0;
  985. case TypeIds_Int64Number:
  986. // we won't lose precision if the int64 is within 32bit boundary; otherwise we need to
  987. // treat it as double anyhow.
  988. return JavascriptMath::ToInt32Core((double)JavascriptInt64Number::FromVar(aValue)->GetValue());
  989. case TypeIds_UInt64Number:
  990. // we won't lose precision if the int64 is within 32bit boundary; otherwise we need to
  991. // treat it as double anyhow.
  992. return JavascriptMath::ToInt32Core((double)JavascriptUInt64Number::FromVar(aValue)->GetValue());
  993. case TypeIds_String:
  994. {
  995. double result;
  996. if (JavascriptString::FromVar(aValue)->ToDouble(&result))
  997. {
  998. return JavascriptMath::ToInt32Core(result);
  999. }
  1000. // If the string isn't a valid number, ToDouble returns NaN, and ToInt32 of that is 0
  1001. return 0;
  1002. }
  1003. case TypeIds_VariantDate:
  1004. return ToInt32(ToNumber_Full(aValue, scriptContext));
  1005. #ifdef ENABLE_SIMDJS
  1006. case TypeIds_SIMDFloat32x4:
  1007. case TypeIds_SIMDFloat64x2:
  1008. case TypeIds_SIMDInt32x4:
  1009. case TypeIds_SIMDInt16x8:
  1010. case TypeIds_SIMDInt8x16:
  1011. case TypeIds_SIMDBool32x4:
  1012. case TypeIds_SIMDBool16x8:
  1013. case TypeIds_SIMDBool8x16:
  1014. case TypeIds_SIMDUint32x4:
  1015. case TypeIds_SIMDUint16x8:
  1016. case TypeIds_SIMDUint8x16:
  1017. JavascriptError::ThrowError(scriptContext, JSERR_NeedNumber);
  1018. #endif
  1019. default:
  1020. AssertMsg(JavascriptOperators::IsObject(aValue), "bad type object in conversion ToInteger32");
  1021. aValue = ToPrimitive(aValue, JavascriptHint::HintNumber, scriptContext);
  1022. }
  1023. switch (JavascriptOperators::GetTypeId(aValue))
  1024. {
  1025. case TypeIds_Symbol:
  1026. JavascriptError::TryThrowTypeError(objectScriptContext, scriptContext, JSERR_NeedNumber);
  1027. // Fallthrough to return 0 if exceptions are disabled
  1028. case TypeIds_Undefined:
  1029. case TypeIds_Null:
  1030. return 0;
  1031. case TypeIds_Integer:
  1032. return TaggedInt::ToInt32(aValue);
  1033. case TypeIds_Boolean:
  1034. return JavascriptBoolean::FromVar(aValue)->GetValue() ? 1 : +0;
  1035. case TypeIds_Number:
  1036. return ToInt32(JavascriptNumber::GetValue(aValue));
  1037. case TypeIds_Int64Number:
  1038. // we won't lose precision if the int64 is within 32bit boundary; otherwise we need to
  1039. // treat it as double anyhow.
  1040. return JavascriptMath::ToInt32Core((double)JavascriptInt64Number::FromVar(aValue)->GetValue());
  1041. case TypeIds_UInt64Number:
  1042. // we won't lose precision if the int64 is within 32bit boundary; otherwise we need to
  1043. // treat it as double anyhow.
  1044. return JavascriptMath::ToInt32Core((double)JavascriptUInt64Number::FromVar(aValue)->GetValue());
  1045. case TypeIds_String:
  1046. {
  1047. double result;
  1048. if (JavascriptString::FromVar(aValue)->ToDouble(&result))
  1049. {
  1050. return ToInt32(result);
  1051. }
  1052. // If the string isn't a valid number, ToDouble returns NaN, and ToInt32 of that is 0
  1053. return 0;
  1054. }
  1055. case TypeIds_VariantDate:
  1056. return ToInt32(ToNumber_Full(aValue, scriptContext));
  1057. default:
  1058. AssertMsg(FALSE, "wrong call in ToInteger32_Full, no dynamic objects should get here.");
  1059. JavascriptError::ThrowError(scriptContext, VBSERR_OLENoPropOrMethod);
  1060. }
  1061. }
  1062. // a strict version of ToInt32 conversion that returns false for non int32 values like, inf, NaN, undef
  1063. BOOL JavascriptConversion::ToInt32Finite(Var aValue, ScriptContext* scriptContext, int32* result)
  1064. {
  1065. ScriptContext * objectScriptContext = RecyclableObject::Is(aValue) ? RecyclableObject::FromVar(aValue)->GetScriptContext() : nullptr;
  1066. BOOL fPrimitiveOnly = false;
  1067. while(true)
  1068. {
  1069. switch (JavascriptOperators::GetTypeId(aValue))
  1070. {
  1071. case TypeIds_Symbol:
  1072. JavascriptError::TryThrowTypeError(objectScriptContext, scriptContext, JSERR_NeedNumber);
  1073. // Fallthrough to return false and set result to 0 if exceptions are disabled
  1074. case TypeIds_Undefined:
  1075. *result = 0;
  1076. return false;
  1077. case TypeIds_Null:
  1078. *result = 0;
  1079. return true;
  1080. case TypeIds_Integer:
  1081. *result = TaggedInt::ToInt32(aValue);
  1082. return true;
  1083. case TypeIds_Boolean:
  1084. *result = JavascriptBoolean::FromVar(aValue)->GetValue() ? 1 : +0;
  1085. return true;
  1086. case TypeIds_Number:
  1087. return ToInt32Finite(JavascriptNumber::GetValue(aValue), result);
  1088. case TypeIds_Int64Number:
  1089. // we won't lose precision if the int64 is within 32bit boundary; otherwise we need to
  1090. // treat it as double anyhow.
  1091. return ToInt32Finite((double)JavascriptInt64Number::FromVar(aValue)->GetValue(), result);
  1092. case TypeIds_UInt64Number:
  1093. // we won't lose precision if the int64 is within 32bit boundary; otherwise we need to
  1094. // treat it as double anyhow.
  1095. return ToInt32Finite((double)JavascriptUInt64Number::FromVar(aValue)->GetValue(), result);
  1096. case TypeIds_String:
  1097. return ToInt32Finite(JavascriptString::FromVar(aValue)->ToDouble(), result);
  1098. case TypeIds_VariantDate:
  1099. return ToInt32Finite(ToNumber_Full(aValue, scriptContext), result);
  1100. #ifdef ENABLE_SIMDJS
  1101. case TypeIds_SIMDFloat32x4:
  1102. case TypeIds_SIMDFloat64x2:
  1103. case TypeIds_SIMDInt32x4:
  1104. case TypeIds_SIMDInt16x8:
  1105. case TypeIds_SIMDInt8x16:
  1106. case TypeIds_SIMDBool32x4:
  1107. case TypeIds_SIMDBool16x8:
  1108. case TypeIds_SIMDBool8x16:
  1109. case TypeIds_SIMDUint32x4:
  1110. case TypeIds_SIMDUint16x8:
  1111. case TypeIds_SIMDUint8x16:
  1112. JavascriptError::ThrowError(scriptContext, JSERR_NeedNumber);
  1113. #endif
  1114. default:
  1115. {
  1116. AssertMsg(JavascriptOperators::IsObject(aValue), "bad type object in conversion ToInteger32");
  1117. if(fPrimitiveOnly)
  1118. {
  1119. AssertMsg(FALSE, "wrong call in ToInteger32_Full, no dynamic objects should get here");
  1120. JavascriptError::ThrowError(scriptContext, VBSERR_OLENoPropOrMethod);
  1121. }
  1122. fPrimitiveOnly = true;
  1123. aValue = ToPrimitive(aValue, JavascriptHint::HintNumber, scriptContext);
  1124. }
  1125. }
  1126. }
  1127. }
  1128. int32 JavascriptConversion::ToInt32(double T1)
  1129. {
  1130. return JavascriptMath::ToInt32Core(T1);
  1131. }
  1132. __int64 JavascriptConversion::ToInt64(Var aValue, ScriptContext* scriptContext)
  1133. {
  1134. switch (JavascriptOperators::GetTypeId(aValue))
  1135. {
  1136. case TypeIds_Integer:
  1137. {
  1138. return TaggedInt::ToInt32(aValue);
  1139. }
  1140. case TypeIds_Int64Number:
  1141. {
  1142. JavascriptInt64Number* int64Number = JavascriptInt64Number::FromVar(aValue);
  1143. return int64Number->GetValue();
  1144. }
  1145. case TypeIds_UInt64Number:
  1146. {
  1147. JavascriptUInt64Number* uint64Number = JavascriptUInt64Number::FromVar(aValue);
  1148. return (__int64)uint64Number->GetValue();
  1149. }
  1150. case TypeIds_Number:
  1151. return JavascriptMath::TryToInt64(JavascriptNumber::GetValue(aValue));
  1152. default:
  1153. return (unsigned __int64)JavascriptConversion::ToInt32_Full(aValue, scriptContext);
  1154. }
  1155. }
  1156. unsigned __int64 JavascriptConversion::ToUInt64(Var aValue, ScriptContext* scriptContext)
  1157. {
  1158. switch (JavascriptOperators::GetTypeId(aValue))
  1159. {
  1160. case TypeIds_Integer:
  1161. {
  1162. return (unsigned __int64)TaggedInt::ToInt32(aValue);
  1163. }
  1164. case TypeIds_Int64Number:
  1165. {
  1166. JavascriptInt64Number* int64Number = JavascriptInt64Number::FromVar(aValue);
  1167. return (unsigned __int64)int64Number->GetValue();
  1168. }
  1169. case TypeIds_UInt64Number:
  1170. {
  1171. JavascriptUInt64Number* uint64Number = JavascriptUInt64Number::FromVar(aValue);
  1172. return uint64Number->GetValue();
  1173. }
  1174. case TypeIds_Number:
  1175. return static_cast<unsigned __int64>(JavascriptMath::TryToInt64(JavascriptNumber::GetValue(aValue)));
  1176. default:
  1177. return (unsigned __int64)JavascriptConversion::ToInt32_Full(aValue, scriptContext);
  1178. }
  1179. }
  1180. BOOL JavascriptConversion::ToInt32Finite(double value, int32* result)
  1181. {
  1182. if((!NumberUtilities::IsFinite(value)) || JavascriptNumber::IsNan(value))
  1183. {
  1184. *result = 0;
  1185. return false;
  1186. }
  1187. else
  1188. {
  1189. *result = JavascriptMath::ToInt32Core(value);
  1190. return true;
  1191. }
  1192. }
  1193. //----------------------------------------------------------------------------
  1194. // (ES3.0: S9.6).
  1195. //----------------------------------------------------------------------------
  1196. uint32 JavascriptConversion::ToUInt32_Full(Var aValue, ScriptContext* scriptContext)
  1197. {
  1198. AssertMsg(!TaggedInt::Is(aValue), "Should be detected");
  1199. ScriptContext * objectScriptContext = RecyclableObject::Is(aValue) ? RecyclableObject::FromVar(aValue)->GetScriptContext() : nullptr;
  1200. BOOL fPrimitiveOnly = false;
  1201. while(true)
  1202. {
  1203. switch (JavascriptOperators::GetTypeId(aValue))
  1204. {
  1205. case TypeIds_Symbol:
  1206. JavascriptError::TryThrowTypeError(objectScriptContext, scriptContext, JSERR_NeedNumber);
  1207. // Fallthrough to return 0 if exceptions are disabled
  1208. case TypeIds_Undefined:
  1209. case TypeIds_Null:
  1210. return 0;
  1211. case TypeIds_Integer:
  1212. return TaggedInt::ToUInt32(aValue);
  1213. case TypeIds_Boolean:
  1214. return JavascriptBoolean::FromVar(aValue)->GetValue() ? 1 : +0;
  1215. case TypeIds_Number:
  1216. return JavascriptMath::ToUInt32(JavascriptNumber::GetValue(aValue));
  1217. case TypeIds_Int64Number:
  1218. // we won't lose precision if the int64 is within 32bit boundary; otherwise we need to
  1219. // treat it as double anyhow.
  1220. return JavascriptMath::ToUInt32((double)JavascriptInt64Number::FromVar(aValue)->GetValue());
  1221. case TypeIds_UInt64Number:
  1222. // we won't lose precision if the int64 is within 32bit boundary; otherwise we need to
  1223. // treat it as double anyhow.
  1224. return JavascriptMath::ToUInt32((double)JavascriptUInt64Number::FromVar(aValue)->GetValue());
  1225. case TypeIds_String:
  1226. {
  1227. double result;
  1228. if (JavascriptString::FromVar(aValue)->ToDouble(&result))
  1229. {
  1230. return JavascriptMath::ToUInt32(result);
  1231. }
  1232. // If the string isn't a valid number, ToDouble returns NaN, and ToUInt32 of that is 0
  1233. return 0;
  1234. }
  1235. case TypeIds_VariantDate:
  1236. return JavascriptMath::ToUInt32(ToNumber_Full(aValue, scriptContext));
  1237. #ifdef ENABLE_SIMDJS
  1238. case TypeIds_SIMDFloat32x4:
  1239. case TypeIds_SIMDFloat64x2:
  1240. case TypeIds_SIMDInt32x4:
  1241. case TypeIds_SIMDInt16x8:
  1242. case TypeIds_SIMDInt8x16:
  1243. case TypeIds_SIMDBool32x4:
  1244. case TypeIds_SIMDBool16x8:
  1245. case TypeIds_SIMDBool8x16:
  1246. case TypeIds_SIMDUint32x4:
  1247. case TypeIds_SIMDUint16x8:
  1248. case TypeIds_SIMDUint8x16:
  1249. JavascriptError::ThrowError(scriptContext, JSERR_NeedNumber);
  1250. #endif
  1251. default:
  1252. {
  1253. AssertMsg(JavascriptOperators::IsObject(aValue), "bad type object in conversion ToUInt32");
  1254. if(fPrimitiveOnly)
  1255. {
  1256. AssertMsg(FALSE, "wrong call in ToUInt32_Full, no dynamic objects should get here");
  1257. JavascriptError::ThrowError(scriptContext, VBSERR_OLENoPropOrMethod);
  1258. }
  1259. fPrimitiveOnly = true;
  1260. aValue = ToPrimitive(aValue, JavascriptHint::HintNumber, scriptContext);
  1261. }
  1262. }
  1263. }
  1264. }
  1265. uint32 JavascriptConversion::ToUInt32(double T1)
  1266. {
  1267. // Same as doing ToInt32 and reinterpret the bits as uint32
  1268. return (uint32)JavascriptMath::ToInt32Core(T1);
  1269. }
  1270. //----------------------------------------------------------------------------
  1271. // ToUInt16() converts the given Var to a UInt16 value, as described in
  1272. // (ES3.0: S9.6).
  1273. //----------------------------------------------------------------------------
  1274. uint16 JavascriptConversion::ToUInt16_Full(IN Var aValue, ScriptContext* scriptContext)
  1275. {
  1276. AssertMsg(!TaggedInt::Is(aValue), "Should be detected");
  1277. ScriptContext * objectScriptContext = RecyclableObject::Is(aValue) ? RecyclableObject::FromVar(aValue)->GetScriptContext() : nullptr;
  1278. BOOL fPrimitiveOnly = false;
  1279. while(true)
  1280. {
  1281. switch (JavascriptOperators::GetTypeId(aValue))
  1282. {
  1283. case TypeIds_Symbol:
  1284. JavascriptError::TryThrowTypeError(objectScriptContext, scriptContext, JSERR_NeedNumber);
  1285. // Fallthrough to return 0 if exceptions are disabled
  1286. case TypeIds_Undefined:
  1287. case TypeIds_Null:
  1288. return 0;
  1289. case TypeIds_Integer:
  1290. return TaggedInt::ToUInt16(aValue);
  1291. case TypeIds_Boolean:
  1292. return JavascriptBoolean::FromVar(aValue)->GetValue() ? 1 : +0;
  1293. case TypeIds_Number:
  1294. return ToUInt16(JavascriptNumber::GetValue(aValue));
  1295. case TypeIds_Int64Number:
  1296. // we won't lose precision if the int64 is within 16bit boundary; otherwise we need to
  1297. // treat it as double anyhow.
  1298. return ToUInt16((double)JavascriptInt64Number::FromVar(aValue)->GetValue());
  1299. case TypeIds_UInt64Number:
  1300. // we won't lose precision if the int64 is within 16bit boundary; otherwise we need to
  1301. // treat it as double anyhow.
  1302. return ToUInt16((double)JavascriptUInt64Number::FromVar(aValue)->GetValue());
  1303. case TypeIds_String:
  1304. {
  1305. double result;
  1306. if (JavascriptString::FromVar(aValue)->ToDouble(&result))
  1307. {
  1308. return ToUInt16(result);
  1309. }
  1310. // If the string isn't a valid number, ToDouble is NaN, and ToUInt16 of that is 0
  1311. return 0;
  1312. }
  1313. case TypeIds_VariantDate:
  1314. return ToUInt16(ToNumber_Full(aValue, scriptContext));
  1315. #ifdef ENABLE_SIMDJS
  1316. case TypeIds_SIMDFloat32x4:
  1317. case TypeIds_SIMDFloat64x2:
  1318. case TypeIds_SIMDInt32x4:
  1319. case TypeIds_SIMDInt16x8:
  1320. case TypeIds_SIMDInt8x16:
  1321. case TypeIds_SIMDBool32x4:
  1322. case TypeIds_SIMDBool16x8:
  1323. case TypeIds_SIMDBool8x16:
  1324. case TypeIds_SIMDUint32x4:
  1325. case TypeIds_SIMDUint16x8:
  1326. case TypeIds_SIMDUint8x16:
  1327. JavascriptError::ThrowError(scriptContext, JSERR_NeedNumber);
  1328. #endif
  1329. default:
  1330. {
  1331. AssertMsg(JavascriptOperators::IsObject(aValue), "bad type object in conversion ToUIn16");
  1332. if(fPrimitiveOnly)
  1333. {
  1334. AssertMsg(FALSE, "wrong call in ToUInt16, no dynamic objects should get here");
  1335. JavascriptError::ThrowError(scriptContext, VBSERR_OLENoPropOrMethod);
  1336. }
  1337. fPrimitiveOnly = true;
  1338. aValue = ToPrimitive(aValue, JavascriptHint::HintNumber, scriptContext);
  1339. }
  1340. }
  1341. }
  1342. }
  1343. inline uint16 JavascriptConversion::ToUInt16(double T1)
  1344. {
  1345. //
  1346. // VC does the right thing here, if we first convert to uint32 and then to uint16
  1347. // Spec says mod should be done.
  1348. //
  1349. uint32 result = JavascriptConversion::ToUInt32(T1);
  1350. #if defined(_M_IX86) && _MSC_FULL_VER < 160030329
  1351. // Well VC doesn't actually do the right thing... It takes (uint16)(uint32)double and removes the
  1352. // middle uint32 cast to (uint16)double, which isn't the same thing. Somehow, it only seems to be a
  1353. // problem for x86. Forcing a store to uint32 prevents the incorrect optimization.
  1354. //
  1355. // A bug has been filled in the Dev11 database: TF bug id #901495
  1356. // Fixed in compiler 16.00.30329.00
  1357. volatile uint32 volResult = result;
  1358. #endif
  1359. return (uint16) result;
  1360. }
  1361. JavascriptString * JavascriptConversion::ToPrimitiveString(Var aValue, ScriptContext * scriptContext)
  1362. {
  1363. return ToString(ToPrimitive(aValue, JavascriptHint::None, scriptContext), scriptContext);
  1364. }
  1365. double JavascriptConversion::LongToDouble(__int64 aValue)
  1366. {
  1367. return static_cast<double>(aValue);
  1368. }
  1369. // Windows x64 version implemented in masm to work around precision limitation
  1370. #if !defined(_WIN32 ) || !defined(_M_X64)
  1371. double JavascriptConversion::ULongToDouble(unsigned __int64 aValue)
  1372. {
  1373. return static_cast<double>(aValue);
  1374. }
  1375. #endif
  1376. float JavascriptConversion::LongToFloat(__int64 aValue)
  1377. {
  1378. return static_cast<float>(aValue);
  1379. }
  1380. float JavascriptConversion::ULongToFloat (unsigned __int64 aValue)
  1381. {
  1382. return static_cast<float>(aValue);
  1383. }
  1384. int32 JavascriptConversion::F32TOI32(float src, ScriptContext * ctx)
  1385. {
  1386. if (Wasm::WasmMath::isInRange<float, uint32, NumberConstants::k_Float32TwoTo31, NumberConstants::k_Float32NegZero, NumberConstants::k_Float32NegTwoTo31,
  1387. &Wasm::WasmMath::LessThan<uint32>, &Wasm::WasmMath::LessOrEqual<uint32>>(src) &&
  1388. !Wasm::WasmMath::isNaN<float>(src))
  1389. {
  1390. return (int32)src;
  1391. }
  1392. JavascriptError::ThrowWebAssemblyRuntimeError(ctx, VBSERR_Overflow);
  1393. }
  1394. uint32 JavascriptConversion::F32TOU32(float src, ScriptContext * ctx)
  1395. {
  1396. if (Wasm::WasmMath::isInRange<float, uint32, NumberConstants::k_Float32TwoTo32, NumberConstants::k_Float32NegZero, NumberConstants::k_Float32NegOne,
  1397. &Wasm::WasmMath::LessThan<uint32>, &Wasm::WasmMath::LessThan<uint32>>(src) &&
  1398. !Wasm::WasmMath::isNaN<float>(src))
  1399. {
  1400. return (uint32)src;
  1401. }
  1402. JavascriptError::ThrowWebAssemblyRuntimeError(ctx, VBSERR_Overflow);
  1403. }
  1404. int32 JavascriptConversion::F64TOI32(double src, ScriptContext * ctx)
  1405. {
  1406. if (Wasm::WasmMath::isInRange<double, uint64, NumberConstants::k_TwoTo31, NumberConstants::k_NegZero, NumberConstants::k_NegTwoTo31,
  1407. &Wasm::WasmMath::LessOrEqual<uint64>, &Wasm::WasmMath::LessOrEqual<uint64>>(src) &&
  1408. !Wasm::WasmMath::isNaN<double>(src))
  1409. {
  1410. return (int32)src;
  1411. }
  1412. JavascriptError::ThrowWebAssemblyRuntimeError(ctx, VBSERR_Overflow);
  1413. }
  1414. uint32 JavascriptConversion::F64TOU32(double src, ScriptContext * ctx)
  1415. {
  1416. if (Wasm::WasmMath::isInRange<double, uint64, NumberConstants::k_TwoTo32, NumberConstants::k_NegZero, NumberConstants::k_NegOne,
  1417. &Wasm::WasmMath::LessOrEqual<uint64>, &Wasm::WasmMath::LessThan<uint64>>(src)
  1418. && !Wasm::WasmMath::isNaN<double>(src))
  1419. {
  1420. return (uint32)src;
  1421. }
  1422. JavascriptError::ThrowWebAssemblyRuntimeError(ctx, VBSERR_Overflow);
  1423. }
  1424. int64 JavascriptConversion::F32TOI64(float src, ScriptContext * ctx)
  1425. {
  1426. if (Wasm::WasmMath::isInRange<float, uint32, NumberConstants::k_Float32TwoTo63, NumberConstants::k_Float32NegZero, NumberConstants::k_Float32NegTwoTo63,
  1427. &Wasm::WasmMath::LessThan<uint32>, &Wasm::WasmMath::LessOrEqual<uint32>>(src) &&
  1428. !Wasm::WasmMath::isNaN<float>(src))
  1429. {
  1430. return (int64)src;
  1431. }
  1432. JavascriptError::ThrowWebAssemblyRuntimeError(ctx, VBSERR_Overflow);
  1433. }
  1434. uint64 JavascriptConversion::F32TOU64(float src, ScriptContext * ctx)
  1435. {
  1436. if (Wasm::WasmMath::isInRange<float, uint32, NumberConstants::k_Float32TwoTo64, NumberConstants::k_Float32NegZero, NumberConstants::k_Float32NegOne,
  1437. &Wasm::WasmMath::LessThan<uint32>, &Wasm::WasmMath::LessThan<uint32>>(src) &&
  1438. !Wasm::WasmMath::isNaN<float>(src))
  1439. {
  1440. return (uint64)src;
  1441. }
  1442. JavascriptError::ThrowWebAssemblyRuntimeError(ctx, VBSERR_Overflow);
  1443. }
  1444. int64 JavascriptConversion::F64TOI64(double src, ScriptContext * ctx)
  1445. {
  1446. if (Wasm::WasmMath::isInRange<double, uint64, NumberConstants::k_TwoTo63, NumberConstants::k_NegZero, NumberConstants::k_NegTwoTo63,
  1447. &Wasm::WasmMath::LessThan<uint64>, &Wasm::WasmMath::LessOrEqual<uint64>>(src) &&
  1448. !Wasm::WasmMath::isNaN<double>(src))
  1449. {
  1450. return (int64)src;
  1451. }
  1452. JavascriptError::ThrowWebAssemblyRuntimeError(ctx, VBSERR_Overflow);
  1453. }
  1454. uint64 JavascriptConversion::F64TOU64(double src, ScriptContext * ctx)
  1455. {
  1456. if (Wasm::WasmMath::isInRange<double, uint64, NumberConstants::k_TwoTo64, NumberConstants::k_NegZero, NumberConstants::k_NegOne,
  1457. &Wasm::WasmMath::LessThan<uint64>, &Wasm::WasmMath::LessThan<uint64>>(src) &&
  1458. !Wasm::WasmMath::isNaN<double>(src))
  1459. {
  1460. return (uint64)src;
  1461. }
  1462. JavascriptError::ThrowWebAssemblyRuntimeError(ctx, VBSERR_Overflow);
  1463. }
  1464. int64 JavascriptConversion::ToLength(Var aValue, ScriptContext* scriptContext)
  1465. {
  1466. if (TaggedInt::Is(aValue))
  1467. {
  1468. int64 length = TaggedInt::ToInt64(aValue);
  1469. return (length < 0) ? 0 : length;
  1470. }
  1471. double length = JavascriptConversion::ToInteger(aValue, scriptContext);
  1472. if (length < 0.0 || JavascriptNumber::IsNegZero(length))
  1473. {
  1474. length = 0.0;
  1475. }
  1476. else if (length > Math::MAX_SAFE_INTEGER)
  1477. {
  1478. length = Math::MAX_SAFE_INTEGER;
  1479. }
  1480. return NumberUtilities::TryToInt64(length);
  1481. }
  1482. } // namespace Js