10b57cec5SDimitry Andric //===- GlobalTypeTableBuilder.cpp -----------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h"
100b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
110b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeView.h"
120b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h"
130b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeIndex.h"
140b57cec5SDimitry Andric #include "llvm/Support/Allocator.h"
1581ad6265SDimitry Andric #include "llvm/Support/ErrorHandling.h"
160b57cec5SDimitry Andric #include <cassert>
170b57cec5SDimitry Andric #include <cstdint>
180b57cec5SDimitry Andric #include <cstring>
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric using namespace llvm;
210b57cec5SDimitry Andric using namespace llvm::codeview;
220b57cec5SDimitry Andric 
nextTypeIndex() const230b57cec5SDimitry Andric TypeIndex GlobalTypeTableBuilder::nextTypeIndex() const {
240b57cec5SDimitry Andric   return TypeIndex::fromArrayIndex(SeenRecords.size());
250b57cec5SDimitry Andric }
260b57cec5SDimitry Andric 
GlobalTypeTableBuilder(BumpPtrAllocator & Storage)270b57cec5SDimitry Andric GlobalTypeTableBuilder::GlobalTypeTableBuilder(BumpPtrAllocator &Storage)
280b57cec5SDimitry Andric     : RecordStorage(Storage) {
290b57cec5SDimitry Andric   SeenRecords.reserve(4096);
300b57cec5SDimitry Andric }
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric GlobalTypeTableBuilder::~GlobalTypeTableBuilder() = default;
330b57cec5SDimitry Andric 
getFirst()34bdd1243dSDimitry Andric std::optional<TypeIndex> GlobalTypeTableBuilder::getFirst() {
350b57cec5SDimitry Andric   if (empty())
36bdd1243dSDimitry Andric     return std::nullopt;
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric   return TypeIndex(TypeIndex::FirstNonSimpleIndex);
390b57cec5SDimitry Andric }
400b57cec5SDimitry Andric 
getNext(TypeIndex Prev)41bdd1243dSDimitry Andric std::optional<TypeIndex> GlobalTypeTableBuilder::getNext(TypeIndex Prev) {
420b57cec5SDimitry Andric   if (++Prev == nextTypeIndex())
43bdd1243dSDimitry Andric     return std::nullopt;
440b57cec5SDimitry Andric   return Prev;
450b57cec5SDimitry Andric }
460b57cec5SDimitry Andric 
getType(TypeIndex Index)470b57cec5SDimitry Andric CVType GlobalTypeTableBuilder::getType(TypeIndex Index) {
480b57cec5SDimitry Andric   CVType Type(SeenRecords[Index.toArrayIndex()]);
490b57cec5SDimitry Andric   return Type;
500b57cec5SDimitry Andric }
510b57cec5SDimitry Andric 
getTypeName(TypeIndex Index)520b57cec5SDimitry Andric StringRef GlobalTypeTableBuilder::getTypeName(TypeIndex Index) {
530b57cec5SDimitry Andric   llvm_unreachable("Method not implemented");
540b57cec5SDimitry Andric }
550b57cec5SDimitry Andric 
contains(TypeIndex Index)560b57cec5SDimitry Andric bool GlobalTypeTableBuilder::contains(TypeIndex Index) {
570b57cec5SDimitry Andric   if (Index.isSimple() || Index.isNoneType())
580b57cec5SDimitry Andric     return false;
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   return Index.toArrayIndex() < SeenRecords.size();
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric 
size()630b57cec5SDimitry Andric uint32_t GlobalTypeTableBuilder::size() { return SeenRecords.size(); }
640b57cec5SDimitry Andric 
capacity()650b57cec5SDimitry Andric uint32_t GlobalTypeTableBuilder::capacity() { return SeenRecords.size(); }
660b57cec5SDimitry Andric 
records() const670b57cec5SDimitry Andric ArrayRef<ArrayRef<uint8_t>> GlobalTypeTableBuilder::records() const {
680b57cec5SDimitry Andric   return SeenRecords;
690b57cec5SDimitry Andric }
700b57cec5SDimitry Andric 
hashes() const710b57cec5SDimitry Andric ArrayRef<GloballyHashedType> GlobalTypeTableBuilder::hashes() const {
720b57cec5SDimitry Andric   return SeenHashes;
730b57cec5SDimitry Andric }
740b57cec5SDimitry Andric 
reset()750b57cec5SDimitry Andric void GlobalTypeTableBuilder::reset() {
760b57cec5SDimitry Andric   HashedRecords.clear();
770b57cec5SDimitry Andric   SeenRecords.clear();
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric 
stabilize(BumpPtrAllocator & Alloc,ArrayRef<uint8_t> Data)805ffd83dbSDimitry Andric static inline ArrayRef<uint8_t> stabilize(BumpPtrAllocator &Alloc,
815ffd83dbSDimitry Andric                                           ArrayRef<uint8_t> Data) {
825ffd83dbSDimitry Andric   uint8_t *Stable = Alloc.Allocate<uint8_t>(Data.size());
835ffd83dbSDimitry Andric   memcpy(Stable, Data.data(), Data.size());
84bdd1243dSDimitry Andric   return ArrayRef(Stable, Data.size());
855ffd83dbSDimitry Andric }
865ffd83dbSDimitry Andric 
insertRecordBytes(ArrayRef<uint8_t> Record)870b57cec5SDimitry Andric TypeIndex GlobalTypeTableBuilder::insertRecordBytes(ArrayRef<uint8_t> Record) {
880b57cec5SDimitry Andric   GloballyHashedType GHT =
890b57cec5SDimitry Andric       GloballyHashedType::hashType(Record, SeenHashes, SeenHashes);
900b57cec5SDimitry Andric   return insertRecordAs(GHT, Record.size(),
910b57cec5SDimitry Andric                         [Record](MutableArrayRef<uint8_t> Data) {
920b57cec5SDimitry Andric                           assert(Data.size() == Record.size());
930b57cec5SDimitry Andric                           ::memcpy(Data.data(), Record.data(), Record.size());
940b57cec5SDimitry Andric                           return Data;
950b57cec5SDimitry Andric                         });
960b57cec5SDimitry Andric }
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric TypeIndex
insertRecord(ContinuationRecordBuilder & Builder)990b57cec5SDimitry Andric GlobalTypeTableBuilder::insertRecord(ContinuationRecordBuilder &Builder) {
1000b57cec5SDimitry Andric   TypeIndex TI;
1010b57cec5SDimitry Andric   auto Fragments = Builder.end(nextTypeIndex());
1020b57cec5SDimitry Andric   assert(!Fragments.empty());
1030b57cec5SDimitry Andric   for (auto C : Fragments)
1040b57cec5SDimitry Andric     TI = insertRecordBytes(C.RecordData);
1050b57cec5SDimitry Andric   return TI;
1060b57cec5SDimitry Andric }
1075ffd83dbSDimitry Andric 
replaceType(TypeIndex & Index,CVType Data,bool Stabilize)1085ffd83dbSDimitry Andric bool GlobalTypeTableBuilder::replaceType(TypeIndex &Index, CVType Data,
1095ffd83dbSDimitry Andric                                          bool Stabilize) {
1105ffd83dbSDimitry Andric   assert(Index.toArrayIndex() < SeenRecords.size() &&
1115ffd83dbSDimitry Andric          "This function cannot be used to insert records!");
1125ffd83dbSDimitry Andric 
1135ffd83dbSDimitry Andric   ArrayRef<uint8_t> Record = Data.data();
1145ffd83dbSDimitry Andric   assert(Record.size() < UINT32_MAX && "Record too big");
1155ffd83dbSDimitry Andric   assert(Record.size() % 4 == 0 &&
1165ffd83dbSDimitry Andric          "The type record size is not a multiple of 4 bytes which will cause "
1175ffd83dbSDimitry Andric          "misalignment in the output TPI stream!");
1185ffd83dbSDimitry Andric 
1195ffd83dbSDimitry Andric   GloballyHashedType Hash =
1205ffd83dbSDimitry Andric       GloballyHashedType::hashType(Record, SeenHashes, SeenHashes);
1215ffd83dbSDimitry Andric   auto Result = HashedRecords.try_emplace(Hash, Index.toArrayIndex());
1225ffd83dbSDimitry Andric   if (!Result.second) {
1235ffd83dbSDimitry Andric     Index = Result.first->second;
1245ffd83dbSDimitry Andric     return false; // The record is already there, at a different location
1255ffd83dbSDimitry Andric   }
1265ffd83dbSDimitry Andric 
1275ffd83dbSDimitry Andric   if (Stabilize)
1285ffd83dbSDimitry Andric     Record = stabilize(RecordStorage, Record);
1295ffd83dbSDimitry Andric 
1305ffd83dbSDimitry Andric   SeenRecords[Index.toArrayIndex()] = Record;
1315ffd83dbSDimitry Andric   SeenHashes[Index.toArrayIndex()] = Hash;
1325ffd83dbSDimitry Andric   return true;
1335ffd83dbSDimitry Andric }
134