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