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