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