summaryrefslogtreecommitdiffstats
path: root/mfbt/Alignment.h
blob: c38e00d12c466e8380930092352175b4db6bde74 (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
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* Functionality related to memory alignment. */

#ifndef mozilla_Alignment_h
#define mozilla_Alignment_h

#include "mozilla/Attributes.h"
#include <stddef.h>
#include <stdint.h>

namespace mozilla {

/*
 * This class, and the corresponding macro MOZ_ALIGNOF, figures out how many
 * bytes of alignment a given type needs.
 */
template <typename T>
class AlignmentFinder {
  struct Aligner {
    char mChar;
    T mT;

    // Aligner may be used to check alignment of types with deleted dtors. This
    // results in such specializations having implicitly deleted dtors, which
    // causes fatal warnings on MSVC (see bug 1481005). As we don't create
    // Aligners, we can avoid this warning by explicitly deleting the dtor.
    ~Aligner() = delete;
  };

 public:
  static const size_t alignment = sizeof(Aligner) - sizeof(T);
};

#define MOZ_ALIGNOF(T) mozilla::AlignmentFinder<T>::alignment

namespace detail {
template <typename T>
struct AlignasHelper {
  T mT;
};
}  // namespace detail

/*
 * Use this instead of alignof to align struct field as if it is inside
 * a struct. On some platforms, there exist types which have different
 * alignment between when it is used on its own and when it is used on
 * a struct field.
 *
 * Known examples are 64bit types (uint64_t, double) on 32bit Linux,
 * where they have 8byte alignment on their own, and 4byte alignment
 * when in struct.
 */
#define MOZ_ALIGNAS_IN_STRUCT(T) alignas(mozilla::detail::AlignasHelper<T>)

/*
 * Declare the MOZ_ALIGNED_DECL macro for declaring aligned types.
 *
 * For instance,
 *
 *   MOZ_ALIGNED_DECL(8, char arr[2]);
 *
 * will declare a two-character array |arr| aligned to 8 bytes.
 */

#if defined(__GNUC__)
#  define MOZ_ALIGNED_DECL(_align, _type) _type __attribute__((aligned(_align)))
#elif defined(_MSC_VER)
#  define MOZ_ALIGNED_DECL(_align, _type) __declspec(align(_align)) _type
#else
#  warning "We don't know how to align variables on this compiler."
#  define MOZ_ALIGNED_DECL(_align, _type) _type
#endif

/*
 * AlignedElem<N> is a structure whose alignment is guaranteed to be at least N
 * bytes.
 *
 * We support 1, 2, 4, 8, and 16-byte alignment.
 */
template <size_t Align>
struct AlignedElem;

/*
 * We have to specialize this template because GCC doesn't like
 * __attribute__((aligned(foo))) where foo is a template parameter.
 */

template <>
struct AlignedElem<1> {
  MOZ_ALIGNED_DECL(1, uint8_t elem);
};

template <>
struct AlignedElem<2> {
  MOZ_ALIGNED_DECL(2, uint8_t elem);
};

template <>
struct AlignedElem<4> {
  MOZ_ALIGNED_DECL(4, uint8_t elem);
};

template <>
struct AlignedElem<8> {
  MOZ_ALIGNED_DECL(8, uint8_t elem);
};

template <>
struct AlignedElem<16> {
  MOZ_ALIGNED_DECL(16, uint8_t elem);
};

template <typename T>
struct MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS AlignedStorage2 {
  union U {
    char mBytes[sizeof(T)];
    uint64_t mDummy;
  } u;

  const T* addr() const { return reinterpret_cast<const T*>(u.mBytes); }
  T* addr() { return static_cast<T*>(static_cast<void*>(u.mBytes)); }

  AlignedStorage2() = default;

  // AlignedStorage2 is non-copyable: the default copy constructor violates
  // strict aliasing rules, per bug 1269319.
  AlignedStorage2(const AlignedStorage2&) = delete;
  void operator=(const AlignedStorage2&) = delete;
};

} /* namespace mozilla */

#endif /* mozilla_Alignment_h */