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