/work/obj-fuzz/dist/include/js/Conversions.h
Line | Count | Source (jump to first uncovered line) |
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 | | /* ECMAScript conversion operations. */ |
8 | | |
9 | | #ifndef js_Conversions_h |
10 | | #define js_Conversions_h |
11 | | |
12 | | #include "mozilla/Casting.h" |
13 | | #include "mozilla/Compiler.h" |
14 | | #include "mozilla/FloatingPoint.h" |
15 | | #include "mozilla/MathAlgorithms.h" |
16 | | #include "mozilla/TypeTraits.h" |
17 | | #include "mozilla/WrappingOperations.h" |
18 | | |
19 | | #include <math.h> |
20 | | |
21 | | #include "jspubtd.h" |
22 | | |
23 | | #include "js/RootingAPI.h" |
24 | | #include "js/Value.h" |
25 | | |
26 | | namespace js { |
27 | | |
28 | | /* DO NOT CALL THIS. Use JS::ToBoolean. */ |
29 | | extern JS_PUBLIC_API(bool) |
30 | | ToBooleanSlow(JS::HandleValue v); |
31 | | |
32 | | /* DO NOT CALL THIS. Use JS::ToNumber. */ |
33 | | extern JS_PUBLIC_API(bool) |
34 | | ToNumberSlow(JSContext* cx, JS::HandleValue v, double* dp); |
35 | | |
36 | | /* DO NOT CALL THIS. Use JS::ToInt8. */ |
37 | | extern JS_PUBLIC_API(bool) |
38 | | ToInt8Slow(JSContext *cx, JS::HandleValue v, int8_t *out); |
39 | | |
40 | | /* DO NOT CALL THIS. Use JS::ToUint8. */ |
41 | | extern JS_PUBLIC_API(bool) |
42 | | ToUint8Slow(JSContext *cx, JS::HandleValue v, uint8_t *out); |
43 | | |
44 | | /* DO NOT CALL THIS. Use JS::ToInt16. */ |
45 | | extern JS_PUBLIC_API(bool) |
46 | | ToInt16Slow(JSContext *cx, JS::HandleValue v, int16_t *out); |
47 | | |
48 | | /* DO NOT CALL THIS. Use JS::ToInt32. */ |
49 | | extern JS_PUBLIC_API(bool) |
50 | | ToInt32Slow(JSContext* cx, JS::HandleValue v, int32_t* out); |
51 | | |
52 | | /* DO NOT CALL THIS. Use JS::ToUint32. */ |
53 | | extern JS_PUBLIC_API(bool) |
54 | | ToUint32Slow(JSContext* cx, JS::HandleValue v, uint32_t* out); |
55 | | |
56 | | /* DO NOT CALL THIS. Use JS::ToUint16. */ |
57 | | extern JS_PUBLIC_API(bool) |
58 | | ToUint16Slow(JSContext* cx, JS::HandleValue v, uint16_t* out); |
59 | | |
60 | | /* DO NOT CALL THIS. Use JS::ToInt64. */ |
61 | | extern JS_PUBLIC_API(bool) |
62 | | ToInt64Slow(JSContext* cx, JS::HandleValue v, int64_t* out); |
63 | | |
64 | | /* DO NOT CALL THIS. Use JS::ToUint64. */ |
65 | | extern JS_PUBLIC_API(bool) |
66 | | ToUint64Slow(JSContext* cx, JS::HandleValue v, uint64_t* out); |
67 | | |
68 | | /* DO NOT CALL THIS. Use JS::ToString. */ |
69 | | extern JS_PUBLIC_API(JSString*) |
70 | | ToStringSlow(JSContext* cx, JS::HandleValue v); |
71 | | |
72 | | /* DO NOT CALL THIS. Use JS::ToObject. */ |
73 | | extern JS_PUBLIC_API(JSObject*) |
74 | | ToObjectSlow(JSContext* cx, JS::HandleValue v, bool reportScanStack); |
75 | | |
76 | | } // namespace js |
77 | | |
78 | | namespace JS { |
79 | | |
80 | | namespace detail { |
81 | | |
82 | | #ifdef JS_DEBUG |
83 | | /** |
84 | | * Assert that we're not doing GC on cx, that we're in a request as |
85 | | * needed, and that the compartments for cx and v are correct. |
86 | | * Also check that GC would be safe at this point. |
87 | | */ |
88 | | extern JS_PUBLIC_API(void) |
89 | | AssertArgumentsAreSane(JSContext* cx, HandleValue v); |
90 | | #else |
91 | | inline void AssertArgumentsAreSane(JSContext* cx, HandleValue v) |
92 | 3.24M | {} |
93 | | #endif /* JS_DEBUG */ |
94 | | |
95 | | } // namespace detail |
96 | | |
97 | | /** |
98 | | * ES6 draft 20141224, 7.1.1, second algorithm. |
99 | | * |
100 | | * Most users shouldn't call this -- use JS::ToBoolean, ToNumber, or ToString |
101 | | * instead. This will typically only be called from custom convert hooks that |
102 | | * wish to fall back to the ES6 default conversion behavior shared by most |
103 | | * objects in JS, codified as OrdinaryToPrimitive. |
104 | | */ |
105 | | extern JS_PUBLIC_API(bool) |
106 | | OrdinaryToPrimitive(JSContext* cx, HandleObject obj, JSType type, MutableHandleValue vp); |
107 | | |
108 | | /* ES6 draft 20141224, 7.1.2. */ |
109 | | MOZ_ALWAYS_INLINE bool |
110 | | ToBoolean(HandleValue v) |
111 | 349 | { |
112 | 349 | if (v.isBoolean()) { |
113 | 255 | return v.toBoolean(); |
114 | 255 | } |
115 | 94 | if (v.isInt32()) { |
116 | 22 | return v.toInt32() != 0; |
117 | 22 | } |
118 | 72 | if (v.isNullOrUndefined()) { |
119 | 3 | return false; |
120 | 3 | } |
121 | 69 | if (v.isDouble()) { |
122 | 0 | double d = v.toDouble(); |
123 | 0 | return !mozilla::IsNaN(d) && d != 0; |
124 | 0 | } |
125 | 69 | if (v.isSymbol()) { |
126 | 0 | return true; |
127 | 0 | } |
128 | 69 | |
129 | 69 | /* The slow path handles strings, BigInts and objects. */ |
130 | 69 | return js::ToBooleanSlow(v); |
131 | 69 | } |
132 | | |
133 | | /* ES6 draft 20141224, 7.1.3. */ |
134 | | MOZ_ALWAYS_INLINE bool |
135 | | ToNumber(JSContext* cx, HandleValue v, double* out) |
136 | 520 | { |
137 | 520 | detail::AssertArgumentsAreSane(cx, v); |
138 | 520 | |
139 | 520 | if (v.isNumber()) { |
140 | 520 | *out = v.toNumber(); |
141 | 520 | return true; |
142 | 520 | } |
143 | 0 | return js::ToNumberSlow(cx, v, out); |
144 | 0 | } |
145 | | |
146 | | /* ES6 draft 20141224, ToInteger (specialized for doubles). */ |
147 | | inline double |
148 | | ToInteger(double d) |
149 | 0 | { |
150 | 0 | if (d == 0) { |
151 | 0 | return d; |
152 | 0 | } |
153 | 0 | |
154 | 0 | if (!mozilla::IsFinite(d)) { |
155 | 0 | if (mozilla::IsNaN(d)) { |
156 | 0 | return 0; |
157 | 0 | } |
158 | 0 | return d; |
159 | 0 | } |
160 | 0 | |
161 | 0 | return d < 0 ? ceil(d) : floor(d); |
162 | 0 | } |
163 | | |
164 | | /* ES6 draft 20141224, 7.1.5. */ |
165 | | MOZ_ALWAYS_INLINE bool |
166 | | ToInt32(JSContext* cx, JS::HandleValue v, int32_t* out) |
167 | 0 | { |
168 | 0 | detail::AssertArgumentsAreSane(cx, v); |
169 | 0 |
|
170 | 0 | if (v.isInt32()) { |
171 | 0 | *out = v.toInt32(); |
172 | 0 | return true; |
173 | 0 | } |
174 | 0 | return js::ToInt32Slow(cx, v, out); |
175 | 0 | } |
176 | | |
177 | | /* ES6 draft 20141224, 7.1.6. */ |
178 | | MOZ_ALWAYS_INLINE bool |
179 | | ToUint32(JSContext* cx, HandleValue v, uint32_t* out) |
180 | 0 | { |
181 | 0 | detail::AssertArgumentsAreSane(cx, v); |
182 | 0 |
|
183 | 0 | if (v.isInt32()) { |
184 | 0 | *out = uint32_t(v.toInt32()); |
185 | 0 | return true; |
186 | 0 | } |
187 | 0 | return js::ToUint32Slow(cx, v, out); |
188 | 0 | } |
189 | | |
190 | | /* ES6 draft 20141224, 7.1.7. */ |
191 | | MOZ_ALWAYS_INLINE bool |
192 | | ToInt16(JSContext *cx, JS::HandleValue v, int16_t *out) |
193 | 0 | { |
194 | 0 | detail::AssertArgumentsAreSane(cx, v); |
195 | 0 |
|
196 | 0 | if (v.isInt32()) { |
197 | 0 | *out = int16_t(v.toInt32()); |
198 | 0 | return true; |
199 | 0 | } |
200 | 0 | return js::ToInt16Slow(cx, v, out); |
201 | 0 | } |
202 | | |
203 | | /* ES6 draft 20141224, 7.1.8. */ |
204 | | MOZ_ALWAYS_INLINE bool |
205 | | ToUint16(JSContext* cx, HandleValue v, uint16_t* out) |
206 | 0 | { |
207 | 0 | detail::AssertArgumentsAreSane(cx, v); |
208 | 0 |
|
209 | 0 | if (v.isInt32()) { |
210 | 0 | *out = uint16_t(v.toInt32()); |
211 | 0 | return true; |
212 | 0 | } |
213 | 0 | return js::ToUint16Slow(cx, v, out); |
214 | 0 | } |
215 | | |
216 | | /* ES6 draft 20141224, 7.1.9 */ |
217 | | MOZ_ALWAYS_INLINE bool |
218 | | ToInt8(JSContext *cx, JS::HandleValue v, int8_t *out) |
219 | 0 | { |
220 | 0 | detail::AssertArgumentsAreSane(cx, v); |
221 | 0 |
|
222 | 0 | if (v.isInt32()) { |
223 | 0 | *out = int8_t(v.toInt32()); |
224 | 0 | return true; |
225 | 0 | } |
226 | 0 | return js::ToInt8Slow(cx, v, out); |
227 | 0 | } |
228 | | |
229 | | /* ES6 ECMA-262, 7.1.10 */ |
230 | | MOZ_ALWAYS_INLINE bool |
231 | | ToUint8(JSContext *cx, JS::HandleValue v, uint8_t *out) |
232 | 0 | { |
233 | 0 | detail::AssertArgumentsAreSane(cx, v); |
234 | 0 |
|
235 | 0 | if (v.isInt32()) { |
236 | 0 | *out = uint8_t(v.toInt32()); |
237 | 0 | return true; |
238 | 0 | } |
239 | 0 | return js::ToUint8Slow(cx, v, out); |
240 | 0 | } |
241 | | |
242 | | /* |
243 | | * Non-standard, with behavior similar to that of ToInt32, except in its |
244 | | * producing an int64_t. |
245 | | */ |
246 | | MOZ_ALWAYS_INLINE bool |
247 | | ToInt64(JSContext* cx, HandleValue v, int64_t* out) |
248 | 0 | { |
249 | 0 | detail::AssertArgumentsAreSane(cx, v); |
250 | 0 |
|
251 | 0 | if (v.isInt32()) { |
252 | 0 | *out = int64_t(v.toInt32()); |
253 | 0 | return true; |
254 | 0 | } |
255 | 0 | return js::ToInt64Slow(cx, v, out); |
256 | 0 | } |
257 | | |
258 | | /* |
259 | | * Non-standard, with behavior similar to that of ToUint32, except in its |
260 | | * producing a uint64_t. |
261 | | */ |
262 | | MOZ_ALWAYS_INLINE bool |
263 | | ToUint64(JSContext* cx, HandleValue v, uint64_t* out) |
264 | 0 | { |
265 | 0 | detail::AssertArgumentsAreSane(cx, v); |
266 | 0 |
|
267 | 0 | if (v.isInt32()) { |
268 | 0 | *out = uint64_t(v.toInt32()); |
269 | 0 | return true; |
270 | 0 | } |
271 | 0 | return js::ToUint64Slow(cx, v, out); |
272 | 0 | } |
273 | | |
274 | | /* ES6 draft 20141224, 7.1.12. */ |
275 | | MOZ_ALWAYS_INLINE JSString* |
276 | | ToString(JSContext* cx, HandleValue v) |
277 | 3.24M | { |
278 | 3.24M | detail::AssertArgumentsAreSane(cx, v); |
279 | 3.24M | |
280 | 3.24M | if (v.isString()) { |
281 | 3.24M | return v.toString(); |
282 | 3.24M | } |
283 | 0 | return js::ToStringSlow(cx, v); |
284 | 0 | } |
285 | | |
286 | | /* ES6 draft 20141224, 7.1.13. */ |
287 | | inline JSObject* |
288 | | ToObject(JSContext* cx, HandleValue v) |
289 | 50 | { |
290 | 50 | detail::AssertArgumentsAreSane(cx, v); |
291 | 50 | |
292 | 50 | if (v.isObject()) { |
293 | 50 | return &v.toObject(); |
294 | 50 | } |
295 | 0 | return js::ToObjectSlow(cx, v, false); |
296 | 0 | } |
297 | | |
298 | | /** |
299 | | * Convert a double value to UnsignedInteger (an unsigned integral type) using |
300 | | * ECMAScript-style semantics (that is, in like manner to how ECMAScript's |
301 | | * ToInt32 converts to int32_t). |
302 | | * |
303 | | * If d is infinite or NaN, return 0. |
304 | | * Otherwise compute d2 = sign(d) * floor(abs(d)), and return the |
305 | | * UnsignedInteger value congruent to d2 % 2**(bit width of UnsignedInteger). |
306 | | * |
307 | | * The algorithm below is inspired by that found in |
308 | | * <https://trac.webkit.org/changeset/67825/webkit/trunk/JavaScriptCore/runtime/JSValue.cpp> |
309 | | * but has been generalized to all integer widths. |
310 | | */ |
311 | | template<typename UnsignedInteger> |
312 | | inline UnsignedInteger |
313 | | ToUnsignedInteger(double d) |
314 | 1.38k | { |
315 | 1.38k | static_assert(mozilla::IsUnsigned<UnsignedInteger>::value, |
316 | 1.38k | "UnsignedInteger must be an unsigned type"); |
317 | 1.38k | |
318 | 1.38k | uint64_t bits = mozilla::BitwiseCast<uint64_t>(d); |
319 | 1.38k | unsigned DoubleExponentShift = mozilla::FloatingPoint<double>::kExponentShift; |
320 | 1.38k | |
321 | 1.38k | // Extract the exponent component. (Be careful here! It's not technically |
322 | 1.38k | // the exponent in NaN, infinities, and subnormals.) |
323 | 1.38k | int_fast16_t exp = |
324 | 1.38k | int_fast16_t((bits & mozilla::FloatingPoint<double>::kExponentBits) >> DoubleExponentShift) - |
325 | 1.38k | int_fast16_t(mozilla::FloatingPoint<double>::kExponentBias); |
326 | 1.38k | |
327 | 1.38k | // If the exponent's less than zero, abs(d) < 1, so the result is 0. (This |
328 | 1.38k | // also handles subnormals.) |
329 | 1.38k | if (exp < 0) { |
330 | 389 | return 0; |
331 | 389 | } |
332 | 992 | |
333 | 992 | uint_fast16_t exponent = mozilla::AssertedCast<uint_fast16_t>(exp); |
334 | 992 | |
335 | 992 | // If the exponent is greater than or equal to the bits of precision of a |
336 | 992 | // double plus UnsignedInteger's width, the number is either infinite, NaN, |
337 | 992 | // or too large to have lower-order bits in the congruent value. (Example: |
338 | 992 | // 2**84 is exactly representable as a double. The next exact double is |
339 | 992 | // 2**84 + 2**32. Thus if UnsignedInteger is uint32_t, an exponent >= 84 |
340 | 992 | // implies floor(abs(d)) == 0 mod 2**32.) Return 0 in all these cases. |
341 | 992 | constexpr size_t ResultWidth = CHAR_BIT * sizeof(UnsignedInteger); |
342 | 992 | if (exponent >= DoubleExponentShift + ResultWidth) { |
343 | 0 | return 0; |
344 | 0 | } |
345 | 992 | |
346 | 992 | // The significand contains the bits that will determine the final result. |
347 | 992 | // Shift those bits left or right, according to the exponent, to their |
348 | 992 | // locations in the unsigned binary representation of floor(abs(d)). |
349 | 992 | static_assert(sizeof(UnsignedInteger) <= sizeof(uint64_t), |
350 | 992 | "left-shifting below would lose upper bits"); |
351 | 992 | UnsignedInteger result = (exponent > DoubleExponentShift) |
352 | 992 | ? UnsignedInteger(bits << (exponent - DoubleExponentShift)) |
353 | 992 | : UnsignedInteger(bits >> (DoubleExponentShift - exponent)); |
354 | 992 | |
355 | 992 | // Two further complications remain. First, |result| may contain bogus |
356 | 992 | // sign/exponent bits. Second, IEEE-754 numbers' significands (excluding |
357 | 992 | // subnormals, but we already handled those) have an implicit leading 1 |
358 | 992 | // which may affect the final result. |
359 | 992 | // |
360 | 992 | // It may appear that there's complexity here depending on how ResultWidth |
361 | 992 | // and DoubleExponentShift relate, but it turns out there's not. |
362 | 992 | // |
363 | 992 | // Assume ResultWidth < DoubleExponentShift: |
364 | 992 | // Only right-shifts leave bogus bits in |result|. For this to happen, |
365 | 992 | // we must right-shift by > |DoubleExponentShift - ResultWidth|, implying |
366 | 992 | // |exponent < ResultWidth|. |
367 | 992 | // The implicit leading bit only matters if it appears in the final |
368 | 992 | // result -- if |2**exponent mod 2**ResultWidth != 0|. This implies |
369 | 992 | // |exponent < ResultWidth|. |
370 | 992 | // Otherwise assume ResultWidth >= DoubleExponentShift: |
371 | 992 | // Any left-shift less than |ResultWidth - DoubleExponentShift| leaves |
372 | 992 | // bogus bits in |result|. This implies |exponent < ResultWidth|. Any |
373 | 992 | // right-shift less than |ResultWidth| does too, which implies |
374 | 992 | // |DoubleExponentShift - ResultWidth < exponent|. By assumption, then, |
375 | 992 | // |exponent| is negative, but we excluded that above. So bogus bits |
376 | 992 | // need only |exponent < ResultWidth|. |
377 | 992 | // The implicit leading bit matters identically to the other case, so |
378 | 992 | // again, |exponent < ResultWidth|. |
379 | 992 | if (exponent < ResultWidth) { |
380 | 992 | UnsignedInteger implicitOne = UnsignedInteger(1) << exponent; |
381 | 992 | result &= implicitOne - 1; // remove bogus bits |
382 | 992 | result += implicitOne; // add the implicit bit |
383 | 992 | } |
384 | 992 | |
385 | 992 | // Compute the congruent value in the signed range. |
386 | 992 | return (bits & mozilla::FloatingPoint<double>::kSignBit) ? ~result + 1 : result; |
387 | 992 | } Unexecuted instantiation: unsigned char JS::ToUnsignedInteger<unsigned char>(double) Unexecuted instantiation: unsigned short JS::ToUnsignedInteger<unsigned short>(double) unsigned int JS::ToUnsignedInteger<unsigned int>(double) Line | Count | Source | 314 | 1.38k | { | 315 | 1.38k | static_assert(mozilla::IsUnsigned<UnsignedInteger>::value, | 316 | 1.38k | "UnsignedInteger must be an unsigned type"); | 317 | 1.38k | | 318 | 1.38k | uint64_t bits = mozilla::BitwiseCast<uint64_t>(d); | 319 | 1.38k | unsigned DoubleExponentShift = mozilla::FloatingPoint<double>::kExponentShift; | 320 | 1.38k | | 321 | 1.38k | // Extract the exponent component. (Be careful here! It's not technically | 322 | 1.38k | // the exponent in NaN, infinities, and subnormals.) | 323 | 1.38k | int_fast16_t exp = | 324 | 1.38k | int_fast16_t((bits & mozilla::FloatingPoint<double>::kExponentBits) >> DoubleExponentShift) - | 325 | 1.38k | int_fast16_t(mozilla::FloatingPoint<double>::kExponentBias); | 326 | 1.38k | | 327 | 1.38k | // If the exponent's less than zero, abs(d) < 1, so the result is 0. (This | 328 | 1.38k | // also handles subnormals.) | 329 | 1.38k | if (exp < 0) { | 330 | 389 | return 0; | 331 | 389 | } | 332 | 992 | | 333 | 992 | uint_fast16_t exponent = mozilla::AssertedCast<uint_fast16_t>(exp); | 334 | 992 | | 335 | 992 | // If the exponent is greater than or equal to the bits of precision of a | 336 | 992 | // double plus UnsignedInteger's width, the number is either infinite, NaN, | 337 | 992 | // or too large to have lower-order bits in the congruent value. (Example: | 338 | 992 | // 2**84 is exactly representable as a double. The next exact double is | 339 | 992 | // 2**84 + 2**32. Thus if UnsignedInteger is uint32_t, an exponent >= 84 | 340 | 992 | // implies floor(abs(d)) == 0 mod 2**32.) Return 0 in all these cases. | 341 | 992 | constexpr size_t ResultWidth = CHAR_BIT * sizeof(UnsignedInteger); | 342 | 992 | if (exponent >= DoubleExponentShift + ResultWidth) { | 343 | 0 | return 0; | 344 | 0 | } | 345 | 992 | | 346 | 992 | // The significand contains the bits that will determine the final result. | 347 | 992 | // Shift those bits left or right, according to the exponent, to their | 348 | 992 | // locations in the unsigned binary representation of floor(abs(d)). | 349 | 992 | static_assert(sizeof(UnsignedInteger) <= sizeof(uint64_t), | 350 | 992 | "left-shifting below would lose upper bits"); | 351 | 992 | UnsignedInteger result = (exponent > DoubleExponentShift) | 352 | 992 | ? UnsignedInteger(bits << (exponent - DoubleExponentShift)) | 353 | 992 | : UnsignedInteger(bits >> (DoubleExponentShift - exponent)); | 354 | 992 | | 355 | 992 | // Two further complications remain. First, |result| may contain bogus | 356 | 992 | // sign/exponent bits. Second, IEEE-754 numbers' significands (excluding | 357 | 992 | // subnormals, but we already handled those) have an implicit leading 1 | 358 | 992 | // which may affect the final result. | 359 | 992 | // | 360 | 992 | // It may appear that there's complexity here depending on how ResultWidth | 361 | 992 | // and DoubleExponentShift relate, but it turns out there's not. | 362 | 992 | // | 363 | 992 | // Assume ResultWidth < DoubleExponentShift: | 364 | 992 | // Only right-shifts leave bogus bits in |result|. For this to happen, | 365 | 992 | // we must right-shift by > |DoubleExponentShift - ResultWidth|, implying | 366 | 992 | // |exponent < ResultWidth|. | 367 | 992 | // The implicit leading bit only matters if it appears in the final | 368 | 992 | // result -- if |2**exponent mod 2**ResultWidth != 0|. This implies | 369 | 992 | // |exponent < ResultWidth|. | 370 | 992 | // Otherwise assume ResultWidth >= DoubleExponentShift: | 371 | 992 | // Any left-shift less than |ResultWidth - DoubleExponentShift| leaves | 372 | 992 | // bogus bits in |result|. This implies |exponent < ResultWidth|. Any | 373 | 992 | // right-shift less than |ResultWidth| does too, which implies | 374 | 992 | // |DoubleExponentShift - ResultWidth < exponent|. By assumption, then, | 375 | 992 | // |exponent| is negative, but we excluded that above. So bogus bits | 376 | 992 | // need only |exponent < ResultWidth|. | 377 | 992 | // The implicit leading bit matters identically to the other case, so | 378 | 992 | // again, |exponent < ResultWidth|. | 379 | 992 | if (exponent < ResultWidth) { | 380 | 992 | UnsignedInteger implicitOne = UnsignedInteger(1) << exponent; | 381 | 992 | result &= implicitOne - 1; // remove bogus bits | 382 | 992 | result += implicitOne; // add the implicit bit | 383 | 992 | } | 384 | 992 | | 385 | 992 | // Compute the congruent value in the signed range. | 386 | 992 | return (bits & mozilla::FloatingPoint<double>::kSignBit) ? ~result + 1 : result; | 387 | 992 | } |
Unexecuted instantiation: unsigned long JS::ToUnsignedInteger<unsigned long>(double) Unexecuted instantiation: unsigned long long JS::ToUnsignedInteger<unsigned long long>(double) Unexecuted instantiation: char16_t JS::ToUnsignedInteger<char16_t>(double) |
388 | | |
389 | | template<typename SignedInteger> |
390 | | inline SignedInteger |
391 | | ToSignedInteger(double d) |
392 | 15 | { |
393 | 15 | static_assert(mozilla::IsSigned<SignedInteger>::value, |
394 | 15 | "SignedInteger must be a signed type"); |
395 | 15 | |
396 | 15 | using UnsignedInteger = typename mozilla::MakeUnsigned<SignedInteger>::Type; |
397 | 15 | UnsignedInteger u = ToUnsignedInteger<UnsignedInteger>(d); |
398 | 15 | |
399 | 15 | return mozilla::WrapToSigned(u); |
400 | 15 | } Unexecuted instantiation: signed char JS::ToSignedInteger<signed char>(double) Unexecuted instantiation: short JS::ToSignedInteger<short>(double) int JS::ToSignedInteger<int>(double) Line | Count | Source | 392 | 15 | { | 393 | 15 | static_assert(mozilla::IsSigned<SignedInteger>::value, | 394 | 15 | "SignedInteger must be a signed type"); | 395 | 15 | | 396 | 15 | using UnsignedInteger = typename mozilla::MakeUnsigned<SignedInteger>::Type; | 397 | 15 | UnsignedInteger u = ToUnsignedInteger<UnsignedInteger>(d); | 398 | 15 | | 399 | 15 | return mozilla::WrapToSigned(u); | 400 | 15 | } |
Unexecuted instantiation: long JS::ToSignedInteger<long>(double) Unexecuted instantiation: long long JS::ToSignedInteger<long long>(double) Unexecuted instantiation: char JS::ToSignedInteger<char>(double) |
401 | | |
402 | | // clang crashes compiling this when targeting arm: |
403 | | // https://llvm.org/bugs/show_bug.cgi?id=22974 |
404 | | #if defined (__arm__) && MOZ_IS_GCC |
405 | | |
406 | | template<> |
407 | | inline int32_t |
408 | | ToSignedInteger<int32_t>(double d) |
409 | | { |
410 | | int32_t i; |
411 | | uint32_t tmp0; |
412 | | uint32_t tmp1; |
413 | | uint32_t tmp2; |
414 | | asm ( |
415 | | // We use a pure integer solution here. In the 'softfp' ABI, the argument |
416 | | // will start in r0 and r1, and VFP can't do all of the necessary ECMA |
417 | | // conversions by itself so some integer code will be required anyway. A |
418 | | // hybrid solution is faster on A9, but this pure integer solution is |
419 | | // notably faster for A8. |
420 | | |
421 | | // %0 is the result register, and may alias either of the %[QR]1 registers. |
422 | | // %Q4 holds the lower part of the mantissa. |
423 | | // %R4 holds the sign, exponent, and the upper part of the mantissa. |
424 | | // %1, %2 and %3 are used as temporary values. |
425 | | |
426 | | // Extract the exponent. |
427 | | " mov %1, %R4, LSR #20\n" |
428 | | " bic %1, %1, #(1 << 11)\n" // Clear the sign. |
429 | | |
430 | | // Set the implicit top bit of the mantissa. This clobbers a bit of the |
431 | | // exponent, but we have already extracted that. |
432 | | " orr %R4, %R4, #(1 << 20)\n" |
433 | | |
434 | | // Special Cases |
435 | | // We should return zero in the following special cases: |
436 | | // - Exponent is 0x000 - 1023: +/-0 or subnormal. |
437 | | // - Exponent is 0x7ff - 1023: +/-INFINITY or NaN |
438 | | // - This case is implicitly handled by the standard code path anyway, |
439 | | // as shifting the mantissa up by the exponent will result in '0'. |
440 | | // |
441 | | // The result is composed of the mantissa, prepended with '1' and |
442 | | // bit-shifted left by the (decoded) exponent. Note that because the r1[20] |
443 | | // is the bit with value '1', r1 is effectively already shifted (left) by |
444 | | // 20 bits, and r0 is already shifted by 52 bits. |
445 | | |
446 | | // Adjust the exponent to remove the encoding offset. If the decoded |
447 | | // exponent is negative, quickly bail out with '0' as such values round to |
448 | | // zero anyway. This also catches +/-0 and subnormals. |
449 | | " sub %1, %1, #0xff\n" |
450 | | " subs %1, %1, #0x300\n" |
451 | | " bmi 8f\n" |
452 | | |
453 | | // %1 = (decoded) exponent >= 0 |
454 | | // %R4 = upper mantissa and sign |
455 | | |
456 | | // ---- Lower Mantissa ---- |
457 | | " subs %3, %1, #52\n" // Calculate exp-52 |
458 | | " bmi 1f\n" |
459 | | |
460 | | // Shift r0 left by exp-52. |
461 | | // Ensure that we don't overflow ARM's 8-bit shift operand range. |
462 | | // We need to handle anything up to an 11-bit value here as we know that |
463 | | // 52 <= exp <= 1024 (0x400). Any shift beyond 31 bits results in zero |
464 | | // anyway, so as long as we don't touch the bottom 5 bits, we can use |
465 | | // a logical OR to push long shifts into the 32 <= (exp&0xff) <= 255 range. |
466 | | " bic %2, %3, #0xff\n" |
467 | | " orr %3, %3, %2, LSR #3\n" |
468 | | // We can now perform a straight shift, avoiding the need for any |
469 | | // conditional instructions or extra branches. |
470 | | " mov %Q4, %Q4, LSL %3\n" |
471 | | " b 2f\n" |
472 | | "1:\n" // Shift r0 right by 52-exp. |
473 | | // We know that 0 <= exp < 52, and we can shift up to 255 bits so 52-exp |
474 | | // will always be a valid shift and we can sk%3 the range check for this case. |
475 | | " rsb %3, %1, #52\n" |
476 | | " mov %Q4, %Q4, LSR %3\n" |
477 | | |
478 | | // %1 = (decoded) exponent |
479 | | // %R4 = upper mantissa and sign |
480 | | // %Q4 = partially-converted integer |
481 | | |
482 | | "2:\n" |
483 | | // ---- Upper Mantissa ---- |
484 | | // This is much the same as the lower mantissa, with a few different |
485 | | // boundary checks and some masking to hide the exponent & sign bit in the |
486 | | // upper word. |
487 | | // Note that the upper mantissa is pre-shifted by 20 in %R4, but we shift |
488 | | // it left more to remove the sign and exponent so it is effectively |
489 | | // pre-shifted by 31 bits. |
490 | | " subs %3, %1, #31\n" // Calculate exp-31 |
491 | | " mov %1, %R4, LSL #11\n" // Re-use %1 as a temporary register. |
492 | | " bmi 3f\n" |
493 | | |
494 | | // Shift %R4 left by exp-31. |
495 | | // Avoid overflowing the 8-bit shift range, as before. |
496 | | " bic %2, %3, #0xff\n" |
497 | | " orr %3, %3, %2, LSR #3\n" |
498 | | // Perform the shift. |
499 | | " mov %2, %1, LSL %3\n" |
500 | | " b 4f\n" |
501 | | "3:\n" // Shift r1 right by 31-exp. |
502 | | // We know that 0 <= exp < 31, and we can shift up to 255 bits so 31-exp |
503 | | // will always be a valid shift and we can skip the range check for this case. |
504 | | " rsb %3, %3, #0\n" // Calculate 31-exp from -(exp-31) |
505 | | " mov %2, %1, LSR %3\n" // Thumb-2 can't do "LSR %3" in "orr". |
506 | | |
507 | | // %Q4 = partially-converted integer (lower) |
508 | | // %R4 = upper mantissa and sign |
509 | | // %2 = partially-converted integer (upper) |
510 | | |
511 | | "4:\n" |
512 | | // Combine the converted parts. |
513 | | " orr %Q4, %Q4, %2\n" |
514 | | // Negate the result if we have to, and move it to %0 in the process. To |
515 | | // avoid conditionals, we can do this by inverting on %R4[31], then adding |
516 | | // %R4[31]>>31. |
517 | | " eor %Q4, %Q4, %R4, ASR #31\n" |
518 | | " add %0, %Q4, %R4, LSR #31\n" |
519 | | " b 9f\n" |
520 | | "8:\n" |
521 | | // +/-INFINITY, +/-0, subnormals, NaNs, and anything else out-of-range that |
522 | | // will result in a conversion of '0'. |
523 | | " mov %0, #0\n" |
524 | | "9:\n" |
525 | | : "=r" (i), "=&r" (tmp0), "=&r" (tmp1), "=&r" (tmp2), "=&r" (d) |
526 | | : "4" (d) |
527 | | : "cc" |
528 | | ); |
529 | | return i; |
530 | | } |
531 | | |
532 | | #endif // defined (__arm__) && MOZ_IS_GCC |
533 | | |
534 | | namespace detail { |
535 | | |
536 | | template<typename IntegerType, |
537 | | bool IsUnsigned = mozilla::IsUnsigned<IntegerType>::value> |
538 | | struct ToSignedOrUnsignedInteger; |
539 | | |
540 | | template<typename IntegerType> |
541 | | struct ToSignedOrUnsignedInteger<IntegerType, true> |
542 | | { |
543 | 0 | static IntegerType compute(double d) { |
544 | 0 | return ToUnsignedInteger<IntegerType>(d); |
545 | 0 | } Unexecuted instantiation: JS::detail::ToSignedOrUnsignedInteger<unsigned int, true>::compute(double) Unexecuted instantiation: JS::detail::ToSignedOrUnsignedInteger<unsigned char, true>::compute(double) Unexecuted instantiation: JS::detail::ToSignedOrUnsignedInteger<unsigned short, true>::compute(double) Unexecuted instantiation: JS::detail::ToSignedOrUnsignedInteger<unsigned long, true>::compute(double) Unexecuted instantiation: JS::detail::ToSignedOrUnsignedInteger<unsigned long long, true>::compute(double) Unexecuted instantiation: JS::detail::ToSignedOrUnsignedInteger<char16_t, true>::compute(double) |
546 | | }; |
547 | | |
548 | | template<typename IntegerType> |
549 | | struct ToSignedOrUnsignedInteger<IntegerType, false> |
550 | | { |
551 | 0 | static IntegerType compute(double d) { |
552 | 0 | return ToSignedInteger<IntegerType>(d); |
553 | 0 | } Unexecuted instantiation: JS::detail::ToSignedOrUnsignedInteger<int, false>::compute(double) Unexecuted instantiation: JS::detail::ToSignedOrUnsignedInteger<long, false>::compute(double) Unexecuted instantiation: JS::detail::ToSignedOrUnsignedInteger<signed char, false>::compute(double) Unexecuted instantiation: JS::detail::ToSignedOrUnsignedInteger<short, false>::compute(double) Unexecuted instantiation: JS::detail::ToSignedOrUnsignedInteger<long long, false>::compute(double) Unexecuted instantiation: JS::detail::ToSignedOrUnsignedInteger<char, false>::compute(double) |
554 | | }; |
555 | | |
556 | | } // namespace detail |
557 | | |
558 | | template<typename IntegerType> |
559 | | inline IntegerType |
560 | | ToSignedOrUnsignedInteger(double d) |
561 | 0 | { |
562 | 0 | return detail::ToSignedOrUnsignedInteger<IntegerType>::compute(d); |
563 | 0 | } Unexecuted instantiation: int JS::ToSignedOrUnsignedInteger<int>(double) Unexecuted instantiation: unsigned int JS::ToSignedOrUnsignedInteger<unsigned int>(double) Unexecuted instantiation: long JS::ToSignedOrUnsignedInteger<long>(double) Unexecuted instantiation: signed char JS::ToSignedOrUnsignedInteger<signed char>(double) Unexecuted instantiation: short JS::ToSignedOrUnsignedInteger<short>(double) Unexecuted instantiation: unsigned char JS::ToSignedOrUnsignedInteger<unsigned char>(double) Unexecuted instantiation: unsigned short JS::ToSignedOrUnsignedInteger<unsigned short>(double) Unexecuted instantiation: unsigned long JS::ToSignedOrUnsignedInteger<unsigned long>(double) Unexecuted instantiation: long long JS::ToSignedOrUnsignedInteger<long long>(double) Unexecuted instantiation: unsigned long long JS::ToSignedOrUnsignedInteger<unsigned long long>(double) Unexecuted instantiation: char JS::ToSignedOrUnsignedInteger<char>(double) Unexecuted instantiation: char16_t JS::ToSignedOrUnsignedInteger<char16_t>(double) |
564 | | |
565 | | /* WEBIDL 4.2.4 */ |
566 | | inline int8_t |
567 | | ToInt8(double d) |
568 | 0 | { |
569 | 0 | return ToSignedInteger<int8_t>(d); |
570 | 0 | } |
571 | | |
572 | | /* ECMA-262 7.1.10 ToUInt8() specialized for doubles. */ |
573 | | inline int8_t |
574 | | ToUint8(double d) |
575 | 0 | { |
576 | 0 | return ToUnsignedInteger<uint8_t>(d); |
577 | 0 | } |
578 | | |
579 | | /* WEBIDL 4.2.6 */ |
580 | | inline int16_t |
581 | | ToInt16(double d) |
582 | 0 | { |
583 | 0 | return ToSignedInteger<int16_t>(d); |
584 | 0 | } |
585 | | |
586 | | inline uint16_t |
587 | | ToUint16(double d) |
588 | 0 | { |
589 | 0 | return ToUnsignedInteger<uint16_t>(d); |
590 | 0 | } |
591 | | |
592 | | /* ES5 9.5 ToInt32 (specialized for doubles). */ |
593 | | inline int32_t |
594 | | ToInt32(double d) |
595 | 15 | { |
596 | 15 | return ToSignedInteger<int32_t>(d); |
597 | 15 | } |
598 | | |
599 | | /* ES5 9.6 (specialized for doubles). */ |
600 | | inline uint32_t |
601 | | ToUint32(double d) |
602 | 1.36k | { |
603 | 1.36k | return ToUnsignedInteger<uint32_t>(d); |
604 | 1.36k | } |
605 | | |
606 | | /* WEBIDL 4.2.10 */ |
607 | | inline int64_t |
608 | | ToInt64(double d) |
609 | 0 | { |
610 | 0 | return ToSignedInteger<int64_t>(d); |
611 | 0 | } |
612 | | |
613 | | /* WEBIDL 4.2.11 */ |
614 | | inline uint64_t |
615 | | ToUint64(double d) |
616 | 0 | { |
617 | 0 | return ToUnsignedInteger<uint64_t>(d); |
618 | 0 | } |
619 | | |
620 | | } // namespace JS |
621 | | |
622 | | #endif /* js_Conversions_h */ |