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