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