js/src/jsnum.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #ifndef jsnum_h
     8 #define jsnum_h
    10 #include "mozilla/FloatingPoint.h"
    12 #include "NamespaceImports.h"
    14 #include "vm/NumericConversions.h"
    16 namespace js {
    18 class StringBuffer;
    20 extern bool
    21 InitRuntimeNumberState(JSRuntime *rt);
    23 #if !EXPOSE_INTL_API
    24 extern void
    25 FinishRuntimeNumberState(JSRuntime *rt);
    26 #endif
    28 } /* namespace js */
    30 /* Initialize the Number class, returning its prototype object. */
    31 extern JSObject *
    32 js_InitNumberClass(JSContext *cx, js::HandleObject obj);
    34 /*
    35  * String constants for global function names, used in jsapi.c and jsnum.c.
    36  */
    37 extern const char js_isNaN_str[];
    38 extern const char js_isFinite_str[];
    39 extern const char js_parseFloat_str[];
    40 extern const char js_parseInt_str[];
    42 class JSAtom;
    44 namespace js {
    46 /*
    47  * When base == 10, this function implements ToString() as specified by
    48  * ECMA-262-5 section 9.8.1; but note that it handles integers specially for
    49  * performance.  See also js::NumberToCString().
    50  */
    51 template <js::AllowGC allowGC>
    52 extern JSString *
    53 NumberToString(js::ThreadSafeContext *cx, double d);
    55 extern JSAtom *
    56 NumberToAtom(js::ExclusiveContext *cx, double d);
    58 template <AllowGC allowGC>
    59 extern JSFlatString *
    60 Int32ToString(ThreadSafeContext *cx, int32_t i);
    62 extern JSAtom *
    63 Int32ToAtom(ExclusiveContext *cx, int32_t si);
    65 /*
    66  * Convert an integer or double (contained in the given value) to a string and
    67  * append to the given buffer.
    68  */
    69 extern bool JS_FASTCALL
    70 NumberValueToStringBuffer(JSContext *cx, const Value &v, StringBuffer &sb);
    72 /* Same as js_NumberToString, different signature. */
    73 extern JSFlatString *
    74 NumberToString(JSContext *cx, double d);
    76 extern JSFlatString *
    77 IndexToString(JSContext *cx, uint32_t index);
    79 /*
    80  * Usually a small amount of static storage is enough, but sometimes we need
    81  * to dynamically allocate much more.  This struct encapsulates that.
    82  * Dynamically allocated memory will be freed when the object is destroyed.
    83  */
    84 struct ToCStringBuf
    85 {
    86     /*
    87      * The longest possible result that would need to fit in sbuf is
    88      * (-0x80000000).toString(2), which has length 33.  Longer cases are
    89      * possible, but they'll go in dbuf.
    90      */
    91     static const size_t sbufSize = 34;
    92     char sbuf[sbufSize];
    93     char *dbuf;
    95     ToCStringBuf();
    96     ~ToCStringBuf();
    97 };
    99 /*
   100  * Convert a number to a C string.  When base==10, this function implements
   101  * ToString() as specified by ECMA-262-5 section 9.8.1.  It handles integral
   102  * values cheaply.  Return nullptr if we ran out of memory.  See also
   103  * js_NumberToCString().
   104  */
   105 extern char *
   106 NumberToCString(JSContext *cx, ToCStringBuf *cbuf, double d, int base = 10);
   108 /*
   109  * The largest positive integer such that all positive integers less than it
   110  * may be precisely represented using the IEEE-754 double-precision format.
   111  */
   112 const double DOUBLE_INTEGRAL_PRECISION_LIMIT = uint64_t(1) << 53;
   114 /*
   115  * Parse a decimal number encoded in |chars|.  The decimal number must be
   116  * sufficiently small that it will not overflow the integrally-precise range of
   117  * the double type -- that is, the number will be smaller than
   118  * DOUBLE_INTEGRAL_PRECISION_LIMIT
   119  */
   120 extern double
   121 ParseDecimalNumber(const JS::TwoByteChars chars);
   123 /*
   124  * Compute the positive integer of the given base described immediately at the
   125  * start of the range [start, end) -- no whitespace-skipping, no magical
   126  * leading-"0" octal or leading-"0x" hex behavior, no "+"/"-" parsing, just
   127  * reading the digits of the integer.  Return the index one past the end of the
   128  * digits of the integer in *endp, and return the integer itself in *dp.  If
   129  * base is 10 or a power of two the returned integer is the closest possible
   130  * double; otherwise extremely large integers may be slightly inaccurate.
   131  *
   132  * If [start, end) does not begin with a number with the specified base,
   133  * *dp == 0 and *endp == start upon return.
   134  */
   135 extern bool
   136 GetPrefixInteger(ThreadSafeContext *cx, const jschar *start, const jschar *end, int base,
   137                  const jschar **endp, double *dp);
   139 /*
   140  * This is like GetPrefixInteger, but only deals with base 10, and doesn't have
   141  * and |endp| outparam.  It should only be used when the jschars are known to
   142  * only contain digits.
   143  */
   144 extern bool
   145 GetDecimalInteger(ExclusiveContext *cx, const jschar *start, const jschar *end, double *dp);
   147 extern bool
   148 StringToNumber(ThreadSafeContext *cx, JSString *str, double *result);
   150 /* ES5 9.3 ToNumber, overwriting *vp with the appropriate number value. */
   151 MOZ_ALWAYS_INLINE bool
   152 ToNumber(JSContext *cx, JS::MutableHandleValue vp)
   153 {
   154     if (vp.isNumber())
   155         return true;
   156     double d;
   157     extern JS_PUBLIC_API(bool) ToNumberSlow(JSContext *cx, Value v, double *dp);
   158     if (!ToNumberSlow(cx, vp, &d))
   159         return false;
   161     vp.setNumber(d);
   162     return true;
   163 }
   165 bool
   166 num_parseInt(JSContext *cx, unsigned argc, Value *vp);
   168 }  /* namespace js */
   170 /*
   171  * Similar to strtod except that it replaces overflows with infinities of the
   172  * correct sign, and underflows with zeros of the correct sign.  Guaranteed to
   173  * return the closest double number to the given input in dp.
   174  *
   175  * Also allows inputs of the form [+|-]Infinity, which produce an infinity of
   176  * the appropriate sign.  The case of the "Infinity" string must match exactly.
   177  * If the string does not contain a number, set *ep to s and return 0.0 in dp.
   178  * Return false if out of memory.
   179  */
   180 extern bool
   181 js_strtod(js::ThreadSafeContext *cx, const jschar *s, const jschar *send,
   182           const jschar **ep, double *dp);
   184 extern bool
   185 js_num_toString(JSContext *cx, unsigned argc, js::Value *vp);
   187 extern bool
   188 js_num_valueOf(JSContext *cx, unsigned argc, js::Value *vp);
   190 namespace js {
   192 static MOZ_ALWAYS_INLINE bool
   193 ValueFitsInInt32(const Value &v, int32_t *pi)
   194 {
   195     if (v.isInt32()) {
   196         *pi = v.toInt32();
   197         return true;
   198     }
   199     return v.isDouble() && mozilla::NumberIsInt32(v.toDouble(), pi);
   200 }
   202 /*
   203  * Returns true if the given value is definitely an index: that is, the value
   204  * is a number that's an unsigned 32-bit integer.
   205  *
   206  * This method prioritizes common-case speed over accuracy in every case.  It
   207  * can produce false negatives (but not false positives): some values which are
   208  * indexes will be reported not to be indexes by this method.  Users must
   209  * consider this possibility when using this method.
   210  */
   211 static MOZ_ALWAYS_INLINE bool
   212 IsDefinitelyIndex(const Value &v, uint32_t *indexp)
   213 {
   214     if (v.isInt32() && v.toInt32() >= 0) {
   215         *indexp = v.toInt32();
   216         return true;
   217     }
   219     int32_t i;
   220     if (v.isDouble() && mozilla::NumberIsInt32(v.toDouble(), &i) && i >= 0) {
   221         *indexp = uint32_t(i);
   222         return true;
   223     }
   225     return false;
   226 }
   228 /* ES5 9.4 ToInteger. */
   229 static inline bool
   230 ToInteger(JSContext *cx, HandleValue v, double *dp)
   231 {
   232     if (v.isInt32()) {
   233         *dp = v.toInt32();
   234         return true;
   235     }
   236     if (v.isDouble()) {
   237         *dp = v.toDouble();
   238     } else {
   239         extern JS_PUBLIC_API(bool) ToNumberSlow(JSContext *cx, Value v, double *dp);
   240         if (!ToNumberSlow(cx, v, dp))
   241             return false;
   242     }
   243     *dp = ToInteger(*dp);
   244     return true;
   245 }
   247 inline bool
   248 SafeAdd(int32_t one, int32_t two, int32_t *res)
   249 {
   250     // Use unsigned for the 32-bit operation since signed overflow gets
   251     // undefined behavior.
   252     *res = uint32_t(one) + uint32_t(two);
   253     int64_t ores = (int64_t)one + (int64_t)two;
   254     return ores == (int64_t)*res;
   255 }
   257 inline bool
   258 SafeSub(int32_t one, int32_t two, int32_t *res)
   259 {
   260     *res = uint32_t(one) - uint32_t(two);
   261     int64_t ores = (int64_t)one - (int64_t)two;
   262     return ores == (int64_t)*res;
   263 }
   265 inline bool
   266 SafeMul(int32_t one, int32_t two, int32_t *res)
   267 {
   268     *res = uint32_t(one) * uint32_t(two);
   269     int64_t ores = (int64_t)one * (int64_t)two;
   270     return ores == (int64_t)*res;
   271 }
   273 extern bool
   274 ToNumberSlow(ExclusiveContext *cx, Value v, double *dp);
   276 // Variant of ToNumber which takes an ExclusiveContext instead of a JSContext.
   277 // ToNumber is part of the API and can't use ExclusiveContext directly.
   278 MOZ_ALWAYS_INLINE bool
   279 ToNumber(ExclusiveContext *cx, const Value &v, double *out)
   280 {
   281     if (v.isNumber()) {
   282         *out = v.toNumber();
   283         return true;
   284     }
   285     return ToNumberSlow(cx, v, out);
   286 }
   288 /*
   289  * Thread safe variants of number conversion functions.
   290  */
   292 bool
   293 NonObjectToNumberSlow(ThreadSafeContext *cx, Value v, double *out);
   295 inline bool
   296 NonObjectToNumber(ThreadSafeContext *cx, const Value &v, double *out)
   297 {
   298     if (v.isNumber()) {
   299         *out = v.toNumber();
   300         return true;
   301     }
   302     return NonObjectToNumberSlow(cx, v, out);
   303 }
   305 bool
   306 NonObjectToInt32Slow(ThreadSafeContext *cx, const Value &v, int32_t *out);
   308 inline bool
   309 NonObjectToInt32(ThreadSafeContext *cx, const Value &v, int32_t *out)
   310 {
   311     if (v.isInt32()) {
   312         *out = v.toInt32();
   313         return true;
   314     }
   315     return NonObjectToInt32Slow(cx, v, out);
   316 }
   318 bool
   319 NonObjectToUint32Slow(ThreadSafeContext *cx, const Value &v, uint32_t *out);
   321 MOZ_ALWAYS_INLINE bool
   322 NonObjectToUint32(ThreadSafeContext *cx, const Value &v, uint32_t *out)
   323 {
   324     if (v.isInt32()) {
   325         *out = uint32_t(v.toInt32());
   326         return true;
   327     }
   328     return NonObjectToUint32Slow(cx, v, out);
   329 }
   331 } /* namespace js */
   333 #endif /* jsnum_h */

mercurial