MemoryArea.cpp revision 22add6ff3426df1a85089fe6a6e1597ee3b6f300
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  SpaceMapType::iterator space, sEnd = m_SpaceMap.end();
36  for (space = m_SpaceMap.begin(); space != sEnd; ++space) {
37    if (space->second != NULL)
38      Space::Destroy(space->second);
39  }
40}
41
42// The layout of MemorySpace in the virtual memory space
43//
44// |  : page boundary
45// [,]: MemoryRegion
46// -  : fillment
47// =  : data
48//
49// |---[=|====|====|==]--|
50// ^   ^              ^  ^
51// |   |              |  |
52// | r_start      +r_len |
53// space.data      +space.size
54//
55// space.file_offset is the offset of the mapped file segment from the start of
56// the file. if the MemorySpace's type is ALLOCATED_ARRAY, the distances of
57// (space.data, r_start) and (r_len, space.size) are zero.
58//
59MemoryRegion* MemoryArea::request(size_t pOffset, size_t pLength)
60{
61  Space* space = find(pOffset, pLength);
62  if (NULL == space) {
63    // not found
64    if (NULL == m_pFileHandle) {
65      // if m_pFileHandle is NULL, clients delegate us an universal Space and
66      // we never remove it. In that way, space can not be NULL.
67      unreachable(diag::err_out_of_range_region) << pOffset << pLength;
68    }
69
70    space = Space::Create(*m_pFileHandle, pOffset, pLength);
71    m_SpaceMap.insert(std::make_pair(Key(pOffset, pLength), space));
72  }
73
74  // adjust r_start
75  off_t distance = pOffset - space->start();
76  void* r_start = space->memory() + distance;
77
78  // now, we have a legal space to hold the new MemoryRegion
79  return MemoryRegion::Create(r_start, pLength, *space);
80}
81
82// release - release a MemoryRegion
83void MemoryArea::release(MemoryRegion* pRegion)
84{
85  if (NULL == pRegion)
86    return;
87
88  Space *space = pRegion->parent();
89  MemoryRegion::Destroy(pRegion);
90
91  if (0 == space->numOfRegions()) {
92
93    if (NULL != m_pFileHandle) {
94      // if m_pFileHandle is NULL, clients delegate us an universal Space and
95      // we never remove it. Otherwise, we have to synchronize and release
96      // Space.
97      if (m_pFileHandle->isWritable()) {
98        // synchronize writable space before we release it.
99        Space::Sync(space, *m_pFileHandle);
100      }
101      m_SpaceMap.erase(Key(space->start(), space->size()));
102      Space::Release(space, *m_pFileHandle);
103    }
104  }
105}
106
107// clear - release all MemoryRegions
108void MemoryArea::clear()
109{
110  if (NULL == m_pFileHandle)
111    return;
112
113  if (m_pFileHandle->isWritable()) {
114    SpaceMapType::iterator space, sEnd = m_SpaceMap.end();
115    for (space = m_SpaceMap.begin(); space != sEnd; ++space) {
116      Space::Sync(space->second, *m_pFileHandle);
117      Space::Release(space->second, *m_pFileHandle);
118    }
119  }
120  else {
121    SpaceMapType::iterator space, sEnd = m_SpaceMap.end();
122    for (space = m_SpaceMap.begin(); space != sEnd; ++space)
123      Space::Release(space->second, *m_pFileHandle);
124  }
125
126  for (SpaceMapType::iterator space = m_SpaceMap.begin(),
127         sEnd = m_SpaceMap.end(); space != sEnd; ++space) {
128    if (space->second != NULL)
129      Space::Destroy(space->second);
130  }
131  m_SpaceMap.clear();
132}
133
134//===--------------------------------------------------------------------===//
135// SpaceList methods
136//===--------------------------------------------------------------------===//
137Space* MemoryArea::find(size_t pOffset, size_t pLength)
138{
139  SpaceMapType::iterator it = m_SpaceMap.find(Key(pOffset, pLength));
140  if (it != m_SpaceMap.end())
141    return it->second;
142
143  return NULL;
144}
145
146const Space* MemoryArea::find(size_t pOffset, size_t pLength) const
147{
148  SpaceMapType::const_iterator it = m_SpaceMap.find(Key(pOffset, pLength));
149  if (it != m_SpaceMap.end())
150    return it->second;
151
152  return NULL;
153}
154
155