Coverage Report

Created: 2018-09-25 14:53

/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 */