summaryrefslogtreecommitdiff
path: root/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/compiler_specific.h
blob: 6e6648b118fb14ccb705878a8a4bf2b659288afc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef PARTITION_ALLOC_PARTITION_ALLOC_BASE_COMPILER_SPECIFIC_H_
#define PARTITION_ALLOC_PARTITION_ALLOC_BASE_COMPILER_SPECIFIC_H_

#include "partition_alloc/build_config.h"

// A wrapper around `__has_cpp_attribute`.
#if defined(__has_cpp_attribute)
#define PA_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
#else
#define PA_HAS_CPP_ATTRIBUTE(x) 0
#endif

// A wrapper around `__has_attribute`, similar to PA_HAS_CPP_ATTRIBUTE.
#if defined(__has_attribute)
#define PA_HAS_ATTRIBUTE(x) __has_attribute(x)
#else
#define PA_HAS_ATTRIBUTE(x) 0
#endif

// A wrapper around `__has_builtin`, similar to PA_HAS_CPP_ATTRIBUTE.
#if defined(__has_builtin)
#define PA_HAS_BUILTIN(x) __has_builtin(x)
#else
#define PA_HAS_BUILTIN(x) 0
#endif

// Annotate a function indicating it should not be inlined.
// Use like:
//   NOINLINE void DoStuff() { ... }
#if defined(__clang__) && PA_HAS_ATTRIBUTE(noinline)
#define PA_NOINLINE [[clang::noinline]]
#elif defined(COMPILER_GCC) && PA_HAS_ATTRIBUTE(noinline)
#define PA_NOINLINE __attribute__((noinline))
#elif defined(COMPILER_MSVC)
#define PA_NOINLINE __declspec(noinline)
#else
#define PA_NOINLINE
#endif

#if defined(__clang__) && defined(NDEBUG) && PA_HAS_ATTRIBUTE(always_inline)
#define PA_ALWAYS_INLINE [[clang::always_inline]] inline
#elif defined(COMPILER_GCC) && defined(NDEBUG) && \
    PA_HAS_ATTRIBUTE(always_inline)
#define PA_ALWAYS_INLINE inline __attribute__((__always_inline__))
#elif defined(COMPILER_MSVC) && defined(NDEBUG)
#define PA_ALWAYS_INLINE __forceinline
#else
#define PA_ALWAYS_INLINE inline
#endif

// Annotate a function indicating it should never be tail called. Useful to make
// sure callers of the annotated function are never omitted from call-stacks.
// To provide the complementary behavior (prevent the annotated function from
// being omitted) look at NOINLINE. Also note that this doesn't prevent code
// folding of multiple identical caller functions into a single signature. To
// prevent code folding, see NO_CODE_FOLDING() in base/debug/alias.h.
// Use like:
//   void NOT_TAIL_CALLED FooBar();
#if defined(__clang__) && PA_HAS_ATTRIBUTE(not_tail_called)
#define PA_NOT_TAIL_CALLED [[clang::not_tail_called]]
#else
#define PA_NOT_TAIL_CALLED
#endif

// Specify memory alignment for structs, classes, etc.
// Use like:
//   class PA_ALIGNAS(16) MyClass { ... }
//   PA_ALIGNAS(16) int array[4];
//
// In most places you can use the C++11 keyword "alignas", which is preferred.
//
// Historically, compilers had trouble mixing __attribute__((...)) syntax with
// alignas(...) syntax. However, at least Clang is very accepting nowadays. It
// may be that this macro can be removed entirely.
#if defined(__clang__)
#define PA_ALIGNAS(byte_alignment) alignas(byte_alignment)
#elif defined(COMPILER_MSVC)
#define PA_ALIGNAS(byte_alignment) __declspec(align(byte_alignment))
#elif defined(COMPILER_GCC) && PA_HAS_ATTRIBUTE(aligned)
#define PA_ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
#endif

// In case the compiler supports it PA_NO_UNIQUE_ADDRESS evaluates to the C++20
// attribute [[no_unique_address]]. This allows annotating data members so that
// they need not have an address distinct from all other non-static data members
// of its class.
//
// References:
// * https://en.cppreference.com/w/cpp/language/attributes/no_unique_address
// * https://wg21.link/dcl.attr.nouniqueaddr
#if defined(COMPILER_MSVC) && PA_HAS_CPP_ATTRIBUTE(msvc::no_unique_address)
// Unfortunately MSVC ignores [[no_unique_address]] (see
// https://devblogs.microsoft.com/cppblog/msvc-cpp20-and-the-std-cpp20-switch/#msvc-extensions-and-abi),
// and clang-cl matches it for ABI compatibility reasons. We need to prefer
// [[msvc::no_unique_address]] when available if we actually want any effect.
#define PA_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
#elif PA_HAS_CPP_ATTRIBUTE(no_unique_address)
#define PA_NO_UNIQUE_ADDRESS [[no_unique_address]]
#else
#define PA_NO_UNIQUE_ADDRESS
#endif

// Tells the compiler a function is using a printf-style format string.
// |format_param| is the one-based index of the format string parameter;
// |dots_param| is the one-based index of the "..." parameter.
// For v*printf functions (which take a va_list), pass 0 for dots_param.
// (This is undocumented but matches what the system C headers do.)
// For member functions, the implicit this parameter counts as index 1.
#if (defined(COMPILER_GCC) || defined(__clang__)) && PA_HAS_ATTRIBUTE(format)
#define PA_PRINTF_FORMAT(format_param, dots_param) \
  __attribute__((format(printf, format_param, dots_param)))
#else
#define PA_PRINTF_FORMAT(format_param, dots_param)
#endif

// Sanitizers annotations.
#if PA_HAS_ATTRIBUTE(no_sanitize)
#define PA_NO_SANITIZE(what) __attribute__((no_sanitize(what)))
#endif
#if !defined(PA_NO_SANITIZE)
#define PA_NO_SANITIZE(what)
#endif

// MemorySanitizer annotations.
#if defined(MEMORY_SANITIZER)
#include <sanitizer/msan_interface.h>

// Mark a memory region fully initialized.
// Use this to annotate code that deliberately reads uninitialized data, for
// example a GC scavenging root set pointers from the stack.
#define PA_MSAN_UNPOISON(p, size) __msan_unpoison(p, size)
#else  // MEMORY_SANITIZER
#define PA_MSAN_UNPOISON(p, size)
#endif  // MEMORY_SANITIZER

// Macro for hinting that an expression is likely to be false.
#if !defined(PA_UNLIKELY)
#if defined(COMPILER_GCC) || defined(__clang__)
#define PA_UNLIKELY(x) __builtin_expect(!!(x), 0)
#else
#define PA_UNLIKELY(x) (x)
#endif  // defined(COMPILER_GCC)
#endif  // !defined(PA_UNLIKELY)

#if !defined(PA_LIKELY)
#if defined(COMPILER_GCC) || defined(__clang__)
#define PA_LIKELY(x) __builtin_expect(!!(x), 1)
#else
#define PA_LIKELY(x) (x)
#endif  // defined(COMPILER_GCC)
#endif  // !defined(PA_LIKELY)

// Compiler feature-detection.
// clang.llvm.org/docs/LanguageExtensions.html#has-feature-and-has-extension
#if defined(__has_feature)
#define PA_HAS_FEATURE(FEATURE) __has_feature(FEATURE)
#else
#define PA_HAS_FEATURE(FEATURE) 0
#endif

#if !defined(PA_CPU_ARM_NEON)
#if defined(__arm__)
#if !defined(__ARMEB__) && !defined(__ARM_EABI__) && !defined(__EABI__) && \
    !defined(__VFP_FP__) && !defined(_WIN32_WCE) && !defined(ANDROID)
#error Chromium does not support middle endian architecture
#endif
#if defined(__ARM_NEON__)
#define PA_CPU_ARM_NEON 1
#endif
#endif  // defined(__arm__)
#endif  // !defined(CPU_ARM_NEON)

#if !defined(PA_HAVE_MIPS_MSA_INTRINSICS)
#if defined(__mips_msa) && defined(__mips_isa_rev) && (__mips_isa_rev >= 5)
#define PA_HAVE_MIPS_MSA_INTRINSICS 1
#endif
#endif

// The ANALYZER_ASSUME_TRUE(bool arg) macro adds compiler-specific hints
// to Clang which control what code paths are statically analyzed,
// and is meant to be used in conjunction with assert & assert-like functions.
// The expression is passed straight through if analysis isn't enabled.
//
// ANALYZER_SKIP_THIS_PATH() suppresses static analysis for the current
// codepath and any other branching codepaths that might follow.
#if defined(__clang_analyzer__)

namespace partition_alloc::internal {

inline constexpr bool AnalyzerNoReturn() __attribute__((analyzer_noreturn)) {
  return false;
}

inline constexpr bool AnalyzerAssumeTrue(bool arg) {
  // PartitionAllocAnalyzerNoReturn() is invoked and analysis is terminated if
  // |arg| is false.
  return arg || AnalyzerNoReturn();
}

}  // namespace partition_alloc::internal

#define PA_ANALYZER_ASSUME_TRUE(arg) \
  ::partition_alloc::internal::AnalyzerAssumeTrue(!!(arg))
#define PA_ANALYZER_SKIP_THIS_PATH() \
  static_cast<void>(::partition_alloc::internal::AnalyzerNoReturn())

#else  // !defined(__clang_analyzer__)

#define PA_ANALYZER_ASSUME_TRUE(arg) (arg)
#define PA_ANALYZER_SKIP_THIS_PATH()

#endif  // defined(__clang_analyzer__)

// Use nomerge attribute to disable optimization of merging multiple same calls.
#if defined(__clang__) && PA_HAS_ATTRIBUTE(nomerge)
#define PA_NOMERGE [[clang::nomerge]]
#else
#define PA_NOMERGE
#endif

// Marks a type as being eligible for the "trivial" ABI despite having a
// non-trivial destructor or copy/move constructor. Such types can be relocated
// after construction by simply copying their memory, which makes them eligible
// to be passed in registers. The canonical example is std::unique_ptr.
//
// Use with caution; this has some subtle effects on constructor/destructor
// ordering and will be very incorrect if the type relies on its address
// remaining constant. When used as a function argument (by value), the value
// may be constructed in the caller's stack frame, passed in a register, and
// then used and destructed in the callee's stack frame. A similar thing can
// occur when values are returned.
//
// TRIVIAL_ABI is not needed for types which have a trivial destructor and
// copy/move constructors, such as base::TimeTicks and other POD.
//
// It is also not likely to be effective on types too large to be passed in one
// or two registers on typical target ABIs.
//
// See also:
//   https://clang.llvm.org/docs/AttributeReference.html#trivial-abi
//   https://libcxx.llvm.org/docs/DesignDocs/UniquePtrTrivialAbi.html
#if defined(__clang__) && PA_HAS_ATTRIBUTE(trivial_abi)
#define PA_TRIVIAL_ABI [[clang::trivial_abi]]
#else
#define PA_TRIVIAL_ABI
#endif

// Requires constant initialization. See constinit in C++20. Allows to rely on a
// variable being initialized before execution, and not requiring a global
// constructor.
#if PA_HAS_ATTRIBUTE(require_constant_initialization)
#define PA_CONSTINIT __attribute__((require_constant_initialization))
#endif
#if !defined(PA_CONSTINIT)
#define PA_CONSTINIT
#endif

#if defined(__clang__)
#define PA_GSL_POINTER [[gsl::Pointer]]
#else
#define PA_GSL_POINTER
#endif

// Constexpr destructors were introduced in C++20. PartitionAlloc's minimum
// supported C++ version is C++17.
#if defined(__cpp_constexpr) && __cpp_constexpr >= 201907L
#define PA_CONSTEXPR_DTOR constexpr
#else
#define PA_CONSTEXPR_DTOR
#endif

// PA_LIFETIME_BOUND indicates that a resource owned by a function parameter or
// implicit object parameter is retained by the return value of the annotated
// function (or, for a parameter of a constructor, in the value of the
// constructed object). This attribute causes warnings to be produced if a
// temporary object does not live long enough.
//
// When applied to a reference parameter, the referenced object is assumed to be
// retained by the return value of the function. When applied to a non-reference
// parameter (for example, a pointer or a class type), all temporaries
// referenced by the parameter are assumed to be retained by the return value of
// the function.
//
// See also the upstream documentation:
// https://clang.llvm.org/docs/AttributeReference.html#lifetimebound
//
// This attribute is based on `ABSL_ATTRIBUTE_LIFETIME_BOUND`, but:
// * A separate definition is provided to avoid PartitionAlloc => Abseil
//   dependency
// * The definition is tweaked to avoid `__attribute__(lifetime))` because it
//   can't be applied in the same places as `[[clang::lifetimebound]]`.  In
//   particular `operator T*&() && __attribute__(lifetime))` fails to compile on
//   `clang` with the following error: 'lifetimebound' attribute only applies to
//   parameters and implicit object parameters
#if PA_HAS_CPP_ATTRIBUTE(clang::lifetimebound)
#define PA_LIFETIME_BOUND [[clang::lifetimebound]]
#else
#define PA_LIFETIME_BOUND
#endif

#endif  // PARTITION_ALLOC_PARTITION_ALLOC_BASE_COMPILER_SPECIFIC_H_