aboutsummaryrefslogtreecommitdiff
path: root/lib/AST/RecordLayoutBuilder.h
blob: 6e4cdd2fe2ee567a1681902236871c4561911773 (plain) (blame)
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
//===- ASTRecordLayoutBuilder.h - Helper class for building record layouts ===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H
#define LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H

#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/DataTypes.h"
#include <map>

namespace clang {
  class ASTContext;
  class ASTRecordLayout;
  class CXXRecordDecl;
  class FieldDecl;
  class ObjCImplementationDecl;
  class ObjCInterfaceDecl;
  class RecordDecl;

class ASTRecordLayoutBuilder {
  ASTContext &Ctx;

  uint64_t Size;
  unsigned Alignment;
  llvm::SmallVector<uint64_t, 16> FieldOffsets;

  /// Packed - Whether the record is packed or not.
  bool Packed;
  
  /// MaxFieldAlignment - The maximum allowed field alignment. This is set by
  /// #pragma pack. 
  unsigned MaxFieldAlignment;
  
  /// DataSize - The data size of the record being laid out.
  uint64_t DataSize;
  
  bool IsUnion;

  uint64_t NonVirtualSize;
  unsigned NonVirtualAlignment;
  const CXXRecordDecl *PrimaryBase;
  bool PrimaryBaseWasVirtual;

  typedef llvm::SmallVector<std::pair<const CXXRecordDecl *, 
                                      uint64_t>, 4> BaseOffsetsTy;
  
  /// Bases - base classes and their offsets from the record.
  BaseOffsetsTy Bases;
  
  // VBases - virtual base classes and their offsets from the record.
  BaseOffsetsTy VBases;

  /// IndirectPrimaryBases - Virtual base classes, direct or indirect, that are
  /// primary base classes for some other direct or indirect base class.
  llvm::SmallSet<const CXXRecordDecl*, 32> IndirectPrimaryBases;
  
  /// EmptyClassOffsets - A map from offsets to empty record decls.
  typedef std::multimap<uint64_t, const CXXRecordDecl *> EmptyClassOffsetsTy;
  EmptyClassOffsetsTy EmptyClassOffsets;
  
  ASTRecordLayoutBuilder(ASTContext &Ctx);

  void Layout(const RecordDecl *D);
  void Layout(const CXXRecordDecl *D);
  void Layout(const ObjCInterfaceDecl *D,
              const ObjCImplementationDecl *Impl);

  void LayoutFields(const RecordDecl *D);
  void LayoutField(const FieldDecl *D);

  void SelectPrimaryBase(const CXXRecordDecl *RD);
  void SelectPrimaryVBase(const CXXRecordDecl *RD,
                          const CXXRecordDecl *&FirstPrimary);
  
  /// IdentifyPrimaryBases - Identify all virtual base classes, direct or 
  /// indirect, that are primary base classes for some other direct or indirect 
  /// base class.
  void IdentifyPrimaryBases(const CXXRecordDecl *RD);
  
  void setPrimaryBase(const CXXRecordDecl *PB, bool Virtual) {
    PrimaryBase = PB;
    PrimaryBaseWasVirtual = Virtual;
  }
  
  bool IsNearlyEmpty(const CXXRecordDecl *RD) const;
  
  /// LayoutBase - Will lay out a base and return the offset where it was 
  /// placed, in bits.
  uint64_t LayoutBase(const CXXRecordDecl *RD);
  
  void LayoutVtable(const CXXRecordDecl *RD);
  void LayoutNonVirtualBases(const CXXRecordDecl *RD);
  void LayoutBaseNonVirtually(const CXXRecordDecl *RD, bool IsVBase);
  void LayoutVirtualBase(const CXXRecordDecl *RD);
  void LayoutVirtualBases(const CXXRecordDecl *RD, const CXXRecordDecl *PB,
                          int64_t Offset,
                                 llvm::SmallSet<const CXXRecordDecl*, 32> &mark,
                     llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary);

  /// canPlaceRecordAtOffset - Return whether a record (either a base class
  /// or a field) can be placed at the given offset. 
  /// Returns false if placing the record will result in two components 
  /// (direct or indirect) of the same type having the same offset.
  bool canPlaceRecordAtOffset(const CXXRecordDecl *RD, uint64_t Offset) const;

  /// canPlaceFieldAtOffset - Return whether a field can be placed at the given
  /// offset.
  bool canPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset) const;

  /// UpdateEmptyClassOffsets - Called after a record (either a base class
  /// or a field) has been placed at the given offset. Will update the
  /// EmptyClassOffsets map if the class is empty or has any empty bases or
  /// fields.
  void UpdateEmptyClassOffsets(const CXXRecordDecl *RD, uint64_t Offset);

  /// UpdateEmptyClassOffsets - Called after a field has been placed at the 
  /// given offset.
  void UpdateEmptyClassOffsets(const FieldDecl *FD, uint64_t Offset);
  
  /// FinishLayout - Finalize record layout. Adjust record size based on the
  /// alignment.
  void FinishLayout();

  void UpdateAlignment(unsigned NewAlignment);

  ASTRecordLayoutBuilder(const ASTRecordLayoutBuilder&);   // DO NOT IMPLEMENT
  void operator=(const ASTRecordLayoutBuilder&); // DO NOT IMPLEMENT
public:
  static const ASTRecordLayout *ComputeLayout(ASTContext &Ctx,
                                              const RecordDecl *RD);
  static const ASTRecordLayout *ComputeLayout(ASTContext &Ctx,
                                              const ObjCInterfaceDecl *D,
                                            const ObjCImplementationDecl *Impl);
};

} // end namespace clang

#endif