1 /* 2 * Copyright (C) 2010 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #ifndef PageReservation_h 27 #define PageReservation_h 28 29 #include <wtf/PageAllocation.h> 30 31 namespace WTF { 32 33 /* 34 PageReservation 35 36 Like PageAllocation, the PageReservation class provides a cross-platform memory 37 allocation interface, but with a set of capabilities more similar to that of 38 VirtualAlloc than posix mmap. PageReservation can be used to allocate virtual 39 memory without committing physical memory pages using PageReservation::reserve. 40 Following a call to reserve all memory in the region is in a decommited state, 41 in which the memory should not be used (accessing the memory may cause a fault). 42 43 Before using memory it must be committed by calling commit, which is passed start 44 and size values (both of which require system page size granularity). One the 45 committed memory is no longer needed 'decommit' may be called to return the 46 memory to its devommitted state. Commit should only be called on memory that is 47 currently decommitted, and decommit should only be called on memory regions that 48 are currently committed. All memory should be decommited before the reservation 49 is deallocated. Values in memory may not be retained accross a pair of calls if 50 the region of memory is decommitted and then committed again. 51 52 Memory protection should not be changed on decommitted memory, and if protection 53 is changed on memory while it is committed it should be returned to the orignal 54 protection before decommit is called. 55 */ 56 57 class PageReservation : private PageBlock { 58 public: 59 PageReservation() 60 : m_committed(0) 61 , m_writable(false) 62 , m_executable(false) 63 { 64 } 65 66 using PageBlock::base; 67 using PageBlock::size; 68 69 #ifndef __clang__ 70 using PageBlock::operator bool; 71 #else 72 // FIXME: This is a workaround for <rdar://problem/8876150>, wherein Clang incorrectly emits an access 73 // control warning when a client tries to use operator bool exposed above via "using PageBlock::operator bool". 74 operator bool() const { return PageBlock::operator bool(); } 75 #endif 76 77 void commit(void* start, size_t size) 78 { 79 ASSERT(*this); 80 ASSERT(isPageAligned(start)); 81 ASSERT(isPageAligned(size)); 82 ASSERT(contains(start, size)); 83 84 m_committed += size; 85 OSAllocator::commit(start, size, m_writable, m_executable); 86 } 87 88 void decommit(void* start, size_t size) 89 { 90 ASSERT(*this); 91 ASSERT(isPageAligned(start)); 92 ASSERT(isPageAligned(size)); 93 ASSERT(contains(start, size)); 94 95 m_committed -= size; 96 OSAllocator::decommit(start, size); 97 } 98 99 size_t committed() 100 { 101 return m_committed; 102 } 103 104 static PageReservation reserve(size_t size, OSAllocator::Usage usage = OSAllocator::UnknownUsage, bool writable = true, bool executable = false) 105 { 106 ASSERT(isPageAligned(size)); 107 return PageReservation(OSAllocator::reserveUncommitted(size, usage, writable, executable), size, writable, executable); 108 } 109 110 void deallocate() 111 { 112 ASSERT(!m_committed); 113 114 // Clear base & size before calling release; if this is *inside* allocation 115 // then we won't be able to clear then after deallocating the memory. 116 PageReservation tmp; 117 std::swap(tmp, *this); 118 119 ASSERT(tmp); 120 ASSERT(!*this); 121 122 OSAllocator::releaseDecommitted(tmp.base(), tmp.size()); 123 } 124 125 private: 126 PageReservation(void* base, size_t size, bool writable, bool executable) 127 : PageBlock(base, size) 128 , m_committed(0) 129 , m_writable(writable) 130 , m_executable(executable) 131 { 132 } 133 134 size_t m_committed; 135 bool m_writable; 136 bool m_executable; 137 }; 138 139 } 140 141 using WTF::PageReservation; 142 143 #endif // PageReservation_h 144