llvm.org GIT mirror llvm / b905a6b
[TrailingObjects] Dynamically realign under-aligned trailing objects. Previously, the code enforced non-decreasing alignment of each trailing type. However, it's easy enough to allow for realignment as needed, and thus avoid the developer having to think about the possiblilities for alignment requirements on all architectures. (E.g. on Linux/x86, a struct with an int64 member is 4-byte aligned, while on other 32-bit archs -- and even with other OSes on x86 -- it has 8-byte alignment. This sort of thing is irritating to have to manually deal with.) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@256533 91177308-0d34-0410-b5e6-96231b3b80d8 James Y Knight 3 years ago
2 changed file(s) with 67 addition(s) and 42 deletion(s). Raw diff Collapse all Expand all
1515 ///
1616 /// The TrailingObject template abstracts away the reinterpret_cast,
1717 /// pointer arithmetic, and size calculations used for the allocation
18 /// and access of appended arrays of objects, as well as asserts that
19 /// the alignment of the classes involved are appropriate for the
20 /// usage. Additionally, it ensures that the base type is final --
21 /// deriving from a class that expects data appended immediately after
22 /// it is typically not safe.
18 /// and access of appended arrays of objects, and takes care that they
19 /// are all allocated at their required alignment. Additionally, it
20 /// ensures that the base type is final -- deriving from a class that
21 /// expects data appended immediately after it is typically not safe.
2322 ///
2423 /// Users are expected to derive from this template, and provide
25 /// numTrailingObjects implementations for each trailing type,
26 /// e.g. like this sample:
24 /// numTrailingObjects implementations for each trailing type except
25 /// the last, e.g. like this sample:
2726 ///
2827 /// \code
2928 /// class VarLengthObj : private TrailingObjects {
3130 ///
3231 /// unsigned NumInts, NumDoubles;
3332 /// size_t numTrailingObjects(OverloadToken) const { return NumInts; }
34 /// size_t numTrailingObjects(OverloadToken) const {
35 /// return NumDoubles;
36 /// }
3733 /// };
3834 /// \endcode
3935 ///
5046 #ifndef LLVM_SUPPORT_TRAILINGOBJECTS_H
5147 #define LLVM_SUPPORT_TRAILINGOBJECTS_H
5248
49 #include "llvm/Support/AlignOf.h"
50 #include "llvm/Support/Compiler.h"
51 #include "llvm/Support/MathExtras.h"
52 #include "llvm/Support/type_traits.h"
5353 #include
5454 #include
55 #include "llvm/Support/AlignOf.h"
56 #include "llvm/Support/Compiler.h"
57 #include "llvm/Support/type_traits.h"
5855
5956 namespace llvm {
6057
148145 using ParentType::getTrailingObjectsImpl;
149146 using ParentType::additionalSizeToAllocImpl;
150147
151 static void verifyTrailingObjectsAssertions() {
152 static_assert(llvm::AlignOf::Alignment >=
153 llvm::AlignOf::Alignment,
154 "A trailing object requires more alignment than the previous "
155 "trailing object provides");
156
157 ParentType::verifyTrailingObjectsAssertions();
148 static LLVM_CONSTEXPR bool requiresRealignment() {
149 return llvm::AlignOf::Alignment < llvm::AlignOf::Alignment;
158150 }
159151
160152 // These two functions are helper functions for
169161 static const NextTy *
170162 getTrailingObjectsImpl(const BaseTy *Obj,
171163 TrailingObjectsBase::OverloadToken) {
172 return reinterpret_cast(
173 TopTrailingObj::getTrailingObjectsImpl(
174 Obj, TrailingObjectsBase::OverloadToken()) +
175 TopTrailingObj::callNumTrailingObjects(
176 Obj, TrailingObjectsBase::OverloadToken()));
164 auto *Ptr = TopTrailingObj::getTrailingObjectsImpl(
165 Obj, TrailingObjectsBase::OverloadToken()) +
166 TopTrailingObj::callNumTrailingObjects(
167 Obj, TrailingObjectsBase::OverloadToken());
168
169 if (requiresRealignment())
170 return reinterpret_cast(
171 llvm::alignAddr(Ptr, llvm::alignOf()));
172 else
173 return reinterpret_cast(Ptr);
177174 }
178175
179176 static NextTy *
180177 getTrailingObjectsImpl(BaseTy *Obj,
181178 TrailingObjectsBase::OverloadToken) {
182 return reinterpret_cast(
183 TopTrailingObj::getTrailingObjectsImpl(
184 Obj, TrailingObjectsBase::OverloadToken()) +
185 TopTrailingObj::callNumTrailingObjects(
186 Obj, TrailingObjectsBase::OverloadToken()));
179 auto *Ptr = TopTrailingObj::getTrailingObjectsImpl(
180 Obj, TrailingObjectsBase::OverloadToken()) +
181 TopTrailingObj::callNumTrailingObjects(
182 Obj, TrailingObjectsBase::OverloadToken());
183
184 if (requiresRealignment())
185 return reinterpret_cast(
186 llvm::alignAddr(Ptr, llvm::alignOf()));
187 else
188 return reinterpret_cast(Ptr);
187189 }
188190
189191 // Helper function for TrailingObjects::additionalSizeToAlloc: this
190192 // function recurses to superclasses, each of which requires one
191193 // fewer size_t argument, and adds its own size.
192194 static LLVM_CONSTEXPR size_t additionalSizeToAllocImpl(
193 size_t Count1,
195 size_t SizeSoFar, size_t Count1,
194196 typename ExtractSecondType::type... MoreCounts) {
195 return sizeof(NextTy) * Count1 + additionalSizeToAllocImpl(MoreCounts...);
197 return additionalSizeToAllocImpl(
198 (requiresRealignment()
199 ? llvm::RoundUpToAlignment(SizeSoFar, llvm::alignOf())
200 : SizeSoFar) +
201 sizeof(NextTy) * Count1,
202 MoreCounts...);
196203 }
197204 };
198205
206213 // up the inheritance chain to subclasses.
207214 static void getTrailingObjectsImpl();
208215
209 static LLVM_CONSTEXPR size_t additionalSizeToAllocImpl() { return 0; }
210
211 static void verifyTrailingObjectsAssertions() {}
216 static LLVM_CONSTEXPR size_t additionalSizeToAllocImpl(size_t SizeSoFar) {
217 return SizeSoFar;
218 }
219
220 template static void verifyTrailingObjectsAlignment() {}
212221 };
213222
214223 } // end namespace trailing_objects_internal
237246
238247 using ParentType::getTrailingObjectsImpl;
239248
240 // Contains static_assert statements for the alignment of the
241 // types. Must not be at class-level, because BaseTy isn't complete
242 // at class instantiation time, but will be by the time this
243 // function is instantiated. Recurses through the superclasses.
249 // This function contains only a static_assert BaseTy is final. The
250 // static_assert must be in a function, and not at class-level
251 // because BaseTy isn't complete at class instantiation time, but
252 // will be by the time this function is instantiated.
244253 static void verifyTrailingObjectsAssertions() {
245254 #ifdef LLVM_IS_FINAL
246255 static_assert(LLVM_IS_FINAL(BaseTy), "BaseTy must be final.");
247256 #endif
248 ParentType::verifyTrailingObjectsAssertions();
249257 }
250258
251259 // These two methods are the base of the recursion for this method.
319327 additionalSizeToAlloc(
320328 typename trailing_objects_internal::ExtractSecondType<
321329 TrailingTys, size_t>::type... Counts) {
322 return ParentType::additionalSizeToAllocImpl(Counts...);
330 return ParentType::additionalSizeToAllocImpl(0, Counts...);
323331 }
324332
325333 /// Returns the total size of an object if it were allocated with the
331339 std::is_same, Foo>::value, size_t>::type
332340 totalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType<
333341 TrailingTys, size_t>::type... Counts) {
334 return sizeof(BaseTy) + ParentType::additionalSizeToAllocImpl(Counts...);
342 return sizeof(BaseTy) + ParentType::additionalSizeToAllocImpl(0, Counts...);
335343 }
336344 };
337345
174174 reinterpret_cast(reinterpret_cast(C + 1) + 1) +
175175 1));
176176 }
177
178 class Class4 final : public TrailingObjects {
179 friend TrailingObjects;
180 size_t numTrailingObjects(OverloadToken) const { return 1; }
181 };
182
183 TEST(TrailingObjects, Realignment) {
184 EXPECT_EQ((Class4::additionalSizeToAlloc(1, 1)),
185 llvm::RoundUpToAlignment(sizeof(long) + 1, llvm::alignOf()));
186 EXPECT_EQ(sizeof(Class4), llvm::RoundUpToAlignment(1, llvm::alignOf()));
187 std::unique_ptr P(new char[1000]);
188 Class4 *C = reinterpret_cast(P.get());
189 EXPECT_EQ(C->getTrailingObjects(), reinterpret_cast(C + 1));
190 EXPECT_EQ(C->getTrailingObjects(),
191 reinterpret_cast(llvm::alignAddr(
192 reinterpret_cast(C + 1) + 1, llvm::alignOf())));
177193 }
194 }