C++程序  |  247行  |  7.99 KB

//===- ScriptFile.cpp -----------------------------------------------------===//
//
//                     The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/Script/ScriptFile.h"

#include "mcld/ADT/HashEntry.h"
#include "mcld/ADT/HashTable.h"
#include "mcld/ADT/StringHash.h"
#include "mcld/Script/AssertCmd.h"
#include "mcld/Script/EntryCmd.h"
#include "mcld/Script/GroupCmd.h"
#include "mcld/Script/InputCmd.h"
#include "mcld/Script/Operand.h"
#include "mcld/Script/OutputArchCmd.h"
#include "mcld/Script/OutputCmd.h"
#include "mcld/Script/OutputFormatCmd.h"
#include "mcld/Script/RpnExpr.h"
#include "mcld/Script/ScriptCommand.h"
#include "mcld/Script/SearchDirCmd.h"
#include "mcld/Script/SectionsCmd.h"
#include "mcld/Script/StringList.h"
#include "mcld/Script/StrToken.h"
#include "mcld/MC/Input.h"
#include "mcld/MC/InputBuilder.h"
#include "mcld/Support/MemoryArea.h"
#include "mcld/InputTree.h"

#include <llvm/Support/Casting.h>
#include <llvm/Support/ManagedStatic.h>

#include <cassert>

namespace mcld {

typedef HashEntry<std::string, void*, hash::StringCompare<std::string> >
    ParserStrEntry;
typedef HashTable<ParserStrEntry,
                  hash::StringHash<hash::DJB>,
                  EntryFactory<ParserStrEntry> > ParserStrPool;
static llvm::ManagedStatic<ParserStrPool> g_ParserStrPool;

//===----------------------------------------------------------------------===//
// ScriptFile
//===----------------------------------------------------------------------===//
ScriptFile::ScriptFile(Kind pKind, Input& pInput, InputBuilder& pBuilder)
    : m_Kind(pKind),
      m_Input(pInput),
      m_Name(pInput.path().native()),
      m_pInputTree(NULL),
      m_Builder(pBuilder),
      m_bHasSectionsCmd(false),
      m_bInSectionsCmd(false),
      m_bInOutputSectDesc(false),
      m_pRpnExpr(NULL),
      m_pStringList(NULL),
      m_bAsNeeded(false) {
  // FIXME: move creation of input tree out of ScriptFile.
  m_pInputTree = new InputTree();
}

ScriptFile::~ScriptFile() {
  for (iterator it = begin(), ie = end(); it != ie; ++it) {
    if (*it != NULL)
      delete *it;
  }
  if (m_pInputTree != NULL)
    delete m_pInputTree;
}

void ScriptFile::dump() const {
  for (const_iterator it = begin(), ie = end(); it != ie; ++it)
    (*it)->dump();
}

void ScriptFile::activate(Module& pModule) {
  for (const_iterator it = begin(), ie = end(); it != ie; ++it)
    (*it)->activate(pModule);
}

void ScriptFile::addEntryPoint(const std::string& pSymbol) {
  EntryCmd* entry = new EntryCmd(pSymbol);

  if (m_bInSectionsCmd) {
    assert(!m_CommandQueue.empty());
    SectionsCmd* sections = llvm::cast<SectionsCmd>(back());
    sections->push_back(entry);
  } else {
    m_CommandQueue.push_back(entry);
  }
}

void ScriptFile::addOutputFormatCmd(const std::string& pName) {
  m_CommandQueue.push_back(new OutputFormatCmd(pName));
}

void ScriptFile::addOutputFormatCmd(const std::string& pDefault,
                                    const std::string& pBig,
                                    const std::string& pLittle) {
  m_CommandQueue.push_back(new OutputFormatCmd(pDefault, pBig, pLittle));
}

void ScriptFile::addInputCmd(StringList& pStringList,
                             ObjectReader& pObjectReader,
                             ArchiveReader& pArchiveReader,
                             DynObjReader& pDynObjReader,
                             const LinkerConfig& pConfig) {
  m_CommandQueue.push_back(new InputCmd(pStringList,
                                        *m_pInputTree,
                                        m_Builder,
                                        pObjectReader,
                                        pArchiveReader,
                                        pDynObjReader,
                                        pConfig));
}

void ScriptFile::addGroupCmd(StringList& pStringList,
                             GroupReader& pGroupReader,
                             const LinkerConfig& pConfig) {
  m_CommandQueue.push_back(new GroupCmd(
      pStringList, *m_pInputTree, m_Builder, pGroupReader, pConfig));
}

void ScriptFile::addOutputCmd(const std::string& pFileName) {
  m_CommandQueue.push_back(new OutputCmd(pFileName));
}

void ScriptFile::addSearchDirCmd(const std::string& pPath) {
  m_CommandQueue.push_back(new SearchDirCmd(pPath));
}

void ScriptFile::addOutputArchCmd(const std::string& pArch) {
  m_CommandQueue.push_back(new OutputArchCmd(pArch));
}

void ScriptFile::addAssertCmd(RpnExpr& pRpnExpr, const std::string& pMessage) {
  m_CommandQueue.push_back(new AssertCmd(pRpnExpr, pMessage));
}

void ScriptFile::addAssignment(const std::string& pSymbolName,
                               RpnExpr& pRpnExpr,
                               Assignment::Type pType) {
  if (m_bInSectionsCmd) {
    assert(!m_CommandQueue.empty());
    SectionsCmd* sections = llvm::cast<SectionsCmd>(back());
    if (m_bInOutputSectDesc) {
      assert(!sections->empty());
      OutputSectDesc* output_desc =
          llvm::cast<OutputSectDesc>(sections->back());
      output_desc->push_back(new Assignment(Assignment::INPUT_SECTION,
                                            pType,
                                            *(SymOperand::create(pSymbolName)),
                                            pRpnExpr));
    } else {
      sections->push_back(new Assignment(Assignment::OUTPUT_SECTION,
                                         pType,
                                         *(SymOperand::create(pSymbolName)),
                                         pRpnExpr));
    }
  } else {
    m_CommandQueue.push_back(new Assignment(Assignment::OUTSIDE_SECTIONS,
                                            pType,
                                            *(SymOperand::create(pSymbolName)),
                                            pRpnExpr));
  }
}

bool ScriptFile::hasSectionsCmd() const {
  return m_bHasSectionsCmd;
}

void ScriptFile::enterSectionsCmd() {
  m_bHasSectionsCmd = true;
  m_bInSectionsCmd = true;
  m_CommandQueue.push_back(new SectionsCmd());
}

void ScriptFile::leaveSectionsCmd() {
  m_bInSectionsCmd = false;
}

void ScriptFile::enterOutputSectDesc(const std::string& pName,
                                     const OutputSectDesc::Prolog& pProlog) {
  assert(!m_CommandQueue.empty());
  assert(m_bInSectionsCmd);
  SectionsCmd* sections = llvm::cast<SectionsCmd>(back());
  sections->push_back(new OutputSectDesc(pName, pProlog));

  m_bInOutputSectDesc = true;
}

void ScriptFile::leaveOutputSectDesc(const OutputSectDesc::Epilog& pEpilog) {
  assert(!m_CommandQueue.empty());
  assert(m_bInSectionsCmd);
  SectionsCmd* sections = llvm::cast<SectionsCmd>(back());

  assert(!sections->empty() && m_bInOutputSectDesc);
  OutputSectDesc* output_desc = llvm::cast<OutputSectDesc>(sections->back());
  output_desc->setEpilog(pEpilog);

  m_bInOutputSectDesc = false;
}

void ScriptFile::addInputSectDesc(InputSectDesc::KeepPolicy pPolicy,
                                  const InputSectDesc::Spec& pSpec) {
  assert(!m_CommandQueue.empty());
  assert(m_bInSectionsCmd);
  SectionsCmd* sections = llvm::cast<SectionsCmd>(back());

  assert(!sections->empty() && m_bInOutputSectDesc);
  OutputSectDesc* output_sect = llvm::cast<OutputSectDesc>(sections->back());

  output_sect->push_back(new InputSectDesc(pPolicy, pSpec, *output_sect));
}

RpnExpr* ScriptFile::createRpnExpr() {
  m_pRpnExpr = RpnExpr::create();
  return m_pRpnExpr;
}

StringList* ScriptFile::createStringList() {
  m_pStringList = StringList::create();
  return m_pStringList;
}

void ScriptFile::setAsNeeded(bool pEnable) {
  m_bAsNeeded = pEnable;
}

const std::string& ScriptFile::createParserStr(const char* pText,
                                               size_t pLength) {
  bool exist = false;
  ParserStrEntry* entry =
      g_ParserStrPool->insert(std::string(pText, pLength), exist);
  return entry->key();
}

void ScriptFile::clearParserStrPool() {
  g_ParserStrPool->clear();
}

}  // namespace mcld