blob: bd51aa413fbb32d40149754ad2493e46e696adcd [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//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Hans Wennborg83e6e1e2014-04-30 16:25:02 +00006//
7//===----------------------------------------------------------------------===//
8
Chandler Carruth6bda14b2017-06-06 11:49:48 +00009#include "llvm/MC/StringTableBuilder.h"
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"
Zachary Turner264b5d92017-06-07 03:48:56 +000013#include "llvm/BinaryFormat/COFF.h"
Hans Wennborgf26bfc12014-09-29 22:43:20 +000014#include "llvm/Support/Endian.h"
Eugene Zelenkod3a6c892017-02-11 00:27:28 +000015#include "llvm/Support/MathExtras.h"
Rafael Espindola39751af2016-10-04 22:43:25 +000016#include "llvm/Support/raw_ostream.h"
Eugene Zelenkod3a6c892017-02-11 00:27:28 +000017#include <cassert>
18#include <cstddef>
19#include <cstdint>
20#include <cstring>
21#include <utility>
Zachary Turnerc55a5042015-10-22 16:42:31 +000022#include <vector>
23
Hans Wennborg83e6e1e2014-04-30 16:25:02 +000024using namespace llvm;
25
Eugene Zelenkod3a6c892017-02-11 00:27:28 +000026StringTableBuilder::~StringTableBuilder() = default;
Rafael Espindola39751af2016-10-04 22:43:25 +000027
28void StringTableBuilder::initSize() {
Reid Kleckner2214ed82016-01-29 00:49:42 +000029 // Account for leading bytes in table so that offsets returned from add are
30 // correct.
31 switch (K) {
32 case RAW:
Paul Robinson1f900292018-02-06 20:29:21 +000033 case DWARF:
Reid Kleckner2214ed82016-01-29 00:49:42 +000034 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 Ueyama15b83272017-10-03 23:12:01 +000085static void multikeySort(MutableArrayRef<StringPair *> Vec, int Pos) {
Rui Ueyamadf948522015-10-26 19:58:29 +000086tailcall:
Rui Ueyama15b83272017-10-03 23:12:01 +000087 if (Vec.size() <= 1)
Rui Ueyamadf948522015-10-26 19:58:29 +000088 return;
89
Rui Ueyama15b83272017-10-03 23:12:01 +000090 // Partition items so that items in [0, I) are greater than the pivot,
91 // [I, J) are the same as the pivot, and [J, Vec.size()) are less than
92 // the pivot.
93 int Pivot = charTailAt(Vec[0], Pos);
94 size_t I = 0;
95 size_t J = Vec.size();
96 for (size_t K = 1; K < J;) {
97 int C = charTailAt(Vec[K], Pos);
Rui Ueyamadf948522015-10-26 19:58:29 +000098 if (C > Pivot)
Rui Ueyama15b83272017-10-03 23:12:01 +000099 std::swap(Vec[I++], Vec[K++]);
Rui Ueyamadf948522015-10-26 19:58:29 +0000100 else if (C < Pivot)
Rui Ueyama15b83272017-10-03 23:12:01 +0000101 std::swap(Vec[--J], Vec[K]);
Rui Ueyamadf948522015-10-26 19:58:29 +0000102 else
Rui Ueyama15b83272017-10-03 23:12:01 +0000103 K++;
Akira Hatanaka8e77dbb2014-09-24 20:37:14 +0000104 }
Rui Ueyamadf948522015-10-26 19:58:29 +0000105
Rui Ueyama15b83272017-10-03 23:12:01 +0000106 multikeySort(Vec.slice(0, I), Pos);
107 multikeySort(Vec.slice(J), Pos);
108
109 // multikeySort(Vec.slice(I, J - I), Pos + 1), but with
110 // tail call optimization.
Rui Ueyamadf948522015-10-26 19:58:29 +0000111 if (Pivot != -1) {
Rui Ueyama15b83272017-10-03 23:12:01 +0000112 Vec = Vec.slice(I, J - I);
Rui Ueyamadf948522015-10-26 19:58:29 +0000113 ++Pos;
114 goto tailcall;
115 }
Akira Hatanaka8e77dbb2014-09-24 20:37:14 +0000116}
117
Rafael Espindola21956e42015-10-23 21:48:05 +0000118void StringTableBuilder::finalize() {
Paul Robinson1f900292018-02-06 20:29:21 +0000119 assert(K != DWARF);
Reid Kleckner2214ed82016-01-29 00:49:42 +0000120 finalizeStringTable(/*Optimize=*/true);
121}
122
123void StringTableBuilder::finalizeInOrder() {
124 finalizeStringTable(/*Optimize=*/false);
125}
126
127void StringTableBuilder::finalizeStringTable(bool Optimize) {
Rafael Espindola39751af2016-10-04 22:43:25 +0000128 Finalized = true;
Hans Wennborg83e6e1e2014-04-30 16:25:02 +0000129
Rafael Espindola39751af2016-10-04 22:43:25 +0000130 if (Optimize) {
131 std::vector<StringPair *> Strings;
132 Strings.reserve(StringIndexMap.size());
133 for (StringPair &P : StringIndexMap)
134 Strings.push_back(&P);
135
Rui Ueyama15b83272017-10-03 23:12:01 +0000136 multikeySort(Strings, 0);
Rafael Espindola39751af2016-10-04 22:43:25 +0000137 initSize();
Hans Wennborg83e6e1e2014-04-30 16:25:02 +0000138
Rafael Espindola39751af2016-10-04 22:43:25 +0000139 StringRef Previous;
140 for (StringPair *P : Strings) {
141 StringRef S = P->first.val();
142 if (Previous.endswith(S)) {
143 size_t Pos = Size - S.size() - (K != RAW);
144 if (!(Pos & (Alignment - 1))) {
145 P->second = Pos;
146 continue;
147 }
Rafael Espindola758de9c2016-02-19 14:13:52 +0000148 }
Hans Wennborg83e6e1e2014-04-30 16:25:02 +0000149
Rafael Espindola39751af2016-10-04 22:43:25 +0000150 Size = alignTo(Size, Alignment);
151 P->second = Size;
Reid Kleckner2214ed82016-01-29 00:49:42 +0000152
Rafael Espindola39751af2016-10-04 22:43:25 +0000153 Size += S.size();
154 if (K != RAW)
155 ++Size;
156 Previous = S;
157 }
Hans Wennborg83e6e1e2014-04-30 16:25:02 +0000158 }
Hans Wennborgf26bfc12014-09-29 22:43:20 +0000159
Rafael Espindola39751af2016-10-04 22:43:25 +0000160 if (K == MachO)
161 Size = alignTo(Size, 4); // Pad to multiple of 4.
Hans Wennborgf26bfc12014-09-29 22:43:20 +0000162}
163
164void StringTableBuilder::clear() {
Rafael Espindola39751af2016-10-04 22:43:25 +0000165 Finalized = false;
Hans Wennborgf26bfc12014-09-29 22:43:20 +0000166 StringIndexMap.clear();
Hans Wennborg83e6e1e2014-04-30 16:25:02 +0000167}
Rafael Espindolafc063e82015-10-22 18:32:06 +0000168
Justin Lebaree34a732016-10-17 22:24:36 +0000169size_t StringTableBuilder::getOffset(CachedHashStringRef S) const {
Rafael Espindolafc063e82015-10-22 18:32:06 +0000170 assert(isFinalized());
Rafael Espindolaa9b39442015-10-23 20:15:35 +0000171 auto I = StringIndexMap.find(S);
Rafael Espindolafc063e82015-10-22 18:32:06 +0000172 assert(I != StringIndexMap.end() && "String is not in table!");
173 return I->second;
174}
175
Justin Lebaree34a732016-10-17 22:24:36 +0000176size_t StringTableBuilder::add(CachedHashStringRef S) {
Rafael Espindola39751af2016-10-04 22:43:25 +0000177 if (K == WinCOFF)
178 assert(S.size() > COFF::NameSize && "Short string in COFF string table!");
179
Rafael Espindolafc063e82015-10-22 18:32:06 +0000180 assert(!isFinalized());
Rafael Espindola4a2ef912016-10-14 17:01:39 +0000181 auto P = StringIndexMap.insert(std::make_pair(S, 0));
182 if (P.second) {
183 size_t Start = alignTo(Size, Alignment);
184 P.first->second = Start;
Rafael Espindola758de9c2016-02-19 14:13:52 +0000185 Size = Start + S.size() + (K != RAW);
Rafael Espindola4a2ef912016-10-14 17:01:39 +0000186 }
Rafael Espindola21956e42015-10-23 21:48:05 +0000187 return P.first->second;
Rafael Espindolafc063e82015-10-22 18:32:06 +0000188}