NumberPrototype.cpp 21.6 KB
Newer Older
weinig@apple.com's avatar
weinig@apple.com committed
1 2
/*
 *  Copyright (C) 1999-2000,2003 Harri Porten (porten@kde.org)
3
 *  Copyright (C) 2007, 2008, 2011 Apple Inc. All rights reserved.
weinig@apple.com's avatar
weinig@apple.com committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
 *  USA
 *
 */

#include "config.h"
#include "NumberPrototype.h"

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 <wtf/dtoa.h>
weinig@apple.com's avatar
weinig@apple.com committed
33 34 35
#include <wtf/Assertions.h>
#include <wtf/MathExtras.h>
#include <wtf/Vector.h>
36 37 38
#include <wtf/dtoa/double-conversion.h>

using namespace WTF::double_conversion;
weinig@apple.com's avatar
weinig@apple.com committed
39

40 41 42
// To avoid conflict with WTF::StringBuilder.
typedef WTF::double_conversion::StringBuilder DoubleConversionStringBuilder;

43
namespace JSC {
weinig@apple.com's avatar
weinig@apple.com committed
44

45 46 47 48 49 50
static EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState*);
static EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState*);
static EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState*);
static EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState*);
static EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState*);
static EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState*);
weinig@apple.com's avatar
weinig@apple.com committed
51

52 53 54 55 56 57
}

#include "NumberPrototype.lut.h"

namespace JSC {

58
const ClassInfo NumberPrototype::s_info = { "Number", &NumberObject::s_info, 0, ExecState::numberPrototypeTable, CREATE_METHOD_TABLE(NumberPrototype) };
59 60 61 62 63 64 65 66 67 68 69

/* Source for NumberPrototype.lut.h
@begin numberPrototypeTable
  toString          numberProtoFuncToString         DontEnum|Function 1
  toLocaleString    numberProtoFuncToLocaleString   DontEnum|Function 0
  valueOf           numberProtoFuncValueOf          DontEnum|Function 0
  toFixed           numberProtoFuncToFixed          DontEnum|Function 1
  toExponential     numberProtoFuncToExponential    DontEnum|Function 1
  toPrecision       numberProtoFuncToPrecision      DontEnum|Function 1
@end
*/
weinig@apple.com's avatar
weinig@apple.com committed
70

71
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(NumberPrototype);
72

73 74
NumberPrototype::NumberPrototype(VM& vm, Structure* structure)
    : NumberObject(vm, structure)
weinig@apple.com's avatar
weinig@apple.com committed
75
{
76 77
}

78
void NumberPrototype::finishCreation(VM& vm, JSGlobalObject*)
79
{
80 81
    Base::finishCreation(vm);
    setInternalValue(vm, jsNumber(0));
weinig@apple.com's avatar
weinig@apple.com committed
82

83
    ASSERT(inherits(info()));
84 85
}

86
bool NumberPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
87
{
88
    return getStaticFunctionSlot<NumberObject>(exec, ExecState::numberPrototypeTable(exec), jsCast<NumberPrototype*>(object), propertyName, slot);
89
}
weinig@apple.com's avatar
weinig@apple.com committed
90 91 92

// ------------------------------ Functions ---------------------------

ggaren@apple.com's avatar
ggaren@apple.com committed
93
static ALWAYS_INLINE bool toThisNumber(JSValue thisValue, double& x)
weinig@apple.com's avatar
weinig@apple.com committed
94
{
ggaren@apple.com's avatar
ggaren@apple.com committed
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
    if (thisValue.isInt32()) {
        x = thisValue.asInt32();
        return true;
    }

    if (thisValue.isDouble()) {
        x = thisValue.asDouble();
        return true;
    }
    
    if (thisValue.isCell() && thisValue.asCell()->structure()->typeInfo().isNumberObject()) {
        x = static_cast<const NumberObject*>(thisValue.asCell())->internalValue().asNumber();
        return true;
    }

    return false;
111 112 113 114 115 116 117 118 119 120 121
}

static ALWAYS_INLINE bool getIntegerArgumentInRange(ExecState* exec, int low, int high, int& result, bool& isUndefined)
{
    result = 0;
    isUndefined = false;

    JSValue argument0 = exec->argument(0);
    if (argument0.isUndefined()) {
        isUndefined = true;
        return true;
weinig@apple.com's avatar
weinig@apple.com committed
122 123
    }

124 125 126 127 128 129
    double asDouble = argument0.toInteger(exec);
    if (asDouble < low || asDouble > high)
        return false;

    result = static_cast<int>(asDouble);
    return true;
weinig@apple.com's avatar
weinig@apple.com committed
130 131
}

132 133 134 135 136 137 138 139 140 141 142 143 144
// The largest finite floating point number is 1.mantissa * 2^(0x7fe-0x3ff).
// Since 2^N in binary is a one bit followed by N zero bits. 1 * 2^3ff requires
// at most 1024 characters to the left of a decimal point, in base 2 (1025 if
// we include a minus sign). For the fraction, a value with an exponent of 0
// has up to 52 bits to the right of the decimal point. Each decrement of the
// exponent down to a minimum of -0x3fe adds an additional digit to the length
// of the fraction. As such the maximum fraction size is 1075 (1076 including
// a point). We pick a buffer size such that can simply place the point in the
// center of the buffer, and are guaranteed to have enough space in each direction
// fo any number of digits an IEEE number may require to represent.
typedef char RadixBuffer[2180];

// Mapping from integers 0..35 to digit identifying this value, for radix 2..36.
145
static const char radixDigits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
146 147 148

static char* toStringWithRadix(RadixBuffer& buffer, double number, unsigned radix)
{
149
    ASSERT(std::isfinite(number));
150 151 152 153 154 155 156 157 158
    ASSERT(radix >= 2 && radix <= 36);

    // Position the decimal point at the center of the string, set
    // the startOfResultString pointer to point at the decimal point.
    char* decimalPoint = buffer + sizeof(buffer) / 2;
    char* startOfResultString = decimalPoint;

    // Extract the sign.
    bool isNegative = number < 0;
159
    if (std::signbit(number))
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
        number = -number;
    double integerPart = floor(number);

    // We use this to test for odd values in odd radix bases.
    // Where the base is even, (e.g. 10), to determine whether a value is even we need only
    // consider the least significant digit. For example, 124 in base 10 is even, because '4'
    // is even. if the radix is odd, then the radix raised to an integer power is also odd.
    // E.g. in base 5, 124 represents (1 * 125 + 2 * 25 + 4 * 5). Since each digit in the value
    // is multiplied by an odd number, the result is even if the sum of all digits is even.
    //
    // For the integer portion of the result, we only need test whether the integer value is
    // even or odd. For each digit of the fraction added, we should invert our idea of whether
    // the number is odd if the new digit is odd.
    //
    // Also initialize digit to this value; for even radix values we only need track whether
    // the last individual digit was odd.
    bool integerPartIsOdd = integerPart <= static_cast<double>(0x1FFFFFFFFFFFFFull) && static_cast<int64_t>(integerPart) & 1;
    ASSERT(integerPartIsOdd == static_cast<bool>(fmod(integerPart, 2)));
    bool isOddInOddRadix = integerPartIsOdd;
    uint32_t digit = integerPartIsOdd;

    // Check if the value has a fractional part to convert.
    double fractionPart = number - integerPart;
    if (fractionPart) {
        // Write the decimal point now.
        *decimalPoint = '.';

        // Higher precision representation of the fractional part.
        Uint16WithFraction fraction(fractionPart);

        bool needsRoundingUp = false;
        char* endOfResultString = decimalPoint + 1;

        // Calculate the delta from the current number to the next & previous possible IEEE numbers.
        double nextNumber = nextafter(number, std::numeric_limits<double>::infinity());
        double lastNumber = nextafter(number, -std::numeric_limits<double>::infinity());
196 197
        ASSERT(std::isfinite(nextNumber) && !std::signbit(nextNumber));
        ASSERT(std::isfinite(lastNumber) && !std::signbit(lastNumber));
198 199
        double deltaNextDouble = nextNumber - number;
        double deltaLastDouble = number - lastNumber;
200 201
        ASSERT(std::isfinite(deltaNextDouble) && !std::signbit(deltaNextDouble));
        ASSERT(std::isfinite(deltaLastDouble) && !std::signbit(deltaLastDouble));
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335

        // We track the delta from the current value to the next, to track how many digits of the
        // fraction we need to write. For example, if the value we are converting is precisely
        // 1.2345, so far we have written the digits "1.23" to a string leaving a remainder of
        // 0.45, and we want to determine whether we can round off, or whether we need to keep
        // appending digits ('4'). We can stop adding digits provided that then next possible
        // lower IEEE value is further from 1.23 than the remainder we'd be rounding off (0.45),
        // which is to say, less than 1.2255. Put another way, the delta between the prior
        // possible value and this number must be more than 2x the remainder we'd be rounding off
        // (or more simply half the delta between numbers must be greater than the remainder).
        //
        // Similarly we need track the delta to the next possible value, to dertermine whether
        // to round up. In almost all cases (other than at exponent boundaries) the deltas to
        // prior and subsequent values are identical, so we don't need track then separately.
        if (deltaNextDouble != deltaLastDouble) {
            // Since the deltas are different track them separately. Pre-multiply by 0.5.
            Uint16WithFraction halfDeltaNext(deltaNextDouble, 1);
            Uint16WithFraction halfDeltaLast(deltaLastDouble, 1);

            while (true) {
                // examine the remainder to determine whether we should be considering rounding
                // up or down. If remainder is precisely 0.5 rounding is to even.
                int dComparePoint5 = fraction.comparePoint5();
                if (dComparePoint5 > 0 || (!dComparePoint5 && (radix & 1 ? isOddInOddRadix : digit & 1))) {
                    // Check for rounding up; are we closer to the value we'd round off to than
                    // the next IEEE value would be?
                    if (fraction.sumGreaterThanOne(halfDeltaNext)) {
                        needsRoundingUp = true;
                        break;
                    }
                } else {
                    // Check for rounding down; are we closer to the value we'd round off to than
                    // the prior IEEE value would be?
                    if (fraction < halfDeltaLast)
                        break;
                }

                ASSERT(endOfResultString < (buffer + sizeof(buffer) - 1));
                // Write a digit to the string.
                fraction *= radix;
                digit = fraction.floorAndSubtract();
                *endOfResultString++ = radixDigits[digit];
                // Keep track whether the portion written is currently even, if the radix is odd.
                if (digit & 1)
                    isOddInOddRadix = !isOddInOddRadix;

                // Shift the fractions by radix.
                halfDeltaNext *= radix;
                halfDeltaLast *= radix;
            }
        } else {
            // This code is identical to that above, except since deltaNextDouble != deltaLastDouble
            // we don't need to track these two values separately.
            Uint16WithFraction halfDelta(deltaNextDouble, 1);

            while (true) {
                int dComparePoint5 = fraction.comparePoint5();
                if (dComparePoint5 > 0 || (!dComparePoint5 && (radix & 1 ? isOddInOddRadix : digit & 1))) {
                    if (fraction.sumGreaterThanOne(halfDelta)) {
                        needsRoundingUp = true;
                        break;
                    }
                } else if (fraction < halfDelta)
                    break;

                ASSERT(endOfResultString < (buffer + sizeof(buffer) - 1));
                fraction *= radix;
                digit = fraction.floorAndSubtract();
                if (digit & 1)
                    isOddInOddRadix = !isOddInOddRadix;
                *endOfResultString++ = radixDigits[digit];

                halfDelta *= radix;
            }
        }

        // Check if the fraction needs rounding off (flag set in the loop writing digits, above).
        if (needsRoundingUp) {
            // Whilst the last digit is the maximum in the current radix, remove it.
            // e.g. rounding up the last digit in "12.3999" is the same as rounding up the
            // last digit in "12.3" - both round up to "12.4".
            while (endOfResultString[-1] == radixDigits[radix - 1])
                --endOfResultString;

            // Radix digits are sequential in ascii/unicode, except for '9' and 'a'.
            // E.g. the first 'if' case handles rounding 67.89 to 67.8a in base 16.
            // The 'else if' case handles rounding of all other digits.
            if (endOfResultString[-1] == '9')
                endOfResultString[-1] = 'a';
            else if (endOfResultString[-1] != '.')
                ++endOfResultString[-1];
            else {
                // One other possibility - there may be no digits to round up in the fraction
                // (or all may be been rounded off already), in which case we may need to
                // round into the integer portion of the number. Remove the decimal point.
                --endOfResultString;
                // In order to get here there must have been a non-zero fraction, in which case
                // there must be at least one bit of the value's mantissa not in use in the
                // integer part of the number. As such, adding to the integer part should not
                // be able to lose precision.
                ASSERT((integerPart + 1) - integerPart == 1);
                ++integerPart;
            }
        } else {
            // We only need to check for trailing zeros if the value does not get rounded up.
            while (endOfResultString[-1] == '0')
                --endOfResultString;
        }

        *endOfResultString = '\0';
        ASSERT(endOfResultString < buffer + sizeof(buffer));
    } else
        *decimalPoint = '\0';

    BigInteger units(integerPart);

    // Always loop at least once, to emit at least '0'.
    do {
        ASSERT(buffer < startOfResultString);

        // Read a single digit and write it to the front of the string.
        // Divide by radix to remove one digit from the value.
        digit = units.divide(radix);
        *--startOfResultString = radixDigits[digit];
    } while (!!units);

    // If the number is negative, prepend '-'.
    if (isNegative)
        *--startOfResultString = '-';
    ASSERT(buffer <= startOfResultString);

    return startOfResultString;
}

336
static String toStringWithRadix(int32_t number, unsigned radix)
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
{
    LChar buf[1 + 32]; // Worst case is radix == 2, which gives us 32 digits + sign.
    LChar* end = buf + WTF_ARRAY_LENGTH(buf);
    LChar* p = end;

    bool negative = false;
    uint32_t positiveNumber = number;
    if (number < 0) {
        negative = true;
        positiveNumber = -number;
    }

    while (positiveNumber) {
        uint32_t index = positiveNumber % radix;
        ASSERT(index < sizeof(radixDigits));
        *--p = static_cast<LChar>(radixDigits[index]);
        positiveNumber /= radix;
    }
    if (negative)
        *--p = '-';

358
    return String(p, static_cast<unsigned>(end - p));
359 360
}

361 362 363 364 365
// toExponential converts a number to a string, always formatting as an expoential.
// This method takes an optional argument specifying a number of *decimal places*
// to round the significand to (or, put another way, this method optionally rounds
// to argument-plus-one significant figures).
EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState* exec)
weinig@apple.com's avatar
weinig@apple.com committed
366
{
367 368 369 370 371 372 373 374
    double x;
    if (!toThisNumber(exec->hostThisValue(), x))
        return throwVMTypeError(exec);

    // Get the argument. 
    int decimalPlacesInExponent;
    bool isUndefined;
    if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlacesInExponent, isUndefined))
375
        return throwVMError(exec, createRangeError(exec, ASCIILiteral("toExponential() argument must be between 0 and 20")));
weinig@apple.com's avatar
weinig@apple.com committed
376

377
    // Handle NaN and Infinity.
378
    if (!std::isfinite(x))
379
        return JSValue::encode(jsString(exec, String::numberToStringECMAScript(x)));
380 381

    // Round if the argument is not undefined, always format as exponential.
382
    char buffer[WTF::NumberToStringBufferLength];
383
    DoubleConversionStringBuilder builder(buffer, WTF::NumberToStringBufferLength);
384 385 386 387 388
    const DoubleToStringConverter& converter = DoubleToStringConverter::EcmaScriptConverter();
    builder.Reset();
    isUndefined
        ? converter.ToExponential(x, -1, &builder)
        : converter.ToExponential(x, decimalPlacesInExponent, &builder);
389
    return JSValue::encode(jsString(exec, String(builder.Finalize())));
weinig@apple.com's avatar
weinig@apple.com committed
390 391
}

392 393 394 395 396
// toFixed converts a number to a string, always formatting as an a decimal fraction.
// This method takes an argument specifying a number of decimal places to round the
// significand to. However when converting large values (1e+21 and above) this
// method will instead fallback to calling ToString. 
EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec)
weinig@apple.com's avatar
weinig@apple.com committed
397
{
ggaren@apple.com's avatar
ggaren@apple.com committed
398 399
    double x;
    if (!toThisNumber(exec->hostThisValue(), x))
400 401 402 403 404 405
        return throwVMTypeError(exec);

    // Get the argument. 
    int decimalPlaces;
    bool isUndefined; // This is ignored; undefined treated as 0.
    if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlaces, isUndefined))
406
        return throwVMError(exec, createRangeError(exec, ASCIILiteral("toFixed() argument must be between 0 and 20")));
407 408 409 410 411

    // 15.7.4.5.7 states "If x >= 10^21, then let m = ToString(x)"
    // This also covers Ininity, and structure the check so that NaN
    // values are also handled by numberToString
    if (!(fabs(x) < 1e+21))
412
        return JSValue::encode(jsString(exec, String::numberToStringECMAScript(x)));
413 414 415

    // The check above will return false for NaN or Infinity, these will be
    // handled by numberToString.
416
    ASSERT(std::isfinite(x));
417

418
    NumberToStringBuffer buffer;
419
    return JSValue::encode(jsString(exec, String(numberToFixedWidthString(x, decimalPlaces, buffer))));
420
}
weinig@apple.com's avatar
weinig@apple.com committed
421

422 423 424 425 426 427 428 429 430
// toPrecision converts a number to a string, takeing an argument specifying a
// number of significant figures to round the significand to. For positive
// exponent, all values that can be represented using a decimal fraction will
// be, e.g. when rounding to 3 s.f. any value up to 999 will be formated as a
// decimal, whilst 1000 is converted to the exponential representation 1.00e+3.
// For negative exponents values >= 1e-6 are formated as decimal fractions,
// with smaller values converted to exponential representation.
EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec)
{
ggaren@apple.com's avatar
ggaren@apple.com committed
431 432
    double x;
    if (!toThisNumber(exec->hostThisValue(), x))
433 434 435 436 437 438
        return throwVMTypeError(exec);

    // Get the argument. 
    int significantFigures;
    bool isUndefined;
    if (!getIntegerArgumentInRange(exec, 1, 21, significantFigures, isUndefined))
439
        return throwVMError(exec, createRangeError(exec, ASCIILiteral("toPrecision() argument must be between 1 and 21")));
440 441 442

    // To precision called with no argument is treated as ToString.
    if (isUndefined)
443
        return JSValue::encode(jsString(exec, String::numberToStringECMAScript(x)));
444 445

    // Handle NaN and Infinity.
446
    if (!std::isfinite(x))
447
        return JSValue::encode(jsString(exec, String::numberToStringECMAScript(x)));
448

449
    NumberToStringBuffer buffer;
450
    return JSValue::encode(jsString(exec, String(numberToFixedPrecisionString(x, significantFigures, buffer))));
weinig@apple.com's avatar
weinig@apple.com committed
451 452
}

453
static inline int32_t extractRadixFromArgs(ExecState* exec)
weinig@apple.com's avatar
weinig@apple.com committed
454
{
455
    JSValue radixValue = exec->argument(0);
456
    int32_t radix;
457 458 459 460 461
    if (radixValue.isInt32())
        radix = radixValue.asInt32();
    else if (radixValue.isUndefined())
        radix = 10;
    else
462 463 464 465 466 467 468 469 470 471 472
        radix = static_cast<int32_t>(radixValue.toInteger(exec)); // nan -> 0

    return radix;
}

static inline EncodedJSValue integerValueToString(ExecState* exec, int32_t radix, int32_t value)
{
    // A negative value casted to unsigned would be bigger than 36 (the max radix).
    if (static_cast<unsigned>(value) < static_cast<unsigned>(radix)) {
        ASSERT(value <= 36);
        ASSERT(value >= 0);
ggaren@apple.com's avatar
ggaren@apple.com committed
473
        VM* vm = &exec->vm();
474
        return JSValue::encode(vm->smallStrings.singleCharacterString(radixDigits[value]));
475 476 477
    }

    if (radix == 10) {
ggaren@apple.com's avatar
ggaren@apple.com committed
478 479
        VM* vm = &exec->vm();
        return JSValue::encode(jsString(vm, vm->numericStrings.add(value)));
480 481
    }

482
    return JSValue::encode(jsString(exec, toStringWithRadix(value, radix)));
483 484

}
485

486 487 488 489 490 491 492
EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec)
{
    double doubleValue;
    if (!toThisNumber(exec->hostThisValue(), doubleValue))
        return throwVMTypeError(exec);

    int32_t radix = extractRadixFromArgs(exec);
493
    if (radix < 2 || radix > 36)
494
        return throwVMError(exec, createRangeError(exec, ASCIILiteral("toString() radix argument must be between 2 and 36")));
weinig@apple.com's avatar
weinig@apple.com committed
495

496 497 498 499 500
    int32_t integerValue = static_cast<int32_t>(doubleValue);
    if (integerValue == doubleValue)
        return integerValueToString(exec, radix, integerValue);

    if (radix == 10) {
ggaren@apple.com's avatar
ggaren@apple.com committed
501 502
        VM* vm = &exec->vm();
        return JSValue::encode(jsString(vm, vm->numericStrings.add(doubleValue)));
503 504
    }

505
    if (!std::isfinite(doubleValue))
506
        return JSValue::encode(jsString(exec, String::numberToStringECMAScript(doubleValue)));
weinig@apple.com's avatar
weinig@apple.com committed
507

508
    RadixBuffer s;
509
    return JSValue::encode(jsString(exec, toStringWithRadix(s, doubleValue, radix)));
weinig@apple.com's avatar
weinig@apple.com committed
510 511
}

512
EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState* exec)
weinig@apple.com's avatar
weinig@apple.com committed
513
{
ggaren@apple.com's avatar
ggaren@apple.com committed
514 515
    double x;
    if (!toThisNumber(exec->hostThisValue(), x))
516
        return throwVMTypeError(exec);
weinig@apple.com's avatar
weinig@apple.com committed
517

518
    return JSValue::encode(jsNumber(x).toString(exec));
weinig@apple.com's avatar
weinig@apple.com committed
519 520
}

521
EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState* exec)
weinig@apple.com's avatar
weinig@apple.com committed
522
{
ggaren@apple.com's avatar
ggaren@apple.com committed
523 524
    double x;
    if (!toThisNumber(exec->hostThisValue(), x))
525
        return throwVMTypeError(exec);
ggaren@apple.com's avatar
ggaren@apple.com committed
526
    return JSValue::encode(jsNumber(x));
weinig@apple.com's avatar
weinig@apple.com committed
527 528
}

529
} // namespace JSC