Unzip initialization lists and constructors in JSCell hierarchy (6/7)
[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 "JSFunction.h"
28 #include "JSGlobalObject.h"
29 #include "JSString.h"
30 #include "Operations.h"
31 #include "Uint16WithFraction.h"
32 #include "dtoa.h"
33 #include <wtf/Assertions.h>
34 #include <wtf/MathExtras.h>
35 #include <wtf/Vector.h>
36 #include <wtf/dtoa/double-conversion.h>
37
38 using namespace WTF::double_conversion;
39
40 // To avoid conflict with WTF::StringBuilder.
41 typedef WTF::double_conversion::StringBuilder DoubleConversionStringBuilder;
42
43 namespace JSC {
44
45 static EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState*);
46 static EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState*);
47 static EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(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, 0, ExecState::numberPrototypeTable };
59
60 /* Source for NumberPrototype.lut.h
61 @begin numberPrototypeTable
62   toString          numberProtoFuncToString         DontEnum|Function 1
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 ASSERT_CLASS_FITS_IN_CELL(NumberPrototype);
72
73 NumberPrototype::NumberPrototype(ExecState* exec, Structure* structure)
74     : NumberObject(exec->globalData(), structure)
75 {
76 }
77
78 void NumberPrototype::finishCreation(ExecState* exec, JSGlobalObject*)
79 {
80     Base::finishCreation(exec->globalData());
81     setInternalValue(exec->globalData(), jsNumber(0));
82
83     ASSERT(inherits(&s_info));
84 }
85
86 bool NumberPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
87 {
88     return getStaticFunctionSlot<NumberObject>(exec, ExecState::numberPrototypeTable(exec), this, propertyName, slot);
89 }
90
91 bool NumberPrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
92 {
93     return getStaticFunctionDescriptor<NumberObject>(exec, ExecState::numberPrototypeTable(exec), this, propertyName, descriptor);
94 }
95
96 // ------------------------------ Functions ---------------------------
97
98 static ALWAYS_INLINE bool toThisNumber(JSValue thisValue, double &x)
99 {
100     JSValue v = thisValue.getJSNumber();
101     if (UNLIKELY(!v))
102         return false;
103     x = v.uncheckedGetNumber();
104     return true;
105 }
106
107 static ALWAYS_INLINE bool getIntegerArgumentInRange(ExecState* exec, int low, int high, int& result, bool& isUndefined)
108 {
109     result = 0;
110     isUndefined = false;
111
112     JSValue argument0 = exec->argument(0);
113     if (argument0.isUndefined()) {
114         isUndefined = true;
115         return true;
116     }
117
118     double asDouble = argument0.toInteger(exec);
119     if (asDouble < low || asDouble > high)
120         return false;
121
122     result = static_cast<int>(asDouble);
123     return true;
124 }
125
126 // The largest finite floating point number is 1.mantissa * 2^(0x7fe-0x3ff).
127 // Since 2^N in binary is a one bit followed by N zero bits. 1 * 2^3ff requires
128 // at most 1024 characters to the left of a decimal point, in base 2 (1025 if
129 // we include a minus sign). For the fraction, a value with an exponent of 0
130 // has up to 52 bits to the right of the decimal point. Each decrement of the
131 // exponent down to a minimum of -0x3fe adds an additional digit to the length
132 // of the fraction. As such the maximum fraction size is 1075 (1076 including
133 // a point). We pick a buffer size such that can simply place the point in the
134 // center of the buffer, and are guaranteed to have enough space in each direction
135 // fo any number of digits an IEEE number may require to represent.
136 typedef char RadixBuffer[2180];
137
138 // Mapping from integers 0..35 to digit identifying this value, for radix 2..36.
139 static const char* const radixDigits = "0123456789abcdefghijklmnopqrstuvwxyz";
140
141 static char* toStringWithRadix(RadixBuffer& buffer, double number, unsigned radix)
142 {
143     ASSERT(isfinite(number));
144     ASSERT(radix >= 2 && radix <= 36);
145
146     // Position the decimal point at the center of the string, set
147     // the startOfResultString pointer to point at the decimal point.
148     char* decimalPoint = buffer + sizeof(buffer) / 2;
149     char* startOfResultString = decimalPoint;
150
151     // Extract the sign.
152     bool isNegative = number < 0;
153     if (signbit(number))
154         number = -number;
155     double integerPart = floor(number);
156
157     // We use this to test for odd values in odd radix bases.
158     // Where the base is even, (e.g. 10), to determine whether a value is even we need only
159     // consider the least significant digit. For example, 124 in base 10 is even, because '4'
160     // is even. if the radix is odd, then the radix raised to an integer power is also odd.
161     // E.g. in base 5, 124 represents (1 * 125 + 2 * 25 + 4 * 5). Since each digit in the value
162     // is multiplied by an odd number, the result is even if the sum of all digits is even.
163     //
164     // For the integer portion of the result, we only need test whether the integer value is
165     // even or odd. For each digit of the fraction added, we should invert our idea of whether
166     // the number is odd if the new digit is odd.
167     //
168     // Also initialize digit to this value; for even radix values we only need track whether
169     // the last individual digit was odd.
170     bool integerPartIsOdd = integerPart <= static_cast<double>(0x1FFFFFFFFFFFFFull) && static_cast<int64_t>(integerPart) & 1;
171     ASSERT(integerPartIsOdd == static_cast<bool>(fmod(integerPart, 2)));
172     bool isOddInOddRadix = integerPartIsOdd;
173     uint32_t digit = integerPartIsOdd;
174
175     // Check if the value has a fractional part to convert.
176     double fractionPart = number - integerPart;
177     if (fractionPart) {
178         // Write the decimal point now.
179         *decimalPoint = '.';
180
181         // Higher precision representation of the fractional part.
182         Uint16WithFraction fraction(fractionPart);
183
184         bool needsRoundingUp = false;
185         char* endOfResultString = decimalPoint + 1;
186
187         // Calculate the delta from the current number to the next & previous possible IEEE numbers.
188         double nextNumber = nextafter(number, std::numeric_limits<double>::infinity());
189         double lastNumber = nextafter(number, -std::numeric_limits<double>::infinity());
190         ASSERT(isfinite(nextNumber) && !signbit(nextNumber));
191         ASSERT(isfinite(lastNumber) && !signbit(lastNumber));
192         double deltaNextDouble = nextNumber - number;
193         double deltaLastDouble = number - lastNumber;
194         ASSERT(isfinite(deltaNextDouble) && !signbit(deltaNextDouble));
195         ASSERT(isfinite(deltaLastDouble) && !signbit(deltaLastDouble));
196
197         // We track the delta from the current value to the next, to track how many digits of the
198         // fraction we need to write. For example, if the value we are converting is precisely
199         // 1.2345, so far we have written the digits "1.23" to a string leaving a remainder of
200         // 0.45, and we want to determine whether we can round off, or whether we need to keep
201         // appending digits ('4'). We can stop adding digits provided that then next possible
202         // lower IEEE value is further from 1.23 than the remainder we'd be rounding off (0.45),
203         // which is to say, less than 1.2255. Put another way, the delta between the prior
204         // possible value and this number must be more than 2x the remainder we'd be rounding off
205         // (or more simply half the delta between numbers must be greater than the remainder).
206         //
207         // Similarly we need track the delta to the next possible value, to dertermine whether
208         // to round up. In almost all cases (other than at exponent boundaries) the deltas to
209         // prior and subsequent values are identical, so we don't need track then separately.
210         if (deltaNextDouble != deltaLastDouble) {
211             // Since the deltas are different track them separately. Pre-multiply by 0.5.
212             Uint16WithFraction halfDeltaNext(deltaNextDouble, 1);
213             Uint16WithFraction halfDeltaLast(deltaLastDouble, 1);
214
215             while (true) {
216                 // examine the remainder to determine whether we should be considering rounding
217                 // up or down. If remainder is precisely 0.5 rounding is to even.
218                 int dComparePoint5 = fraction.comparePoint5();
219                 if (dComparePoint5 > 0 || (!dComparePoint5 && (radix & 1 ? isOddInOddRadix : digit & 1))) {
220                     // Check for rounding up; are we closer to the value we'd round off to than
221                     // the next IEEE value would be?
222                     if (fraction.sumGreaterThanOne(halfDeltaNext)) {
223                         needsRoundingUp = true;
224                         break;
225                     }
226                 } else {
227                     // Check for rounding down; are we closer to the value we'd round off to than
228                     // the prior IEEE value would be?
229                     if (fraction < halfDeltaLast)
230                         break;
231                 }
232
233                 ASSERT(endOfResultString < (buffer + sizeof(buffer) - 1));
234                 // Write a digit to the string.
235                 fraction *= radix;
236                 digit = fraction.floorAndSubtract();
237                 *endOfResultString++ = radixDigits[digit];
238                 // Keep track whether the portion written is currently even, if the radix is odd.
239                 if (digit & 1)
240                     isOddInOddRadix = !isOddInOddRadix;
241
242                 // Shift the fractions by radix.
243                 halfDeltaNext *= radix;
244                 halfDeltaLast *= radix;
245             }
246         } else {
247             // This code is identical to that above, except since deltaNextDouble != deltaLastDouble
248             // we don't need to track these two values separately.
249             Uint16WithFraction halfDelta(deltaNextDouble, 1);
250
251             while (true) {
252                 int dComparePoint5 = fraction.comparePoint5();
253                 if (dComparePoint5 > 0 || (!dComparePoint5 && (radix & 1 ? isOddInOddRadix : digit & 1))) {
254                     if (fraction.sumGreaterThanOne(halfDelta)) {
255                         needsRoundingUp = true;
256                         break;
257                     }
258                 } else if (fraction < halfDelta)
259                     break;
260
261                 ASSERT(endOfResultString < (buffer + sizeof(buffer) - 1));
262                 fraction *= radix;
263                 digit = fraction.floorAndSubtract();
264                 if (digit & 1)
265                     isOddInOddRadix = !isOddInOddRadix;
266                 *endOfResultString++ = radixDigits[digit];
267
268                 halfDelta *= radix;
269             }
270         }
271
272         // Check if the fraction needs rounding off (flag set in the loop writing digits, above).
273         if (needsRoundingUp) {
274             // Whilst the last digit is the maximum in the current radix, remove it.
275             // e.g. rounding up the last digit in "12.3999" is the same as rounding up the
276             // last digit in "12.3" - both round up to "12.4".
277             while (endOfResultString[-1] == radixDigits[radix - 1])
278                 --endOfResultString;
279
280             // Radix digits are sequential in ascii/unicode, except for '9' and 'a'.
281             // E.g. the first 'if' case handles rounding 67.89 to 67.8a in base 16.
282             // The 'else if' case handles rounding of all other digits.
283             if (endOfResultString[-1] == '9')
284                 endOfResultString[-1] = 'a';
285             else if (endOfResultString[-1] != '.')
286                 ++endOfResultString[-1];
287             else {
288                 // One other possibility - there may be no digits to round up in the fraction
289                 // (or all may be been rounded off already), in which case we may need to
290                 // round into the integer portion of the number. Remove the decimal point.
291                 --endOfResultString;
292                 // In order to get here there must have been a non-zero fraction, in which case
293                 // there must be at least one bit of the value's mantissa not in use in the
294                 // integer part of the number. As such, adding to the integer part should not
295                 // be able to lose precision.
296                 ASSERT((integerPart + 1) - integerPart == 1);
297                 ++integerPart;
298             }
299         } else {
300             // We only need to check for trailing zeros if the value does not get rounded up.
301             while (endOfResultString[-1] == '0')
302                 --endOfResultString;
303         }
304
305         *endOfResultString = '\0';
306         ASSERT(endOfResultString < buffer + sizeof(buffer));
307     } else
308         *decimalPoint = '\0';
309
310     BigInteger units(integerPart);
311
312     // Always loop at least once, to emit at least '0'.
313     do {
314         ASSERT(buffer < startOfResultString);
315
316         // Read a single digit and write it to the front of the string.
317         // Divide by radix to remove one digit from the value.
318         digit = units.divide(radix);
319         *--startOfResultString = radixDigits[digit];
320     } while (!!units);
321
322     // If the number is negative, prepend '-'.
323     if (isNegative)
324         *--startOfResultString = '-';
325     ASSERT(buffer <= startOfResultString);
326
327     return startOfResultString;
328 }
329
330 // toExponential converts a number to a string, always formatting as an expoential.
331 // This method takes an optional argument specifying a number of *decimal places*
332 // to round the significand to (or, put another way, this method optionally rounds
333 // to argument-plus-one significant figures).
334 EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState* exec)
335 {
336     // Get x (the double value of this, which should be a Number).
337     double x;
338     if (!toThisNumber(exec->hostThisValue(), x))
339         return throwVMTypeError(exec);
340
341     // Get the argument. 
342     int decimalPlacesInExponent;
343     bool isUndefined;
344     if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlacesInExponent, isUndefined))
345         return throwVMError(exec, createRangeError(exec, "toExponential() argument must be between 0 and 20"));
346
347     // Handle NaN and Infinity.
348     if (!isfinite(x))
349         return JSValue::encode(jsString(exec, UString::number(x)));
350
351     // Round if the argument is not undefined, always format as exponential.
352     char buffer[WTF::NumberToStringBufferLength];
353     DoubleConversionStringBuilder builder(buffer, WTF::NumberToStringBufferLength);
354     const DoubleToStringConverter& converter = DoubleToStringConverter::EcmaScriptConverter();
355     builder.Reset();
356     isUndefined
357         ? converter.ToExponential(x, -1, &builder)
358         : converter.ToExponential(x, decimalPlacesInExponent, &builder);
359     return JSValue::encode(jsString(exec, UString(builder.Finalize())));
360 }
361
362 // toFixed converts a number to a string, always formatting as an a decimal fraction.
363 // This method takes an argument specifying a number of decimal places to round the
364 // significand to. However when converting large values (1e+21 and above) this
365 // method will instead fallback to calling ToString. 
366 EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec)
367 {
368     // Get x (the double value of this, which should be a Number).
369     JSValue thisValue = exec->hostThisValue();
370     JSValue v = thisValue.getJSNumber();
371     if (!v)
372         return throwVMTypeError(exec);
373     double x = v.uncheckedGetNumber();
374
375     // Get the argument. 
376     int decimalPlaces;
377     bool isUndefined; // This is ignored; undefined treated as 0.
378     if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlaces, isUndefined))
379         return throwVMError(exec, createRangeError(exec, "toFixed() argument must be between 0 and 20"));
380
381     // 15.7.4.5.7 states "If x >= 10^21, then let m = ToString(x)"
382     // This also covers Ininity, and structure the check so that NaN
383     // values are also handled by numberToString
384     if (!(fabs(x) < 1e+21))
385         return JSValue::encode(jsString(exec, UString::number(x)));
386
387     // The check above will return false for NaN or Infinity, these will be
388     // handled by numberToString.
389     ASSERT(isfinite(x));
390
391     char buffer[WTF::NumberToStringBufferLength];
392     DoubleConversionStringBuilder builder(buffer, WTF::NumberToStringBufferLength);
393     const DoubleToStringConverter& converter = DoubleToStringConverter::EcmaScriptConverter();
394     builder.Reset();
395     converter.ToFixed(x, decimalPlaces, &builder);
396     return JSValue::encode(jsString(exec, UString(builder.Finalize())));
397 }
398
399 // toPrecision converts a number to a string, takeing an argument specifying a
400 // number of significant figures to round the significand to. For positive
401 // exponent, all values that can be represented using a decimal fraction will
402 // be, e.g. when rounding to 3 s.f. any value up to 999 will be formated as a
403 // decimal, whilst 1000 is converted to the exponential representation 1.00e+3.
404 // For negative exponents values >= 1e-6 are formated as decimal fractions,
405 // with smaller values converted to exponential representation.
406 EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec)
407 {
408     // Get x (the double value of this, which should be a Number).
409     JSValue thisValue = exec->hostThisValue();
410     JSValue v = thisValue.getJSNumber();
411     if (!v)
412         return throwVMTypeError(exec);
413     double x = v.uncheckedGetNumber();
414
415     // Get the argument. 
416     int significantFigures;
417     bool isUndefined;
418     if (!getIntegerArgumentInRange(exec, 1, 21, significantFigures, isUndefined))
419         return throwVMError(exec, createRangeError(exec, "toPrecision() argument must be between 1 and 21"));
420
421     // To precision called with no argument is treated as ToString.
422     if (isUndefined)
423         return JSValue::encode(jsString(exec, UString::number(x)));
424
425     // Handle NaN and Infinity.
426     if (!isfinite(x))
427         return JSValue::encode(jsString(exec, UString::number(x)));
428
429     char buffer[WTF::NumberToStringBufferLength];
430     DoubleConversionStringBuilder builder(buffer, WTF::NumberToStringBufferLength);
431     const DoubleToStringConverter& converter = DoubleToStringConverter::EcmaScriptConverter();
432     builder.Reset();
433     converter.ToPrecision(x, significantFigures, &builder);
434     return JSValue::encode(jsString(exec, UString(builder.Finalize())));
435 }
436
437 EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec)
438 {
439     JSValue thisValue = exec->hostThisValue();
440     JSValue v = thisValue.getJSNumber();
441     if (!v)
442         return throwVMTypeError(exec);
443
444     JSValue radixValue = exec->argument(0);
445     int radix;
446     if (radixValue.isInt32())
447         radix = radixValue.asInt32();
448     else if (radixValue.isUndefined())
449         radix = 10;
450     else
451         radix = static_cast<int>(radixValue.toInteger(exec)); // nan -> 0
452
453     if (radix == 10)
454         return JSValue::encode(jsString(exec, v.toString(exec)));
455
456     // Fast path for number to character conversion.
457     if (radix == 36) {
458         if (v.isInt32()) {
459             int x = v.asInt32();
460             if (static_cast<unsigned>(x) < 36) { // Exclude negatives
461                 JSGlobalData* globalData = &exec->globalData();
462                 return JSValue::encode(globalData->smallStrings.singleCharacterString(globalData, radixDigits[x]));
463             }
464         }
465     }
466
467     if (radix < 2 || radix > 36)
468         return throwVMError(exec, createRangeError(exec, "toString() radix argument must be between 2 and 36"));
469
470     double x = v.uncheckedGetNumber();
471     if (!isfinite(x))
472         return JSValue::encode(jsString(exec, UString::number(x)));
473
474     RadixBuffer s;
475     return JSValue::encode(jsString(exec, toStringWithRadix(s, x, radix)));
476 }
477
478 EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState* exec)
479 {
480     JSValue thisValue = exec->hostThisValue();
481     // FIXME: Not implemented yet.
482
483     JSValue v = thisValue.getJSNumber();
484     if (!v)
485         return throwVMTypeError(exec);
486
487     return JSValue::encode(jsString(exec, v.toString(exec)));
488 }
489
490 EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState* exec)
491 {
492     JSValue thisValue = exec->hostThisValue();
493     JSValue v = thisValue.getJSNumber();
494     if (!v)
495         return throwVMTypeError(exec);
496
497     return JSValue::encode(v);
498 }
499
500 } // namespace JSC