1 //===- SymbolCategory.cpp -------------------------------------------------===//
2 //
3 //                     The MCLinker Project
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 #include "mcld/MC/SymbolCategory.h"
10 
11 #include "mcld/LD/LDSymbol.h"
12 #include "mcld/LD/ResolveInfo.h"
13 
14 #include <algorithm>
15 #include <cassert>
16 
17 namespace mcld {
18 
19 //===----------------------------------------------------------------------===//
20 // Category
categorize(const ResolveInfo & pInfo)21 SymbolCategory::Category::Type SymbolCategory::Category::categorize(
22     const ResolveInfo& pInfo) {
23   if (ResolveInfo::File == pInfo.type())
24     return Category::File;
25   if (ResolveInfo::Local == pInfo.binding())
26     return Category::Local;
27   if (ResolveInfo::Common == pInfo.desc())
28     return Category::Common;
29   if (ResolveInfo::Default == pInfo.visibility() ||
30       ResolveInfo::Protected == pInfo.visibility())
31     return Category::Dynamic;
32   return Category::Regular;
33 }
34 
35 //===----------------------------------------------------------------------===//
36 // SymbolCategory
SymbolCategory()37 SymbolCategory::SymbolCategory() {
38   m_pFile = new Category(Category::File);
39   m_pLocal = new Category(Category::Local);
40   m_pLocalDyn = new Category(Category::LocalDyn);
41   m_pCommon = new Category(Category::Common);
42   m_pDynamic = new Category(Category::Dynamic);
43   m_pRegular = new Category(Category::Regular);
44 
45   m_pFile->next = m_pLocal;
46   m_pLocal->next = m_pLocalDyn;
47   m_pLocalDyn->next = m_pCommon;
48   m_pCommon->next = m_pDynamic;
49   m_pDynamic->next = m_pRegular;
50 
51   m_pRegular->prev = m_pDynamic;
52   m_pDynamic->prev = m_pCommon;
53   m_pCommon->prev = m_pLocalDyn;
54   m_pLocalDyn->prev = m_pLocal;
55   m_pLocal->prev = m_pFile;
56 }
57 
~SymbolCategory()58 SymbolCategory::~SymbolCategory() {
59   Category* current = m_pFile;
60   while (current != NULL) {
61     Category* tmp = current;
62     current = current->next;
63     delete tmp;
64   }
65 }
66 
add(LDSymbol & pSymbol,Category::Type pTarget)67 SymbolCategory& SymbolCategory::add(LDSymbol& pSymbol, Category::Type pTarget) {
68   Category* current = m_pRegular;
69   m_OutputSymbols.push_back(&pSymbol);
70 
71   // use non-stable bubble sort to arrange the order of symbols.
72   while (current != NULL) {
73     if (current->type == pTarget) {
74       current->end++;
75       break;
76     } else {
77       if (!current->empty()) {
78         std::swap(m_OutputSymbols[current->begin],
79                   m_OutputSymbols[current->end]);
80       }
81       current->end++;
82       current->begin++;
83       current = current->prev;
84     }
85   }
86   return *this;
87 }
88 
add(LDSymbol & pSymbol)89 SymbolCategory& SymbolCategory::add(LDSymbol& pSymbol) {
90   assert(pSymbol.resolveInfo() != NULL);
91   return add(pSymbol, Category::categorize(*pSymbol.resolveInfo()));
92 }
93 
forceLocal(LDSymbol & pSymbol)94 SymbolCategory& SymbolCategory::forceLocal(LDSymbol& pSymbol) {
95   return add(pSymbol, Category::Local);
96 }
97 
arrange(LDSymbol & pSymbol,Category::Type pSource,Category::Type pTarget)98 SymbolCategory& SymbolCategory::arrange(LDSymbol& pSymbol,
99                                         Category::Type pSource,
100                                         Category::Type pTarget) {
101   int distance = pTarget - pSource;
102   if (distance == 0) {
103     // in the same category, do not need to re-arrange
104     return *this;
105   }
106 
107   // source and target are not in the same category
108   // find the category of source
109   Category* current = m_pFile;
110   while (current != NULL) {
111     if (pSource == current->type)
112       break;
113     current = current->next;
114   }
115 
116   assert(current != NULL);
117   size_t pos = 0;
118   if (!current->empty()) {
119     // find the position of source
120     pos = current->begin;
121     while (pos != current->end) {
122       if (m_OutputSymbols[pos] == &pSymbol)
123         break;
124       ++pos;
125     }
126   }
127   // FIXME: Try to search the symbol explicitly, if symbol is not in the given
128   // source category. Or we need to add some logics like shouldForceLocal() in
129   // SymbolCategory::Category::categorize().
130   if (current->end == pos || current->empty()) {
131     current = m_pFile;
132     do {
133       pos = current->begin;
134       while (pos != current->end) {
135         if (m_OutputSymbols[pos] == &pSymbol) {
136           distance = pTarget - current->type;
137           break;
138         }
139         ++pos;
140       }
141       if (pos != current->end)
142         break;
143       current = current->next;
144     } while (current != NULL);
145     assert(current != NULL);
146   }
147 
148   // The distance is positive. It means we should bubble sort downward.
149   if (distance > 0) {
150     // downward
151     size_t rear;
152     do {
153       if (current->type == pTarget) {
154         break;
155       } else {
156         assert(!current->isLast() && "target category is wrong.");
157         rear = current->end - 1;
158         std::swap(m_OutputSymbols[pos], m_OutputSymbols[rear]);
159         pos = rear;
160         current->next->begin--;
161         current->end--;
162       }
163       current = current->next;
164     } while (current != NULL);
165 
166     return *this;
167   }  // downward
168 
169   // The distance is negative. It means we should bubble sort upward.
170   if (distance < 0) {
171     // upward
172     do {
173       if (current->type == pTarget) {
174         break;
175       } else {
176         assert(!current->isFirst() && "target category is wrong.");
177         std::swap(m_OutputSymbols[current->begin], m_OutputSymbols[pos]);
178         pos = current->begin;
179         current->begin++;
180         current->prev->end++;
181       }
182       current = current->prev;
183     } while (current != NULL);
184 
185     return *this;
186   }  // upward
187   return *this;
188 }
189 
arrange(LDSymbol & pSymbol,const ResolveInfo & pSourceInfo)190 SymbolCategory& SymbolCategory::arrange(LDSymbol& pSymbol,
191                                         const ResolveInfo& pSourceInfo) {
192   assert(pSymbol.resolveInfo() != NULL);
193   return arrange(pSymbol,
194                  Category::categorize(pSourceInfo),
195                  Category::categorize(*pSymbol.resolveInfo()));
196 }
197 
changeCommonsToGlobal()198 SymbolCategory& SymbolCategory::changeCommonsToGlobal() {
199   // Change Common to Dynamic/Regular
200   while (!emptyCommons()) {
201     size_t pos = m_pCommon->end - 1;
202     switch (Category::categorize(*(m_OutputSymbols[pos]->resolveInfo()))) {
203       case Category::Dynamic:
204         m_pCommon->end--;
205         m_pDynamic->begin--;
206         break;
207       case Category::Regular:
208         std::swap(m_OutputSymbols[pos], m_OutputSymbols[m_pDynamic->end - 1]);
209         m_pCommon->end--;
210         m_pDynamic->begin--;
211         m_pDynamic->end--;
212         m_pRegular->begin--;
213         break;
214       default:
215         assert(0);
216         break;
217     }
218   }
219   return *this;
220 }
221 
changeToDynamic(LDSymbol & pSymbol)222 SymbolCategory& SymbolCategory::changeToDynamic(LDSymbol& pSymbol) {
223   assert(pSymbol.resolveInfo() != NULL);
224   return arrange(pSymbol,
225                  Category::categorize(*pSymbol.resolveInfo()),
226                  Category::LocalDyn);
227 }
228 
numOfSymbols() const229 size_t SymbolCategory::numOfSymbols() const {
230   return m_OutputSymbols.size();
231 }
232 
numOfFiles() const233 size_t SymbolCategory::numOfFiles() const {
234   return m_pFile->size();
235 }
236 
numOfLocals() const237 size_t SymbolCategory::numOfLocals() const {
238   return m_pLocal->size();
239 }
240 
numOfLocalDyns() const241 size_t SymbolCategory::numOfLocalDyns() const {
242   return m_pLocalDyn->size();
243 }
244 
numOfCommons() const245 size_t SymbolCategory::numOfCommons() const {
246   return m_pCommon->size();
247 }
248 
numOfDynamics() const249 size_t SymbolCategory::numOfDynamics() const {
250   return m_pDynamic->size();
251 }
252 
numOfRegulars() const253 size_t SymbolCategory::numOfRegulars() const {
254   return m_pRegular->size();
255 }
256 
empty() const257 bool SymbolCategory::empty() const {
258   return m_OutputSymbols.empty();
259 }
260 
emptyFiles() const261 bool SymbolCategory::emptyFiles() const {
262   return m_pFile->empty();
263 }
264 
emptyLocals() const265 bool SymbolCategory::emptyLocals() const {
266   return m_pLocal->empty();
267 }
268 
emptyLocalDyns() const269 bool SymbolCategory::emptyLocalDyns() const {
270   return m_pLocalDyn->empty();
271 }
272 
emptyCommons() const273 bool SymbolCategory::emptyCommons() const {
274   return m_pCommon->empty();
275 }
276 
emptyDynamics() const277 bool SymbolCategory::emptyDynamics() const {
278   return m_pDynamic->empty();
279 }
280 
emptyRegulars() const281 bool SymbolCategory::emptyRegulars() const {
282   return m_pRegular->empty();
283 }
284 
begin()285 SymbolCategory::iterator SymbolCategory::begin() {
286   return m_OutputSymbols.begin();
287 }
288 
end()289 SymbolCategory::iterator SymbolCategory::end() {
290   return m_OutputSymbols.end();
291 }
292 
begin() const293 SymbolCategory::const_iterator SymbolCategory::begin() const {
294   return m_OutputSymbols.begin();
295 }
296 
end() const297 SymbolCategory::const_iterator SymbolCategory::end() const {
298   return m_OutputSymbols.end();
299 }
300 
fileBegin()301 SymbolCategory::iterator SymbolCategory::fileBegin() {
302   return m_OutputSymbols.begin();
303 }
304 
fileEnd()305 SymbolCategory::iterator SymbolCategory::fileEnd() {
306   iterator iter = fileBegin();
307   iter += m_pFile->size();
308   return iter;
309 }
310 
fileBegin() const311 SymbolCategory::const_iterator SymbolCategory::fileBegin() const {
312   return m_OutputSymbols.begin();
313 }
314 
fileEnd() const315 SymbolCategory::const_iterator SymbolCategory::fileEnd() const {
316   const_iterator iter = fileBegin();
317   iter += m_pFile->size();
318   return iter;
319 }
320 
localBegin()321 SymbolCategory::iterator SymbolCategory::localBegin() {
322   return fileEnd();
323 }
324 
localEnd()325 SymbolCategory::iterator SymbolCategory::localEnd() {
326   iterator iter = localBegin();
327   iter += m_pLocal->size();
328   return iter;
329 }
330 
localBegin() const331 SymbolCategory::const_iterator SymbolCategory::localBegin() const {
332   return fileEnd();
333 }
334 
localEnd() const335 SymbolCategory::const_iterator SymbolCategory::localEnd() const {
336   const_iterator iter = localBegin();
337   iter += m_pLocal->size();
338   return iter;
339 }
340 
localDynBegin()341 SymbolCategory::iterator SymbolCategory::localDynBegin() {
342   return localEnd();
343 }
344 
localDynEnd()345 SymbolCategory::iterator SymbolCategory::localDynEnd() {
346   iterator iter = localDynBegin();
347   iter += m_pLocalDyn->size();
348   return iter;
349 }
350 
localDynBegin() const351 SymbolCategory::const_iterator SymbolCategory::localDynBegin() const {
352   return localEnd();
353 }
354 
localDynEnd() const355 SymbolCategory::const_iterator SymbolCategory::localDynEnd() const {
356   const_iterator iter = localDynBegin();
357   iter += m_pLocalDyn->size();
358   return iter;
359 }
360 
commonBegin()361 SymbolCategory::iterator SymbolCategory::commonBegin() {
362   return localDynEnd();
363 }
364 
commonEnd()365 SymbolCategory::iterator SymbolCategory::commonEnd() {
366   iterator iter = commonBegin();
367   iter += m_pCommon->size();
368   return iter;
369 }
370 
commonBegin() const371 SymbolCategory::const_iterator SymbolCategory::commonBegin() const {
372   return localDynEnd();
373 }
374 
commonEnd() const375 SymbolCategory::const_iterator SymbolCategory::commonEnd() const {
376   const_iterator iter = commonBegin();
377   iter += m_pCommon->size();
378   return iter;
379 }
380 
dynamicBegin()381 SymbolCategory::iterator SymbolCategory::dynamicBegin() {
382   return commonEnd();
383 }
384 
dynamicEnd()385 SymbolCategory::iterator SymbolCategory::dynamicEnd() {
386   iterator iter = dynamicBegin();
387   iter += m_pDynamic->size();
388   return iter;
389 }
390 
dynamicBegin() const391 SymbolCategory::const_iterator SymbolCategory::dynamicBegin() const {
392   return commonEnd();
393 }
394 
dynamicEnd() const395 SymbolCategory::const_iterator SymbolCategory::dynamicEnd() const {
396   const_iterator iter = dynamicBegin();
397   iter += m_pDynamic->size();
398   return iter;
399 }
400 
regularBegin()401 SymbolCategory::iterator SymbolCategory::regularBegin() {
402   return dynamicEnd();
403 }
404 
regularEnd()405 SymbolCategory::iterator SymbolCategory::regularEnd() {
406   return m_OutputSymbols.end();
407 }
408 
regularBegin() const409 SymbolCategory::const_iterator SymbolCategory::regularBegin() const {
410   return dynamicEnd();
411 }
412 
regularEnd() const413 SymbolCategory::const_iterator SymbolCategory::regularEnd() const {
414   return m_OutputSymbols.end();
415 }
416 
417 }  // namespace mcld
418