| //===- MemoryArea.cpp -----------------------------------------------------===// |
| // |
| // The MCLinker Project |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| #include <mcld/Support/RegionFactory.h> |
| #include <mcld/Support/MemoryArea.h> |
| #include <mcld/Support/MemoryRegion.h> |
| #include <mcld/Support/FileHandle.h> |
| #include <mcld/Support/MsgHandling.h> |
| |
| using namespace mcld; |
| |
| //===--------------------------------------------------------------------===// |
| // MemoryArea |
| |
| // MemoryArea - special constructor |
| // This constructor is used for *SPECIAL* situation. I'm sorry I can not |
| // reveal what is the special situation. |
| MemoryArea::MemoryArea(RegionFactory& pRegionFactory, Space& pUniverse) |
| : m_RegionFactory(pRegionFactory), m_pFileHandle(NULL) { |
| m_SpaceList.push_back(&pUniverse); |
| } |
| |
| MemoryArea::MemoryArea(RegionFactory& pRegionFactory, FileHandle& pFileHandle) |
| : m_RegionFactory(pRegionFactory), m_pFileHandle(&pFileHandle) { |
| } |
| |
| MemoryArea::~MemoryArea() |
| { |
| } |
| |
| // The layout of MemorySpace in the virtual memory space |
| // |
| // | : page boundary |
| // [,]: MemoryRegion |
| // - : fillment |
| // = : data |
| // |
| // |---[=|====|====|==]--| |
| // ^ ^ ^ ^ |
| // | | | | |
| // | r_start +r_len | |
| // space.data +space.size |
| // |
| // space.file_offset is the offset of the mapped file segment from the start of |
| // the file. if the MemorySpace's type is ALLOCATED_ARRAY, the distances of |
| // (space.data, r_start) and (r_len, space.size) are zero. |
| // |
| MemoryRegion* MemoryArea::request(size_t pOffset, size_t pLength) |
| { |
| Space* space = find(pOffset, pLength); |
| if (NULL == space) { |
| |
| // not found |
| if (NULL == m_pFileHandle) { |
| // if m_pFileHandle is NULL, clients delegate us an universal Space and |
| // we never remove it. In that way, space can not be NULL. |
| unreachable(diag::err_out_of_range_region); |
| } |
| |
| space = Space::createSpace(*m_pFileHandle, pOffset, pLength); |
| m_SpaceList.push_back(space); |
| } |
| |
| // adjust r_start |
| off_t distance = pOffset - space->start(); |
| void* r_start = space->memory() + distance; |
| |
| // now, we have a legal space to hold the new MemoryRegion |
| return m_RegionFactory.produce(*space, r_start, pLength); |
| } |
| |
| // release - release a MemoryRegion |
| void MemoryArea::release(MemoryRegion* pRegion) |
| { |
| if (NULL == pRegion) |
| return; |
| |
| Space *space = pRegion->parent(); |
| m_RegionFactory.destruct(pRegion); |
| |
| if (0 == space->numOfRegions()) { |
| |
| if (NULL != m_pFileHandle) { |
| // if m_pFileHandle is NULL, clients delegate us an universal Space and |
| // we never remove it. Otherwise, we have to synchronize and release |
| // Space. |
| if (m_pFileHandle->isWritable()) { |
| // synchronize writable space before we release it. |
| Space::syncSpace(space, *m_pFileHandle); |
| } |
| Space::releaseSpace(space, *m_pFileHandle); |
| } |
| m_SpaceList.erase(space); |
| } |
| } |
| |
| // clear - release all MemoryRegions |
| void MemoryArea::clear() |
| { |
| if (NULL == m_pFileHandle) |
| return; |
| |
| if (m_pFileHandle->isWritable()) { |
| SpaceList::iterator space, sEnd = m_SpaceList.end(); |
| for (space = m_SpaceList.begin(); space != sEnd; ++space) { |
| Space::syncSpace(space, *m_pFileHandle); |
| Space::releaseSpace(space, *m_pFileHandle); |
| } |
| } |
| else { |
| SpaceList::iterator space, sEnd = m_SpaceList.end(); |
| for (space = m_SpaceList.begin(); space != sEnd; ++space) |
| Space::releaseSpace(space, *m_pFileHandle); |
| } |
| |
| m_SpaceList.clear(); |
| } |
| |
| //===--------------------------------------------------------------------===// |
| // SpaceList methods |
| Space* MemoryArea::find(size_t pOffset, size_t pLength) |
| { |
| SpaceList::iterator sIter, sEnd = m_SpaceList.end(); |
| for (sIter = m_SpaceList.begin(); sIter!=sEnd; ++sIter) { |
| if (sIter->start() <= pOffset && |
| (pOffset+pLength) <= (sIter->start()+sIter->size()) ) { |
| // within |
| return sIter; |
| } |
| } |
| return NULL; |
| } |
| |
| const Space* MemoryArea::find(size_t pOffset, size_t pLength) const |
| { |
| SpaceList::const_iterator sIter, sEnd = m_SpaceList.end(); |
| for (sIter = m_SpaceList.begin(); sIter!=sEnd; ++sIter) { |
| if (sIter->start() <= pOffset && |
| (pOffset+pLength) <= (sIter->start()+sIter->size()) ) { |
| // within |
| return sIter; |
| } |
| } |
| return NULL; |
| } |
| |