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