/src/keystone/llvm/lib/MC/StringTableBuilder.cpp
Line | Count | Source |
1 | | //===-- 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 | | |
10 | | #include "llvm/MC/StringTableBuilder.h" |
11 | | #include "llvm/ADT/STLExtras.h" |
12 | | #include "llvm/Support/COFF.h" |
13 | | #include "llvm/Support/Endian.h" |
14 | | |
15 | | #include <vector> |
16 | | |
17 | | using namespace llvm_ks; |
18 | | |
19 | 128k | StringTableBuilder::StringTableBuilder(Kind K) : K(K) { |
20 | | // Account for leading bytes in table so that offsets returned from add are |
21 | | // correct. |
22 | 128k | switch (K) { |
23 | 0 | case RAW: |
24 | 0 | Size = 0; |
25 | 0 | break; |
26 | 0 | case MachO: |
27 | 128k | case ELF: |
28 | 128k | Size = 1; |
29 | 128k | break; |
30 | 0 | case WinCOFF: |
31 | 0 | Size = 4; |
32 | 0 | break; |
33 | 128k | } |
34 | 128k | } |
35 | | |
36 | | typedef std::pair<StringRef, size_t> StringPair; |
37 | | |
38 | | // Returns the character at Pos from end of a string. |
39 | 0 | static int charTailAt(StringPair *P, size_t Pos) { |
40 | 0 | StringRef S = P->first; |
41 | 0 | if (Pos >= S.size()) |
42 | 0 | return -1; |
43 | 0 | return (unsigned char)S[S.size() - Pos - 1]; |
44 | 0 | } |
45 | | |
46 | | // Three-way radix quicksort. This is much faster than std::sort with strcmp |
47 | | // because it does not compare characters that we already know the same. |
48 | 0 | static void multikey_qsort(StringPair **Begin, StringPair **End, int Pos) { |
49 | 0 | tailcall: |
50 | 0 | if (End - Begin <= 1) |
51 | 0 | return; |
52 | | |
53 | | // Partition items. Items in [Begin, P) are greater than the pivot, |
54 | | // [P, Q) are the same as the pivot, and [Q, End) are less than the pivot. |
55 | 0 | int Pivot = charTailAt(*Begin, Pos); |
56 | 0 | StringPair **P = Begin; |
57 | 0 | StringPair **Q = End; |
58 | 0 | for (StringPair **R = Begin + 1; R < Q;) { |
59 | 0 | int C = charTailAt(*R, Pos); |
60 | 0 | if (C > Pivot) |
61 | 0 | std::swap(*P++, *R++); |
62 | 0 | else if (C < Pivot) |
63 | 0 | std::swap(*--Q, *R); |
64 | 0 | else |
65 | 0 | R++; |
66 | 0 | } |
67 | |
|
68 | 0 | multikey_qsort(Begin, P, Pos); |
69 | 0 | multikey_qsort(Q, End, Pos); |
70 | 0 | if (Pivot != -1) { |
71 | | // qsort(P, Q, Pos + 1), but with tail call optimization. |
72 | 0 | Begin = P; |
73 | 0 | End = Q; |
74 | 0 | ++Pos; |
75 | 0 | goto tailcall; |
76 | 0 | } |
77 | 0 | } |
78 | | |
79 | 0 | void StringTableBuilder::finalize() { |
80 | 0 | finalizeStringTable(/*Optimize=*/true); |
81 | 0 | } |
82 | | |
83 | 0 | void StringTableBuilder::finalizeInOrder() { |
84 | 0 | finalizeStringTable(/*Optimize=*/false); |
85 | 0 | } |
86 | | |
87 | 0 | void StringTableBuilder::finalizeStringTable(bool Optimize) { |
88 | 0 | typedef std::pair<StringRef, size_t> StringOffsetPair; |
89 | 0 | std::vector<StringOffsetPair *> Strings; |
90 | 0 | Strings.reserve(StringIndexMap.size()); |
91 | 0 | for (StringOffsetPair &P : StringIndexMap) |
92 | 0 | Strings.push_back(&P); |
93 | |
|
94 | 0 | if (!Strings.empty()) { |
95 | | // If we're optimizing, sort by name. If not, sort by previously assigned |
96 | | // offset. |
97 | 0 | if (Optimize) { |
98 | 0 | multikey_qsort(&Strings[0], &Strings[0] + Strings.size(), 0); |
99 | 0 | } else { |
100 | 0 | std::sort(Strings.begin(), Strings.end(), |
101 | 0 | [](const StringOffsetPair *LHS, const StringOffsetPair *RHS) { |
102 | 0 | return LHS->second < RHS->second; |
103 | 0 | }); |
104 | 0 | } |
105 | 0 | } |
106 | |
|
107 | 0 | switch (K) { |
108 | 0 | case RAW: |
109 | 0 | break; |
110 | 0 | case ELF: |
111 | 0 | case MachO: |
112 | | // Start the table with a NUL byte. |
113 | 0 | StringTable += '\x00'; |
114 | 0 | break; |
115 | 0 | case WinCOFF: |
116 | | // Make room to write the table size later. |
117 | 0 | StringTable.append(4, '\x00'); |
118 | 0 | break; |
119 | 0 | } |
120 | | |
121 | 0 | StringRef Previous; |
122 | 0 | for (StringOffsetPair *P : Strings) { |
123 | 0 | StringRef S = P->first; |
124 | 0 | if (K == WinCOFF) |
125 | 0 | assert(S.size() > COFF::NameSize && "Short string in COFF string table!"); |
126 | | |
127 | 0 | if (Optimize && Previous.endswith(S)) { |
128 | 0 | P->second = StringTable.size() - S.size() - (K != RAW); |
129 | 0 | continue; |
130 | 0 | } |
131 | | |
132 | 0 | if (Optimize) |
133 | 0 | P->second = StringTable.size(); |
134 | 0 | else |
135 | 0 | assert(P->second == StringTable.size() && |
136 | 0 | "different strtab offset after finalization"); |
137 | | |
138 | 0 | StringTable += S; |
139 | 0 | if (K != RAW) |
140 | 0 | StringTable += '\x00'; |
141 | 0 | Previous = S; |
142 | 0 | } |
143 | | |
144 | 0 | switch (K) { |
145 | 0 | case RAW: |
146 | 0 | case ELF: |
147 | 0 | break; |
148 | 0 | case MachO: |
149 | | // Pad to multiple of 4. |
150 | 0 | while (StringTable.size() % 4) |
151 | 0 | StringTable += '\x00'; |
152 | 0 | break; |
153 | 0 | case WinCOFF: |
154 | | // Write the table size in the first word. |
155 | 0 | assert(StringTable.size() <= std::numeric_limits<uint32_t>::max()); |
156 | 0 | uint32_t Size = static_cast<uint32_t>(StringTable.size()); |
157 | 0 | support::endian::write<uint32_t, support::little, support::unaligned>( |
158 | 0 | StringTable.data(), Size); |
159 | 0 | break; |
160 | 0 | } |
161 | | |
162 | 0 | Size = StringTable.size(); |
163 | 0 | } |
164 | | |
165 | 0 | void StringTableBuilder::clear() { |
166 | 0 | StringTable.clear(); |
167 | 0 | StringIndexMap.clear(); |
168 | 0 | } |
169 | | |
170 | 0 | size_t StringTableBuilder::getOffset(StringRef S) const { |
171 | 0 | assert(isFinalized()); |
172 | 0 | auto I = StringIndexMap.find(S); |
173 | 0 | assert(I != StringIndexMap.end() && "String is not in table!"); |
174 | 0 | return I->second; |
175 | 0 | } |
176 | | |
177 | 105k | size_t StringTableBuilder::add(StringRef S) { |
178 | 105k | assert(!isFinalized()); |
179 | 105k | auto P = StringIndexMap.insert(std::make_pair(S, Size)); |
180 | 105k | if (P.second) |
181 | 104k | Size += S.size() + (K != RAW); |
182 | 105k | return P.first->second; |
183 | 105k | } |