//===- 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>
using 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::Weak == pInfo.binding())
return Category::Weak;
return Category::Global;
}
//===----------------------------------------------------------------------===//
// SymbolCategory
SymbolCategory::SymbolCategory()
{
m_pFile = new Category(Category::File);
m_pLocal = new Category(Category::Local);
m_pCommon = new Category(Category::Common);
m_pWeak = new Category(Category::Weak);
m_pGlobal = new Category(Category::Global);
m_pFile->next = m_pLocal;
m_pLocal->next = m_pCommon;
m_pCommon->next = m_pWeak;
m_pWeak->next = m_pGlobal;
m_pGlobal->prev = m_pWeak;
m_pWeak->prev = m_pCommon;
m_pCommon->prev = m_pLocal;
m_pLocal->prev = m_pFile;
}
SymbolCategory::~SymbolCategory()
{
Category* current = m_pFile;
while (NULL != current) {
Category* tmp = current;
current = current->next;
delete tmp;
}
}
SymbolCategory& SymbolCategory::add(LDSymbol& pSymbol)
{
m_OutputSymbols.push_back(&pSymbol);
assert(NULL != pSymbol.resolveInfo());
Category::Type target = Category::categorize(*pSymbol.resolveInfo());
Category* current = m_pGlobal;
// use non-stable bubble sort to arrange the order of symbols.
while (NULL != current) {
if (current->type == target) {
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::forceLocal(LDSymbol& pSymbol)
{
m_OutputSymbols.insert(localEnd(), &pSymbol);
m_pLocal->end++;
m_pCommon->begin++;
m_pCommon->end++;
m_pWeak->begin++;
m_pWeak->end++;
m_pGlobal->begin++;
m_pGlobal->end++;
return *this;
}
SymbolCategory& SymbolCategory::arrange(LDSymbol& pSymbol, const ResolveInfo& pSourceInfo)
{
assert(NULL != pSymbol.resolveInfo());
Category::Type source = Category::categorize(pSourceInfo);
Category::Type target = Category::categorize(*pSymbol.resolveInfo());
int distance = target - source;
if (0 == distance) {
// 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(NULL != current) {
if (source == current->type)
break;
current = current->next;
}
assert(NULL != current);
assert(!current->empty());
// find the position of source
size_t pos = current->begin;
while (pos != current->end) {
if (m_OutputSymbols[pos] == &pSymbol)
break;
++pos;
}
assert(current->end != pos);
// The distance is positive. It means we should bubble sort downward.
if (distance > 0) {
// downward
size_t rear;
do {
if (current->type == target) {
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(NULL != current);
return *this;
} // downward
// The distance is negative. It means we should bubble sort upward.
if (distance < 0) {
// upward
do {
if (current->type == target) {
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(NULL != current);
return *this;
} // upward
return *this;
}
SymbolCategory& SymbolCategory::changeCommonsToGlobal()
{
if (emptyCommons())
return *this;
size_t com_rear = m_pCommon->end - 1;
size_t com_front = m_pCommon->begin;
size_t weak_rear = m_pWeak->end - 1;
size_t weak_size = m_pWeak->end - m_pWeak->begin;
for (size_t sym = com_rear; sym >= com_front; --sym) {
std::swap(m_OutputSymbols[weak_rear], m_OutputSymbols[sym]);
--weak_rear;
}
m_pWeak->begin = m_pCommon->begin;
m_pWeak->end = m_pCommon->begin + weak_size;
m_pGlobal->begin = m_pWeak->end;
m_pCommon->begin = m_pCommon->end = m_pWeak->begin;
return *this;
}
size_t SymbolCategory::numOfSymbols() const
{
return m_OutputSymbols.size();
}
size_t SymbolCategory::numOfLocals() const
{
return (m_pFile->size() + m_pLocal->size());
}
size_t SymbolCategory::numOfCommons() const
{
return m_pCommon->size();
}
size_t SymbolCategory::numOfRegulars() const
{
return (m_pWeak->size() + m_pGlobal->size());
}
bool SymbolCategory::empty() const
{
return (emptyLocals() &&
emptyCommons() &&
emptyRegulars());
}
bool SymbolCategory::emptyLocals() const
{
return (m_pFile->empty() && m_pLocal->empty());
}
bool SymbolCategory::emptyCommons() const
{
return m_pCommon->empty();
}
bool SymbolCategory::emptyRegulars() const
{
return (m_pWeak->empty() && m_pGlobal->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::localBegin()
{
return m_OutputSymbols.begin();
}
SymbolCategory::iterator SymbolCategory::localEnd()
{
iterator iter = m_OutputSymbols.begin();
iter += m_pFile->size();
iter += m_pLocal->size();
return iter;
}
SymbolCategory::const_iterator SymbolCategory::localBegin() const
{
return m_OutputSymbols.begin();
}
SymbolCategory::const_iterator SymbolCategory::localEnd() const
{
const_iterator iter = m_OutputSymbols.begin();
iter += m_pFile->size();
iter += m_pLocal->size();
return iter;
}
SymbolCategory::iterator SymbolCategory::commonBegin()
{
return localEnd();
}
SymbolCategory::iterator SymbolCategory::commonEnd()
{
iterator iter = localEnd();
iter += m_pCommon->size();
return iter;
}
SymbolCategory::const_iterator SymbolCategory::commonBegin() const
{
return localEnd();
}
SymbolCategory::const_iterator SymbolCategory::commonEnd() const
{
const_iterator iter = localEnd();
iter += m_pCommon->size();
return iter;
}
SymbolCategory::iterator SymbolCategory::regularBegin()
{
return commonEnd();
}
SymbolCategory::iterator SymbolCategory::regularEnd()
{
return m_OutputSymbols.end();
}
SymbolCategory::const_iterator SymbolCategory::regularBegin() const
{
return commonEnd();
}
SymbolCategory::const_iterator SymbolCategory::regularEnd() const
{
return m_OutputSymbols.end();
}