Home | History | Annotate | Download | only in wtf
      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