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