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