PageRenderTime 145ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/src/qt/qtwebkit/Source/JavaScriptCore/runtime/NumberPrototype.cpp

https://gitlab.com/x33n/phantomjs
C++ | 534 lines | 314 code | 85 blank | 135 comment | 79 complexity | de3570c42e74f2f79b64307020ed71f5 MD5 | raw file
  1. /*
  2. * Copyright (C) 1999-2000,2003 Harri Porten (porten@kde.org)
  3. * Copyright (C) 2007, 2008, 2011 Apple Inc. All rights reserved.
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2 of the License, or (at your option) any later version.
  9. *
  10. * This library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public
  16. * License along with this library; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
  18. * USA
  19. *
  20. */
  21. #include "config.h"
  22. #include "NumberPrototype.h"
  23. #include "BigInteger.h"
  24. #include "Error.h"
  25. #include "JSFunction.h"
  26. #include "JSGlobalObject.h"
  27. #include "JSString.h"
  28. #include "Operations.h"
  29. #include "Uint16WithFraction.h"
  30. #include <wtf/dtoa.h>
  31. #include <wtf/Assertions.h>
  32. #include <wtf/MathExtras.h>
  33. #include <wtf/Vector.h>
  34. #include <wtf/dtoa/double-conversion.h>
  35. using namespace WTF::double_conversion;
  36. // To avoid conflict with WTF::StringBuilder.
  37. typedef WTF::double_conversion::StringBuilder DoubleConversionStringBuilder;
  38. namespace JSC {
  39. static EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState*);
  40. static EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState*);
  41. static EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState*);
  42. static EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState*);
  43. static EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState*);
  44. static EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState*);
  45. }
  46. #include "NumberPrototype.lut.h"
  47. namespace JSC {
  48. const ClassInfo NumberPrototype::s_info = { "Number", &NumberObject::s_info, 0, ExecState::numberPrototypeTable, CREATE_METHOD_TABLE(NumberPrototype) };
  49. /* Source for NumberPrototype.lut.h
  50. @begin numberPrototypeTable
  51. toString numberProtoFuncToString DontEnum|Function 1
  52. toLocaleString numberProtoFuncToLocaleString DontEnum|Function 0
  53. valueOf numberProtoFuncValueOf DontEnum|Function 0
  54. toFixed numberProtoFuncToFixed DontEnum|Function 1
  55. toExponential numberProtoFuncToExponential DontEnum|Function 1
  56. toPrecision numberProtoFuncToPrecision DontEnum|Function 1
  57. @end
  58. */
  59. ASSERT_HAS_TRIVIAL_DESTRUCTOR(NumberPrototype);
  60. NumberPrototype::NumberPrototype(ExecState* exec, Structure* structure)
  61. : NumberObject(exec->vm(), structure)
  62. {
  63. }
  64. void NumberPrototype::finishCreation(ExecState* exec, JSGlobalObject*)
  65. {
  66. Base::finishCreation(exec->vm());
  67. setInternalValue(exec->vm(), jsNumber(0));
  68. ASSERT(inherits(&s_info));
  69. }
  70. bool NumberPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
  71. {
  72. return getStaticFunctionSlot<NumberObject>(exec, ExecState::numberPrototypeTable(exec), jsCast<NumberPrototype*>(cell), propertyName, slot);
  73. }
  74. bool NumberPrototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
  75. {
  76. return getStaticFunctionDescriptor<NumberObject>(exec, ExecState::numberPrototypeTable(exec), jsCast<NumberPrototype*>(object), propertyName, descriptor);
  77. }
  78. // ------------------------------ Functions ---------------------------
  79. static ALWAYS_INLINE bool toThisNumber(JSValue thisValue, double& x)
  80. {
  81. if (thisValue.isInt32()) {
  82. x = thisValue.asInt32();
  83. return true;
  84. }
  85. if (thisValue.isDouble()) {
  86. x = thisValue.asDouble();
  87. return true;
  88. }
  89. if (thisValue.isCell() && thisValue.asCell()->structure()->typeInfo().isNumberObject()) {
  90. x = static_cast<const NumberObject*>(thisValue.asCell())->internalValue().asNumber();
  91. return true;
  92. }
  93. return false;
  94. }
  95. static ALWAYS_INLINE bool getIntegerArgumentInRange(ExecState* exec, int low, int high, int& result, bool& isUndefined)
  96. {
  97. result = 0;
  98. isUndefined = false;
  99. JSValue argument0 = exec->argument(0);
  100. if (argument0.isUndefined()) {
  101. isUndefined = true;
  102. return true;
  103. }
  104. double asDouble = argument0.toInteger(exec);
  105. if (asDouble < low || asDouble > high)
  106. return false;
  107. result = static_cast<int>(asDouble);
  108. return true;
  109. }
  110. // The largest finite floating point number is 1.mantissa * 2^(0x7fe-0x3ff).
  111. // Since 2^N in binary is a one bit followed by N zero bits. 1 * 2^3ff requires
  112. // at most 1024 characters to the left of a decimal point, in base 2 (1025 if
  113. // we include a minus sign). For the fraction, a value with an exponent of 0
  114. // has up to 52 bits to the right of the decimal point. Each decrement of the
  115. // exponent down to a minimum of -0x3fe adds an additional digit to the length
  116. // of the fraction. As such the maximum fraction size is 1075 (1076 including
  117. // a point). We pick a buffer size such that can simply place the point in the
  118. // center of the buffer, and are guaranteed to have enough space in each direction
  119. // fo any number of digits an IEEE number may require to represent.
  120. typedef char RadixBuffer[2180];
  121. // Mapping from integers 0..35 to digit identifying this value, for radix 2..36.
  122. static const char radixDigits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
  123. static char* toStringWithRadix(RadixBuffer& buffer, double number, unsigned radix)
  124. {
  125. ASSERT(std::isfinite(number));
  126. ASSERT(radix >= 2 && radix <= 36);
  127. // Position the decimal point at the center of the string, set
  128. // the startOfResultString pointer to point at the decimal point.
  129. char* decimalPoint = buffer + sizeof(buffer) / 2;
  130. char* startOfResultString = decimalPoint;
  131. // Extract the sign.
  132. bool isNegative = number < 0;
  133. if (std::signbit(number))
  134. number = -number;
  135. double integerPart = floor(number);
  136. // We use this to test for odd values in odd radix bases.
  137. // Where the base is even, (e.g. 10), to determine whether a value is even we need only
  138. // consider the least significant digit. For example, 124 in base 10 is even, because '4'
  139. // is even. if the radix is odd, then the radix raised to an integer power is also odd.
  140. // E.g. in base 5, 124 represents (1 * 125 + 2 * 25 + 4 * 5). Since each digit in the value
  141. // is multiplied by an odd number, the result is even if the sum of all digits is even.
  142. //
  143. // For the integer portion of the result, we only need test whether the integer value is
  144. // even or odd. For each digit of the fraction added, we should invert our idea of whether
  145. // the number is odd if the new digit is odd.
  146. //
  147. // Also initialize digit to this value; for even radix values we only need track whether
  148. // the last individual digit was odd.
  149. bool integerPartIsOdd = integerPart <= static_cast<double>(0x1FFFFFFFFFFFFFull) && static_cast<int64_t>(integerPart) & 1;
  150. ASSERT(integerPartIsOdd == static_cast<bool>(fmod(integerPart, 2)));
  151. bool isOddInOddRadix = integerPartIsOdd;
  152. uint32_t digit = integerPartIsOdd;
  153. // Check if the value has a fractional part to convert.
  154. double fractionPart = number - integerPart;
  155. if (fractionPart) {
  156. // Write the decimal point now.
  157. *decimalPoint = '.';
  158. // Higher precision representation of the fractional part.
  159. Uint16WithFraction fraction(fractionPart);
  160. bool needsRoundingUp = false;
  161. char* endOfResultString = decimalPoint + 1;
  162. // Calculate the delta from the current number to the next & previous possible IEEE numbers.
  163. double nextNumber = nextafter(number, std::numeric_limits<double>::infinity());
  164. double lastNumber = nextafter(number, -std::numeric_limits<double>::infinity());
  165. ASSERT(std::isfinite(nextNumber) && !std::signbit(nextNumber));
  166. ASSERT(std::isfinite(lastNumber) && !std::signbit(lastNumber));
  167. double deltaNextDouble = nextNumber - number;
  168. double deltaLastDouble = number - lastNumber;
  169. ASSERT(std::isfinite(deltaNextDouble) && !std::signbit(deltaNextDouble));
  170. ASSERT(std::isfinite(deltaLastDouble) && !std::signbit(deltaLastDouble));
  171. // We track the delta from the current value to the next, to track how many digits of the
  172. // fraction we need to write. For example, if the value we are converting is precisely
  173. // 1.2345, so far we have written the digits "1.23" to a string leaving a remainder of
  174. // 0.45, and we want to determine whether we can round off, or whether we need to keep
  175. // appending digits ('4'). We can stop adding digits provided that then next possible
  176. // lower IEEE value is further from 1.23 than the remainder we'd be rounding off (0.45),
  177. // which is to say, less than 1.2255. Put another way, the delta between the prior
  178. // possible value and this number must be more than 2x the remainder we'd be rounding off
  179. // (or more simply half the delta between numbers must be greater than the remainder).
  180. //
  181. // Similarly we need track the delta to the next possible value, to dertermine whether
  182. // to round up. In almost all cases (other than at exponent boundaries) the deltas to
  183. // prior and subsequent values are identical, so we don't need track then separately.
  184. if (deltaNextDouble != deltaLastDouble) {
  185. // Since the deltas are different track them separately. Pre-multiply by 0.5.
  186. Uint16WithFraction halfDeltaNext(deltaNextDouble, 1);
  187. Uint16WithFraction halfDeltaLast(deltaLastDouble, 1);
  188. while (true) {
  189. // examine the remainder to determine whether we should be considering rounding
  190. // up or down. If remainder is precisely 0.5 rounding is to even.
  191. int dComparePoint5 = fraction.comparePoint5();
  192. if (dComparePoint5 > 0 || (!dComparePoint5 && (radix & 1 ? isOddInOddRadix : digit & 1))) {
  193. // Check for rounding up; are we closer to the value we'd round off to than
  194. // the next IEEE value would be?
  195. if (fraction.sumGreaterThanOne(halfDeltaNext)) {
  196. needsRoundingUp = true;
  197. break;
  198. }
  199. } else {
  200. // Check for rounding down; are we closer to the value we'd round off to than
  201. // the prior IEEE value would be?
  202. if (fraction < halfDeltaLast)
  203. break;
  204. }
  205. ASSERT(endOfResultString < (buffer + sizeof(buffer) - 1));
  206. // Write a digit to the string.
  207. fraction *= radix;
  208. digit = fraction.floorAndSubtract();
  209. *endOfResultString++ = radixDigits[digit];
  210. // Keep track whether the portion written is currently even, if the radix is odd.
  211. if (digit & 1)
  212. isOddInOddRadix = !isOddInOddRadix;
  213. // Shift the fractions by radix.
  214. halfDeltaNext *= radix;
  215. halfDeltaLast *= radix;
  216. }
  217. } else {
  218. // This code is identical to that above, except since deltaNextDouble != deltaLastDouble
  219. // we don't need to track these two values separately.
  220. Uint16WithFraction halfDelta(deltaNextDouble, 1);
  221. while (true) {
  222. int dComparePoint5 = fraction.comparePoint5();
  223. if (dComparePoint5 > 0 || (!dComparePoint5 && (radix & 1 ? isOddInOddRadix : digit & 1))) {
  224. if (fraction.sumGreaterThanOne(halfDelta)) {
  225. needsRoundingUp = true;
  226. break;
  227. }
  228. } else if (fraction < halfDelta)
  229. break;
  230. ASSERT(endOfResultString < (buffer + sizeof(buffer) - 1));
  231. fraction *= radix;
  232. digit = fraction.floorAndSubtract();
  233. if (digit & 1)
  234. isOddInOddRadix = !isOddInOddRadix;
  235. *endOfResultString++ = radixDigits[digit];
  236. halfDelta *= radix;
  237. }
  238. }
  239. // Check if the fraction needs rounding off (flag set in the loop writing digits, above).
  240. if (needsRoundingUp) {
  241. // Whilst the last digit is the maximum in the current radix, remove it.
  242. // e.g. rounding up the last digit in "12.3999" is the same as rounding up the
  243. // last digit in "12.3" - both round up to "12.4".
  244. while (endOfResultString[-1] == radixDigits[radix - 1])
  245. --endOfResultString;
  246. // Radix digits are sequential in ascii/unicode, except for '9' and 'a'.
  247. // E.g. the first 'if' case handles rounding 67.89 to 67.8a in base 16.
  248. // The 'else if' case handles rounding of all other digits.
  249. if (endOfResultString[-1] == '9')
  250. endOfResultString[-1] = 'a';
  251. else if (endOfResultString[-1] != '.')
  252. ++endOfResultString[-1];
  253. else {
  254. // One other possibility - there may be no digits to round up in the fraction
  255. // (or all may be been rounded off already), in which case we may need to
  256. // round into the integer portion of the number. Remove the decimal point.
  257. --endOfResultString;
  258. // In order to get here there must have been a non-zero fraction, in which case
  259. // there must be at least one bit of the value's mantissa not in use in the
  260. // integer part of the number. As such, adding to the integer part should not
  261. // be able to lose precision.
  262. ASSERT((integerPart + 1) - integerPart == 1);
  263. ++integerPart;
  264. }
  265. } else {
  266. // We only need to check for trailing zeros if the value does not get rounded up.
  267. while (endOfResultString[-1] == '0')
  268. --endOfResultString;
  269. }
  270. *endOfResultString = '\0';
  271. ASSERT(endOfResultString < buffer + sizeof(buffer));
  272. } else
  273. *decimalPoint = '\0';
  274. BigInteger units(integerPart);
  275. // Always loop at least once, to emit at least '0'.
  276. do {
  277. ASSERT(buffer < startOfResultString);
  278. // Read a single digit and write it to the front of the string.
  279. // Divide by radix to remove one digit from the value.
  280. digit = units.divide(radix);
  281. *--startOfResultString = radixDigits[digit];
  282. } while (!!units);
  283. // If the number is negative, prepend '-'.
  284. if (isNegative)
  285. *--startOfResultString = '-';
  286. ASSERT(buffer <= startOfResultString);
  287. return startOfResultString;
  288. }
  289. static String toStringWithRadix(int32_t number, unsigned radix)
  290. {
  291. LChar buf[1 + 32]; // Worst case is radix == 2, which gives us 32 digits + sign.
  292. LChar* end = buf + WTF_ARRAY_LENGTH(buf);
  293. LChar* p = end;
  294. bool negative = false;
  295. uint32_t positiveNumber = number;
  296. if (number < 0) {
  297. negative = true;
  298. positiveNumber = -number;
  299. }
  300. while (positiveNumber) {
  301. uint32_t index = positiveNumber % radix;
  302. ASSERT(index < sizeof(radixDigits));
  303. *--p = static_cast<LChar>(radixDigits[index]);
  304. positiveNumber /= radix;
  305. }
  306. if (negative)
  307. *--p = '-';
  308. return String(p, static_cast<unsigned>(end - p));
  309. }
  310. // toExponential converts a number to a string, always formatting as an expoential.
  311. // This method takes an optional argument specifying a number of *decimal places*
  312. // to round the significand to (or, put another way, this method optionally rounds
  313. // to argument-plus-one significant figures).
  314. EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState* exec)
  315. {
  316. double x;
  317. if (!toThisNumber(exec->hostThisValue(), x))
  318. return throwVMTypeError(exec);
  319. // Get the argument.
  320. int decimalPlacesInExponent;
  321. bool isUndefined;
  322. if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlacesInExponent, isUndefined))
  323. return throwVMError(exec, createRangeError(exec, ASCIILiteral("toExponential() argument must be between 0 and 20")));
  324. // Handle NaN and Infinity.
  325. if (!std::isfinite(x))
  326. return JSValue::encode(jsString(exec, String::numberToStringECMAScript(x)));
  327. // Round if the argument is not undefined, always format as exponential.
  328. char buffer[WTF::NumberToStringBufferLength];
  329. DoubleConversionStringBuilder builder(buffer, WTF::NumberToStringBufferLength);
  330. const DoubleToStringConverter& converter = DoubleToStringConverter::EcmaScriptConverter();
  331. builder.Reset();
  332. isUndefined
  333. ? converter.ToExponential(x, -1, &builder)
  334. : converter.ToExponential(x, decimalPlacesInExponent, &builder);
  335. return JSValue::encode(jsString(exec, String(builder.Finalize())));
  336. }
  337. // toFixed converts a number to a string, always formatting as an a decimal fraction.
  338. // This method takes an argument specifying a number of decimal places to round the
  339. // significand to. However when converting large values (1e+21 and above) this
  340. // method will instead fallback to calling ToString.
  341. EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec)
  342. {
  343. double x;
  344. if (!toThisNumber(exec->hostThisValue(), x))
  345. return throwVMTypeError(exec);
  346. // Get the argument.
  347. int decimalPlaces;
  348. bool isUndefined; // This is ignored; undefined treated as 0.
  349. if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlaces, isUndefined))
  350. return throwVMError(exec, createRangeError(exec, ASCIILiteral("toFixed() argument must be between 0 and 20")));
  351. // 15.7.4.5.7 states "If x >= 10^21, then let m = ToString(x)"
  352. // This also covers Ininity, and structure the check so that NaN
  353. // values are also handled by numberToString
  354. if (!(fabs(x) < 1e+21))
  355. return JSValue::encode(jsString(exec, String::numberToStringECMAScript(x)));
  356. // The check above will return false for NaN or Infinity, these will be
  357. // handled by numberToString.
  358. ASSERT(std::isfinite(x));
  359. NumberToStringBuffer buffer;
  360. return JSValue::encode(jsString(exec, String(numberToFixedWidthString(x, decimalPlaces, buffer))));
  361. }
  362. // toPrecision converts a number to a string, takeing an argument specifying a
  363. // number of significant figures to round the significand to. For positive
  364. // exponent, all values that can be represented using a decimal fraction will
  365. // be, e.g. when rounding to 3 s.f. any value up to 999 will be formated as a
  366. // decimal, whilst 1000 is converted to the exponential representation 1.00e+3.
  367. // For negative exponents values >= 1e-6 are formated as decimal fractions,
  368. // with smaller values converted to exponential representation.
  369. EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec)
  370. {
  371. double x;
  372. if (!toThisNumber(exec->hostThisValue(), x))
  373. return throwVMTypeError(exec);
  374. // Get the argument.
  375. int significantFigures;
  376. bool isUndefined;
  377. if (!getIntegerArgumentInRange(exec, 1, 21, significantFigures, isUndefined))
  378. return throwVMError(exec, createRangeError(exec, ASCIILiteral("toPrecision() argument must be between 1 and 21")));
  379. // To precision called with no argument is treated as ToString.
  380. if (isUndefined)
  381. return JSValue::encode(jsString(exec, String::numberToStringECMAScript(x)));
  382. // Handle NaN and Infinity.
  383. if (!std::isfinite(x))
  384. return JSValue::encode(jsString(exec, String::numberToStringECMAScript(x)));
  385. NumberToStringBuffer buffer;
  386. return JSValue::encode(jsString(exec, String(numberToFixedPrecisionString(x, significantFigures, buffer))));
  387. }
  388. static inline int32_t extractRadixFromArgs(ExecState* exec)
  389. {
  390. JSValue radixValue = exec->argument(0);
  391. int32_t radix;
  392. if (radixValue.isInt32())
  393. radix = radixValue.asInt32();
  394. else if (radixValue.isUndefined())
  395. radix = 10;
  396. else
  397. radix = static_cast<int32_t>(radixValue.toInteger(exec)); // nan -> 0
  398. return radix;
  399. }
  400. static inline EncodedJSValue integerValueToString(ExecState* exec, int32_t radix, int32_t value)
  401. {
  402. // A negative value casted to unsigned would be bigger than 36 (the max radix).
  403. if (static_cast<unsigned>(value) < static_cast<unsigned>(radix)) {
  404. ASSERT(value <= 36);
  405. ASSERT(value >= 0);
  406. VM* vm = &exec->vm();
  407. return JSValue::encode(vm->smallStrings.singleCharacterString(vm, radixDigits[value]));
  408. }
  409. if (radix == 10) {
  410. VM* vm = &exec->vm();
  411. return JSValue::encode(jsString(vm, vm->numericStrings.add(value)));
  412. }
  413. return JSValue::encode(jsString(exec, toStringWithRadix(value, radix)));
  414. }
  415. EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec)
  416. {
  417. double doubleValue;
  418. if (!toThisNumber(exec->hostThisValue(), doubleValue))
  419. return throwVMTypeError(exec);
  420. int32_t radix = extractRadixFromArgs(exec);
  421. if (radix < 2 || radix > 36)
  422. return throwVMError(exec, createRangeError(exec, ASCIILiteral("toString() radix argument must be between 2 and 36")));
  423. int32_t integerValue = static_cast<int32_t>(doubleValue);
  424. if (integerValue == doubleValue)
  425. return integerValueToString(exec, radix, integerValue);
  426. if (radix == 10) {
  427. VM* vm = &exec->vm();
  428. return JSValue::encode(jsString(vm, vm->numericStrings.add(doubleValue)));
  429. }
  430. if (!std::isfinite(doubleValue))
  431. return JSValue::encode(jsString(exec, String::numberToStringECMAScript(doubleValue)));
  432. RadixBuffer s;
  433. return JSValue::encode(jsString(exec, toStringWithRadix(s, doubleValue, radix)));
  434. }
  435. EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState* exec)
  436. {
  437. double x;
  438. if (!toThisNumber(exec->hostThisValue(), x))
  439. return throwVMTypeError(exec);
  440. return JSValue::encode(jsNumber(x).toString(exec));
  441. }
  442. EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState* exec)
  443. {
  444. double x;
  445. if (!toThisNumber(exec->hostThisValue(), x))
  446. return throwVMTypeError(exec);
  447. return JSValue::encode(jsNumber(x));
  448. }
  449. } // namespace JSC