1//===--- LayoutOverrideSource.cpp --Override Record Layouts ---------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9#include "clang/Frontend/LayoutOverrideSource.h"
10#include "clang/AST/Decl.h"
11#include "clang/Basic/CharInfo.h"
12#include "llvm/Support/raw_ostream.h"
13#include <fstream>
14#include <string>
15
16using namespace clang;
17
18/// \brief Parse a simple identifier.
19static std::string parseName(StringRef S) {
20  if (S.empty() || !isIdentifierHead(S[0]))
21    return "";
22
23  unsigned Offset = 1;
24  while (Offset < S.size() && isIdentifierBody(S[Offset]))
25    ++Offset;
26
27  return S.substr(0, Offset).str();
28}
29
30LayoutOverrideSource::LayoutOverrideSource(StringRef Filename) {
31  std::ifstream Input(Filename.str().c_str());
32  if (!Input.is_open())
33    return;
34
35  // Parse the output of -fdump-record-layouts.
36  std::string CurrentType;
37  Layout CurrentLayout;
38  bool ExpectingType = false;
39
40  while (Input.good()) {
41    std::string Line;
42    getline(Input, Line);
43
44    StringRef LineStr(Line);
45
46    // Determine whether the following line will start a
47    if (LineStr.find("*** Dumping AST Record Layout") != StringRef::npos)  {
48      // Flush the last type/layout, if there is one.
49      if (!CurrentType.empty())
50        Layouts[CurrentType] = CurrentLayout;
51      CurrentLayout = Layout();
52
53      ExpectingType = true;
54      continue;
55    }
56
57    // If we're expecting a type, grab it.
58    if (ExpectingType) {
59      ExpectingType = false;
60
61      StringRef::size_type Pos;
62      if ((Pos = LineStr.find("struct ")) != StringRef::npos)
63        LineStr = LineStr.substr(Pos + strlen("struct "));
64      else if ((Pos = LineStr.find("class ")) != StringRef::npos)
65        LineStr = LineStr.substr(Pos + strlen("class "));
66      else if ((Pos = LineStr.find("union ")) != StringRef::npos)
67        LineStr = LineStr.substr(Pos + strlen("union "));
68      else
69        continue;
70
71      // Find the name of the type.
72      CurrentType = parseName(LineStr);
73      CurrentLayout = Layout();
74      continue;
75    }
76
77    // Check for the size of the type.
78    StringRef::size_type Pos = LineStr.find(" Size:");
79    if (Pos != StringRef::npos) {
80      // Skip past the " Size:" prefix.
81      LineStr = LineStr.substr(Pos + strlen(" Size:"));
82
83      unsigned long long Size = 0;
84      (void)LineStr.getAsInteger(10, Size);
85      CurrentLayout.Size = Size;
86      continue;
87    }
88
89    // Check for the alignment of the type.
90    Pos = LineStr.find("Alignment:");
91    if (Pos != StringRef::npos) {
92      // Skip past the "Alignment:" prefix.
93      LineStr = LineStr.substr(Pos + strlen("Alignment:"));
94
95      unsigned long long Alignment = 0;
96      (void)LineStr.getAsInteger(10, Alignment);
97      CurrentLayout.Align = Alignment;
98      continue;
99    }
100
101    // Check for the size/alignment of the type.
102    Pos = LineStr.find("sizeof=");
103    if (Pos != StringRef::npos) {
104      /* Skip past the sizeof= prefix. */
105      LineStr = LineStr.substr(Pos + strlen("sizeof="));
106
107      // Parse size.
108      unsigned long long Size = 0;
109      (void)LineStr.getAsInteger(10, Size);
110      CurrentLayout.Size = Size;
111
112      Pos = LineStr.find("align=");
113      if (Pos != StringRef::npos) {
114        /* Skip past the align= prefix. */
115        LineStr = LineStr.substr(Pos + strlen("align="));
116
117        // Parse alignment.
118        unsigned long long Alignment = 0;
119        (void)LineStr.getAsInteger(10, Alignment);
120        CurrentLayout.Align = Alignment;
121      }
122
123      continue;
124    }
125
126    // Check for the field offsets of the type.
127    Pos = LineStr.find("FieldOffsets: [");
128    if (Pos == StringRef::npos)
129      continue;
130
131    LineStr = LineStr.substr(Pos + strlen("FieldOffsets: ["));
132    while (!LineStr.empty() && isDigit(LineStr[0])) {
133      // Parse this offset.
134      unsigned Idx = 1;
135      while (Idx < LineStr.size() && isDigit(LineStr[Idx]))
136        ++Idx;
137
138      unsigned long long Offset = 0;
139      (void)LineStr.substr(0, Idx).getAsInteger(10, Offset);
140
141      CurrentLayout.FieldOffsets.push_back(Offset);
142
143      // Skip over this offset, the following comma, and any spaces.
144      LineStr = LineStr.substr(Idx + 1);
145      while (!LineStr.empty() && isWhitespace(LineStr[0]))
146        LineStr = LineStr.substr(1);
147    }
148  }
149
150  // Flush the last type/layout, if there is one.
151  if (!CurrentType.empty())
152    Layouts[CurrentType] = CurrentLayout;
153}
154
155bool
156LayoutOverrideSource::layoutRecordType(const RecordDecl *Record,
157  uint64_t &Size, uint64_t &Alignment,
158  llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets,
159  llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets,
160  llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets)
161{
162  // We can't override unnamed declarations.
163  if (!Record->getIdentifier())
164    return false;
165
166  // Check whether we have a layout for this record.
167  llvm::StringMap<Layout>::iterator Known = Layouts.find(Record->getName());
168  if (Known == Layouts.end())
169    return false;
170
171  // Provide field layouts.
172  unsigned NumFields = 0;
173  for (RecordDecl::field_iterator F = Record->field_begin(),
174                               FEnd = Record->field_end();
175       F != FEnd; ++F, ++NumFields) {
176    if (NumFields >= Known->second.FieldOffsets.size())
177      continue;
178
179    FieldOffsets[*F] = Known->second.FieldOffsets[NumFields];
180  }
181
182  // Wrong number of fields.
183  if (NumFields != Known->second.FieldOffsets.size())
184    return false;
185
186  Size = Known->second.Size;
187  Alignment = Known->second.Align;
188  return true;
189}
190
191void LayoutOverrideSource::dump() {
192  raw_ostream &OS = llvm::errs();
193  for (llvm::StringMap<Layout>::iterator L = Layouts.begin(),
194                                      LEnd = Layouts.end();
195       L != LEnd; ++L) {
196    OS << "Type: blah " << L->first() << '\n';
197    OS << "  Size:" << L->second.Size << '\n';
198    OS << "  Alignment:" << L->second.Align << '\n';
199    OS << "  FieldOffsets: [";
200    for (unsigned I = 0, N = L->second.FieldOffsets.size(); I != N; ++I) {
201      if (I)
202        OS << ", ";
203      OS << L->second.FieldOffsets[I];
204    }
205    OS << "]\n";
206  }
207}
208
209