| //===- BranchIslandFactory.cpp --------------------------------------------===// |
| // |
| // The MCLinker Project |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| #include <mcld/LD/BranchIslandFactory.h> |
| #include <mcld/Fragment/Fragment.h> |
| |
| using namespace mcld; |
| |
| //===----------------------------------------------------------------------===// |
| // BranchIslandFactory |
| //===----------------------------------------------------------------------===// |
| |
| /// ctor |
| /// @param pMaxBranchRange - the max branch range of the target backend |
| /// @param pMaxIslandSize - a predifned value (1KB here) to decide the max |
| /// size of the island |
| BranchIslandFactory::BranchIslandFactory(uint64_t pMaxBranchRange, |
| uint64_t pMaxIslandSize) |
| : GCFactory<BranchIsland, 0>(1u), // magic number |
| m_MaxBranchRange(pMaxBranchRange - pMaxIslandSize), |
| m_MaxIslandSize(pMaxIslandSize) |
| { |
| } |
| |
| BranchIslandFactory::~BranchIslandFactory() |
| { |
| } |
| |
| /// produce - produce a island for the given fragment |
| /// @param pFragment - the fragment needs a branch island |
| BranchIsland* BranchIslandFactory::produce(Fragment& pFragment) |
| { |
| assert(NULL == find(pFragment)); |
| uint64_t island_offset = pFragment.getOffset() + m_MaxBranchRange - |
| (pFragment.getOffset() % m_MaxBranchRange); |
| |
| // find out the last fragment whose offset is smaller than the calculated |
| // offset of the island |
| Fragment* frag = &pFragment; |
| while (NULL != frag->getNextNode()) { |
| if (frag->getNextNode()->getOffset() > island_offset) |
| break; |
| frag = frag->getNextNode(); |
| } |
| |
| // fall back one step if needed |
| if (NULL != frag && |
| (frag->getOffset() + frag->size()) > island_offset) |
| frag = frag->getPrevNode(); |
| |
| // check not to break the alignment constraint in the target section |
| // (i.e., do not insert the island after a Alignment fragment) |
| while (NULL != frag && |
| Fragment::Alignment == frag->getKind()) { |
| frag = frag->getPrevNode(); |
| } |
| |
| // can not find an entry fragment to bridge the island |
| if (NULL == frag) |
| return NULL; |
| |
| BranchIsland *island = allocate(); |
| new (island) BranchIsland(*frag, // entry fragment to the island |
| m_MaxIslandSize, // the max size of the island |
| size() - 1u); // index in the island factory |
| return island; |
| } |
| |
| /// find - find a island for the given fragment |
| /// @param pFragment - the fragment needs a branch isladn |
| BranchIsland* BranchIslandFactory::find(const Fragment& pFragment) |
| { |
| // Currently we always find the island in a forward direction. |
| // TODO: If we can search backward, then we may reduce the number of islands. |
| for (iterator it = begin(), ie = end(); it != ie; ++it) { |
| if ((pFragment.getOffset() < (*it).offset()) && |
| ((pFragment.getOffset() + m_MaxBranchRange) >= (*it).offset())) |
| return &(*it); |
| } |
| return NULL; |
| } |
| |