JavascriptConversion.cpp 67 KB

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