blob: 9d95952a6d3033611834070420927fd9462cca11 [file] [log] [blame]
Hans Wennborg83e6e1e2014-04-30 16:25:02 +00001//===-- StringTableBuilder.cpp - String table building utility ------------===//
2//
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
Rafael Espindola97de4742014-07-03 02:01:39 +000010#include "llvm/MC/StringTableBuilder.h"
Rafael Espindola0169a452015-10-22 15:15:44 +000011#include "llvm/ADT/STLExtras.h"
Hans Wennborgf26bfc12014-09-29 22:43:20 +000012#include "llvm/Support/COFF.h"
13#include "llvm/Support/Endian.h"
Hans Wennborg83e6e1e2014-04-30 16:25:02 +000014
Zachary Turnerc55a5042015-10-22 16:42:31 +000015#include <vector>
16
Hans Wennborg83e6e1e2014-04-30 16:25:02 +000017using namespace llvm;
18
Rafael Espindola758de9c2016-02-19 14:13:52 +000019StringTableBuilder::StringTableBuilder(Kind K, unsigned Alignment)
20 : K(K), Alignment(Alignment) {
Reid Kleckner2214ed82016-01-29 00:49:42 +000021 // Account for leading bytes in table so that offsets returned from add are
22 // correct.
23 switch (K) {
24 case RAW:
25 Size = 0;
26 break;
27 case MachO:
28 case ELF:
29 Size = 1;
30 break;
31 case WinCOFF:
32 Size = 4;
33 break;
34 }
35}
Rafael Espindola21956e42015-10-23 21:48:05 +000036
Rui Ueyama02d71ad2016-05-06 00:51:58 +000037typedef std::pair<CachedHash<StringRef>, size_t> StringPair;
Rui Ueyamadf948522015-10-26 19:58:29 +000038
39// Returns the character at Pos from end of a string.
40static int charTailAt(StringPair *P, size_t Pos) {
Rui Ueyama02d71ad2016-05-06 00:51:58 +000041 StringRef S = P->first.Val;
Rui Ueyamadf948522015-10-26 19:58:29 +000042 if (Pos >= S.size())
43 return -1;
44 return (unsigned char)S[S.size() - Pos - 1];
45}
46
47// Three-way radix quicksort. This is much faster than std::sort with strcmp
48// because it does not compare characters that we already know the same.
Rui Ueyama5579e0b2015-10-27 16:57:50 +000049static void multikey_qsort(StringPair **Begin, StringPair **End, int Pos) {
Rui Ueyamadf948522015-10-26 19:58:29 +000050tailcall:
51 if (End - Begin <= 1)
52 return;
53
54 // Partition items. Items in [Begin, P) are greater than the pivot,
55 // [P, Q) are the same as the pivot, and [Q, End) are less than the pivot.
56 int Pivot = charTailAt(*Begin, Pos);
57 StringPair **P = Begin;
58 StringPair **Q = End;
59 for (StringPair **R = Begin + 1; R < Q;) {
60 int C = charTailAt(*R, Pos);
61 if (C > Pivot)
62 std::swap(*P++, *R++);
63 else if (C < Pivot)
64 std::swap(*--Q, *R);
65 else
66 R++;
Akira Hatanaka8e77dbb2014-09-24 20:37:14 +000067 }
Rui Ueyamadf948522015-10-26 19:58:29 +000068
Rui Ueyama5579e0b2015-10-27 16:57:50 +000069 multikey_qsort(Begin, P, Pos);
70 multikey_qsort(Q, End, Pos);
Rui Ueyamadf948522015-10-26 19:58:29 +000071 if (Pivot != -1) {
72 // qsort(P, Q, Pos + 1), but with tail call optimization.
73 Begin = P;
74 End = Q;
75 ++Pos;
76 goto tailcall;
77 }
Akira Hatanaka8e77dbb2014-09-24 20:37:14 +000078}
79
Rafael Espindola21956e42015-10-23 21:48:05 +000080void StringTableBuilder::finalize() {
Reid Kleckner2214ed82016-01-29 00:49:42 +000081 finalizeStringTable(/*Optimize=*/true);
82}
83
84void StringTableBuilder::finalizeInOrder() {
85 finalizeStringTable(/*Optimize=*/false);
86}
87
88void StringTableBuilder::finalizeStringTable(bool Optimize) {
Rui Ueyama02d71ad2016-05-06 00:51:58 +000089 typedef std::pair<CachedHash<StringRef>, size_t> StringOffsetPair;
Reid Kleckner2214ed82016-01-29 00:49:42 +000090 std::vector<StringOffsetPair *> Strings;
Hans Wennborgf26bfc12014-09-29 22:43:20 +000091 Strings.reserve(StringIndexMap.size());
Reid Kleckner2214ed82016-01-29 00:49:42 +000092 for (StringOffsetPair &P : StringIndexMap)
Rafael Espindolae015f662015-10-22 15:26:35 +000093 Strings.push_back(&P);
Hans Wennborg83e6e1e2014-04-30 16:25:02 +000094
Reid Kleckner2214ed82016-01-29 00:49:42 +000095 if (!Strings.empty()) {
96 // If we're optimizing, sort by name. If not, sort by previously assigned
97 // offset.
98 if (Optimize) {
99 multikey_qsort(&Strings[0], &Strings[0] + Strings.size(), 0);
100 } else {
101 std::sort(Strings.begin(), Strings.end(),
102 [](const StringOffsetPair *LHS, const StringOffsetPair *RHS) {
103 return LHS->second < RHS->second;
104 });
105 }
106 }
Hans Wennborg83e6e1e2014-04-30 16:25:02 +0000107
Rafael Espindolaa9b39442015-10-23 20:15:35 +0000108 switch (K) {
Rafael Espindola21956e42015-10-23 21:48:05 +0000109 case RAW:
110 break;
Hans Wennborg1b1a3992014-10-06 17:05:19 +0000111 case ELF:
112 case MachO:
Hans Wennborgf26bfc12014-09-29 22:43:20 +0000113 // Start the table with a NUL byte.
114 StringTable += '\x00';
Hans Wennborg1b1a3992014-10-06 17:05:19 +0000115 break;
116 case WinCOFF:
Hans Wennborgf26bfc12014-09-29 22:43:20 +0000117 // Make room to write the table size later.
118 StringTable.append(4, '\x00');
Hans Wennborg1b1a3992014-10-06 17:05:19 +0000119 break;
Hans Wennborgf26bfc12014-09-29 22:43:20 +0000120 }
Hans Wennborg83e6e1e2014-04-30 16:25:02 +0000121
122 StringRef Previous;
Reid Kleckner2214ed82016-01-29 00:49:42 +0000123 for (StringOffsetPair *P : Strings) {
Rui Ueyama02d71ad2016-05-06 00:51:58 +0000124 StringRef S = P->first.Val;
Rafael Espindolaa9b39442015-10-23 20:15:35 +0000125 if (K == WinCOFF)
126 assert(S.size() > COFF::NameSize && "Short string in COFF string table!");
Hans Wennborgf26bfc12014-09-29 22:43:20 +0000127
Reid Kleckner2214ed82016-01-29 00:49:42 +0000128 if (Optimize && Previous.endswith(S)) {
Rafael Espindola758de9c2016-02-19 14:13:52 +0000129 size_t Pos = StringTable.size() - S.size() - (K != RAW);
130 if (!(Pos & (Alignment - 1))) {
131 P->second = Pos;
132 continue;
133 }
Hans Wennborg83e6e1e2014-04-30 16:25:02 +0000134 }
135
Rafael Espindola758de9c2016-02-19 14:13:52 +0000136 if (Optimize) {
137 size_t Start = alignTo(StringTable.size(), Alignment);
138 P->second = Start;
139 StringTable.append(Start - StringTable.size(), '\0');
140 } else {
Reid Kleckner2214ed82016-01-29 00:49:42 +0000141 assert(P->second == StringTable.size() &&
142 "different strtab offset after finalization");
Rafael Espindola758de9c2016-02-19 14:13:52 +0000143 }
Reid Kleckner2214ed82016-01-29 00:49:42 +0000144
Rafael Espindolaa9b39442015-10-23 20:15:35 +0000145 StringTable += S;
Rafael Espindola21956e42015-10-23 21:48:05 +0000146 if (K != RAW)
147 StringTable += '\x00';
Rafael Espindolaa9b39442015-10-23 20:15:35 +0000148 Previous = S;
Hans Wennborg83e6e1e2014-04-30 16:25:02 +0000149 }
Hans Wennborgf26bfc12014-09-29 22:43:20 +0000150
Rafael Espindolaa9b39442015-10-23 20:15:35 +0000151 switch (K) {
Rafael Espindola21956e42015-10-23 21:48:05 +0000152 case RAW:
Hans Wennborg1b1a3992014-10-06 17:05:19 +0000153 case ELF:
154 break;
155 case MachO:
156 // Pad to multiple of 4.
157 while (StringTable.size() % 4)
158 StringTable += '\x00';
159 break;
160 case WinCOFF:
161 // Write the table size in the first word.
Hans Wennborgf26bfc12014-09-29 22:43:20 +0000162 assert(StringTable.size() <= std::numeric_limits<uint32_t>::max());
Rafael Espindolaa9b39442015-10-23 20:15:35 +0000163 uint32_t Size = static_cast<uint32_t>(StringTable.size());
Hans Wennborgf26bfc12014-09-29 22:43:20 +0000164 support::endian::write<uint32_t, support::little, support::unaligned>(
Rafael Espindolaa9b39442015-10-23 20:15:35 +0000165 StringTable.data(), Size);
Hans Wennborg1b1a3992014-10-06 17:05:19 +0000166 break;
Hans Wennborgf26bfc12014-09-29 22:43:20 +0000167 }
Rafael Espindola21956e42015-10-23 21:48:05 +0000168
169 Size = StringTable.size();
Hans Wennborgf26bfc12014-09-29 22:43:20 +0000170}
171
172void StringTableBuilder::clear() {
173 StringTable.clear();
174 StringIndexMap.clear();
Hans Wennborg83e6e1e2014-04-30 16:25:02 +0000175}
Rafael Espindolafc063e82015-10-22 18:32:06 +0000176
Rafael Espindolaa9b39442015-10-23 20:15:35 +0000177size_t StringTableBuilder::getOffset(StringRef S) const {
Rafael Espindolafc063e82015-10-22 18:32:06 +0000178 assert(isFinalized());
Rafael Espindolaa9b39442015-10-23 20:15:35 +0000179 auto I = StringIndexMap.find(S);
Rafael Espindolafc063e82015-10-22 18:32:06 +0000180 assert(I != StringIndexMap.end() && "String is not in table!");
181 return I->second;
182}
183
Rafael Espindola21956e42015-10-23 21:48:05 +0000184size_t StringTableBuilder::add(StringRef S) {
Rafael Espindolafc063e82015-10-22 18:32:06 +0000185 assert(!isFinalized());
Rafael Espindola758de9c2016-02-19 14:13:52 +0000186 size_t Start = alignTo(Size, Alignment);
187 auto P = StringIndexMap.insert(std::make_pair(S, Start));
Rafael Espindola21956e42015-10-23 21:48:05 +0000188 if (P.second)
Rafael Espindola758de9c2016-02-19 14:13:52 +0000189 Size = Start + S.size() + (K != RAW);
Rafael Espindola21956e42015-10-23 21:48:05 +0000190 return P.first->second;
Rafael Espindolafc063e82015-10-22 18:32:06 +0000191}