//===- SymbolCategory.cpp -------------------------------------------------===// // // The MCLinker Project // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "mcld/MC/SymbolCategory.h" #include "mcld/LD/LDSymbol.h" #include "mcld/LD/ResolveInfo.h" #include <algorithm> #include <cassert> namespace mcld { //===----------------------------------------------------------------------===// // Category SymbolCategory::Category::Type SymbolCategory::Category::categorize( const ResolveInfo& pInfo) { if (ResolveInfo::File == pInfo.type()) return Category::File; if (ResolveInfo::Local == pInfo.binding()) return Category::Local; if (ResolveInfo::Common == pInfo.desc()) return Category::Common; if (ResolveInfo::Default == pInfo.visibility() || ResolveInfo::Protected == pInfo.visibility()) return Category::Dynamic; return Category::Regular; } //===----------------------------------------------------------------------===// // SymbolCategory SymbolCategory::SymbolCategory() { m_pFile = new Category(Category::File); m_pLocal = new Category(Category::Local); m_pLocalDyn = new Category(Category::LocalDyn); m_pCommon = new Category(Category::Common); m_pDynamic = new Category(Category::Dynamic); m_pRegular = new Category(Category::Regular); m_pFile->next = m_pLocal; m_pLocal->next = m_pLocalDyn; m_pLocalDyn->next = m_pCommon; m_pCommon->next = m_pDynamic; m_pDynamic->next = m_pRegular; m_pRegular->prev = m_pDynamic; m_pDynamic->prev = m_pCommon; m_pCommon->prev = m_pLocalDyn; m_pLocalDyn->prev = m_pLocal; m_pLocal->prev = m_pFile; } SymbolCategory::~SymbolCategory() { Category* current = m_pFile; while (current != NULL) { Category* tmp = current; current = current->next; delete tmp; } } SymbolCategory& SymbolCategory::add(LDSymbol& pSymbol, Category::Type pTarget) { Category* current = m_pRegular; m_OutputSymbols.push_back(&pSymbol); // use non-stable bubble sort to arrange the order of symbols. while (current != NULL) { if (current->type == pTarget) { current->end++; break; } else { if (!current->empty()) { std::swap(m_OutputSymbols[current->begin], m_OutputSymbols[current->end]); } current->end++; current->begin++; current = current->prev; } } return *this; } SymbolCategory& SymbolCategory::add(LDSymbol& pSymbol) { assert(pSymbol.resolveInfo() != NULL); return add(pSymbol, Category::categorize(*pSymbol.resolveInfo())); } SymbolCategory& SymbolCategory::forceLocal(LDSymbol& pSymbol) { return add(pSymbol, Category::Local); } SymbolCategory& SymbolCategory::arrange(LDSymbol& pSymbol, Category::Type pSource, Category::Type pTarget) { int distance = pTarget - pSource; if (distance == 0) { // in the same category, do not need to re-arrange return *this; } // source and target are not in the same category // find the category of source Category* current = m_pFile; while (current != NULL) { if (pSource == current->type) break; current = current->next; } assert(current != NULL); size_t pos = 0; if (!current->empty()) { // find the position of source pos = current->begin; while (pos != current->end) { if (m_OutputSymbols[pos] == &pSymbol) break; ++pos; } } // FIXME: Try to search the symbol explicitly, if symbol is not in the given // source category. Or we need to add some logics like shouldForceLocal() in // SymbolCategory::Category::categorize(). if (current->end == pos || current->empty()) { current = m_pFile; do { pos = current->begin; while (pos != current->end) { if (m_OutputSymbols[pos] == &pSymbol) { distance = pTarget - current->type; break; } ++pos; } if (pos != current->end) break; current = current->next; } while (current != NULL); assert(current != NULL); } // The distance is positive. It means we should bubble sort downward. if (distance > 0) { // downward size_t rear; do { if (current->type == pTarget) { break; } else { assert(!current->isLast() && "target category is wrong."); rear = current->end - 1; std::swap(m_OutputSymbols[pos], m_OutputSymbols[rear]); pos = rear; current->next->begin--; current->end--; } current = current->next; } while (current != NULL); return *this; } // downward // The distance is negative. It means we should bubble sort upward. if (distance < 0) { // upward do { if (current->type == pTarget) { break; } else { assert(!current->isFirst() && "target category is wrong."); std::swap(m_OutputSymbols[current->begin], m_OutputSymbols[pos]); pos = current->begin; current->begin++; current->prev->end++; } current = current->prev; } while (current != NULL); return *this; } // upward return *this; } SymbolCategory& SymbolCategory::arrange(LDSymbol& pSymbol, const ResolveInfo& pSourceInfo) { assert(pSymbol.resolveInfo() != NULL); return arrange(pSymbol, Category::categorize(pSourceInfo), Category::categorize(*pSymbol.resolveInfo())); } SymbolCategory& SymbolCategory::changeCommonsToGlobal() { // Change Common to Dynamic/Regular while (!emptyCommons()) { size_t pos = m_pCommon->end - 1; switch (Category::categorize(*(m_OutputSymbols[pos]->resolveInfo()))) { case Category::Dynamic: m_pCommon->end--; m_pDynamic->begin--; break; case Category::Regular: std::swap(m_OutputSymbols[pos], m_OutputSymbols[m_pDynamic->end - 1]); m_pCommon->end--; m_pDynamic->begin--; m_pDynamic->end--; m_pRegular->begin--; break; default: assert(0); break; } } return *this; } SymbolCategory& SymbolCategory::changeToDynamic(LDSymbol& pSymbol) { assert(pSymbol.resolveInfo() != NULL); return arrange(pSymbol, Category::categorize(*pSymbol.resolveInfo()), Category::LocalDyn); } size_t SymbolCategory::numOfSymbols() const { return m_OutputSymbols.size(); } size_t SymbolCategory::numOfFiles() const { return m_pFile->size(); } size_t SymbolCategory::numOfLocals() const { return m_pLocal->size(); } size_t SymbolCategory::numOfLocalDyns() const { return m_pLocalDyn->size(); } size_t SymbolCategory::numOfCommons() const { return m_pCommon->size(); } size_t SymbolCategory::numOfDynamics() const { return m_pDynamic->size(); } size_t SymbolCategory::numOfRegulars() const { return m_pRegular->size(); } bool SymbolCategory::empty() const { return m_OutputSymbols.empty(); } bool SymbolCategory::emptyFiles() const { return m_pFile->empty(); } bool SymbolCategory::emptyLocals() const { return m_pLocal->empty(); } bool SymbolCategory::emptyLocalDyns() const { return m_pLocalDyn->empty(); } bool SymbolCategory::emptyCommons() const { return m_pCommon->empty(); } bool SymbolCategory::emptyDynamics() const { return m_pDynamic->empty(); } bool SymbolCategory::emptyRegulars() const { return m_pRegular->empty(); } SymbolCategory::iterator SymbolCategory::begin() { return m_OutputSymbols.begin(); } SymbolCategory::iterator SymbolCategory::end() { return m_OutputSymbols.end(); } SymbolCategory::const_iterator SymbolCategory::begin() const { return m_OutputSymbols.begin(); } SymbolCategory::const_iterator SymbolCategory::end() const { return m_OutputSymbols.end(); } SymbolCategory::iterator SymbolCategory::fileBegin() { return m_OutputSymbols.begin(); } SymbolCategory::iterator SymbolCategory::fileEnd() { iterator iter = fileBegin(); iter += m_pFile->size(); return iter; } SymbolCategory::const_iterator SymbolCategory::fileBegin() const { return m_OutputSymbols.begin(); } SymbolCategory::const_iterator SymbolCategory::fileEnd() const { const_iterator iter = fileBegin(); iter += m_pFile->size(); return iter; } SymbolCategory::iterator SymbolCategory::localBegin() { return fileEnd(); } SymbolCategory::iterator SymbolCategory::localEnd() { iterator iter = localBegin(); iter += m_pLocal->size(); return iter; } SymbolCategory::const_iterator SymbolCategory::localBegin() const { return fileEnd(); } SymbolCategory::const_iterator SymbolCategory::localEnd() const { const_iterator iter = localBegin(); iter += m_pLocal->size(); return iter; } SymbolCategory::iterator SymbolCategory::localDynBegin() { return localEnd(); } SymbolCategory::iterator SymbolCategory::localDynEnd() { iterator iter = localDynBegin(); iter += m_pLocalDyn->size(); return iter; } SymbolCategory::const_iterator SymbolCategory::localDynBegin() const { return localEnd(); } SymbolCategory::const_iterator SymbolCategory::localDynEnd() const { const_iterator iter = localDynBegin(); iter += m_pLocalDyn->size(); return iter; } SymbolCategory::iterator SymbolCategory::commonBegin() { return localDynEnd(); } SymbolCategory::iterator SymbolCategory::commonEnd() { iterator iter = commonBegin(); iter += m_pCommon->size(); return iter; } SymbolCategory::const_iterator SymbolCategory::commonBegin() const { return localDynEnd(); } SymbolCategory::const_iterator SymbolCategory::commonEnd() const { const_iterator iter = commonBegin(); iter += m_pCommon->size(); return iter; } SymbolCategory::iterator SymbolCategory::dynamicBegin() { return commonEnd(); } SymbolCategory::iterator SymbolCategory::dynamicEnd() { iterator iter = dynamicBegin(); iter += m_pDynamic->size(); return iter; } SymbolCategory::const_iterator SymbolCategory::dynamicBegin() const { return commonEnd(); } SymbolCategory::const_iterator SymbolCategory::dynamicEnd() const { const_iterator iter = dynamicBegin(); iter += m_pDynamic->size(); return iter; } SymbolCategory::iterator SymbolCategory::regularBegin() { return dynamicEnd(); } SymbolCategory::iterator SymbolCategory::regularEnd() { return m_OutputSymbols.end(); } SymbolCategory::const_iterator SymbolCategory::regularBegin() const { return dynamicEnd(); } SymbolCategory::const_iterator SymbolCategory::regularEnd() const { return m_OutputSymbols.end(); } } // namespace mcld