MemoryArea.cpp revision 6f75755c9204b1d8817ae5a65a2f7e5af0ec3f70
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/MemoryArea.h>
10#include <mcld/Support/Space.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// MemoryArea - special constructor
21// This constructor is used for *SPECIAL* situation. I'm sorry I can not
22// reveal what is the special situation.
23MemoryArea::MemoryArea(Space& pUniverse)
24  : m_pFileHandle(NULL) {
25  m_SpaceMap.insert(std::make_pair(Key(pUniverse.start(), pUniverse.size()),
26                                   &pUniverse));
27}
28
29MemoryArea::MemoryArea(FileHandle& pFileHandle)
30  : 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::Create(*m_pFileHandle, pOffset, pLength);
66    m_SpaceMap.insert(std::make_pair(Key(space->start(), space->size()), 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 MemoryRegion::Create(r_start, pLength, *space);
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  MemoryRegion::Destroy(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::Sync(space, *m_pFileHandle);
95      }
96
97      std::pair<SpaceMapType::iterator, SpaceMapType::iterator> range =
98        m_SpaceMap.equal_range(Key(space->start(), space->size()));
99      SpaceMapType::iterator it;
100      for (it = range.first; it != range.second; ++it) {
101        if (space == it->second)
102          break;
103      }
104      m_SpaceMap.erase(it);
105
106      Space::Release(space, *m_pFileHandle);
107      assert(NULL != space);
108      Space::Destroy(space);
109    }
110  }
111}
112
113// clear - release all MemoryRegions
114void MemoryArea::clear()
115{
116  if (NULL == m_pFileHandle)
117    return;
118
119  SpaceMapType::iterator space, sEnd = m_SpaceMap.end();
120  if (m_pFileHandle->isWritable()) {
121    for (space = m_SpaceMap.begin(); space != sEnd; ++space) {
122      Space::Sync(space->second, *m_pFileHandle);
123      Space::Release(space->second, *m_pFileHandle);
124      assert(NULL != space->second);
125      Space::Destroy(space->second);
126    }
127  }
128  else {
129    for (space = m_SpaceMap.begin(); space != sEnd; ++space) {
130      Space::Release(space->second, *m_pFileHandle);
131      assert(NULL != space->second);
132      Space::Destroy(space->second);
133    }
134  }
135
136  m_SpaceMap.clear();
137}
138
139//===--------------------------------------------------------------------===//
140// SpaceList methods
141//===--------------------------------------------------------------------===//
142Space* MemoryArea::find(size_t pOffset, size_t pLength)
143{
144  SpaceMapType::iterator it = m_SpaceMap.find(Key(pOffset, pLength));
145  if (it != m_SpaceMap.end())
146    return it->second;
147
148  return NULL;
149}
150
151const Space* MemoryArea::find(size_t pOffset, size_t pLength) const
152{
153  SpaceMapType::const_iterator it = m_SpaceMap.find(Key(pOffset, pLength));
154  if (it != m_SpaceMap.end())
155    return it->second;
156
157  return NULL;
158}
159
160