diff options
Diffstat (limited to 'JavaScriptCore/wtf/PageReservation.h')
| -rw-r--r-- | JavaScriptCore/wtf/PageReservation.h | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/JavaScriptCore/wtf/PageReservation.h b/JavaScriptCore/wtf/PageReservation.h new file mode 100644 index 0000000..cfc7cd9 --- /dev/null +++ b/JavaScriptCore/wtf/PageReservation.h @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PageReservation_h +#define PageReservation_h + +#include <wtf/PageAllocation.h> + +namespace WTF { + +/* + PageReservation + + Like PageAllocation, the PageReservation class provides a cross-platform memory + allocation interface, but with a set of capabilities more similar to that of + VirtualAlloc than posix mmap. PageReservation can be used to allocate virtual + memory without committing physical memory pages using PageReservation::reserve. + Following a call to reserve all memory in the region is in a decommited state, + in which the memory should not be used (accessing the memory may cause a fault). + + Before using memory it must be committed by calling commit, which is passed start + and size values (both of which require system page size granularity). One the + committed memory is no longer needed 'decommit' may be called to return the + memory to its devommitted state. Commit should only be called on memory that is + currently decommitted, and decommit should only be called on memory regions that + are currently committed. All memory should be decommited before the reservation + is deallocated. Values in memory may not be retained accross a pair of calls if + the region of memory is decommitted and then committed again. + + Where HAVE(PAGE_ALLOCATE_AT) is available a PageReservation::reserveAt method + also exists, with behaviour mirroring PageAllocation::allocateAt. + + Memory protection should not be changed on decommitted memory, and if protection + is changed on memory while it is committed it should be returned to the orignal + protection before decommit is called. + + Note: Inherits from PageAllocation privately to prevent clients accidentally + calling PageAllocation::deallocate on a PageReservation. +*/ +class PageReservation : private PageAllocation { +public: + PageReservation() + { + } + + using PageAllocation::operator!; + using PageAllocation::base; + using PageAllocation::size; + + bool commit(void* start, size_t size) + { + ASSERT(m_base); + ASSERT(isPageAligned(start)); + ASSERT(isPageAligned(size)); + + bool commited = systemCommit(start, size); +#ifndef NDEBUG + if (commited) + m_committed += size; +#endif + return commited; + } + void decommit(void* start, size_t size) + { + ASSERT(m_base); + ASSERT(isPageAligned(start)); + ASSERT(isPageAligned(size)); + +#ifndef NDEBUG + m_committed -= size; +#endif + systemDecommit(start, size); + } + + static PageReservation reserve(size_t size, Usage usage = UnknownUsage, bool writable = true, bool executable = false) + { + ASSERT(isPageAligned(size)); + return systemReserve(size, usage, writable, executable); + } + +#if HAVE(PAGE_ALLOCATE_AT) + static PageReservation reserveAt(void* address, bool fixed, size_t size, Usage usage = UnknownUsage, bool writable = true, bool executable = false) + { + ASSERT(isPageAligned(address)); + ASSERT(isPageAligned(size)); + return systemReserveAt(address, fixed, size, usage, writable, executable); + } +#endif + + void deallocate() + { + ASSERT(m_base); + ASSERT(!m_committed); + systemDeallocate(false); + } + +#ifndef NDEBUG + using PageAllocation::lastError; +#endif + +private: +#if OS(SYMBIAN) + PageReservation(void* base, size_t size, RChunk* chunk) + : PageAllocation(base, size, chunk) +#else + PageReservation(void* base, size_t size) + : PageAllocation(base, size) +#endif +#ifndef NDEBUG + , m_committed(0) +#endif + { + } + + bool systemCommit(void*, size_t); + void systemDecommit(void*, size_t); + static PageReservation systemReserve(size_t, Usage, bool, bool); +#if HAVE(PAGE_ALLOCATE_AT) + static PageReservation systemReserveAt(void*, bool, size_t, Usage, bool, bool); +#endif + +#if HAVE(VIRTUALALLOC) + DWORD m_protection; +#endif +#ifndef NDEBUG + size_t m_committed; +#endif +}; + + +#if HAVE(MMAP) + + +inline bool PageReservation::systemCommit(void* start, size_t size) +{ +#if HAVE(MADV_FREE_REUSE) + while (madvise(start, size, MADV_FREE_REUSE) == -1 && errno == EAGAIN) { } +#else + UNUSED_PARAM(start); + UNUSED_PARAM(size); +#endif + return true; +} + +inline void PageReservation::systemDecommit(void* start, size_t size) +{ +#if HAVE(MADV_FREE_REUSE) + while (madvise(start, size, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { } +#elif HAVE(MADV_FREE) + while (madvise(start, size, MADV_FREE) == -1 && errno == EAGAIN) { } +#elif HAVE(MADV_DONTNEED) + while (madvise(start, size, MADV_DONTNEED) == -1 && errno == EAGAIN) { } +#else + UNUSED_PARAM(start); + UNUSED_PARAM(size); +#endif +} + +inline PageReservation PageReservation::systemReserve(size_t size, Usage usage, bool writable, bool executable) +{ + return systemReserveAt(0, false, size, usage, writable, executable); +} + +inline PageReservation PageReservation::systemReserveAt(void* address, bool fixed, size_t size, Usage usage, bool writable, bool executable) +{ + void* base = systemAllocateAt(address, fixed, size, usage, writable, executable).base(); +#if HAVE(MADV_FREE_REUSE) + // When using MADV_FREE_REUSE we keep all decommitted memory marked as REUSABLE. + // We call REUSE on commit, and REUSABLE on decommit. + if (base) + while (madvise(base, size, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { } +#endif + return PageReservation(base, size); +} + + +#elif HAVE(VIRTUALALLOC) + + +inline bool PageReservation::systemCommit(void* start, size_t size) +{ + return VirtualAlloc(start, size, MEM_COMMIT, m_protection) == start; +} + +inline void PageReservation::systemDecommit(void* start, size_t size) +{ + VirtualFree(start, size, MEM_DECOMMIT); +} + +inline PageReservation PageReservation::systemReserve(size_t size, Usage usage, bool writable, bool executable) +{ + // Record the protection for use during commit. + DWORD protection = executable ? + (writable ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ) : + (writable ? PAGE_READWRITE : PAGE_READONLY); + PageReservation reservation(VirtualAlloc(0, size, MEM_RESERVE, protection), size); + reservation.m_protection = protection; + return reservation; +} + + +#elif OS(SYMBIAN) + + +inline bool PageReservation::systemCommit(void* start, size_t size) +{ + intptr_t offset = reinterpret_cast<intptr_t>(start) - reinterpret_cast<intptr_t>(m_base); + m_chunk->Commit(offset, size); + return true; +} + +inline void PageReservation::systemDecommit(void* start, size_t size) +{ + intptr_t offset = reinterpret_cast<intptr_t>(start) - reinterpret_cast<intptr_t>(m_base); + m_chunk->Decommit(offset, size); +} + +inline PageReservation PageReservation::systemReserve(size_t size, Usage usage, bool writable, bool executable) +{ + RChunk* rchunk = new RChunk(); + if (executable) + rchunk->CreateLocalCode(0, size); + else + rchunk->CreateDisconnectedLocal(0, 0, size); + return PageReservation(rchunk->Base(), size, rchunk); +} + + +#endif + + +} + +using WTF::PageReservation; + +#endif // PageReservation_h |
