LLVM  4.0.0
TypeSerializer.cpp
Go to the documentation of this file.
1 //===- TypeSerialzier.cpp ---------------------------------------*- C++ -*-===//
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 
11 
13 
14 #include <string.h>
15 
16 using namespace llvm;
17 using namespace llvm::codeview;
18 
19 bool TypeSerializer::isInFieldList() const {
20  return TypeKind.hasValue() && *TypeKind == TypeLeafKind::LF_FIELDLIST;
21 }
22 
23 TypeIndex TypeSerializer::calcNextTypeIndex() const {
24  if (LastTypeIndex.isNoneType())
26  else
27  return TypeIndex(LastTypeIndex.getIndex() + 1);
28 }
29 
30 TypeIndex TypeSerializer::incrementTypeIndex() {
31  TypeIndex Previous = LastTypeIndex;
32  LastTypeIndex = calcNextTypeIndex();
33  return Previous;
34 }
35 
36 MutableArrayRef<uint8_t> TypeSerializer::getCurrentSubRecordData() {
37  assert(isInFieldList());
38  return getCurrentRecordData().drop_front(CurrentSegment.length());
39 }
40 
41 MutableArrayRef<uint8_t> TypeSerializer::getCurrentRecordData() {
42  return MutableArrayRef<uint8_t>(RecordBuffer).take_front(Writer.getOffset());
43 }
44 
45 Error TypeSerializer::writeRecordPrefix(TypeLeafKind Kind) {
47  Prefix.RecordKind = Kind;
48  Prefix.RecordLen = 0;
49  if (auto EC = Writer.writeObject(Prefix))
50  return EC;
51  return Error::success();
52 }
53 
55 TypeSerializer::insertRecordBytesPrivate(MutableArrayRef<uint8_t> Record) {
56  assert(Record.size() % 4 == 0 && "Record is not aligned to 4 bytes!");
57 
58  StringRef S(reinterpret_cast<const char *>(Record.data()), Record.size());
59 
60  TypeIndex NextTypeIndex = calcNextTypeIndex();
61  auto Result = HashedRecords.try_emplace(S, NextTypeIndex);
62  if (Result.second) {
63  LastTypeIndex = NextTypeIndex;
64  SeenRecords.push_back(Record);
65  }
66  return Result.first->getValue();
67 }
68 
70 TypeSerializer::addPadding(MutableArrayRef<uint8_t> Record) {
71  uint32_t Align = Record.size() % 4;
72  if (Align == 0)
73  return Record;
74 
75  int PaddingBytes = 4 - Align;
76  int N = PaddingBytes;
77  while (PaddingBytes > 0) {
78  uint8_t Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes);
79  if (auto EC = Writer.writeInteger(Pad))
80  return std::move(EC);
81  --PaddingBytes;
82  }
83  return MutableArrayRef<uint8_t>(Record.data(), Record.size() + N);
84 }
85 
87  : RecordStorage(Storage), LastTypeIndex(),
88  RecordBuffer(MaxRecordLength * 2), Stream(RecordBuffer), Writer(Stream),
89  Mapping(Writer) {
90  // RecordBuffer needs to be able to hold enough data so that if we are 1
91  // byte short of MaxRecordLen, and then we try to write MaxRecordLen bytes,
92  // we won't overflow.
93 }
94 
96  return SeenRecords;
97 }
98 
99 TypeIndex TypeSerializer::getLastTypeIndex() const { return LastTypeIndex; }
100 
102  assert(!TypeKind.hasValue() && "Already in a type mapping!");
103  assert(Writer.getOffset() == 0 && "Stream has data already!");
104 
105  return insertRecordBytesPrivate(Record);
106 }
107 
109  assert(!TypeKind.hasValue() && "Already in a type mapping!");
110  assert(Writer.getOffset() == 0 && "Stream has data already!");
111 
112  if (auto EC = writeRecordPrefix(Record.kind()))
113  return EC;
114 
115  TypeKind = Record.kind();
116  if (auto EC = Mapping.visitTypeBegin(Record))
117  return EC;
118 
119  return Error::success();
120 }
121 
123  assert(TypeKind.hasValue() && "Not in a type mapping!");
124  if (auto EC = Mapping.visitTypeEnd(Record))
125  return std::move(EC);
126 
127  // Update the record's length and fill out the CVType members to point to
128  // the stable memory holding the record's data.
129  auto ThisRecordData = getCurrentRecordData();
130  auto ExpectedData = addPadding(ThisRecordData);
131  if (!ExpectedData)
132  return ExpectedData.takeError();
133  ThisRecordData = *ExpectedData;
134 
135  RecordPrefix *Prefix =
136  reinterpret_cast<RecordPrefix *>(ThisRecordData.data());
137  Prefix->RecordLen = ThisRecordData.size() - sizeof(uint16_t);
138 
139  uint8_t *Copy = RecordStorage.Allocate<uint8_t>(ThisRecordData.size());
140  ::memcpy(Copy, ThisRecordData.data(), ThisRecordData.size());
141  ThisRecordData = MutableArrayRef<uint8_t>(Copy, ThisRecordData.size());
142  Record = CVType(*TypeKind, ThisRecordData);
143  TypeIndex InsertedTypeIndex = insertRecordBytesPrivate(ThisRecordData);
144 
145  // Write out each additional segment in reverse order, and update each
146  // record's continuation index to point to the previous one.
147  for (auto X : reverse(FieldListSegments)) {
148  auto CIBytes = X.take_back(sizeof(uint32_t));
150  reinterpret_cast<support::ulittle32_t *>(CIBytes.data());
151  assert(*CI == 0xB0C0B0C0 && "Invalid TypeIndex placeholder");
152  *CI = InsertedTypeIndex.getIndex();
153  InsertedTypeIndex = insertRecordBytesPrivate(X);
154  }
155 
156  TypeKind.reset();
157  Writer.setOffset(0);
158  FieldListSegments.clear();
159  CurrentSegment.SubRecords.clear();
160 
161  return InsertedTypeIndex;
162 }
163 
165  auto ExpectedIndex = visitTypeEndGetIndex(Record);
166  if (!ExpectedIndex)
167  return ExpectedIndex.takeError();
168  return Error::success();
169 }
170 
172  assert(isInFieldList() && "Not in a field list!");
173  assert(!MemberKind.hasValue() && "Already in a member record!");
174  MemberKind = Record.Kind;
175 
176  if (auto EC = Mapping.visitMemberBegin(Record))
177  return EC;
178 
179  return Error::success();
180 }
181 
183  if (auto EC = Mapping.visitMemberEnd(Record))
184  return EC;
185 
186  // Check if this subrecord makes the current segment not fit in 64K minus
187  // the space for a continuation record (8 bytes). If the segment does not
188  // fit, insert a continuation record.
189  if (Writer.getOffset() > MaxRecordLength - ContinuationLength) {
190  MutableArrayRef<uint8_t> Data = getCurrentRecordData();
191  SubRecord LastSubRecord = CurrentSegment.SubRecords.back();
192  uint32_t CopySize = CurrentSegment.length() - LastSubRecord.Size;
193  auto CopyData = Data.take_front(CopySize);
194  auto LeftOverData = Data.drop_front(CopySize);
195  assert(LastSubRecord.Size == LeftOverData.size());
196 
197  // Allocate stable storage for the record and copy the old record plus
198  // continuation over.
199  uint16_t LengthWithSize = CopySize + ContinuationLength;
200  assert(LengthWithSize <= MaxRecordLength);
201  RecordPrefix *Prefix = reinterpret_cast<RecordPrefix *>(CopyData.data());
202  Prefix->RecordLen = LengthWithSize - sizeof(uint16_t);
203 
204  uint8_t *SegmentBytes = RecordStorage.Allocate<uint8_t>(LengthWithSize);
205  auto SavedSegment = MutableArrayRef<uint8_t>(SegmentBytes, LengthWithSize);
206  msf::MutableByteStream CS(SavedSegment);
207  msf::StreamWriter CW(CS);
208  if (auto EC = CW.writeBytes(CopyData))
209  return EC;
210  if (auto EC = CW.writeEnum(TypeLeafKind::LF_INDEX))
211  return EC;
212  if (auto EC = CW.writeInteger(uint16_t(0)))
213  return EC;
214  if (auto EC = CW.writeInteger(uint32_t(0xB0C0B0C0)))
215  return EC;
216  FieldListSegments.push_back(SavedSegment);
217 
218  // Write a new placeholder record prefix to mark the start of this new
219  // top-level record.
220  Writer.setOffset(0);
221  if (auto EC = writeRecordPrefix(TypeLeafKind::LF_FIELDLIST))
222  return EC;
223 
224  // Then move over the subrecord that overflowed the old segment to the
225  // beginning of this segment. Note that we have to use memmove here
226  // instead of Writer.writeBytes(), because the new and old locations
227  // could overlap.
228  ::memmove(Stream.data().data() + sizeof(RecordPrefix), LeftOverData.data(),
229  LeftOverData.size());
230  // And point the segment writer at the end of that subrecord.
231  Writer.setOffset(LeftOverData.size() + sizeof(RecordPrefix));
232 
233  CurrentSegment.SubRecords.clear();
234  CurrentSegment.SubRecords.push_back(LastSubRecord);
235  }
236 
237  // Update the CVMemberRecord since we may have shifted around or gotten
238  // padded.
239  Record.Data = getCurrentSubRecordData();
240 
241  MemberKind.reset();
242  return Error::success();
243 }
void push_back(const T &Elt)
Definition: SmallVector.h:211
void setOffset(uint32_t Off)
Definition: StreamWriter.h:79
MutableArrayRef< T > take_front(size_t N=1) const
Return a copy of *this with only the first N elements.
Definition: ArrayRef.h:380
bool isNoneType() const
Definition: TypeIndex.h:107
bool hasValue() const
Definition: Optional.h:125
TypeLeafKind
Duplicate copy of the above enum, but using the official CV names.
Definition: CodeView.h:28
ArrayRef< uint8_t > Data
Definition: TypeRecord.h:43
Error visitMemberBegin(CVMemberRecord &Record) override
T * data() const
Definition: ArrayRef.h:322
Error visitTypeEnd(CVType &Record) override
Error visitMemberEnd(CVMemberRecord &Record) override
Tagged union holding either a T or a Error.
Error visitTypeEnd(CVType &Record) override
CVRecord< TypeLeafKind > CVType
Definition: TypeRecord.h:39
Error writeObject(const T &Obj)
Definition: StreamWriter.h:49
auto reverse(ContainerTy &&C, typename std::enable_if< has_rbegin< ContainerTy >::value >::type *=nullptr) -> decltype(make_range(C.rbegin(), C.rend()))
Definition: STLExtras.h:241
ArrayRef< MutableArrayRef< uint8_t > > records() const
Error visitTypeBegin(CVType &Record) override
Paired begin/end actions for all types.
static const uint32_t FirstNonSimpleIndex
Definition: TypeIndex.h:91
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...
Definition: APInt.h:33
A 32-bit type reference.
Definition: TypeIndex.h:89
Kind kind() const
Definition: CVRecord.h:33
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:141
Error writeBytes(ArrayRef< uint8_t > Buffer)
uint32_t getIndex() const
Definition: TypeIndex.h:103
Error visitTypeBegin(CVType &Record) override
Paired begin/end actions for all types.
Allocate memory in an ever growing pool, as if by bump-pointer.
Definition: Allocator.h:138
LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void * Allocate(size_t Size, size_t Alignment)
Allocate space at the specified alignment.
Definition: Allocator.h:212
TypeIndex insertRecordBytes(MutableArrayRef< uint8_t > Record)
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang","erlang-compatible garbage collector")
MutableArrayRef< uint8_t > data() const
Definition: ByteStream.h:112
Error writeInteger(uint8_t Int)
static ErrorSuccess success()
Create a success value.
TypeIndex getLastTypeIndex() const
uint32_t getOffset() const
Definition: StreamWriter.h:80
MutableArrayRef< T > drop_front(size_t N=1) const
Drop the first N elements of the array.
Definition: ArrayRef.h:355
#define N
Error visitMemberEnd(CVMemberRecord &Record) override
const unsigned Kind
void reset()
Definition: Optional.h:108
Error writeEnum(T Num)
Definition: StreamWriter.h:44
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Lightweight error class with error context and mandatory checking.
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:47
Error visitMemberBegin(CVMemberRecord &Record) override
TypeSerializer(BumpPtrAllocator &Storage)
Expected< TypeIndex > visitTypeEndGetIndex(CVType &Record)