1//===- MemoryArea.cpp -----------------------------------------------------===//
2//
3//                     The MCLinker Project
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9#include <mcld/Support/RegionFactory.h>
10#include <mcld/Support/MemoryArea.h>
11#include <mcld/Support/MemoryRegion.h>
12#include <mcld/Support/FileHandle.h>
13#include <mcld/Support/MsgHandling.h>
14
15using namespace mcld;
16
17//===--------------------------------------------------------------------===//
18// MemoryArea
19//===--------------------------------------------------------------------===//
20
21// MemoryArea - special constructor
22// This constructor is used for *SPECIAL* situation. I'm sorry I can not
23// reveal what is the special situation.
24MemoryArea::MemoryArea(RegionFactory& pRegionFactory, Space& pUniverse)
25  : m_RegionFactory(pRegionFactory), m_pFileHandle(NULL) {
26  m_SpaceList.push_back(&pUniverse);
27}
28
29MemoryArea::MemoryArea(RegionFactory& pRegionFactory, FileHandle& pFileHandle)
30  : m_RegionFactory(pRegionFactory), m_pFileHandle(&pFileHandle) {
31}
32
33MemoryArea::~MemoryArea()
34{
35}
36
37// The layout of MemorySpace in the virtual memory space
38//
39// |  : page boundary
40// [,]: MemoryRegion
41// -  : fillment
42// =  : data
43//
44// |---[=|====|====|==]--|
45// ^   ^              ^  ^
46// |   |              |  |
47// | r_start      +r_len |
48// space.data      +space.size
49//
50// space.file_offset is the offset of the mapped file segment from the start of
51// the file. if the MemorySpace's type is ALLOCATED_ARRAY, the distances of
52// (space.data, r_start) and (r_len, space.size) are zero.
53//
54MemoryRegion* MemoryArea::request(size_t pOffset, size_t pLength)
55{
56  Space* space = find(pOffset, pLength);
57  if (NULL == space) {
58    // not found
59    if (NULL == m_pFileHandle) {
60      // if m_pFileHandle is NULL, clients delegate us an universal Space and
61      // we never remove it. In that way, space can not be NULL.
62      unreachable(diag::err_out_of_range_region) << pOffset << pLength;
63    }
64
65    space = Space::createSpace(*m_pFileHandle, pOffset, pLength);
66    m_SpaceList.push_back(space);
67  }
68
69  // adjust r_start
70  off_t distance = pOffset - space->start();
71  void* r_start = space->memory() + distance;
72
73  // now, we have a legal space to hold the new MemoryRegion
74  return m_RegionFactory.produce(*space, r_start, pLength);
75}
76
77// release - release a MemoryRegion
78void MemoryArea::release(MemoryRegion* pRegion)
79{
80  if (NULL == pRegion)
81    return;
82
83  Space *space = pRegion->parent();
84  m_RegionFactory.destruct(pRegion);
85
86  if (0 == space->numOfRegions()) {
87
88    if (NULL != m_pFileHandle) {
89      // if m_pFileHandle is NULL, clients delegate us an universal Space and
90      // we never remove it. Otherwise, we have to synchronize and release
91      // Space.
92      if (m_pFileHandle->isWritable()) {
93        // synchronize writable space before we release it.
94        Space::syncSpace(space, *m_pFileHandle);
95      }
96      Space::releaseSpace(space, *m_pFileHandle);
97      m_SpaceList.erase(space);
98    }
99  }
100}
101
102// clear - release all MemoryRegions
103void MemoryArea::clear()
104{
105  if (NULL == m_pFileHandle)
106    return;
107
108  if (m_pFileHandle->isWritable()) {
109    SpaceList::iterator space, sEnd = m_SpaceList.end();
110    for (space = m_SpaceList.begin(); space != sEnd; ++space) {
111      Space::syncSpace(space, *m_pFileHandle);
112      Space::releaseSpace(space, *m_pFileHandle);
113    }
114  }
115  else {
116    SpaceList::iterator space, sEnd = m_SpaceList.end();
117    for (space = m_SpaceList.begin(); space != sEnd; ++space)
118      Space::releaseSpace(space, *m_pFileHandle);
119  }
120
121  m_SpaceList.clear();
122}
123
124//===--------------------------------------------------------------------===//
125// SpaceList methods
126Space* MemoryArea::find(size_t pOffset, size_t pLength)
127{
128  SpaceList::iterator sIter, sEnd = m_SpaceList.end();
129  for (sIter = m_SpaceList.begin(); sIter!=sEnd; ++sIter) {
130    if (sIter->start() <= pOffset &&
131       (pOffset+pLength) <= (sIter->start()+sIter->size()) ) {
132      // within
133      return sIter;
134    }
135  }
136  return NULL;
137}
138
139const Space* MemoryArea::find(size_t pOffset, size_t pLength) const
140{
141  SpaceList::const_iterator sIter, sEnd = m_SpaceList.end();
142  for (sIter = m_SpaceList.begin(); sIter!=sEnd; ++sIter) {
143    if (sIter->start() <= pOffset &&
144       (pOffset+pLength) <= (sIter->start()+sIter->size()) ) {
145      // within
146      return sIter;
147    }
148  }
149  return NULL;
150}
151
152