Coverage Report

Created: 2025-12-27 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}