xref: /llvm-project/llvm/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp (revision 0060c54e0da6d1429875da2d30895faa7562b706)
1 //===- GlobalTypeTableBuilder.cpp -----------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h"
10 #include "llvm/ADT/ArrayRef.h"
11 #include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h"
12 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
13 #include "llvm/Support/Allocator.h"
14 #include "llvm/Support/ErrorHandling.h"
15 #include <cassert>
16 #include <cstdint>
17 #include <cstring>
18 
19 using namespace llvm;
20 using namespace llvm::codeview;
21 
22 TypeIndex GlobalTypeTableBuilder::nextTypeIndex() const {
23   return TypeIndex::fromArrayIndex(SeenRecords.size());
24 }
25 
26 GlobalTypeTableBuilder::GlobalTypeTableBuilder(BumpPtrAllocator &Storage)
27     : RecordStorage(Storage) {
28   SeenRecords.reserve(4096);
29 }
30 
31 GlobalTypeTableBuilder::~GlobalTypeTableBuilder() = default;
32 
33 std::optional<TypeIndex> GlobalTypeTableBuilder::getFirst() {
34   if (empty())
35     return std::nullopt;
36 
37   return TypeIndex(TypeIndex::FirstNonSimpleIndex);
38 }
39 
40 std::optional<TypeIndex> GlobalTypeTableBuilder::getNext(TypeIndex Prev) {
41   if (++Prev == nextTypeIndex())
42     return std::nullopt;
43   return Prev;
44 }
45 
46 CVType GlobalTypeTableBuilder::getType(TypeIndex Index) {
47   CVType Type(SeenRecords[Index.toArrayIndex()]);
48   return Type;
49 }
50 
51 StringRef GlobalTypeTableBuilder::getTypeName(TypeIndex Index) {
52   llvm_unreachable("Method not implemented");
53 }
54 
55 bool GlobalTypeTableBuilder::contains(TypeIndex Index) {
56   if (Index.isSimple() || Index.isNoneType())
57     return false;
58 
59   return Index.toArrayIndex() < SeenRecords.size();
60 }
61 
62 uint32_t GlobalTypeTableBuilder::size() { return SeenRecords.size(); }
63 
64 uint32_t GlobalTypeTableBuilder::capacity() { return SeenRecords.size(); }
65 
66 ArrayRef<ArrayRef<uint8_t>> GlobalTypeTableBuilder::records() const {
67   return SeenRecords;
68 }
69 
70 ArrayRef<GloballyHashedType> GlobalTypeTableBuilder::hashes() const {
71   return SeenHashes;
72 }
73 
74 void GlobalTypeTableBuilder::reset() {
75   HashedRecords.clear();
76   SeenRecords.clear();
77 }
78 
79 static inline ArrayRef<uint8_t> stabilize(BumpPtrAllocator &Alloc,
80                                           ArrayRef<uint8_t> Data) {
81   uint8_t *Stable = Alloc.Allocate<uint8_t>(Data.size());
82   memcpy(Stable, Data.data(), Data.size());
83   return ArrayRef(Stable, Data.size());
84 }
85 
86 TypeIndex GlobalTypeTableBuilder::insertRecordBytes(ArrayRef<uint8_t> Record) {
87   GloballyHashedType GHT =
88       GloballyHashedType::hashType(Record, SeenHashes, SeenHashes);
89   return insertRecordAs(GHT, Record.size(),
90                         [Record](MutableArrayRef<uint8_t> Data) {
91                           assert(Data.size() == Record.size());
92                           ::memcpy(Data.data(), Record.data(), Record.size());
93                           return Data;
94                         });
95 }
96 
97 TypeIndex
98 GlobalTypeTableBuilder::insertRecord(ContinuationRecordBuilder &Builder) {
99   TypeIndex TI;
100   auto Fragments = Builder.end(nextTypeIndex());
101   assert(!Fragments.empty());
102   for (auto C : Fragments)
103     TI = insertRecordBytes(C.RecordData);
104   return TI;
105 }
106 
107 bool GlobalTypeTableBuilder::replaceType(TypeIndex &Index, CVType Data,
108                                          bool Stabilize) {
109   assert(Index.toArrayIndex() < SeenRecords.size() &&
110          "This function cannot be used to insert records!");
111 
112   ArrayRef<uint8_t> Record = Data.data();
113   assert(Record.size() < UINT32_MAX && "Record too big");
114   assert(Record.size() % 4 == 0 &&
115          "The type record size is not a multiple of 4 bytes which will cause "
116          "misalignment in the output TPI stream!");
117 
118   GloballyHashedType Hash =
119       GloballyHashedType::hashType(Record, SeenHashes, SeenHashes);
120   auto Result = HashedRecords.try_emplace(Hash, Index.toArrayIndex());
121   if (!Result.second) {
122     Index = Result.first->second;
123     return false; // The record is already there, at a different location
124   }
125 
126   if (Stabilize)
127     Record = stabilize(RecordStorage, Record);
128 
129   SeenRecords[Index.toArrayIndex()] = Record;
130   SeenHashes[Index.toArrayIndex()] = Hash;
131   return true;
132 }
133