Refine the DOM element iterator implementation
[WebKit-https.git] / Source / JavaScriptCore / runtime / NumberPrototype.cpp
1 /*
2  *  Copyright (C) 1999-2000,2003 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2007-2019 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
22 #include "config.h"
23 #include "NumberPrototype.h"
24
25 #include "BigInteger.h"
26 #include "Error.h"
27 #include "IntlNumberFormat.h"
28 #include "IntlObject.h"
29 #include "JSCInlines.h"
30 #include "JSFunction.h"
31 #include "JSGlobalObject.h"
32 #include "JSString.h"
33 #include "ParseInt.h"
34 #include "Uint16WithFraction.h"
35 #include <wtf/dtoa.h>
36 #include <wtf/Assertions.h>
37 #include <wtf/MathExtras.h>
38 #include <wtf/dtoa/double-conversion.h>
39
40 using DoubleToStringConverter = WTF::double_conversion::DoubleToStringConverter;
41
42 // To avoid conflict with WTF::StringBuilder.
43 typedef WTF::double_conversion::StringBuilder DoubleConversionStringBuilder;
44
45 namespace JSC {
46
47 static EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(JSGlobalObject*, CallFrame*);
48 static EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(JSGlobalObject*, CallFrame*);
49 static EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(JSGlobalObject*, CallFrame*);
50 static EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(JSGlobalObject*, CallFrame*);
51
52 }
53
54 #include "NumberPrototype.lut.h"
55
56 namespace JSC {
57
58 const ClassInfo NumberPrototype::s_info = { "Number", &NumberObject::s_info, &numberPrototypeTable, nullptr, CREATE_METHOD_TABLE(NumberPrototype) };
59
60 /* Source for NumberPrototype.lut.h
61 @begin numberPrototypeTable
62   toLocaleString    numberProtoFuncToLocaleString   DontEnum|Function 0
63   valueOf           numberProtoFuncValueOf          DontEnum|Function 0
64   toFixed           numberProtoFuncToFixed          DontEnum|Function 1
65   toExponential     numberProtoFuncToExponential    DontEnum|Function 1
66   toPrecision       numberProtoFuncToPrecision      DontEnum|Function 1
67 @end
68 */
69
70 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(NumberPrototype);
71
72 NumberPrototype::NumberPrototype(VM& vm, Structure* structure)
73     : NumberObject(vm, structure)
74 {
75 }
76
77 void NumberPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
78 {
79     Base::finishCreation(vm);
80     setInternalValue(vm, jsNumber(0));
81     putDirectWithoutTransition(vm, vm.propertyNames->toString, globalObject->numberProtoToStringFunction(), static_cast<unsigned>(PropertyAttribute::DontEnum));
82     ASSERT(inherits(vm, info()));
83     globalObject->installNumberPrototypeWatchpoint(this);
84 }
85
86 // ------------------------------ Functions ---------------------------
87
88 static ALWAYS_INLINE bool toThisNumber(VM& vm, JSValue thisValue, double& x)
89 {
90     if (thisValue.isInt32()) {
91         x = thisValue.asInt32();
92         return true;
93     }
94
95     if (thisValue.isDouble()) {
96         x = thisValue.asDouble();
97         return true;
98     }
99
100     if (auto* numberObject = jsDynamicCast<NumberObject*>(vm, thisValue)) {
101         x = numberObject->internalValue().asNumber();
102         return true;
103     }
104
105     return false;
106 }
107
108 static ALWAYS_INLINE EncodedJSValue throwVMToThisNumberError(JSGlobalObject* globalObject, ThrowScope& scope, JSValue thisValue)
109 {
110     auto typeString = asString(jsTypeStringForValue(globalObject->vm(), globalObject, thisValue))->value(globalObject);
111     scope.assertNoException();
112     return throwVMTypeError(globalObject, scope, WTF::makeString("thisNumberValue called on incompatible ", typeString));
113 }
114
115 // The largest finite floating point number is 1.mantissa * 2^(0x7fe-0x3ff).
116 // Since 2^N in binary is a one bit followed by N zero bits. 1 * 2^3ff requires
117 // at most 1024 characters to the left of a decimal point, in base 2 (1025 if
118 // we include a minus sign). For the fraction, a value with an exponent of 0
119 // has up to 52 bits to the right of the decimal point. Each decrement of the
120 // exponent down to a minimum of -0x3fe adds an additional digit to the length
121 // of the fraction. As such the maximum fraction size is 1075 (1076 including
122 // a point). We pick a buffer size such that can simply place the point in the
123 // center of the buffer, and are guaranteed to have enough space in each direction
124 // fo any number of digits an IEEE number may require to represent.
125 typedef char RadixBuffer[2180];
126
127 static inline char* int52ToStringWithRadix(char* startOfResultString, int64_t int52Value, unsigned radix)
128 {
129     bool negative = false;
130     uint64_t positiveNumber = int52Value;
131     if (int52Value < 0) {
132         negative = true;
133         positiveNumber = -int52Value;
134     }
135
136     do {
137         uint64_t index = positiveNumber % radix;
138         ASSERT(index < sizeof(radixDigits));
139         *--startOfResultString = radixDigits[index];
140         positiveNumber /= radix;
141     } while (positiveNumber);
142     if (negative)
143         *--startOfResultString = '-';
144
145     return startOfResultString;
146 }
147
148 static char* toStringWithRadixInternal(RadixBuffer& buffer, double originalNumber, unsigned radix)
149 {
150     ASSERT(std::isfinite(originalNumber));
151     ASSERT(radix >= 2 && radix <= 36);
152
153     // Position the decimal point at the center of the string, set
154     // the startOfResultString pointer to point at the decimal point.
155     char* decimalPoint = buffer + sizeof(buffer) / 2;
156     char* startOfResultString = decimalPoint;
157
158     // Extract the sign.
159     bool isNegative = originalNumber < 0;
160     double number = originalNumber;
161     if (std::signbit(originalNumber))
162         number = -originalNumber;
163     double integerPart = floor(number);
164
165     // Check if the value has a fractional part to convert.
166     double fractionPart = number - integerPart;
167     if (!fractionPart) {
168         *decimalPoint = '\0';
169         // We do not need to care the negative zero (-0) since it is also converted to "0" in all the radix.
170         if (integerPart < (static_cast<int64_t>(1) << (JSValue::numberOfInt52Bits - 1)))
171             return int52ToStringWithRadix(startOfResultString, static_cast<int64_t>(originalNumber), radix);
172     } else {
173         // We use this to test for odd values in odd radix bases.
174         // Where the base is even, (e.g. 10), to determine whether a value is even we need only
175         // consider the least significant digit. For example, 124 in base 10 is even, because '4'
176         // is even. if the radix is odd, then the radix raised to an integer power is also odd.
177         // E.g. in base 5, 124 represents (1 * 125 + 2 * 25 + 4 * 5). Since each digit in the value
178         // is multiplied by an odd number, the result is even if the sum of all digits is even.
179         //
180         // For the integer portion of the result, we only need test whether the integer value is
181         // even or odd. For each digit of the fraction added, we should invert our idea of whether
182         // the number is odd if the new digit is odd.
183         //
184         // Also initialize digit to this value; for even radix values we only need track whether
185         // the last individual digit was odd.
186         bool integerPartIsOdd = integerPart <= static_cast<double>(0x1FFFFFFFFFFFFFull) && static_cast<int64_t>(integerPart) & 1;
187         ASSERT(integerPartIsOdd == static_cast<bool>(fmod(integerPart, 2)));
188         bool isOddInOddRadix = integerPartIsOdd;
189         uint32_t digit = integerPartIsOdd;
190
191         // Write the decimal point now.
192         *decimalPoint = '.';
193
194         // Higher precision representation of the fractional part.
195         Uint16WithFraction fraction(fractionPart);
196
197         bool needsRoundingUp = false;
198         char* endOfResultString = decimalPoint + 1;
199
200         // Calculate the delta from the current number to the next & previous possible IEEE numbers.
201         double nextNumber = nextafter(number, std::numeric_limits<double>::infinity());
202         double lastNumber = nextafter(number, -std::numeric_limits<double>::infinity());
203         ASSERT(std::isfinite(nextNumber) && !std::signbit(nextNumber));
204         ASSERT(std::isfinite(lastNumber) && !std::signbit(lastNumber));
205         double deltaNextDouble = nextNumber - number;
206         double deltaLastDouble = number - lastNumber;
207         ASSERT(std::isfinite(deltaNextDouble) && !std::signbit(deltaNextDouble));
208         ASSERT(std::isfinite(deltaLastDouble) && !std::signbit(deltaLastDouble));
209
210         // We track the delta from the current value to the next, to track how many digits of the
211         // fraction we need to write. For example, if the value we are converting is precisely
212         // 1.2345, so far we have written the digits "1.23" to a string leaving a remainder of
213         // 0.45, and we want to determine whether we can round off, or whether we need to keep
214         // appending digits ('4'). We can stop adding digits provided that then next possible
215         // lower IEEE value is further from 1.23 than the remainder we'd be rounding off (0.45),
216         // which is to say, less than 1.2255. Put another way, the delta between the prior
217         // possible value and this number must be more than 2x the remainder we'd be rounding off
218         // (or more simply half the delta between numbers must be greater than the remainder).
219         //
220         // Similarly we need track the delta to the next possible value, to dertermine whether
221         // to round up. In almost all cases (other than at exponent boundaries) the deltas to
222         // prior and subsequent values are identical, so we don't need track then separately.
223         if (deltaNextDouble != deltaLastDouble) {
224             // Since the deltas are different track them separately. Pre-multiply by 0.5.
225             Uint16WithFraction halfDeltaNext(deltaNextDouble, 1);
226             Uint16WithFraction halfDeltaLast(deltaLastDouble, 1);
227
228             while (true) {
229                 // examine the remainder to determine whether we should be considering rounding
230                 // up or down. If remainder is precisely 0.5 rounding is to even.
231                 int dComparePoint5 = fraction.comparePoint5();
232                 if (dComparePoint5 > 0 || (!dComparePoint5 && (radix & 1 ? isOddInOddRadix : digit & 1))) {
233                     // Check for rounding up; are we closer to the value we'd round off to than
234                     // the next IEEE value would be?
235                     if (fraction.sumGreaterThanOne(halfDeltaNext)) {
236                         needsRoundingUp = true;
237                         break;
238                     }
239                 } else {
240                     // Check for rounding down; are we closer to the value we'd round off to than
241                     // the prior IEEE value would be?
242                     if (fraction < halfDeltaLast)
243                         break;
244                 }
245
246                 ASSERT(endOfResultString < (buffer + sizeof(buffer) - 1));
247                 // Write a digit to the string.
248                 fraction *= radix;
249                 digit = fraction.floorAndSubtract();
250                 *endOfResultString++ = radixDigits[digit];
251                 // Keep track whether the portion written is currently even, if the radix is odd.
252                 if (digit & 1)
253                     isOddInOddRadix = !isOddInOddRadix;
254
255                 // Shift the fractions by radix.
256                 halfDeltaNext *= radix;
257                 halfDeltaLast *= radix;
258             }
259         } else {
260             // This code is identical to that above, except since deltaNextDouble != deltaLastDouble
261             // we don't need to track these two values separately.
262             Uint16WithFraction halfDelta(deltaNextDouble, 1);
263
264             while (true) {
265                 int dComparePoint5 = fraction.comparePoint5();
266                 if (dComparePoint5 > 0 || (!dComparePoint5 && (radix & 1 ? isOddInOddRadix : digit & 1))) {
267                     if (fraction.sumGreaterThanOne(halfDelta)) {
268                         needsRoundingUp = true;
269                         break;
270                     }
271                 } else if (fraction < halfDelta)
272                     break;
273
274                 ASSERT(endOfResultString < (buffer + sizeof(buffer) - 1));
275                 fraction *= radix;
276                 digit = fraction.floorAndSubtract();
277                 if (digit & 1)
278                     isOddInOddRadix = !isOddInOddRadix;
279                 *endOfResultString++ = radixDigits[digit];
280
281                 halfDelta *= radix;
282             }
283         }
284
285         // Check if the fraction needs rounding off (flag set in the loop writing digits, above).
286         if (needsRoundingUp) {
287             // Whilst the last digit is the maximum in the current radix, remove it.
288             // e.g. rounding up the last digit in "12.3999" is the same as rounding up the
289             // last digit in "12.3" - both round up to "12.4".
290             while (endOfResultString[-1] == radixDigits[radix - 1])
291                 --endOfResultString;
292
293             // Radix digits are sequential in ascii/unicode, except for '9' and 'a'.
294             // E.g. the first 'if' case handles rounding 67.89 to 67.8a in base 16.
295             // The 'else if' case handles rounding of all other digits.
296             if (endOfResultString[-1] == '9')
297                 endOfResultString[-1] = 'a';
298             else if (endOfResultString[-1] != '.')
299                 ++endOfResultString[-1];
300             else {
301                 // One other possibility - there may be no digits to round up in the fraction
302                 // (or all may be been rounded off already), in which case we may need to
303                 // round into the integer portion of the number. Remove the decimal point.
304                 --endOfResultString;
305                 // In order to get here there must have been a non-zero fraction, in which case
306                 // there must be at least one bit of the value's mantissa not in use in the
307                 // integer part of the number. As such, adding to the integer part should not
308                 // be able to lose precision.
309                 ASSERT((integerPart + 1) - integerPart == 1);
310                 ++integerPart;
311             }
312         } else {
313             // We only need to check for trailing zeros if the value does not get rounded up.
314             while (endOfResultString[-1] == '0')
315                 --endOfResultString;
316         }
317
318         *endOfResultString = '\0';
319         ASSERT(endOfResultString < buffer + sizeof(buffer));
320     }
321
322     BigInteger units(integerPart);
323
324     // Always loop at least once, to emit at least '0'.
325     do {
326         ASSERT(buffer < startOfResultString);
327
328         // Read a single digit and write it to the front of the string.
329         // Divide by radix to remove one digit from the value.
330         uint32_t digit = units.divide(radix);
331         *--startOfResultString = radixDigits[digit];
332     } while (!!units);
333
334     // If the number is negative, prepend '-'.
335     if (isNegative)
336         *--startOfResultString = '-';
337     ASSERT(buffer <= startOfResultString);
338
339     return startOfResultString;
340 }
341
342 static String toStringWithRadixInternal(int32_t number, unsigned radix)
343 {
344     LChar buf[1 + 32]; // Worst case is radix == 2, which gives us 32 digits + sign.
345     LChar* end = std::end(buf);
346     LChar* p = end;
347
348     bool negative = false;
349     uint32_t positiveNumber = number;
350     if (number < 0) {
351         negative = true;
352         positiveNumber = static_cast<uint32_t>(-static_cast<int64_t>(number));
353     }
354
355     // Always loop at least once, to emit at least '0'.
356     do {
357         uint32_t index = positiveNumber % radix;
358         ASSERT(index < sizeof(radixDigits));
359         *--p = static_cast<LChar>(radixDigits[index]);
360         positiveNumber /= radix;
361     } while (positiveNumber);
362
363     if (negative)
364         *--p = '-';
365
366     return String(p, static_cast<unsigned>(end - p));
367 }
368
369 String toStringWithRadix(double doubleValue, int32_t radix)
370 {
371     ASSERT(2 <= radix && radix <= 36);
372
373     int32_t integerValue = static_cast<int32_t>(doubleValue);
374     if (integerValue == doubleValue)
375         return toStringWithRadixInternal(integerValue, radix);
376
377     if (radix == 10 || !std::isfinite(doubleValue))
378         return String::number(doubleValue);
379
380     RadixBuffer buffer;
381     return toStringWithRadixInternal(buffer, doubleValue, radix);
382 }
383
384 // toExponential converts a number to a string, always formatting as an exponential.
385 // This method takes an optional argument specifying a number of *decimal places*
386 // to round the significand to (or, put another way, this method optionally rounds
387 // to argument-plus-one significant figures).
388 EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(JSGlobalObject* globalObject, CallFrame* callFrame)
389 {
390     VM& vm = globalObject->vm();
391     auto scope = DECLARE_THROW_SCOPE(vm);
392
393     double x;
394     if (!toThisNumber(vm, callFrame->thisValue(), x))
395         return throwVMToThisNumberError(globalObject, scope, callFrame->thisValue());
396
397     JSValue arg = callFrame->argument(0);
398     // Perform ToInteger on the argument before remaining steps.
399     int decimalPlaces = static_cast<int>(arg.toInteger(globalObject));
400     RETURN_IF_EXCEPTION(scope, { });
401
402     // Handle NaN and Infinity.
403     if (!std::isfinite(x))
404         return JSValue::encode(jsNontrivialString(vm, String::number(x)));
405
406     if (decimalPlaces < 0 || decimalPlaces > 100)
407         return throwVMRangeError(globalObject, scope, "toExponential() argument must be between 0 and 100"_s);
408
409     // Round if the argument is not undefined, always format as exponential.
410     NumberToStringBuffer buffer;
411     DoubleConversionStringBuilder builder { &buffer[0], sizeof(buffer) };
412     const DoubleToStringConverter& converter = DoubleToStringConverter::EcmaScriptConverter();
413     builder.Reset();
414     if (arg.isUndefined())
415         converter.ToExponential(x, -1, &builder);
416     else
417         converter.ToExponential(x, decimalPlaces, &builder);
418     return JSValue::encode(jsString(vm, builder.Finalize()));
419 }
420
421 // toFixed converts a number to a string, always formatting as an a decimal fraction.
422 // This method takes an argument specifying a number of decimal places to round the
423 // significand to. However when converting large values (1e+21 and above) this
424 // method will instead fallback to calling ToString. 
425 EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(JSGlobalObject* globalObject, CallFrame* callFrame)
426 {
427     VM& vm = globalObject->vm();
428     auto scope = DECLARE_THROW_SCOPE(vm);
429
430     double x;
431     if (!toThisNumber(vm, callFrame->thisValue(), x))
432         return throwVMToThisNumberError(globalObject, scope, callFrame->thisValue());
433
434     int decimalPlaces = static_cast<int>(callFrame->argument(0).toInteger(globalObject));
435     RETURN_IF_EXCEPTION(scope, { });
436     if (decimalPlaces < 0 || decimalPlaces > 100)
437         return throwVMRangeError(globalObject, scope, "toFixed() argument must be between 0 and 100"_s);
438
439     // 15.7.4.5.7 states "If x >= 10^21, then let m = ToString(x)"
440     // This also covers Ininity, and structure the check so that NaN
441     // values are also handled by numberToString
442     if (!(fabs(x) < 1e+21))
443         return JSValue::encode(jsString(vm, String::number(x)));
444
445     // The check above will return false for NaN or Infinity, these will be
446     // handled by numberToString.
447     ASSERT(std::isfinite(x));
448
449     return JSValue::encode(jsString(vm, String::numberToStringFixedWidth(x, decimalPlaces)));
450 }
451
452 // toPrecision converts a number to a string, taking an argument specifying a
453 // number of significant figures to round the significand to. For positive
454 // exponent, all values that can be represented using a decimal fraction will
455 // be, e.g. when rounding to 3 s.f. any value up to 999 will be formated as a
456 // decimal, whilst 1000 is converted to the exponential representation 1.00e+3.
457 // For negative exponents values >= 1e-6 are formated as decimal fractions,
458 // with smaller values converted to exponential representation.
459 EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(JSGlobalObject* globalObject, CallFrame* callFrame)
460 {
461     VM& vm = globalObject->vm();
462     auto scope = DECLARE_THROW_SCOPE(vm);
463
464     double x;
465     if (!toThisNumber(vm, callFrame->thisValue(), x))
466         return throwVMToThisNumberError(globalObject, scope, callFrame->thisValue());
467
468     JSValue arg = callFrame->argument(0);
469     // To precision called with no argument is treated as ToString.
470     if (arg.isUndefined())
471         return JSValue::encode(jsString(vm, String::number(x)));
472
473     // Perform ToInteger on the argument before remaining steps.
474     int significantFigures = static_cast<int>(arg.toInteger(globalObject));
475     RETURN_IF_EXCEPTION(scope, { });
476
477     // Handle NaN and Infinity.
478     if (!std::isfinite(x))
479         return JSValue::encode(jsNontrivialString(vm, String::number(x)));
480
481     if (significantFigures < 1 || significantFigures > 100)
482         return throwVMRangeError(globalObject, scope, "toPrecision() argument must be between 1 and 100"_s);
483
484     return JSValue::encode(jsString(vm, String::numberToStringFixedPrecision(x, significantFigures, KeepTrailingZeros)));
485 }
486
487 static ALWAYS_INLINE JSString* int32ToStringInternal(VM& vm, int32_t value, int32_t radix)
488 {
489     ASSERT(!(radix < 2 || radix > 36));
490     // A negative value casted to unsigned would be bigger than 36 (the max radix).
491     if (static_cast<unsigned>(value) < static_cast<unsigned>(radix)) {
492         ASSERT(value <= 36);
493         ASSERT(value >= 0);
494         return vm.smallStrings.singleCharacterString(radixDigits[value]);
495     }
496
497     if (radix == 10)
498         return jsNontrivialString(vm, vm.numericStrings.add(value));
499
500     return jsNontrivialString(vm, toStringWithRadixInternal(value, radix));
501
502 }
503
504 static ALWAYS_INLINE JSString* numberToStringInternal(VM& vm, double doubleValue, int32_t radix)
505 {
506     ASSERT(!(radix < 2 || radix > 36));
507
508     int32_t integerValue = static_cast<int32_t>(doubleValue);
509     if (integerValue == doubleValue)
510         return int32ToStringInternal(vm, integerValue, radix);
511
512     if (radix == 10)
513         return jsString(vm, vm.numericStrings.add(doubleValue));
514
515     if (!std::isfinite(doubleValue))
516         return jsNontrivialString(vm, String::number(doubleValue));
517
518     RadixBuffer buffer;
519     return jsString(vm, toStringWithRadixInternal(buffer, doubleValue, radix));
520 }
521
522 JSString* int32ToString(VM& vm, int32_t value, int32_t radix)
523 {
524     return int32ToStringInternal(vm, value, radix);
525 }
526
527 JSString* int52ToString(VM& vm, int64_t value, int32_t radix)
528 {
529     ASSERT(!(radix < 2 || radix > 36));
530     // A negative value casted to unsigned would be bigger than 36 (the max radix).
531     if (static_cast<uint64_t>(value) < static_cast<uint64_t>(radix)) {
532         ASSERT(value <= 36);
533         ASSERT(value >= 0);
534         return vm.smallStrings.singleCharacterString(radixDigits[value]);
535     }
536
537     if (radix == 10)
538         return jsNontrivialString(vm, vm.numericStrings.add(static_cast<double>(value)));
539
540     // Position the decimal point at the center of the string, set
541     // the startOfResultString pointer to point at the decimal point.
542     RadixBuffer buffer;
543     char* decimalPoint = buffer + sizeof(buffer) / 2;
544     char* startOfResultString = decimalPoint;
545     *decimalPoint = '\0';
546
547     return jsNontrivialString(vm, int52ToStringWithRadix(startOfResultString, value, radix));
548 }
549
550 JSString* numberToString(VM& vm, double doubleValue, int32_t radix)
551 {
552     return numberToStringInternal(vm, doubleValue, radix);
553 }
554
555 EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(JSGlobalObject* globalObject, CallFrame* callFrame)
556 {
557     VM& vm = globalObject->vm();
558     auto scope = DECLARE_THROW_SCOPE(vm);
559
560     double doubleValue;
561     if (!toThisNumber(vm, callFrame->thisValue(), doubleValue))
562         return throwVMToThisNumberError(globalObject, scope, callFrame->thisValue());
563
564     auto radix = extractToStringRadixArgument(globalObject, callFrame->argument(0), scope);
565     RETURN_IF_EXCEPTION(scope, encodedJSValue());
566
567     return JSValue::encode(numberToStringInternal(vm, doubleValue, radix));
568 }
569
570 EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(JSGlobalObject* globalObject, CallFrame* callFrame)
571 {
572     VM& vm = globalObject->vm();
573     auto scope = DECLARE_THROW_SCOPE(vm);
574
575     double x;
576     if (!toThisNumber(vm, callFrame->thisValue(), x))
577         return throwVMToThisNumberError(globalObject, scope, callFrame->thisValue());
578
579 #if ENABLE(INTL)
580     IntlNumberFormat* numberFormat = IntlNumberFormat::create(vm, globalObject->numberFormatStructure());
581     numberFormat->initializeNumberFormat(globalObject, callFrame->argument(0), callFrame->argument(1));
582     RETURN_IF_EXCEPTION(scope, encodedJSValue());
583     RELEASE_AND_RETURN(scope, JSValue::encode(numberFormat->formatNumber(globalObject, x)));
584 #else
585     return JSValue::encode(jsNumber(x).toString(globalObject));
586 #endif
587 }
588
589 EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(JSGlobalObject* globalObject, CallFrame* callFrame)
590 {
591     VM& vm = globalObject->vm();
592     auto scope = DECLARE_THROW_SCOPE(vm);
593
594     double x;
595     JSValue thisValue = callFrame->thisValue();
596     if (!toThisNumber(vm, thisValue, x))
597         return throwVMToThisNumberError(globalObject, scope, callFrame->thisValue());
598     return JSValue::encode(jsNumber(x));
599 }
600
601 int32_t extractToStringRadixArgument(JSGlobalObject* globalObject, JSValue radixValue, ThrowScope& throwScope)
602 {
603     if (radixValue.isUndefined())
604         return 10;
605
606     if (radixValue.isInt32()) {
607         int32_t radix = radixValue.asInt32();
608         if (radix >= 2 && radix <= 36)
609             return radix;
610     } else {
611         double radixDouble = radixValue.toInteger(globalObject);
612         RETURN_IF_EXCEPTION(throwScope, 0);
613         if (radixDouble >= 2 && radixDouble <= 36)
614             return static_cast<int32_t>(radixDouble);   
615     }
616
617     throwRangeError(globalObject, throwScope, "toString() radix argument must be between 2 and 36"_s);
618     return 0;
619 }
620
621 } // namespace JSC