no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / js / src / util / CheckedArithmetic.h
blob4bab3f440affd1bfa1558f6d9c03329364572703
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
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/. */
7 #ifndef util_CheckedArithmetic_h
8 #define util_CheckedArithmetic_h
10 #include "mozilla/Compiler.h"
11 #include "mozilla/MathAlgorithms.h"
13 #include <stdint.h>
15 // This macro is should be `one' if current compiler supports builtin functions
16 // like __builtin_sadd_overflow.
17 #if MOZ_IS_GCC
18 // GCC supports these functions.
19 # define BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(x) 1
20 #else
21 // For CLANG, we use its own function to check for this.
22 # ifdef __has_builtin
23 # define BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(x) __has_builtin(x)
24 # endif
25 #endif
26 #ifndef BUILTIN_CHECKED_ARITHMETIC_SUPPORTED
27 # define BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(x) 0
28 #endif
30 namespace js {
32 [[nodiscard]] inline bool SafeAdd(int32_t one, int32_t two, int32_t* res) {
33 #if BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(__builtin_sadd_overflow)
34 // Using compiler's builtin function.
35 return !__builtin_sadd_overflow(one, two, res);
36 #else
37 // Use unsigned for the 32-bit operation since signed overflow gets
38 // undefined behavior.
39 *res = uint32_t(one) + uint32_t(two);
40 int64_t ores = (int64_t)one + (int64_t)two;
41 return ores == (int64_t)*res;
42 #endif
45 [[nodiscard]] inline bool SafeSub(int32_t one, int32_t two, int32_t* res) {
46 #if BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(__builtin_ssub_overflow)
47 return !__builtin_ssub_overflow(one, two, res);
48 #else
49 *res = uint32_t(one) - uint32_t(two);
50 int64_t ores = (int64_t)one - (int64_t)two;
51 return ores == (int64_t)*res;
52 #endif
55 [[nodiscard]] inline bool SafeMul(int32_t one, int32_t two, int32_t* res) {
56 #if BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(__builtin_smul_overflow)
57 return !__builtin_smul_overflow(one, two, res);
58 #else
59 *res = uint32_t(one) * uint32_t(two);
60 int64_t ores = (int64_t)one * (int64_t)two;
61 return ores == (int64_t)*res;
62 #endif
65 [[nodiscard]] inline bool SafeMul(uint64_t one, uint64_t two, uint64_t* res) {
66 #if BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(__builtin_mul_overflow)
67 return !__builtin_mul_overflow(one, two, res);
68 #else
69 // Hacker's Delight, 2nd edition, 2-13 Overflow detection, Fig. 2-2.
70 int zeroes =
71 mozilla::CountLeadingZeroes64(one) + mozilla::CountLeadingZeroes64(two);
72 if (zeroes <= 62) {
73 return false;
75 uint64_t half = one * (two >> 1);
76 if (int64_t(half) < 0) {
77 return false;
79 *res = half * 2;
80 if (two & 1) {
81 *res += one;
82 if (*res < one) {
83 return false;
86 return true;
87 #endif
90 } /* namespace js */
92 #endif /* util_CheckedArithmetic_h */