Skip to content

Commit 16160e3

Browse files
committed
Refactor code into tidier classes
New changes: * RecordFieldOrganizer is an interface that can be used to manipulate a RecordDecl's field order. * RecordFieldOrganizer is a "friend" to the DeclContext (which maintains the linked list) * The Randstruct class is a subclass that performs cache friendly randomization
1 parent 73325c9 commit 16160e3

File tree

7 files changed

+104
-43
lines changed

7 files changed

+104
-43
lines changed

clang/include/clang/AST/Decl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class Module;
6565
class NamespaceDecl;
6666
class ParmVarDecl;
6767
class RecordDecl;
68+
class RecordFieldReorganizer;
6869
class Stmt;
6970
class StringLiteral;
7071
class TagDecl;

clang/include/clang/AST/DeclBase.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,8 @@ class DeclContext {
12701270
friend class ExternalASTSource;
12711271
/// For CreateStoredDeclsMap
12721272
friend class DependentDiagnostic;
1273+
/// For fine-grained control of field order
1274+
friend class RecordFieldReorganizer;
12731275
/// For hasNeedToReconcileExternalVisibleStorage,
12741276
/// hasLazyLocalLexicalLookups, hasLazyExternalLexicalLookups
12751277
friend class ASTWriter;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//===-- RecordFieldReorganizer.h - Interface for manipulating field order --*-
2+
// C++
3+
//-*-===//
4+
//
5+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
6+
// See https://llvm.org/LICENSE.txt for license information.
7+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8+
//
9+
//===----------------------------------------------------------------------===//
10+
//
11+
// This header file contains the base class that defines an interface for
12+
// manipulating a RecordDecl's field layouts.
13+
//
14+
//===----------------------------------------------------------------------===//
15+
16+
#ifndef LLVM_CLANG_LIB_AST_RECORDFIELDREORGANIZER_H
17+
#define LLVM_CLANG_LIB_AST_RECORDFIELDREORGANIZER_H
18+
19+
#include "Decl.h"
20+
21+
namespace clang {
22+
23+
// FIXME: Find a better alternative to SmallVector with hardcoded size!
24+
25+
class RecordFieldReorganizer {
26+
public:
27+
virtual ~RecordFieldReorganizer() = default;
28+
void reorganizeFields(const ASTContext &C, const RecordDecl *D) const;
29+
30+
protected:
31+
virtual void reorganize(const ASTContext &C, const RecordDecl *D,
32+
SmallVector<Decl *, 64> &NewOrder) const = 0;
33+
34+
private:
35+
void commit(const RecordDecl *D,
36+
SmallVectorImpl<Decl *> &NewFieldOrder) const;
37+
};
38+
39+
class Randstruct : public RecordFieldReorganizer {
40+
protected:
41+
virtual void reorganize(const ASTContext &C, const RecordDecl *D,
42+
SmallVector<Decl *, 64> &NewOrder) const override;
43+
};
44+
45+
} // namespace clang
46+
47+
#endif

clang/lib/AST/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ add_clang_library(clangAST
4444
InheritViz.cpp
4545
ItaniumCXXABI.cpp
4646
ItaniumMangle.cpp
47-
LayoutFieldRandomizer.cpp
47+
RecordFieldReorganizer.cpp
4848
Mangle.cpp
4949
MicrosoftCXXABI.cpp
5050
MicrosoftMangle.cpp

clang/lib/AST/LayoutFieldRandomizer.h

Lines changed: 0 additions & 27 deletions
This file was deleted.

clang/lib/AST/LayoutFieldRandomizer.cpp renamed to clang/lib/AST/RecordFieldReorganizer.cpp

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===----- LayoutFieldRandomizer.cpp - Randstruct Implementation -*- C++
1+
//===----- RecordFieldReorganizer.cpp - Implementation for field reorder -*- C++
22
//-*-===//
33
//
44
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
@@ -7,20 +7,59 @@
77
//
88
//===----------------------------------------------------------------------===//
99
//
10-
// Cache line best-effort field randomization
10+
// Contains the implementation for RecordDecl field reordering.
1111
//
1212
//===----------------------------------------------------------------------===//
1313

14-
#include "LayoutFieldRandomizer.h"
15-
#include "llvm/ADT/SmallVector.h"
14+
#include "clang/AST/RecordFieldReorganizer.h"
15+
#include "clang/AST/ASTContext.h"
1616

1717
#include <algorithm>
1818
#include <cstdint>
1919
#include <random>
20+
#include <set>
2021
#include <vector>
2122

23+
// FIXME: Find a better alternative to SmallVector with hardcoded size!
24+
2225
namespace clang {
2326

27+
void RecordFieldReorganizer::reorganizeFields(const ASTContext &C,
28+
const RecordDecl *D) const {
29+
// Save original fields for asserting later that a subclass hasn't
30+
// sabotaged the RecordDecl by removing or adding fields
31+
std::set<Decl *> mutateGuard;
32+
33+
SmallVector<Decl *, 64> fields;
34+
for (auto f : D->fields()) {
35+
mutateGuard.insert(f);
36+
fields.push_back(f);
37+
}
38+
39+
// Now allow subclass implementations to reorder the fields
40+
reorganize(C, D, fields);
41+
42+
// Assert all fields are still present
43+
assert(mutateGuard.size() == fields.size() &&
44+
"Field count altered after reorganization");
45+
for (auto f : fields) {
46+
auto found = std::find(std::begin(mutateGuard), std::end(mutateGuard), f);
47+
assert(found != std::end(mutateGuard) &&
48+
"Unknown field encountered after reorganization");
49+
}
50+
51+
commit(D, fields);
52+
}
53+
54+
void RecordFieldReorganizer::commit(
55+
const RecordDecl *D, SmallVectorImpl<Decl *> &NewFieldOrder) const {
56+
Decl *First, *Last;
57+
std::tie(First, Last) = DeclContext::BuildDeclChain(
58+
NewFieldOrder, D->hasLoadedFieldsFromExternalStorage());
59+
D->FirstDecl = First;
60+
D->LastDecl = Last;
61+
}
62+
2463
/// Bucket to store fields up to size of a cache line during randomization.
2564
class Bucket {
2665
public:
@@ -51,11 +90,11 @@ class BitfieldRun : public Bucket {
5190
virtual bool isBitfieldRun() const override;
5291
};
5392

54-
// TODO: Is there a way to detect this? (i.e. on 32bit system vs 64?)
93+
// FIXME: Is there a way to detect this? (i.e. on 32bit system vs 64?)
5594
const size_t CACHE_LINE = 64;
5695

5796
SmallVector<FieldDecl *, 64> Bucket::randomize() {
58-
// TODO use seed
97+
// FIXME use seed
5998
auto rng = std::default_random_engine{};
6099
std::shuffle(std::begin(fields), std::end(fields), rng);
61100
return fields;
@@ -100,10 +139,7 @@ bool BitfieldRun::canFit(size_t size) const {
100139
return true;
101140
}
102141

103-
bool BitfieldRun::isBitfieldRun() const {
104-
// Yes.
105-
return true;
106-
}
142+
bool BitfieldRun::isBitfieldRun() const { return true; }
107143

108144
SmallVector<Decl *, 64> randomize(SmallVector<Decl *, 64> fields) {
109145
auto rng = std::default_random_engine{};
@@ -161,7 +197,6 @@ SmallVector<Decl *, 64> perfrandomize(const ASTContext &ctx,
161197
currentBucket = llvm::make_unique<Bucket>();
162198
}
163199

164-
// FIXME get access to AST Context
165200
auto width = ctx.getTypeInfo(f->getType()).Width;
166201

167202
// If we can fit, add it.
@@ -209,9 +244,10 @@ SmallVector<Decl *, 64> perfrandomize(const ASTContext &ctx,
209244
return finalOrder;
210245
}
211246

212-
SmallVector<Decl *, 64> rearrange(const ASTContext &ctx,
213-
SmallVector<Decl *, 64> fields) {
214-
return perfrandomize(ctx, fields);
247+
void Randstruct::reorganize(const ASTContext &C, const RecordDecl *D,
248+
SmallVector<Decl *, 64> &NewOrder) const {
249+
SmallVector<Decl *, 64> randomized = perfrandomize(C, NewOrder);
250+
NewOrder = randomized;
215251
}
216252

217253
} // namespace clang

clang/lib/AST/RecordLayoutBuilder.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9-
#include "LayoutFieldRandomizer.h"
109
#include "clang/AST/RecordLayout.h"
1110
#include "clang/AST/ASTContext.h"
1211
#include "clang/AST/ASTDiagnostic.h"
@@ -16,6 +15,7 @@
1615
#include "clang/AST/DeclCXX.h"
1716
#include "clang/AST/DeclObjC.h"
1817
#include "clang/AST/Expr.h"
18+
#include "clang/AST/RecordFieldReorganizer.h"
1919
#include "clang/Basic/TargetInfo.h"
2020
#include "llvm/ADT/SmallSet.h"
2121
#include "llvm/Support/Format.h"
@@ -2989,6 +2989,8 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
29892989

29902990
bool ShouldBeRandomized = D->getAttr<RandomizeLayoutAttr>() != nullptr;
29912991
if (ShouldBeRandomized) {
2992+
Randstruct randstruct;
2993+
randstruct.reorganizeFields(*this, D);
29922994
}
29932995

29942996
if (isMsLayout(*this)) {

0 commit comments

Comments
 (0)