v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
safe_math_shared_impl.h
Go to the documentation of this file.
1// Copyright 2017 The Chromium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Slightly adapted for inclusion in V8.
6// Copyright 2025 the V8 project authors. All rights reserved.
7
8#ifndef V8_BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
9#define V8_BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
10
11// IWYU pragma: private
12
13#include <concepts>
14#include <type_traits>
15
16#include "build/build_config.h"
18
19#if defined(__asmjs__) || defined(__wasm__)
20// Optimized safe math instructions are incompatible with asmjs.
21#define BASE_HAS_OPTIMIZED_SAFE_MATH (0)
22// Where available use builtin math overflow support on Clang and GCC.
23#elif !defined(__native_client__) && \
24 ((defined(__clang__) && \
25 ((__clang_major__ > 3) || \
26 (__clang_major__ == 3 && __clang_minor__ >= 4))) || \
27 (defined(__GNUC__) && __GNUC__ >= 5))
28#include "src/base/numerics/safe_math_clang_gcc_impl.h" // IWYU pragma: export
29#define BASE_HAS_OPTIMIZED_SAFE_MATH (1)
30#else
31#define BASE_HAS_OPTIMIZED_SAFE_MATH (0)
32#endif
33
34namespace v8::base {
35namespace internal {
36
37// These are the non-functioning boilerplate implementations of the optimized
38// safe math routines.
39#if !BASE_HAS_OPTIMIZED_SAFE_MATH
40template <typename T, typename U>
42 static const bool is_supported = false;
43 template <typename V>
44 static constexpr bool Do(T, U, V*) {
45 // Force a compile failure if instantiated.
46 return CheckOnFailure::template HandleFailure<bool>();
47 }
48};
49
50template <typename T, typename U>
52 static const bool is_supported = false;
53 template <typename V>
54 static constexpr bool Do(T, U, V*) {
55 // Force a compile failure if instantiated.
56 return CheckOnFailure::template HandleFailure<bool>();
57 }
58};
59
60template <typename T, typename U>
62 static const bool is_supported = false;
63 template <typename V>
64 static constexpr bool Do(T, U, V*) {
65 // Force a compile failure if instantiated.
66 return CheckOnFailure::template HandleFailure<bool>();
67 }
68};
69
70template <typename T, typename U>
72 static const bool is_supported = false;
73 template <typename V>
74 static constexpr V Do(T, U) {
75 // Force a compile failure if instantiated.
76 return CheckOnFailure::template HandleFailure<V>();
77 }
78};
79
80template <typename T, typename U>
82 static const bool is_supported = false;
83 template <typename V>
84 static constexpr V Do(T, U) {
85 // Force a compile failure if instantiated.
86 return CheckOnFailure::template HandleFailure<V>();
87 }
88};
89
90template <typename T, typename U>
92 static const bool is_supported = false;
93 template <typename V>
94 static constexpr V Do(T, U) {
95 // Force a compile failure if instantiated.
96 return CheckOnFailure::template HandleFailure<V>();
97 }
98};
99
100template <typename T>
102 static const bool is_supported = false;
103 static constexpr T Do(T) {
104 // Force a compile failure if instantiated.
105 return CheckOnFailure::template HandleFailure<T>();
106 }
107};
108#endif // BASE_HAS_OPTIMIZED_SAFE_MATH
109#undef BASE_HAS_OPTIMIZED_SAFE_MATH
110
111// This is used for UnsignedAbs, where we need to support floating-point
112// template instantiations even though we don't actually support the operations.
113// However, there is no corresponding implementation of e.g. SafeUnsignedAbs,
114// so the float versions will not compile.
115template <typename Numeric>
117
118template <typename Numeric>
119 requires(std::integral<Numeric>)
121 using type = typename std::make_unsigned<Numeric>::type;
122};
123
124template <typename Numeric>
125 requires(std::floating_point<Numeric>)
129
130// Wrap the unary operations to allow SFINAE when instantiating integrals versus
131// floating points. These don't perform any overflow checking. Rather, they
132// exhibit well-defined overflow semantics and rely on the caller to detect
133// if an overflow occurred.
134
135template <typename T>
136 requires(std::integral<T>)
137constexpr T NegateWrapper(T value) {
138 using UnsignedT = typename std::make_unsigned<T>::type;
139 // This will compile to a NEG on Intel, and is normal negation on ARM.
140 return static_cast<T>(UnsignedT(0) - static_cast<UnsignedT>(value));
141}
142
143template <typename T>
144 requires(std::floating_point<T>)
145constexpr T NegateWrapper(T value) {
146 return -value;
147}
148
149template <typename T>
150 requires(std::integral<T>)
151constexpr typename std::make_unsigned<T>::type InvertWrapper(T value) {
152 return ~value;
153}
154
155template <typename T>
156 requires(std::integral<T>)
157constexpr T AbsWrapper(T value) {
158 return static_cast<T>(SafeUnsignedAbs(value));
159}
160
161template <typename T>
162 requires(std::floating_point<T>)
163constexpr T AbsWrapper(T value) {
164 return value < 0 ? -value : value;
165}
166
167template <template <typename, typename> class M, typename L, typename R,
168 typename Math = M<UnderlyingType<L>, UnderlyingType<R>>>
169 requires requires { typename Math::result_type; }
171 using math = Math;
172 using type = typename math::result_type;
173};
174
175// The following macros are just boilerplate for the standard arithmetic
176// operator overloads and variadic function templates. A macro isn't the nicest
177// solution, but it beats rewriting these over and over again.
178#define BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME) \
179 template <typename L, typename R, typename... Args> \
180 constexpr auto CL_ABBR##OP_NAME(L lhs, R rhs, Args... args) { \
181 return CL_ABBR##MathOp<CLASS##OP_NAME##Op, L, R, Args...>(lhs, rhs, \
182 args...); \
183 }
184
185#define BASE_NUMERIC_ARITHMETIC_OPERATORS(CLASS, CL_ABBR, OP_NAME, OP, CMP_OP) \
186 /* Binary arithmetic operator for all CLASS##Numeric operations. */ \
187 template <typename L, typename R> \
188 requires(Is##CLASS##Op<L, R>) \
189 constexpr CLASS##Numeric<typename MathWrapper<CLASS##OP_NAME##Op, L, \
190 R>::type> operator OP(L lhs, \
191 R rhs) { \
192 return decltype(lhs OP rhs)::template MathOp<CLASS##OP_NAME##Op>(lhs, \
193 rhs); \
194 } \
195 /* Assignment arithmetic operator implementation from CLASS##Numeric. */ \
196 template <typename L> \
197 requires std::is_arithmetic_v<L> \
198 template <typename R> \
199 constexpr CLASS##Numeric<L>& CLASS##Numeric<L>::operator CMP_OP(R rhs) { \
200 return MathOp<CLASS##OP_NAME##Op>(rhs); \
201 } \
202 /* Variadic arithmetic functions that return CLASS##Numeric. */ \
203 BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)
204
205} // namespace internal
206} // namespace v8::base
207
208#endif // V8_BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
#define V(Name)
constexpr auto SafeUnsignedAbs(T value)
constexpr T NegateWrapper(T value)
constexpr std::make_unsigned< T >::type InvertWrapper(T value)
UnderlyingTypeImpl< T >::type UnderlyingType
constexpr T AbsWrapper(T value)
static constexpr bool Do(T, U, V *)
static constexpr bool Do(T, U, V *)
static constexpr bool Do(T, U, V *)
typename std::make_unsigned< Numeric >::type type
std::unique_ptr< ValueMirror > value