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
15 using 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.
MemoryArea(RegionFactory & pRegionFactory,Space & pUniverse)24 MemoryArea::MemoryArea(RegionFactory& pRegionFactory, Space& pUniverse)
25 : m_RegionFactory(pRegionFactory), m_pFileHandle(NULL) {
26 m_SpaceList.push_back(&pUniverse);
27 }
28
MemoryArea(RegionFactory & pRegionFactory,FileHandle & pFileHandle)29 MemoryArea::MemoryArea(RegionFactory& pRegionFactory, FileHandle& pFileHandle)
30 : m_RegionFactory(pRegionFactory), m_pFileHandle(&pFileHandle) {
31 }
32
~MemoryArea()33 MemoryArea::~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 //
request(size_t pOffset,size_t pLength)54 MemoryRegion* 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
release(MemoryRegion * pRegion)78 void 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
clear()103 void 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
find(size_t pOffset,size_t pLength)126 Space* 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
find(size_t pOffset,size_t pLength) const139 const 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