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