blob: 304f3a6ed11ee1da6124281ee1e09a82b626b22c [file] [log] [blame]
Zachary Turnerf04d6e82017-01-20 22:41:15 +00001//===- StringTableBuilder.cpp - PDB String Table ----------------*- C++ -*-===//
Rui Ueyamadcd32932017-01-15 00:36:02 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Adrian McCarthy6b6b8c42017-01-25 22:38:55 +000010#include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h"
Rui Ueyamadcd32932017-01-15 00:36:02 +000011#include "llvm/ADT/ArrayRef.h"
12#include "llvm/DebugInfo/MSF/StreamWriter.h"
Adrian McCarthy6b6b8c42017-01-25 22:38:55 +000013#include "llvm/DebugInfo/PDB/Native/Hash.h"
14#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
Rui Ueyamadcd32932017-01-15 00:36:02 +000015#include "llvm/Support/Endian.h"
16
17using namespace llvm;
18using namespace llvm::support;
19using namespace llvm::support::endian;
20using namespace llvm::pdb;
21
Zachary Turnerf04d6e82017-01-20 22:41:15 +000022uint32_t StringTableBuilder::insert(StringRef S) {
Rui Ueyamadcd32932017-01-15 00:36:02 +000023 auto P = Strings.insert({S, StringSize});
24
25 // If a given string didn't exist in the string table, we want to increment
26 // the string table size.
27 if (P.second)
28 StringSize += S.size() + 1; // +1 for '\0'
29 return P.first->second;
30}
31
32static uint32_t computeBucketCount(uint32_t NumStrings) {
33 // The /names stream is basically an on-disk open-addressing hash table.
34 // Hash collisions are resolved by linear probing. We cannot make
35 // utilization 100% because it will make the linear probing extremely
36 // slow. But lower utilization wastes disk space. As a reasonable
37 // load factor, we choose 80%. We need +1 because slot 0 is reserved.
38 return (NumStrings + 1) * 1.25;
39}
40
Zachary Turner760ad4d2017-01-20 22:42:09 +000041uint32_t StringTableBuilder::finalize() {
Rui Ueyamadcd32932017-01-15 00:36:02 +000042 uint32_t Size = 0;
Zachary Turnerf04d6e82017-01-20 22:41:15 +000043 Size += sizeof(StringTableHeader);
Rui Ueyamadcd32932017-01-15 00:36:02 +000044 Size += StringSize;
Zachary Turner760ad4d2017-01-20 22:42:09 +000045 Size += sizeof(uint32_t); // Hash table begins with 4-byte size field.
Rui Ueyamadcd32932017-01-15 00:36:02 +000046
47 uint32_t BucketCount = computeBucketCount(Strings.size());
Zachary Turner760ad4d2017-01-20 22:42:09 +000048 Size += BucketCount * sizeof(uint32_t);
Rui Ueyamadcd32932017-01-15 00:36:02 +000049
Zachary Turner760ad4d2017-01-20 22:42:09 +000050 Size +=
51 sizeof(uint32_t); // The /names stream ends with the number of strings.
Rui Ueyamadcd32932017-01-15 00:36:02 +000052 return Size;
53}
54
Zachary Turnerf04d6e82017-01-20 22:41:15 +000055Error StringTableBuilder::commit(msf::StreamWriter &Writer) const {
Rui Ueyamadcd32932017-01-15 00:36:02 +000056 // Write a header
Zachary Turnerf04d6e82017-01-20 22:41:15 +000057 StringTableHeader H;
58 H.Signature = StringTableSignature;
Rui Ueyamadcd32932017-01-15 00:36:02 +000059 H.HashVersion = 1;
60 H.ByteSize = StringSize;
61 if (auto EC = Writer.writeObject(H))
62 return EC;
63
64 // Write a string table.
65 uint32_t StringStart = Writer.getOffset();
66 for (auto Pair : Strings) {
67 StringRef S = Pair.first;
68 uint32_t Offset = Pair.second;
69 Writer.setOffset(StringStart + Offset);
70 if (auto EC = Writer.writeZeroString(S))
71 return EC;
72 }
73 Writer.setOffset(StringStart + StringSize);
74
75 // Write a hash table.
76 uint32_t BucketCount = computeBucketCount(Strings.size());
Zachary Turner181fe172017-02-18 01:35:33 +000077 if (auto EC = Writer.writeInteger(BucketCount, llvm::support::little))
Rui Ueyamadcd32932017-01-15 00:36:02 +000078 return EC;
79 std::vector<ulittle32_t> Buckets(BucketCount);
80
81 for (auto Pair : Strings) {
82 StringRef S = Pair.first;
83 uint32_t Offset = Pair.second;
84 uint32_t Hash = hashStringV1(S);
85
86 for (uint32_t I = 0; I != BucketCount; ++I) {
87 uint32_t Slot = (Hash + I) % BucketCount;
88 if (Slot == 0)
89 continue; // Skip reserved slot
90 if (Buckets[Slot] != 0)
91 continue;
92 Buckets[Slot] = Offset;
93 break;
94 }
95 }
96
97 if (auto EC = Writer.writeArray(ArrayRef<ulittle32_t>(Buckets)))
98 return EC;
Zachary Turner181fe172017-02-18 01:35:33 +000099 if (auto EC = Writer.writeInteger(static_cast<uint32_t>(Strings.size()),
100 llvm::support::little))
Rui Ueyamadcd32932017-01-15 00:36:02 +0000101 return EC;
102 return Error::success();
103}