//===- MemoryArea.h -------------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef MCLD_SUPPORT_MEMORY_AREA_H
#define MCLD_SUPPORT_MEMORY_AREA_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
#include <mcld/ADT/Uncopyable.h>
#include <cstddef>
#include <map>
#if defined(ENABLE_UNITTEST)
namespace mcldtest {
class MemoryAreaTest;
} // namespace of mcldtest
#endif
namespace mcld {
class Space;
class FileHandle;
class MemoryRegion;
/** \class MemoryArea
* \brief MemoryArea is used to manage distinct MemoryRegions of address space.
*
* Good linkers must well manipulate memory mapped I/O and dynamic memory.
* In MCLinker, MemoryArea is the decision-maker to use memory mapped I/O or
* dynamic memory. When a client requests MemoryArea for a piece of memory
* to hold a part of a file, MemoryArea is going to see whether the requested
* part of the file is already in any existing memory which is requested
* before. If it is, MemoryArea creates a new MemoryRegion within the memory
* requested before. Otherwise, MemoryArea uses memory mapped I/O or dynamic
* memory to load the file.
*
* If the part a file being loaded is larger than 3/4 pages, MemoryArea uses
* memory mapped I/O to load the file. Otherwise, MemoryArea uses dynamic
* memory to read the content of file into the memory space.
*/
class MemoryArea : private Uncopyable
{
friend class MemoryAreaFactory;
public:
// constructor by file handler.
// If the given file handler is read-only, client can not request a region
// that out of the file size.
// @param pFileHandle - file handler
explicit MemoryArea(FileHandle& pFileHandle);
// constructor by set universal space.
// Client can not request a region that out of the universal space.
// @param pUniverse - file handler
explicit MemoryArea(Space& pUniverse);
// destructor
~MemoryArea();
// request - create a MemoryRegion within a sufficient space
// find an existing space to hold the MemoryRegion.
// if MemoryArea does not find such space, then it creates a new space and
// assign a MemoryRegion into the space.
MemoryRegion* request(size_t pOffset, size_t pLength);
// release - release a MemoryRegion.
// release a MemoryRegion does not cause
void release(MemoryRegion* pRegion);
// clear - release all memory regions.
void clear();
const FileHandle* handler() const { return m_pFileHandle; }
FileHandle* handler() { return m_pFileHandle; }
bool hasHandler() const { return (NULL != m_pFileHandle); }
// ----- space list methods ----- //
Space* find(size_t pOffset, size_t pLength);
const Space* find(size_t pOffset, size_t pLength) const;
private:
class Key {
public:
Key(size_t pOffset, size_t pLength)
: m_Offset(pOffset), m_Length(pLength)
{ }
size_t offset() const { return m_Offset; }
size_t length() const { return m_Length; }
struct Compare {
bool operator()(const Key& KEY1, const Key& KEY2) const
{
return KEY1.offset() + KEY1.length() < KEY2.offset() ||
(KEY1.offset() < KEY2.offset() &&
(KEY1.offset() + KEY1.length() < KEY2.offset() + KEY2.length()));
}
};
private:
size_t m_Offset;
size_t m_Length;
};
typedef std::multimap<Key, Space*, Key::Compare> SpaceMapType;
private:
SpaceMapType m_SpaceMap;
FileHandle* m_pFileHandle;
};
} // namespace of mcld
#endif