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