blob: a0fb33846fcf7046776f8bcbf4f228cbb1183f86 [file] [log] [blame]
Eugene Zelenkod3a6c892017-02-11 00:27:28 +00001//===- StringTableBuilder.cpp - String table building utility -------------===//
Hans Wennborg83e6e1e2014-04-30 16:25: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
Eugene Zelenkod3a6c892017-02-11 00:27:28 +000010#include "llvm/ADT/CachedHashString.h"
Justin Lebaree34a732016-10-17 22:24:36 +000011#include "llvm/ADT/SmallString.h"
Eugene Zelenkod3a6c892017-02-11 00:27:28 +000012#include "llvm/ADT/StringRef.h"
13#include "llvm/MC/StringTableBuilder.h"
Hans Wennborgf26bfc12014-09-29 22:43:20 +000014#include "llvm/Support/COFF.h"
15#include "llvm/Support/Endian.h"
Eugene Zelenkod3a6c892017-02-11 00:27:28 +000016#include "llvm/Support/MathExtras.h"
Rafael Espindola39751af2016-10-04 22:43:25 +000017#include "llvm/Support/raw_ostream.h"
Eugene Zelenkod3a6c892017-02-11 00:27:28 +000018#include <cassert>
19#include <cstddef>
20#include <cstdint>
21#include <cstring>
22#include <utility>
Zachary Turnerc55a5042015-10-22 16:42:31 +000023#include <vector>
24
Hans Wennborg83e6e1e2014-04-30 16:25:02 +000025using namespace llvm;
26
Eugene Zelenkod3a6c892017-02-11 00:27:28 +000027StringTableBuilder::~StringTableBuilder() = default;
Rafael Espindola39751af2016-10-04 22:43:25 +000028
29void StringTableBuilder::initSize() {
Reid Kleckner2214ed82016-01-29 00:49:42 +000030 // Account for leading bytes in table so that offsets returned from add are
31 // correct.
32 switch (K) {
33 case RAW:
34 Size = 0;
35 break;
36 case MachO:
37 case ELF:
Rafael Espindola39751af2016-10-04 22:43:25 +000038 // Start the table with a NUL byte.
Reid Kleckner2214ed82016-01-29 00:49:42 +000039 Size = 1;
40 break;
41 case WinCOFF:
Rafael Espindola39751af2016-10-04 22:43:25 +000042 // Make room to write the table size later.
Reid Kleckner2214ed82016-01-29 00:49:42 +000043 Size = 4;
44 break;
45 }
46}
Rafael Espindola21956e42015-10-23 21:48:05 +000047
Rafael Espindola39751af2016-10-04 22:43:25 +000048StringTableBuilder::StringTableBuilder(Kind K, unsigned Alignment)
49 : K(K), Alignment(Alignment) {
50 initSize();
51}
52
53void StringTableBuilder::write(raw_ostream &OS) const {
54 assert(isFinalized());
55 SmallString<0> Data;
56 Data.resize(getSize());
Peter Collingbourne28a2ede2017-04-06 00:10:17 +000057 write((uint8_t *)Data.data());
Rafael Espindola39751af2016-10-04 22:43:25 +000058 OS << Data;
59}
60
Eugene Zelenko7975b992017-04-26 22:31:39 +000061using StringPair = std::pair<CachedHashStringRef, size_t>;
Rafael Espindola39751af2016-10-04 22:43:25 +000062
63void StringTableBuilder::write(uint8_t *Buf) const {
64 assert(isFinalized());
65 for (const StringPair &P : StringIndexMap) {
66 StringRef Data = P.first.val();
Rafael Espindola24db10d2016-10-05 16:33:03 +000067 if (!Data.empty())
68 memcpy(Buf + P.second, Data.data(), Data.size());
Rafael Espindola39751af2016-10-04 22:43:25 +000069 }
70 if (K != WinCOFF)
71 return;
72 support::endian::write32le(Buf, Size);
73}
Rui Ueyamadf948522015-10-26 19:58:29 +000074
75// Returns the character at Pos from end of a string.
76static int charTailAt(StringPair *P, size_t Pos) {
Rafael Espindola39751af2016-10-04 22:43:25 +000077 StringRef S = P->first.val();
Rui Ueyamadf948522015-10-26 19:58:29 +000078 if (Pos >= S.size())
79 return -1;
80 return (unsigned char)S[S.size() - Pos - 1];
81}
82
83// Three-way radix quicksort. This is much faster than std::sort with strcmp
84// because it does not compare characters that we already know the same.
Rui Ueyama5579e0b2015-10-27 16:57:50 +000085static void multikey_qsort(StringPair **Begin, StringPair **End, int Pos) {
Rui Ueyamadf948522015-10-26 19:58:29 +000086tailcall:
87 if (End - Begin <= 1)
88 return;
89
90 // Partition items. Items in [Begin, P) are greater than the pivot,
91 // [P, Q) are the same as the pivot, and [Q, End) are less than the pivot.
92 int Pivot = charTailAt(*Begin, Pos);
93 StringPair **P = Begin;
94 StringPair **Q = End;
95 for (StringPair **R = Begin + 1; R < Q;) {
96 int C = charTailAt(*R, Pos);
97 if (C > Pivot)
98 std::swap(*P++, *R++);
99 else if (C < Pivot)
100 std::swap(*--Q, *R);
101 else
102 R++;
Akira Hatanaka8e77dbb2014-09-24 20:37:14 +0000103 }
Rui Ueyamadf948522015-10-26 19:58:29 +0000104
Rui Ueyama5579e0b2015-10-27 16:57:50 +0000105 multikey_qsort(Begin, P, Pos);
106 multikey_qsort(Q, End, Pos);
Rui Ueyamadf948522015-10-26 19:58:29 +0000107 if (Pivot != -1) {
108 // qsort(P, Q, Pos + 1), but with tail call optimization.
109 Begin = P;
110 End = Q;
111 ++Pos;
112 goto tailcall;
113 }
Akira Hatanaka8e77dbb2014-09-24 20:37:14 +0000114}
115
Rafael Espindola21956e42015-10-23 21:48:05 +0000116void StringTableBuilder::finalize() {
Reid Kleckner2214ed82016-01-29 00:49:42 +0000117 finalizeStringTable(/*Optimize=*/true);
118}
119
120void StringTableBuilder::finalizeInOrder() {
121 finalizeStringTable(/*Optimize=*/false);
122}
123
124void StringTableBuilder::finalizeStringTable(bool Optimize) {
Rafael Espindola39751af2016-10-04 22:43:25 +0000125 Finalized = true;
Hans Wennborg83e6e1e2014-04-30 16:25:02 +0000126
Rafael Espindola39751af2016-10-04 22:43:25 +0000127 if (Optimize) {
128 std::vector<StringPair *> Strings;
129 Strings.reserve(StringIndexMap.size());
130 for (StringPair &P : StringIndexMap)
131 Strings.push_back(&P);
132
133 if (!Strings.empty()) {
134 // If we're optimizing, sort by name. If not, sort by previously assigned
135 // offset.
Reid Kleckner2214ed82016-01-29 00:49:42 +0000136 multikey_qsort(&Strings[0], &Strings[0] + Strings.size(), 0);
Reid Kleckner2214ed82016-01-29 00:49:42 +0000137 }
Hans Wennborg83e6e1e2014-04-30 16:25:02 +0000138
Rafael Espindola39751af2016-10-04 22:43:25 +0000139 initSize();
Hans Wennborg83e6e1e2014-04-30 16:25:02 +0000140
Rafael Espindola39751af2016-10-04 22:43:25 +0000141 StringRef Previous;
142 for (StringPair *P : Strings) {
143 StringRef S = P->first.val();
144 if (Previous.endswith(S)) {
145 size_t Pos = Size - S.size() - (K != RAW);
146 if (!(Pos & (Alignment - 1))) {
147 P->second = Pos;
148 continue;
149 }
Rafael Espindola758de9c2016-02-19 14:13:52 +0000150 }
Hans Wennborg83e6e1e2014-04-30 16:25:02 +0000151
Rafael Espindola39751af2016-10-04 22:43:25 +0000152 Size = alignTo(Size, Alignment);
153 P->second = Size;
Reid Kleckner2214ed82016-01-29 00:49:42 +0000154
Rafael Espindola39751af2016-10-04 22:43:25 +0000155 Size += S.size();
156 if (K != RAW)
157 ++Size;
158 Previous = S;
159 }
Hans Wennborg83e6e1e2014-04-30 16:25:02 +0000160 }
Hans Wennborgf26bfc12014-09-29 22:43:20 +0000161
Rafael Espindola39751af2016-10-04 22:43:25 +0000162 if (K == MachO)
163 Size = alignTo(Size, 4); // Pad to multiple of 4.
Hans Wennborgf26bfc12014-09-29 22:43:20 +0000164}
165
166void StringTableBuilder::clear() {
Rafael Espindola39751af2016-10-04 22:43:25 +0000167 Finalized = false;
Hans Wennborgf26bfc12014-09-29 22:43:20 +0000168 StringIndexMap.clear();
Hans Wennborg83e6e1e2014-04-30 16:25:02 +0000169}
Rafael Espindolafc063e82015-10-22 18:32:06 +0000170
Justin Lebaree34a732016-10-17 22:24:36 +0000171size_t StringTableBuilder::getOffset(CachedHashStringRef S) const {
Rafael Espindolafc063e82015-10-22 18:32:06 +0000172 assert(isFinalized());
Rafael Espindolaa9b39442015-10-23 20:15:35 +0000173 auto I = StringIndexMap.find(S);
Rafael Espindolafc063e82015-10-22 18:32:06 +0000174 assert(I != StringIndexMap.end() && "String is not in table!");
175 return I->second;
176}
177
Justin Lebaree34a732016-10-17 22:24:36 +0000178size_t StringTableBuilder::add(CachedHashStringRef S) {
Rafael Espindola39751af2016-10-04 22:43:25 +0000179 if (K == WinCOFF)
180 assert(S.size() > COFF::NameSize && "Short string in COFF string table!");
181
Rafael Espindolafc063e82015-10-22 18:32:06 +0000182 assert(!isFinalized());
Rafael Espindola4a2ef912016-10-14 17:01:39 +0000183 auto P = StringIndexMap.insert(std::make_pair(S, 0));
184 if (P.second) {
185 size_t Start = alignTo(Size, Alignment);
186 P.first->second = Start;
Rafael Espindola758de9c2016-02-19 14:13:52 +0000187 Size = Start + S.size() + (K != RAW);
Rafael Espindola4a2ef912016-10-14 17:01:39 +0000188 }
Rafael Espindola21956e42015-10-23 21:48:05 +0000189 return P.first->second;
Rafael Espindolafc063e82015-10-22 18:32:06 +0000190}