~ubuntu-branches/debian/sid/iceweasel/sid

« back to all changes in this revision

Viewing changes to .pc/porting/Bug-589735-Allow-static-JS-strings-to-be-turned-off-.patch/js/src/jsnum.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Mike Hommey
  • Date: 2011-08-26 09:48:52 UTC
  • Revision ID: james.westby@ubuntu.com-20110826094852-9kt0erj7rc2jgf3i
Tags: 6.0-3
* debian/libmozjs-dev.install: Add more missing headers to libmozjs-dev.
* debian/rules, debian/xulrunner-GRE_VERSION.install.in: Install
  plugin-container on all architectures. Closes: #639289.
* debian/extra-stuff/reportbug-helper-script: Avoid listing all debian
  packages in the reportbug helper when no addons are installed.
* debian/duckduckgo.xml, debian/iceweasel.install: Add DuckDuckGo search
  plugin. Closes: #616115.

* js/src/jsgcinlines.h, js/src/jsnum.cpp, js/src/jsstr.cpp, js/src/jsstr.h,
  js/src/jsstrinlines.h, js/src/jstracer.cpp, js/src/jstracer.h,
  js/src/tracejit/Writer.cpp: Allow static JS strings to be turned off;
  turn off on ia64. bz#589735.
* memory/jemalloc/jemalloc.c: Allocate memory with an address with high 17
  bits clear on ia64. bz#589735. This should finally make Iceweasel
  actually work on ia64.
* js/src/jsval.h, js/src/jsvalue.h: Fix jsval_layout on 64-bit big-endian
  platforms. bz#674522. Closes: #638623.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 
2
 *
 
3
 * ***** BEGIN LICENSE BLOCK *****
 
4
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
5
 *
 
6
 * The contents of this file are subject to the Mozilla Public License Version
 
7
 * 1.1 (the "License"); you may not use this file except in compliance with
 
8
 * the License. You may obtain a copy of the License at
 
9
 * http://www.mozilla.org/MPL/
 
10
 *
 
11
 * Software distributed under the License is distributed on an "AS IS" basis,
 
12
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
13
 * for the specific language governing rights and limitations under the
 
14
 * License.
 
15
 *
 
16
 * The Original Code is Mozilla Communicator client code, released
 
17
 * March 31, 1998.
 
18
 *
 
19
 * The Initial Developer of the Original Code is
 
20
 * Netscape Communications Corporation.
 
21
 * Portions created by the Initial Developer are Copyright (C) 1998
 
22
 * the Initial Developer. All Rights Reserved.
 
23
 *
 
24
 * Contributor(s):
 
25
 *   IBM Corp.
 
26
 *
 
27
 * Alternatively, the contents of this file may be used under the terms of
 
28
 * either of the GNU General Public License Version 2 or later (the "GPL"),
 
29
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
30
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
31
 * of those above. If you wish to allow use of your version of this file only
 
32
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
33
 * use your version of this file under the terms of the MPL, indicate your
 
34
 * decision by deleting the provisions above and replace them with the notice
 
35
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
36
 * the provisions above, a recipient may use your version of this file under
 
37
 * the terms of any one of the MPL, the GPL or the LGPL.
 
38
 *
 
39
 * ***** END LICENSE BLOCK ***** */
 
40
 
 
41
/*
 
42
 * JS number type and wrapper class.
 
43
 */
 
44
#ifdef XP_OS2
 
45
#define _PC_53  PC_53
 
46
#define _MCW_EM MCW_EM
 
47
#define _MCW_PC MCW_PC
 
48
#endif
 
49
#include <locale.h>
 
50
#include <limits.h>
 
51
#include <math.h>
 
52
#include <stdlib.h>
 
53
#include <string.h>
 
54
#include "jstypes.h"
 
55
#include "jsstdint.h"
 
56
#include "jsutil.h"
 
57
#include "jsapi.h"
 
58
#include "jsatom.h"
 
59
#include "jsbuiltins.h"
 
60
#include "jscntxt.h"
 
61
#include "jsversion.h"
 
62
#include "jsdtoa.h"
 
63
#include "jsgc.h"
 
64
#include "jsinterp.h"
 
65
#include "jsnum.h"
 
66
#include "jsobj.h"
 
67
#include "jsopcode.h"
 
68
#include "jsprf.h"
 
69
#include "jsscope.h"
 
70
#include "jsstr.h"
 
71
#include "jstracer.h"
 
72
#include "jsvector.h"
 
73
 
 
74
#include "jsinterpinlines.h"
 
75
#include "jsobjinlines.h"
 
76
#include "jsstrinlines.h"
 
77
 
 
78
using namespace js;
 
79
 
 
80
#ifndef JS_HAVE_STDINT_H /* Native support is innocent until proven guilty. */
 
81
 
 
82
JS_STATIC_ASSERT(uint8_t(-1) == UINT8_MAX);
 
83
JS_STATIC_ASSERT(uint16_t(-1) == UINT16_MAX);
 
84
JS_STATIC_ASSERT(uint32_t(-1) == UINT32_MAX);
 
85
JS_STATIC_ASSERT(uint64_t(-1) == UINT64_MAX);
 
86
 
 
87
JS_STATIC_ASSERT(INT8_MAX > INT8_MIN);
 
88
JS_STATIC_ASSERT(uint8_t(INT8_MAX) + uint8_t(1) == uint8_t(INT8_MIN));
 
89
JS_STATIC_ASSERT(INT16_MAX > INT16_MIN);
 
90
JS_STATIC_ASSERT(uint16_t(INT16_MAX) + uint16_t(1) == uint16_t(INT16_MIN));
 
91
JS_STATIC_ASSERT(INT32_MAX > INT32_MIN);
 
92
JS_STATIC_ASSERT(uint32_t(INT32_MAX) + uint32_t(1) == uint32_t(INT32_MIN));
 
93
JS_STATIC_ASSERT(INT64_MAX > INT64_MIN);
 
94
JS_STATIC_ASSERT(uint64_t(INT64_MAX) + uint64_t(1) == uint64_t(INT64_MIN));
 
95
 
 
96
JS_STATIC_ASSERT(INTPTR_MAX > INTPTR_MIN);
 
97
JS_STATIC_ASSERT(uintptr_t(INTPTR_MAX) + uintptr_t(1) == uintptr_t(INTPTR_MIN));
 
98
JS_STATIC_ASSERT(uintptr_t(-1) == UINTPTR_MAX);
 
99
JS_STATIC_ASSERT(size_t(-1) == SIZE_MAX);
 
100
JS_STATIC_ASSERT(PTRDIFF_MAX > PTRDIFF_MIN);
 
101
JS_STATIC_ASSERT(ptrdiff_t(PTRDIFF_MAX) == PTRDIFF_MAX);
 
102
JS_STATIC_ASSERT(ptrdiff_t(PTRDIFF_MIN) == PTRDIFF_MIN);
 
103
JS_STATIC_ASSERT(uintptr_t(PTRDIFF_MAX) + uintptr_t(1) == uintptr_t(PTRDIFF_MIN));
 
104
 
 
105
#endif /* JS_HAVE_STDINT_H */
 
106
 
 
107
/*
 
108
 * If we're accumulating a decimal number and the number is >= 2^53, then the
 
109
 * fast result from the loop in GetPrefixInteger may be inaccurate. Call
 
110
 * js_strtod_harder to get the correct answer.
 
111
 */
 
112
static bool
 
113
ComputeAccurateDecimalInteger(JSContext *cx, const jschar *start, const jschar *end, jsdouble *dp)
 
114
{
 
115
    size_t length = end - start;
 
116
    char *cstr = static_cast<char *>(cx->malloc_(length + 1));
 
117
    if (!cstr)
 
118
        return false;
 
119
 
 
120
    for (size_t i = 0; i < length; i++) {
 
121
        char c = char(start[i]);
 
122
        JS_ASSERT(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'));
 
123
        cstr[i] = c;
 
124
    }
 
125
    cstr[length] = 0;
 
126
 
 
127
    char *estr;
 
128
    int err = 0;
 
129
    *dp = js_strtod_harder(JS_THREAD_DATA(cx)->dtoaState, cstr, &estr, &err);
 
130
    if (err == JS_DTOA_ENOMEM) {
 
131
        JS_ReportOutOfMemory(cx);
 
132
        cx->free_(cstr);
 
133
        return false;
 
134
    }
 
135
    if (err == JS_DTOA_ERANGE && *dp == HUGE_VAL)
 
136
        *dp = js_PositiveInfinity;
 
137
    cx->free_(cstr);
 
138
    return true;
 
139
}
 
140
 
 
141
class BinaryDigitReader
 
142
{
 
143
    const int base;      /* Base of number; must be a power of 2 */
 
144
    int digit;           /* Current digit value in radix given by base */
 
145
    int digitMask;       /* Mask to extract the next bit from digit */
 
146
    const jschar *start; /* Pointer to the remaining digits */
 
147
    const jschar *end;   /* Pointer to first non-digit */
 
148
 
 
149
  public:
 
150
    BinaryDigitReader(int base, const jschar *start, const jschar *end)
 
151
      : base(base), digit(0), digitMask(0), start(start), end(end)
 
152
    {
 
153
    }
 
154
 
 
155
    /* Return the next binary digit from the number, or -1 if done. */
 
156
    int nextDigit() {
 
157
        if (digitMask == 0) {
 
158
            if (start == end)
 
159
                return -1;
 
160
 
 
161
            int c = *start++;
 
162
            JS_ASSERT(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'));
 
163
            if ('0' <= c && c <= '9')
 
164
                digit = c - '0';
 
165
            else if ('a' <= c && c <= 'z')
 
166
                digit = c - 'a' + 10;
 
167
            else
 
168
                digit = c - 'A' + 10;
 
169
            digitMask = base >> 1;
 
170
        }
 
171
 
 
172
        int bit = (digit & digitMask) != 0;
 
173
        digitMask >>= 1;
 
174
        return bit;
 
175
    }
 
176
};
 
177
 
 
178
/*
 
179
 * The fast result might also have been inaccurate for power-of-two bases. This
 
180
 * happens if the addition in value * 2 + digit causes a round-down to an even
 
181
 * least significant mantissa bit when the first dropped bit is a one.  If any
 
182
 * of the following digits in the number (which haven't been added in yet) are
 
183
 * nonzero, then the correct action would have been to round up instead of
 
184
 * down.  An example occurs when reading the number 0x1000000000000081, which
 
185
 * rounds to 0x1000000000000000 instead of 0x1000000000000100.
 
186
 */
 
187
static jsdouble
 
188
ComputeAccurateBinaryBaseInteger(JSContext *cx, const jschar *start, const jschar *end, int base)
 
189
{
 
190
    BinaryDigitReader bdr(base, start, end);
 
191
 
 
192
    /* Skip leading zeroes. */
 
193
    int bit;
 
194
    do {
 
195
        bit = bdr.nextDigit();
 
196
    } while (bit == 0);
 
197
 
 
198
    JS_ASSERT(bit == 1); // guaranteed by GetPrefixInteger
 
199
 
 
200
    /* Gather the 53 significant bits (including the leading 1). */
 
201
    jsdouble value = 1.0;
 
202
    for (int j = 52; j > 0; j--) {
 
203
        bit = bdr.nextDigit();
 
204
        if (bit < 0)
 
205
            return value;
 
206
        value = value * 2 + bit;
 
207
    }
 
208
 
 
209
    /* bit2 is the 54th bit (the first dropped from the mantissa). */
 
210
    int bit2 = bdr.nextDigit();
 
211
    if (bit2 >= 0) {
 
212
        jsdouble factor = 2.0;
 
213
        int sticky = 0;  /* sticky is 1 if any bit beyond the 54th is 1 */
 
214
        int bit3;
 
215
 
 
216
        while ((bit3 = bdr.nextDigit()) >= 0) {
 
217
            sticky |= bit3;
 
218
            factor *= 2;
 
219
        }
 
220
        value += bit2 & (bit | sticky);
 
221
        value *= factor;
 
222
    }
 
223
 
 
224
    return value;
 
225
}
 
226
 
 
227
namespace js {
 
228
 
 
229
bool
 
230
GetPrefixInteger(JSContext *cx, const jschar *start, const jschar *end, int base,
 
231
                 const jschar **endp, jsdouble *dp)
 
232
{
 
233
    JS_ASSERT(start <= end);
 
234
    JS_ASSERT(2 <= base && base <= 36);
 
235
 
 
236
    const jschar *s = start;
 
237
    jsdouble d = 0.0;
 
238
    for (; s < end; s++) {
 
239
        int digit;
 
240
        jschar c = *s;
 
241
        if ('0' <= c && c <= '9')
 
242
            digit = c - '0';
 
243
        else if ('a' <= c && c <= 'z')
 
244
            digit = c - 'a' + 10;
 
245
        else if ('A' <= c && c <= 'Z')
 
246
            digit = c - 'A' + 10;
 
247
        else
 
248
            break;
 
249
        if (digit >= base)
 
250
            break;
 
251
        d = d * base + digit;
 
252
    }
 
253
 
 
254
    *endp = s;
 
255
    *dp = d;
 
256
 
 
257
    /* If we haven't reached the limit of integer precision, we're done. */
 
258
    if (d < DOUBLE_INTEGRAL_PRECISION_LIMIT)
 
259
        return true;
 
260
 
 
261
    /*
 
262
     * Otherwise compute the correct integer from the prefix of valid digits
 
263
     * if we're computing for base ten or a power of two.  Don't worry about
 
264
     * other bases; see 15.1.2.2 step 13.
 
265
     */
 
266
    if (base == 10)
 
267
        return ComputeAccurateDecimalInteger(cx, start, s, dp);
 
268
    if ((base & (base - 1)) == 0)
 
269
        *dp = ComputeAccurateBinaryBaseInteger(cx, start, s, base);
 
270
 
 
271
    return true;
 
272
}
 
273
 
 
274
} // namespace js
 
275
 
 
276
static JSBool
 
277
num_isNaN(JSContext *cx, uintN argc, Value *vp)
 
278
{
 
279
    if (argc == 0) {
 
280
        vp->setBoolean(true);
 
281
        return JS_TRUE;
 
282
    }
 
283
    jsdouble x;
 
284
    if (!ValueToNumber(cx, vp[2], &x))
 
285
        return false;
 
286
    vp->setBoolean(JSDOUBLE_IS_NaN(x));
 
287
    return JS_TRUE;
 
288
}
 
289
 
 
290
static JSBool
 
291
num_isFinite(JSContext *cx, uintN argc, Value *vp)
 
292
{
 
293
    if (argc == 0) {
 
294
        vp->setBoolean(false);
 
295
        return JS_TRUE;
 
296
    }
 
297
    jsdouble x;
 
298
    if (!ValueToNumber(cx, vp[2], &x))
 
299
        return JS_FALSE;
 
300
    vp->setBoolean(JSDOUBLE_IS_FINITE(x));
 
301
    return JS_TRUE;
 
302
}
 
303
 
 
304
static JSBool
 
305
num_parseFloat(JSContext *cx, uintN argc, Value *vp)
 
306
{
 
307
    JSString *str;
 
308
    jsdouble d;
 
309
    const jschar *bp, *end, *ep;
 
310
 
 
311
    if (argc == 0) {
 
312
        vp->setDouble(js_NaN);
 
313
        return JS_TRUE;
 
314
    }
 
315
    str = js_ValueToString(cx, vp[2]);
 
316
    if (!str)
 
317
        return JS_FALSE;
 
318
    bp = str->getChars(cx);
 
319
    if (!bp)
 
320
        return JS_FALSE;
 
321
    end = bp + str->length();
 
322
    if (!js_strtod(cx, bp, end, &ep, &d))
 
323
        return JS_FALSE;
 
324
    if (ep == bp) {
 
325
        vp->setDouble(js_NaN);
 
326
        return JS_TRUE;
 
327
    }
 
328
    vp->setNumber(d);
 
329
    return JS_TRUE;
 
330
}
 
331
 
 
332
#ifdef JS_TRACER
 
333
static jsdouble FASTCALL
 
334
ParseFloat(JSContext* cx, JSString* str)
 
335
{
 
336
    TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx);
 
337
 
 
338
    const jschar *bp = str->getChars(cx);
 
339
    if (!bp) {
 
340
        SetBuiltinError(tm);
 
341
        return js_NaN;
 
342
    }
 
343
    const jschar *end = bp + str->length();
 
344
 
 
345
    const jschar *ep;
 
346
    double d;
 
347
    if (!js_strtod(cx, bp, end, &ep, &d) || ep == bp)
 
348
        return js_NaN;
 
349
    return d;
 
350
}
 
351
#endif
 
352
 
 
353
static bool
 
354
ParseIntStringHelper(JSContext *cx, const jschar *ws, const jschar *end, int maybeRadix,
 
355
                     bool stripPrefix, jsdouble *dp)
 
356
{
 
357
    JS_ASSERT(maybeRadix == 0 || (2 <= maybeRadix && maybeRadix <= 36));
 
358
    JS_ASSERT(ws <= end);
 
359
 
 
360
    const jschar *s = js_SkipWhiteSpace(ws, end);
 
361
    JS_ASSERT(ws <= s);
 
362
    JS_ASSERT(s <= end);
 
363
 
 
364
    /* 15.1.2.2 steps 3-4. */
 
365
    bool negative = (s != end && s[0] == '-');
 
366
 
 
367
    /* 15.1.2.2 step 5. */
 
368
    if (s != end && (s[0] == '-' || s[0] == '+'))
 
369
        s++;
 
370
 
 
371
    /* 15.1.2.2 step 9. */
 
372
    int radix = maybeRadix;
 
373
    if (radix == 0) {
 
374
        if (end - s >= 2 && s[0] == '0' && (s[1] != 'x' && s[1] != 'X')) {
 
375
            /*
 
376
             * Non-standard: ES5 requires that parseInt interpret leading-zero
 
377
             * strings not starting with "0x" or "0X" as decimal (absent an
 
378
             * explicitly specified non-zero radix), but we continue to
 
379
             * interpret such strings as octal, as per ES3 and web practice.
 
380
             */
 
381
            radix = 8;
 
382
        } else {
 
383
            radix = 10;
 
384
        }
 
385
    }
 
386
 
 
387
    /* 15.1.2.2 step 10. */
 
388
    if (stripPrefix) {
 
389
        if (end - s >= 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
 
390
            s += 2;
 
391
            radix = 16;
 
392
        }
 
393
    }
 
394
 
 
395
    /* 15.1.2.2 steps 11-14. */
 
396
    const jschar *actualEnd;
 
397
    if (!GetPrefixInteger(cx, s, end, radix, &actualEnd, dp))
 
398
        return false;
 
399
    if (s == actualEnd)
 
400
        *dp = js_NaN;
 
401
    else if (negative)
 
402
        *dp = -*dp;
 
403
    return true;
 
404
}
 
405
 
 
406
static jsdouble
 
407
ParseIntDoubleHelper(jsdouble d)
 
408
{
 
409
    JS_ASSERT(-1e21 < d && d < 1e21);
 
410
    if (d > 0)
 
411
        return floor(d);
 
412
    if (d < 0)
 
413
        return -floor(-d);
 
414
    return 0;
 
415
}
 
416
 
 
417
/* See ECMA 15.1.2.2. */
 
418
static JSBool
 
419
num_parseInt(JSContext *cx, uintN argc, Value *vp)
 
420
{
 
421
    /* Fast paths and exceptional cases. */
 
422
    if (argc == 0) {
 
423
        vp->setDouble(js_NaN);
 
424
        return true;
 
425
    }
 
426
 
 
427
    if (argc == 1 || (vp[3].isInt32() && (vp[3].toInt32() == 0 || vp[3].toInt32() == 10))) {
 
428
        if (vp[2].isInt32()) {
 
429
            *vp = vp[2];
 
430
            return true;
 
431
        }
 
432
        /*
 
433
         * Step 1 is |inputString = ToString(string)|. When string >= 
 
434
         * 1e21, ToString(string) is in the form "NeM". 'e' marks the end of
 
435
         * the word, which would mean the result of parseInt(string) should be |N|.
 
436
         *
 
437
         * To preserve this behaviour, we can't use the fast-path when string >
 
438
         * 1e21, or else the result would be |NeM|.
 
439
         */
 
440
        if (vp[2].isDouble() &&
 
441
            vp[2].toDouble() > -1.0e21 &&
 
442
            vp[2].toDouble() < 1.0e21) {
 
443
            vp->setDouble(ParseIntDoubleHelper(vp[2].toDouble()));
 
444
            return true;
 
445
        }
 
446
    }
 
447
 
 
448
    /* Step 1. */
 
449
    JSString *inputString = js_ValueToString(cx, vp[2]);
 
450
    if (!inputString)
 
451
        return false;
 
452
    vp[2].setString(inputString);
 
453
 
 
454
    /* 15.1.2.2 steps 6-8. */
 
455
    bool stripPrefix = true;
 
456
    int32_t radix = 0;
 
457
    if (argc > 1) {
 
458
        if (!ValueToECMAInt32(cx, vp[3], &radix))
 
459
            return false;
 
460
        if (radix != 0) {
 
461
            if (radix < 2 || radix > 36) {
 
462
                vp->setDouble(js_NaN);
 
463
                return true;
 
464
            }
 
465
            if (radix != 16)
 
466
                stripPrefix = false;
 
467
        }
 
468
    }
 
469
 
 
470
    /* Steps 2-5, 9-14. */
 
471
    const jschar *ws = inputString->getChars(cx);
 
472
    if (!ws)
 
473
        return false;
 
474
    const jschar *end = ws + inputString->length();
 
475
 
 
476
    jsdouble number;
 
477
    if (!ParseIntStringHelper(cx, ws, end, radix, stripPrefix, &number))
 
478
        return false;
 
479
 
 
480
    /* Step 15. */
 
481
    vp->setNumber(number);
 
482
    return true;
 
483
}
 
484
 
 
485
#ifdef JS_TRACER
 
486
static jsdouble FASTCALL
 
487
ParseInt(JSContext* cx, JSString* str)
 
488
{
 
489
    TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx);
 
490
 
 
491
    const jschar *start = str->getChars(cx);
 
492
    if (!start) {
 
493
        SetBuiltinError(tm);
 
494
        return js_NaN;
 
495
    }
 
496
    const jschar *end = start + str->length();
 
497
 
 
498
    jsdouble d;
 
499
    if (!ParseIntStringHelper(cx, start, end, 0, true, &d)) {
 
500
        SetBuiltinError(tm);
 
501
        return js_NaN;
 
502
    }
 
503
    return d;
 
504
}
 
505
 
 
506
static jsdouble FASTCALL
 
507
ParseIntDouble(JSContext* cx, jsdouble d)
 
508
{
 
509
    /* Fast path - see comment in numParseInt. */
 
510
    if (-1.0e21 < d && d < 1.0e21)
 
511
        return ParseIntDoubleHelper(d);
 
512
 
 
513
    /* Slow path - convert to a string and parse normally. */
 
514
    JSString *inputString = js_NumberToString(cx, d);
 
515
    if (!inputString) {
 
516
        TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx);
 
517
        SetBuiltinError(tm);
 
518
        return js_NaN;
 
519
    }
 
520
 
 
521
    return ParseInt(cx, inputString);
 
522
}
 
523
#endif
 
524
 
 
525
const char js_Infinity_str[]   = "Infinity";
 
526
const char js_NaN_str[]        = "NaN";
 
527
const char js_isNaN_str[]      = "isNaN";
 
528
const char js_isFinite_str[]   = "isFinite";
 
529
const char js_parseFloat_str[] = "parseFloat";
 
530
const char js_parseInt_str[]   = "parseInt";
 
531
 
 
532
#ifdef JS_TRACER
 
533
 
 
534
JS_DEFINE_TRCINFO_2(num_parseInt,
 
535
    (2, (static, DOUBLE_FAIL, ParseInt, CONTEXT, STRING,1, nanojit::ACCSET_NONE)),
 
536
    (2, (static, DOUBLE_FAIL, ParseIntDouble, CONTEXT, DOUBLE,1, nanojit::ACCSET_NONE)))
 
537
 
 
538
JS_DEFINE_TRCINFO_1(num_parseFloat,
 
539
    (2, (static, DOUBLE_FAIL, ParseFloat, CONTEXT, STRING,   1, nanojit::ACCSET_NONE)))
 
540
 
 
541
#endif /* JS_TRACER */
 
542
 
 
543
static JSFunctionSpec number_functions[] = {
 
544
    JS_FN(js_isNaN_str,         num_isNaN,           1,0),
 
545
    JS_FN(js_isFinite_str,      num_isFinite,        1,0),
 
546
    JS_TN(js_parseFloat_str,    num_parseFloat,      1,0, &num_parseFloat_trcinfo),
 
547
    JS_TN(js_parseInt_str,      num_parseInt,        2,0, &num_parseInt_trcinfo),
 
548
    JS_FS_END
 
549
};
 
550
 
 
551
Class js_NumberClass = {
 
552
    js_Number_str,
 
553
    JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Number),
 
554
    PropertyStub,         /* addProperty */
 
555
    PropertyStub,         /* delProperty */
 
556
    PropertyStub,         /* getProperty */
 
557
    StrictPropertyStub,   /* setProperty */
 
558
    EnumerateStub,
 
559
    ResolveStub,
 
560
    ConvertStub
 
561
};
 
562
 
 
563
static JSBool
 
564
Number(JSContext *cx, uintN argc, Value *vp)
 
565
{
 
566
    /* Sample JS_CALLEE before clobbering. */
 
567
    bool isConstructing = IsConstructing(vp);
 
568
 
 
569
    if (argc > 0) {
 
570
        if (!ValueToNumber(cx, &vp[2]))
 
571
            return false;
 
572
        vp[0] = vp[2];
 
573
    } else {
 
574
        vp[0].setInt32(0);
 
575
    }
 
576
 
 
577
    if (!isConstructing)
 
578
        return true;
 
579
    
 
580
    JSObject *obj = NewBuiltinClassInstance(cx, &js_NumberClass);
 
581
    if (!obj)
 
582
        return false;
 
583
    obj->setPrimitiveThis(vp[0]);
 
584
    vp->setObject(*obj);
 
585
    return true;
 
586
}
 
587
 
 
588
#if JS_HAS_TOSOURCE
 
589
static JSBool
 
590
num_toSource(JSContext *cx, uintN argc, Value *vp)
 
591
{
 
592
    double d;
 
593
    if (!GetPrimitiveThis(cx, vp, &d))
 
594
        return false;
 
595
 
 
596
    ToCStringBuf cbuf;
 
597
    char *numStr = NumberToCString(cx, &cbuf, d);
 
598
    if (!numStr) {
 
599
        JS_ReportOutOfMemory(cx);
 
600
        return false;
 
601
    }
 
602
 
 
603
    char buf[64];
 
604
    JS_snprintf(buf, sizeof buf, "(new %s(%s))", js_NumberClass.name, numStr);
 
605
    JSString *str = js_NewStringCopyZ(cx, buf);
 
606
    if (!str)
 
607
        return false;
 
608
    vp->setString(str);
 
609
    return true;
 
610
}
 
611
#endif
 
612
 
 
613
ToCStringBuf::ToCStringBuf() :dbuf(NULL)
 
614
{
 
615
    JS_STATIC_ASSERT(sbufSize >= DTOSTR_STANDARD_BUFFER_SIZE);
 
616
}
 
617
 
 
618
ToCStringBuf::~ToCStringBuf()
 
619
{
 
620
    if (dbuf)
 
621
        UnwantedForeground::free_(dbuf);
 
622
}
 
623
 
 
624
JSString * JS_FASTCALL
 
625
js_IntToString(JSContext *cx, int32 si)
 
626
{
 
627
    uint32 ui;
 
628
    if (si >= 0) {
 
629
        if (JSAtom::hasIntStatic(si))
 
630
            return &JSAtom::intStatic(si);
 
631
        ui = si;
 
632
    } else {
 
633
        ui = uint32(-si);
 
634
        JS_ASSERT_IF(si == INT32_MIN, ui == uint32(INT32_MAX) + 1);
 
635
    }
 
636
 
 
637
    JSCompartment *c = cx->compartment;
 
638
    if (JSString *str = c->dtoaCache.lookup(10, si))
 
639
        return str;
 
640
 
 
641
    JSShortString *str = js_NewGCShortString(cx);
 
642
    if (!str)
 
643
        return NULL;
 
644
 
 
645
    /* +1, since MAX_LENGTH does not count the null char. */
 
646
    JS_STATIC_ASSERT(JSShortString::MAX_LENGTH + 1 >= sizeof("-2147483648"));
 
647
 
 
648
    jschar *end = str->inlineStorageBeforeInit() + JSShortString::MAX_SHORT_LENGTH;
 
649
    jschar *cp = end;
 
650
    *cp = 0;
 
651
 
 
652
    do {
 
653
        jsuint newui = ui / 10, digit = ui % 10;  /* optimizers are our friends */
 
654
        *--cp = '0' + digit;
 
655
        ui = newui;
 
656
    } while (ui != 0);
 
657
 
 
658
    if (si < 0)
 
659
        *--cp = '-';
 
660
 
 
661
    str->initAtOffsetInBuffer(cp, end - cp);
 
662
 
 
663
    c->dtoaCache.cache(10, si, str);
 
664
    return str;
 
665
}
 
666
 
 
667
/* Returns a non-NULL pointer to inside cbuf.  */
 
668
static char *
 
669
IntToCString(ToCStringBuf *cbuf, jsint i, jsint base = 10)
 
670
{
 
671
    char *cp;
 
672
    jsuint u;
 
673
 
 
674
    u = (i < 0) ? -i : i;
 
675
 
 
676
    cp = cbuf->sbuf + cbuf->sbufSize;   /* one past last buffer cell */
 
677
    *--cp = '\0';                       /* null terminate the string to be */
 
678
 
 
679
    /*
 
680
     * Build the string from behind. We use multiply and subtraction
 
681
     * instead of modulus because that's much faster.
 
682
     */
 
683
    switch (base) {
 
684
    case 10:
 
685
      do {
 
686
          jsuint newu = u / 10;
 
687
          *--cp = (char)(u - newu * 10) + '0';
 
688
          u = newu;
 
689
      } while (u != 0);
 
690
      break;
 
691
    case 16:
 
692
      do {
 
693
          jsuint newu = u / 16;
 
694
          *--cp = "0123456789abcdef"[u - newu * 16];
 
695
          u = newu;
 
696
      } while (u != 0);
 
697
      break;
 
698
    default:
 
699
      JS_ASSERT(base >= 2 && base <= 36);
 
700
      do {
 
701
          jsuint newu = u / base;
 
702
          *--cp = "0123456789abcdefghijklmnopqrstuvwxyz"[u - newu * base];
 
703
          u = newu;
 
704
      } while (u != 0);
 
705
      break;
 
706
    }
 
707
    if (i < 0)
 
708
        *--cp = '-';
 
709
 
 
710
    JS_ASSERT(cp >= cbuf->sbuf);
 
711
    return cp;
 
712
}
 
713
 
 
714
static JSString * JS_FASTCALL
 
715
js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base);
 
716
 
 
717
static JSBool
 
718
num_toString(JSContext *cx, uintN argc, Value *vp)
 
719
{
 
720
    double d;
 
721
    if (!GetPrimitiveThis(cx, vp, &d))
 
722
        return false;
 
723
 
 
724
    int32 base = 10;
 
725
    if (argc != 0 && !vp[2].isUndefined()) {
 
726
        jsdouble d2;
 
727
        if (!ToInteger(cx, vp[2], &d2))
 
728
            return false;
 
729
 
 
730
        if (d2 < 2 || d2 > 36) {
 
731
            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_RADIX);
 
732
            return false;
 
733
        }
 
734
 
 
735
        base = int32(d2);
 
736
    }
 
737
    JSString *str = js_NumberToStringWithBase(cx, d, base);
 
738
    if (!str) {
 
739
        JS_ReportOutOfMemory(cx);
 
740
        return JS_FALSE;
 
741
    }
 
742
    vp->setString(str);
 
743
    return JS_TRUE;
 
744
}
 
745
 
 
746
static JSBool
 
747
num_toLocaleString(JSContext *cx, uintN argc, Value *vp)
 
748
{
 
749
    size_t thousandsLength, decimalLength;
 
750
    const char *numGrouping, *tmpGroup;
 
751
    JSRuntime *rt;
 
752
    JSString *str;
 
753
    const char *num, *end, *tmpSrc;
 
754
    char *buf, *tmpDest;
 
755
    const char *nint;
 
756
    int digits, buflen, remainder, nrepeat;
 
757
 
 
758
    /*
 
759
     * Create the string, move back to bytes to make string twiddling
 
760
     * a bit easier and so we can insert platform charset seperators.
 
761
     */
 
762
    if (!num_toString(cx, 0, vp))
 
763
        return JS_FALSE;
 
764
    JS_ASSERT(vp->isString());
 
765
    JSAutoByteString numBytes(cx, vp->toString());
 
766
    if (!numBytes)
 
767
        return JS_FALSE;
 
768
    num = numBytes.ptr();
 
769
    if (!num)
 
770
        return JS_FALSE;
 
771
 
 
772
    /*
 
773
     * Find the first non-integer value, whether it be a letter as in
 
774
     * 'Infinity', a decimal point, or an 'e' from exponential notation.
 
775
     */
 
776
    nint = num;
 
777
    if (*nint == '-')
 
778
        nint++;
 
779
    while (*nint >= '0' && *nint <= '9')
 
780
        nint++;
 
781
    digits = nint - num;
 
782
    end = num + digits;
 
783
    if (!digits)
 
784
        return JS_TRUE;
 
785
 
 
786
    rt = cx->runtime;
 
787
    thousandsLength = strlen(rt->thousandsSeparator);
 
788
    decimalLength = strlen(rt->decimalSeparator);
 
789
 
 
790
    /* Figure out how long resulting string will be. */
 
791
    buflen = strlen(num);
 
792
    if (*nint == '.')
 
793
        buflen += decimalLength - 1; /* -1 to account for existing '.' */
 
794
 
 
795
    numGrouping = tmpGroup = rt->numGrouping;
 
796
    remainder = digits;
 
797
    if (*num == '-')
 
798
        remainder--;
 
799
 
 
800
    while (*tmpGroup != CHAR_MAX && *tmpGroup != '\0') {
 
801
        if (*tmpGroup >= remainder)
 
802
            break;
 
803
        buflen += thousandsLength;
 
804
        remainder -= *tmpGroup;
 
805
        tmpGroup++;
 
806
    }
 
807
    if (*tmpGroup == '\0' && *numGrouping != '\0') {
 
808
        nrepeat = (remainder - 1) / tmpGroup[-1];
 
809
        buflen += thousandsLength * nrepeat;
 
810
        remainder -= nrepeat * tmpGroup[-1];
 
811
    } else {
 
812
        nrepeat = 0;
 
813
    }
 
814
    tmpGroup--;
 
815
 
 
816
    buf = (char *)cx->malloc_(buflen + 1);
 
817
    if (!buf)
 
818
        return JS_FALSE;
 
819
 
 
820
    tmpDest = buf;
 
821
    tmpSrc = num;
 
822
 
 
823
    while (*tmpSrc == '-' || remainder--) {
 
824
        JS_ASSERT(tmpDest - buf < buflen);
 
825
        *tmpDest++ = *tmpSrc++;
 
826
    }
 
827
    while (tmpSrc < end) {
 
828
        JS_ASSERT(tmpDest - buf + ptrdiff_t(thousandsLength) <= buflen);
 
829
        strcpy(tmpDest, rt->thousandsSeparator);
 
830
        tmpDest += thousandsLength;
 
831
        JS_ASSERT(tmpDest - buf + *tmpGroup <= buflen);
 
832
        memcpy(tmpDest, tmpSrc, *tmpGroup);
 
833
        tmpDest += *tmpGroup;
 
834
        tmpSrc += *tmpGroup;
 
835
        if (--nrepeat < 0)
 
836
            tmpGroup--;
 
837
    }
 
838
 
 
839
    if (*nint == '.') {
 
840
        JS_ASSERT(tmpDest - buf + ptrdiff_t(decimalLength) <= buflen);
 
841
        strcpy(tmpDest, rt->decimalSeparator);
 
842
        tmpDest += decimalLength;
 
843
        JS_ASSERT(tmpDest - buf + ptrdiff_t(strlen(nint + 1)) <= buflen);
 
844
        strcpy(tmpDest, nint + 1);
 
845
    } else {
 
846
        JS_ASSERT(tmpDest - buf + ptrdiff_t(strlen(nint)) <= buflen);
 
847
        strcpy(tmpDest, nint);
 
848
    }
 
849
 
 
850
    if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode) {
 
851
        JSBool ok = cx->localeCallbacks->localeToUnicode(cx, buf, Jsvalify(vp));
 
852
        cx->free_(buf);
 
853
        return ok;
 
854
    }
 
855
 
 
856
    str = js_NewStringCopyN(cx, buf, buflen);
 
857
    cx->free_(buf);
 
858
    if (!str)
 
859
        return JS_FALSE;
 
860
 
 
861
    vp->setString(str);
 
862
    return JS_TRUE;
 
863
}
 
864
 
 
865
JSBool
 
866
js_num_valueOf(JSContext *cx, uintN argc, Value *vp)
 
867
{
 
868
    double d;
 
869
    if (!GetPrimitiveThis(cx, vp, &d))
 
870
        return false;
 
871
 
 
872
    vp->setNumber(d);
 
873
    return true;
 
874
}
 
875
 
 
876
 
 
877
#define MAX_PRECISION 100
 
878
 
 
879
static JSBool
 
880
num_to(JSContext *cx, JSDToStrMode zeroArgMode, JSDToStrMode oneArgMode,
 
881
       jsint precisionMin, jsint precisionMax, jsint precisionOffset,
 
882
       uintN argc, Value *vp)
 
883
{
 
884
    /* Use MAX_PRECISION+1 because precisionOffset can be 1. */
 
885
    char buf[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION+1)];
 
886
    char *numStr;
 
887
 
 
888
    double d;
 
889
    if (!GetPrimitiveThis(cx, vp, &d))
 
890
        return false;
 
891
 
 
892
    double precision;
 
893
    if (argc == 0) {
 
894
        precision = 0.0;
 
895
        oneArgMode = zeroArgMode;
 
896
    } else {
 
897
        if (!ToInteger(cx, vp[2], &precision))
 
898
            return false;
 
899
        if (precision < precisionMin || precision > precisionMax) {
 
900
            ToCStringBuf cbuf;
 
901
            numStr = IntToCString(&cbuf, jsint(precision));
 
902
            JS_ASSERT(numStr);
 
903
            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PRECISION_RANGE, numStr);
 
904
            return JS_FALSE;
 
905
        }
 
906
    }
 
907
 
 
908
    numStr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, buf, sizeof buf,
 
909
                       oneArgMode, (jsint)precision + precisionOffset, d);
 
910
    if (!numStr) {
 
911
        JS_ReportOutOfMemory(cx);
 
912
        return JS_FALSE;
 
913
    }
 
914
    JSString *str = js_NewStringCopyZ(cx, numStr);
 
915
    if (!str)
 
916
        return JS_FALSE;
 
917
    vp->setString(str);
 
918
    return JS_TRUE;
 
919
}
 
920
 
 
921
/*
 
922
 * In the following three implementations, we allow a larger range of precision
 
923
 * than ECMA requires; this is permitted by ECMA-262.
 
924
 */
 
925
static JSBool
 
926
num_toFixed(JSContext *cx, uintN argc, Value *vp)
 
927
{
 
928
    return num_to(cx, DTOSTR_FIXED, DTOSTR_FIXED, -20, MAX_PRECISION, 0,
 
929
                  argc, vp);
 
930
}
 
931
 
 
932
static JSBool
 
933
num_toExponential(JSContext *cx, uintN argc, Value *vp)
 
934
{
 
935
    return num_to(cx, DTOSTR_STANDARD_EXPONENTIAL, DTOSTR_EXPONENTIAL, 0, MAX_PRECISION, 1,
 
936
                  argc, vp);
 
937
}
 
938
 
 
939
static JSBool
 
940
num_toPrecision(JSContext *cx, uintN argc, Value *vp)
 
941
{
 
942
    if (argc == 0 || vp[2].isUndefined())
 
943
        return num_toString(cx, 0, vp);
 
944
    return num_to(cx, DTOSTR_STANDARD, DTOSTR_PRECISION, 1, MAX_PRECISION, 0,
 
945
                  argc, vp);
 
946
}
 
947
 
 
948
#ifdef JS_TRACER
 
949
 
 
950
JS_DEFINE_TRCINFO_2(num_toString,
 
951
    (2, (extern, STRING_RETRY, js_NumberToString,         CONTEXT, THIS_DOUBLE,
 
952
         1, nanojit::ACCSET_NONE)),
 
953
    (3, (static, STRING_RETRY, js_NumberToStringWithBase, CONTEXT, THIS_DOUBLE, INT32,
 
954
         1, nanojit::ACCSET_NONE)))
 
955
 
 
956
#endif /* JS_TRACER */
 
957
 
 
958
static JSFunctionSpec number_methods[] = {
 
959
#if JS_HAS_TOSOURCE
 
960
    JS_FN(js_toSource_str,       num_toSource,          0, 0),
 
961
#endif
 
962
    JS_TN(js_toString_str,       num_toString,          1, 0, &num_toString_trcinfo),
 
963
    JS_FN(js_toLocaleString_str, num_toLocaleString,    0, 0),
 
964
    JS_FN(js_valueOf_str,        js_num_valueOf,        0, 0),
 
965
    JS_FN("toFixed",             num_toFixed,           1, 0),
 
966
    JS_FN("toExponential",       num_toExponential,     1, 0),
 
967
    JS_FN("toPrecision",         num_toPrecision,       1, 0),
 
968
    JS_FS_END
 
969
};
 
970
 
 
971
/* NB: Keep this in synch with number_constants[]. */
 
972
enum nc_slot {
 
973
    NC_NaN,
 
974
    NC_POSITIVE_INFINITY,
 
975
    NC_NEGATIVE_INFINITY,
 
976
    NC_MAX_VALUE,
 
977
    NC_MIN_VALUE,
 
978
    NC_LIMIT
 
979
};
 
980
 
 
981
/*
 
982
 * Some to most C compilers forbid spelling these at compile time, or barf
 
983
 * if you try, so all but MAX_VALUE are set up by js_InitRuntimeNumberState
 
984
 * using union jsdpun.
 
985
 */
 
986
static JSConstDoubleSpec number_constants[] = {
 
987
    {0,                         js_NaN_str,          0,{0,0,0}},
 
988
    {0,                         "POSITIVE_INFINITY", 0,{0,0,0}},
 
989
    {0,                         "NEGATIVE_INFINITY", 0,{0,0,0}},
 
990
    {1.7976931348623157E+308,   "MAX_VALUE",         0,{0,0,0}},
 
991
    {0,                         "MIN_VALUE",         0,{0,0,0}},
 
992
    {0,0,0,{0,0,0}}
 
993
};
 
994
 
 
995
jsdouble js_NaN;
 
996
jsdouble js_PositiveInfinity;
 
997
jsdouble js_NegativeInfinity;
 
998
 
 
999
#if (defined __GNUC__ && defined __i386__) || \
 
1000
    (defined __SUNPRO_CC && defined __i386)
 
1001
 
 
1002
/*
 
1003
 * Set the exception mask to mask all exceptions and set the FPU precision
 
1004
 * to 53 bit mantissa (64 bit doubles).
 
1005
 */
 
1006
inline void FIX_FPU() {
 
1007
    short control;
 
1008
    asm("fstcw %0" : "=m" (control) : );
 
1009
    control &= ~0x300; // Lower bits 8 and 9 (precision control).
 
1010
    control |= 0x2f3;  // Raise bits 0-5 (exception masks) and 9 (64-bit precision).
 
1011
    asm("fldcw %0" : : "m" (control) );
 
1012
}
 
1013
 
 
1014
#else
 
1015
 
 
1016
#define FIX_FPU() ((void)0)
 
1017
 
 
1018
#endif
 
1019
 
 
1020
JSBool
 
1021
js_InitRuntimeNumberState(JSContext *cx)
 
1022
{
 
1023
    JSRuntime *rt = cx->runtime;
 
1024
 
 
1025
    FIX_FPU();
 
1026
 
 
1027
    jsdpun u;
 
1028
    u.s.hi = JSDOUBLE_HI32_NAN;
 
1029
    u.s.lo = JSDOUBLE_LO32_NAN;
 
1030
    number_constants[NC_NaN].dval = js_NaN = u.d;
 
1031
    rt->NaNValue.setDouble(u.d);
 
1032
 
 
1033
    u.s.hi = JSDOUBLE_HI32_EXPMASK;
 
1034
    u.s.lo = 0x00000000;
 
1035
    number_constants[NC_POSITIVE_INFINITY].dval = js_PositiveInfinity = u.d;
 
1036
    rt->positiveInfinityValue.setDouble(u.d);
 
1037
 
 
1038
    u.s.hi = JSDOUBLE_HI32_SIGNBIT | JSDOUBLE_HI32_EXPMASK;
 
1039
    u.s.lo = 0x00000000;
 
1040
    number_constants[NC_NEGATIVE_INFINITY].dval = js_NegativeInfinity = u.d;
 
1041
    rt->negativeInfinityValue.setDouble(u.d);
 
1042
 
 
1043
    u.s.hi = 0;
 
1044
    u.s.lo = 1;
 
1045
    number_constants[NC_MIN_VALUE].dval = u.d;
 
1046
 
 
1047
#ifndef HAVE_LOCALECONV
 
1048
    const char* thousands_sep = getenv("LOCALE_THOUSANDS_SEP");
 
1049
    const char* decimal_point = getenv("LOCALE_DECIMAL_POINT");
 
1050
    const char* grouping = getenv("LOCALE_GROUPING");
 
1051
 
 
1052
    rt->thousandsSeparator =
 
1053
        JS_strdup(cx, thousands_sep ? thousands_sep : "'");
 
1054
    rt->decimalSeparator =
 
1055
        JS_strdup(cx, decimal_point ? decimal_point : ".");
 
1056
    rt->numGrouping =
 
1057
        JS_strdup(cx, grouping ? grouping : "\3\0");
 
1058
#else
 
1059
    struct lconv *locale = localeconv();
 
1060
    rt->thousandsSeparator =
 
1061
        JS_strdup(cx, locale->thousands_sep ? locale->thousands_sep : "'");
 
1062
    rt->decimalSeparator =
 
1063
        JS_strdup(cx, locale->decimal_point ? locale->decimal_point : ".");
 
1064
    rt->numGrouping =
 
1065
        JS_strdup(cx, locale->grouping ? locale->grouping : "\3\0");
 
1066
#endif
 
1067
 
 
1068
    return rt->thousandsSeparator && rt->decimalSeparator && rt->numGrouping;
 
1069
}
 
1070
 
 
1071
void
 
1072
js_FinishRuntimeNumberState(JSContext *cx)
 
1073
{
 
1074
    JSRuntime *rt = cx->runtime;
 
1075
 
 
1076
    cx->free_((void *) rt->thousandsSeparator);
 
1077
    cx->free_((void *) rt->decimalSeparator);
 
1078
    cx->free_((void *) rt->numGrouping);
 
1079
    rt->thousandsSeparator = rt->decimalSeparator = rt->numGrouping = NULL;
 
1080
}
 
1081
 
 
1082
JSObject *
 
1083
js_InitNumberClass(JSContext *cx, JSObject *obj)
 
1084
{
 
1085
    JSObject *proto, *ctor;
 
1086
    JSRuntime *rt;
 
1087
 
 
1088
    /* XXX must do at least once per new thread, so do it per JSContext... */
 
1089
    FIX_FPU();
 
1090
 
 
1091
    if (!JS_DefineFunctions(cx, obj, number_functions))
 
1092
        return NULL;
 
1093
 
 
1094
    proto = js_InitClass(cx, obj, NULL, &js_NumberClass, Number, 1,
 
1095
                         NULL, number_methods, NULL, NULL);
 
1096
    if (!proto || !(ctor = JS_GetConstructor(cx, proto)))
 
1097
        return NULL;
 
1098
    proto->setPrimitiveThis(Int32Value(0));
 
1099
    if (!JS_DefineConstDoubles(cx, ctor, number_constants))
 
1100
        return NULL;
 
1101
 
 
1102
    /* ECMA 15.1.1.1 */
 
1103
    rt = cx->runtime;
 
1104
    if (!JS_DefineProperty(cx, obj, js_NaN_str, Jsvalify(rt->NaNValue),
 
1105
                           JS_PropertyStub, JS_StrictPropertyStub,
 
1106
                           JSPROP_PERMANENT | JSPROP_READONLY)) {
 
1107
        return NULL;
 
1108
    }
 
1109
 
 
1110
    /* ECMA 15.1.1.2 */
 
1111
    if (!JS_DefineProperty(cx, obj, js_Infinity_str, Jsvalify(rt->positiveInfinityValue),
 
1112
                           JS_PropertyStub, JS_StrictPropertyStub,
 
1113
                           JSPROP_PERMANENT | JSPROP_READONLY)) {
 
1114
        return NULL;
 
1115
    }
 
1116
    return proto;
 
1117
}
 
1118
 
 
1119
namespace v8 {
 
1120
namespace internal {
 
1121
extern char* DoubleToCString(double v, char* buffer, int buflen);
 
1122
}
 
1123
}
 
1124
 
 
1125
namespace js {
 
1126
 
 
1127
static char *
 
1128
FracNumberToCString(JSContext *cx, ToCStringBuf *cbuf, jsdouble d, jsint base = 10)
 
1129
{
 
1130
#ifdef DEBUG
 
1131
    {
 
1132
        int32_t _;
 
1133
        JS_ASSERT(!JSDOUBLE_IS_INT32(d, &_));
 
1134
    }
 
1135
#endif
 
1136
 
 
1137
    char* numStr;
 
1138
    if (base == 10) {
 
1139
        /*
 
1140
         * This is V8's implementation of the algorithm described in the
 
1141
         * following paper:
 
1142
         *
 
1143
         *   Printing floating-point numbers quickly and accurately with integers. 
 
1144
         *   Florian Loitsch, PLDI 2010.
 
1145
         *
 
1146
         * It fails on a small number of cases, whereupon we fall back to
 
1147
         * js_dtostr() (which uses David Gay's dtoa).
 
1148
         */
 
1149
        numStr = v8::internal::DoubleToCString(d, cbuf->sbuf, cbuf->sbufSize);
 
1150
        if (!numStr)
 
1151
            numStr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, cbuf->sbuf, cbuf->sbufSize,
 
1152
                               DTOSTR_STANDARD, 0, d);
 
1153
    } else {
 
1154
        numStr = cbuf->dbuf = js_dtobasestr(JS_THREAD_DATA(cx)->dtoaState, base, d);
 
1155
    }
 
1156
    return numStr;
 
1157
}
 
1158
 
 
1159
char *
 
1160
NumberToCString(JSContext *cx, ToCStringBuf *cbuf, jsdouble d, jsint base/* = 10*/)
 
1161
{
 
1162
    int32_t i;
 
1163
    return (JSDOUBLE_IS_INT32(d, &i))
 
1164
           ? IntToCString(cbuf, i, base)
 
1165
           : FracNumberToCString(cx, cbuf, d, base);
 
1166
}
 
1167
 
 
1168
}
 
1169
 
 
1170
static JSString * JS_FASTCALL
 
1171
js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base)
 
1172
{
 
1173
    ToCStringBuf cbuf;
 
1174
    char *numStr;
 
1175
 
 
1176
    /*
 
1177
     * Caller is responsible for error reporting. When called from trace,
 
1178
     * returning NULL here will cause us to fall of trace and then retry
 
1179
     * from the interpreter (which will report the error).
 
1180
     */
 
1181
    if (base < 2 || base > 36)
 
1182
        return NULL;
 
1183
 
 
1184
    JSCompartment *c = cx->compartment;
 
1185
 
 
1186
    int32_t i;
 
1187
    if (JSDOUBLE_IS_INT32(d, &i)) {
 
1188
        if (base == 10 && JSAtom::hasIntStatic(i))
 
1189
            return &JSAtom::intStatic(i);
 
1190
        if (jsuint(i) < jsuint(base)) {
 
1191
            if (i < 10)
 
1192
                return &JSAtom::intStatic(i);
 
1193
            jschar c = 'a' + i - 10;
 
1194
            JS_ASSERT(JSAtom::hasUnitStatic(c));
 
1195
            return &JSAtom::unitStatic(c);
 
1196
        }
 
1197
 
 
1198
        if (JSFlatString *str = c->dtoaCache.lookup(base, d))
 
1199
            return str;
 
1200
 
 
1201
        numStr = IntToCString(&cbuf, i, base);
 
1202
        JS_ASSERT(!cbuf.dbuf && numStr >= cbuf.sbuf && numStr < cbuf.sbuf + cbuf.sbufSize);
 
1203
    } else {
 
1204
        if (JSFlatString *str = c->dtoaCache.lookup(base, d))
 
1205
            return str;
 
1206
 
 
1207
        numStr = FracNumberToCString(cx, &cbuf, d, base);
 
1208
        if (!numStr) {
 
1209
            JS_ReportOutOfMemory(cx);
 
1210
            return NULL;
 
1211
        }
 
1212
        JS_ASSERT_IF(base == 10,
 
1213
                     !cbuf.dbuf && numStr >= cbuf.sbuf && numStr < cbuf.sbuf + cbuf.sbufSize);
 
1214
        JS_ASSERT_IF(base != 10,
 
1215
                     cbuf.dbuf && cbuf.dbuf == numStr);
 
1216
    }
 
1217
 
 
1218
    JSFixedString *s = js_NewStringCopyZ(cx, numStr);
 
1219
    c->dtoaCache.cache(base, d, s);
 
1220
    return s;
 
1221
}
 
1222
 
 
1223
JSString * JS_FASTCALL
 
1224
js_NumberToString(JSContext *cx, jsdouble d)
 
1225
{
 
1226
    return js_NumberToStringWithBase(cx, d, 10);
 
1227
}
 
1228
 
 
1229
namespace js {
 
1230
 
 
1231
JSFixedString *
 
1232
NumberToString(JSContext *cx, jsdouble d)
 
1233
{
 
1234
    if (JSString *str = js_NumberToStringWithBase(cx, d, 10))
 
1235
        return &str->asFixed();
 
1236
    return NULL;
 
1237
}
 
1238
 
 
1239
bool JS_FASTCALL
 
1240
NumberValueToStringBuffer(JSContext *cx, const Value &v, StringBuffer &sb)
 
1241
{
 
1242
    /* Convert to C-string. */
 
1243
    ToCStringBuf cbuf;
 
1244
    const char *cstr;
 
1245
    if (v.isInt32()) {
 
1246
        cstr = IntToCString(&cbuf, v.toInt32());
 
1247
    } else {
 
1248
        cstr = NumberToCString(cx, &cbuf, v.toDouble());
 
1249
        if (!cstr) {
 
1250
            JS_ReportOutOfMemory(cx);
 
1251
            return JS_FALSE;
 
1252
        }
 
1253
    }
 
1254
 
 
1255
    /*
 
1256
     * Inflate to jschar string.  The input C-string characters are < 127, so
 
1257
     * even if jschars are UTF-8, all chars should map to one jschar.
 
1258
     */
 
1259
    size_t cstrlen = strlen(cstr);
 
1260
    JS_ASSERT(!cbuf.dbuf && cstrlen < cbuf.sbufSize);
 
1261
    return sb.appendInflated(cstr, cstrlen);
 
1262
}
 
1263
 
 
1264
bool
 
1265
ValueToNumberSlow(JSContext *cx, Value v, double *out)
 
1266
{
 
1267
    JS_ASSERT(!v.isNumber());
 
1268
    goto skip_int_double;
 
1269
    for (;;) {
 
1270
        if (v.isNumber()) {
 
1271
            *out = v.toNumber();
 
1272
            return true;
 
1273
        }
 
1274
      skip_int_double:
 
1275
        if (v.isString())
 
1276
            return StringToNumberType<jsdouble>(cx, v.toString(), out);
 
1277
        if (v.isBoolean()) {
 
1278
            if (v.toBoolean()) {
 
1279
                *out = 1.0;
 
1280
                return true;
 
1281
            }
 
1282
            *out = 0.0;
 
1283
            return true;
 
1284
        }
 
1285
        if (v.isNull()) {
 
1286
            *out = 0.0;
 
1287
            return true;
 
1288
        }
 
1289
        if (v.isUndefined())
 
1290
            break;
 
1291
 
 
1292
        JS_ASSERT(v.isObject());
 
1293
        if (!DefaultValue(cx, &v.toObject(), JSTYPE_NUMBER, &v))
 
1294
            return false;
 
1295
        if (v.isObject())
 
1296
            break;
 
1297
    }
 
1298
 
 
1299
    *out = js_NaN;
 
1300
    return true;
 
1301
}
 
1302
 
 
1303
bool
 
1304
ValueToECMAInt32Slow(JSContext *cx, const Value &v, int32_t *out)
 
1305
{
 
1306
    JS_ASSERT(!v.isInt32());
 
1307
    jsdouble d;
 
1308
    if (v.isDouble()) {
 
1309
        d = v.toDouble();
 
1310
    } else {
 
1311
        if (!ValueToNumberSlow(cx, v, &d))
 
1312
            return false;
 
1313
    }
 
1314
    *out = js_DoubleToECMAInt32(d);
 
1315
    return true;
 
1316
}
 
1317
 
 
1318
bool
 
1319
ValueToECMAUint32Slow(JSContext *cx, const Value &v, uint32_t *out)
 
1320
{
 
1321
    JS_ASSERT(!v.isInt32());
 
1322
    jsdouble d;
 
1323
    if (v.isDouble()) {
 
1324
        d = v.toDouble();
 
1325
    } else {
 
1326
        if (!ValueToNumberSlow(cx, v, &d))
 
1327
            return false;
 
1328
    }
 
1329
    *out = js_DoubleToECMAUint32(d);
 
1330
    return true;
 
1331
}
 
1332
 
 
1333
}  /* namespace js */
 
1334
 
 
1335
uint32
 
1336
js_DoubleToECMAUint32(jsdouble d)
 
1337
{
 
1338
    int32 i;
 
1339
    JSBool neg;
 
1340
    jsdouble two32;
 
1341
 
 
1342
    if (!JSDOUBLE_IS_FINITE(d))
 
1343
        return 0;
 
1344
 
 
1345
    /*
 
1346
     * We check whether d fits int32, not uint32, as all but the ">>>" bit
 
1347
     * manipulation bytecode stores the result as int, not uint. When the
 
1348
     * result does not fit int Value, it will be stored as a negative double.
 
1349
     */
 
1350
    i = (int32) d;
 
1351
    if ((jsdouble) i == d)
 
1352
        return (int32)i;
 
1353
 
 
1354
    neg = (d < 0);
 
1355
    d = floor(neg ? -d : d);
 
1356
    d = neg ? -d : d;
 
1357
 
 
1358
    two32 = 4294967296.0;
 
1359
    d = fmod(d, two32);
 
1360
 
 
1361
    return (uint32) (d >= 0 ? d : d + two32);
 
1362
}
 
1363
 
 
1364
namespace js {
 
1365
 
 
1366
bool
 
1367
ValueToInt32Slow(JSContext *cx, const Value &v, int32_t *out)
 
1368
{
 
1369
    JS_ASSERT(!v.isInt32());
 
1370
    jsdouble d;
 
1371
    if (v.isDouble()) {
 
1372
        d = v.toDouble();
 
1373
    } else if (!ValueToNumberSlow(cx, v, &d)) {
 
1374
        return false;
 
1375
    }
 
1376
 
 
1377
    if (JSDOUBLE_IS_NaN(d) || d <= -2147483649.0 || 2147483648.0 <= d) {
 
1378
        js_ReportValueError(cx, JSMSG_CANT_CONVERT,
 
1379
                            JSDVG_SEARCH_STACK, v, NULL);
 
1380
        return false;
 
1381
    }
 
1382
    *out = (int32) floor(d + 0.5);  /* Round to nearest */
 
1383
    return true;
 
1384
}
 
1385
 
 
1386
bool
 
1387
ValueToUint16Slow(JSContext *cx, const Value &v, uint16_t *out)
 
1388
{
 
1389
    JS_ASSERT(!v.isInt32());
 
1390
    jsdouble d;
 
1391
    if (v.isDouble()) {
 
1392
        d = v.toDouble();
 
1393
    } else if (!ValueToNumberSlow(cx, v, &d)) {
 
1394
        return false;
 
1395
    }
 
1396
 
 
1397
    if (d == 0 || !JSDOUBLE_IS_FINITE(d)) {
 
1398
        *out = 0;
 
1399
        return true;
 
1400
    }
 
1401
 
 
1402
    uint16 u = (uint16) d;
 
1403
    if ((jsdouble)u == d) {
 
1404
        *out = u;
 
1405
        return true;
 
1406
    }
 
1407
 
 
1408
    bool neg = (d < 0);
 
1409
    d = floor(neg ? -d : d);
 
1410
    d = neg ? -d : d;
 
1411
    jsuint m = JS_BIT(16);
 
1412
    d = fmod(d, (double) m);
 
1413
    if (d < 0)
 
1414
        d += m;
 
1415
    *out = (uint16_t) d;
 
1416
    return true;
 
1417
}
 
1418
 
 
1419
}  /* namespace js */
 
1420
 
 
1421
JSBool
 
1422
js_strtod(JSContext *cx, const jschar *s, const jschar *send,
 
1423
          const jschar **ep, jsdouble *dp)
 
1424
{
 
1425
    const jschar *s1;
 
1426
    size_t length, i;
 
1427
    char cbuf[32];
 
1428
    char *cstr, *istr, *estr;
 
1429
    JSBool negative;
 
1430
    jsdouble d;
 
1431
 
 
1432
    s1 = js_SkipWhiteSpace(s, send);
 
1433
    length = send - s1;
 
1434
 
 
1435
    /* Use cbuf to avoid malloc */
 
1436
    if (length >= sizeof cbuf) {
 
1437
        cstr = (char *) cx->malloc_(length + 1);
 
1438
        if (!cstr)
 
1439
           return JS_FALSE;
 
1440
    } else {
 
1441
        cstr = cbuf;
 
1442
    }
 
1443
 
 
1444
    for (i = 0; i != length; i++) {
 
1445
        if (s1[i] >> 8)
 
1446
            break;
 
1447
        cstr[i] = (char)s1[i];
 
1448
    }
 
1449
    cstr[i] = 0;
 
1450
 
 
1451
    istr = cstr;
 
1452
    if ((negative = (*istr == '-')) != 0 || *istr == '+')
 
1453
        istr++;
 
1454
    if (*istr == 'I' && !strncmp(istr, js_Infinity_str, sizeof js_Infinity_str - 1)) {
 
1455
        d = negative ? js_NegativeInfinity : js_PositiveInfinity;
 
1456
        estr = istr + 8;
 
1457
    } else {
 
1458
        int err;
 
1459
        d = js_strtod_harder(JS_THREAD_DATA(cx)->dtoaState, cstr, &estr, &err);
 
1460
        if (d == HUGE_VAL)
 
1461
            d = js_PositiveInfinity;
 
1462
        else if (d == -HUGE_VAL)
 
1463
            d = js_NegativeInfinity;
 
1464
    }
 
1465
 
 
1466
    i = estr - cstr;
 
1467
    if (cstr != cbuf)
 
1468
        cx->free_(cstr);
 
1469
    *ep = i ? s1 + i : s;
 
1470
    *dp = d;
 
1471
    return JS_TRUE;
 
1472
}