1 /* 2 * Copyright (C) 2008 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 #include "config.h" 27 28 #if ENABLE(PURGEABLE_MEMORY) 29 30 #include "PurgeableBuffer.h" 31 32 #include <mach/mach.h> 33 #include <wtf/Assertions.h> 34 #include <wtf/VMTags.h> 35 36 namespace WebCore { 37 38 // Purgeable buffers are allocated in multiples of the page size (4KB in common CPUs) so 39 // it does not make sense for very small buffers. Set our minimum size to 16KB. 40 static const size_t minPurgeableBufferSize = 4 * 4096; 41 42 PurgeableBuffer::PurgeableBuffer(char* data, size_t size) 43 : m_data(data) 44 , m_size(size) 45 , m_purgePriority(PurgeDefault) 46 , m_state(NonVolatile) 47 { 48 } 49 50 PurgeableBuffer::~PurgeableBuffer() 51 { 52 vm_deallocate(mach_task_self(), reinterpret_cast<vm_address_t>(m_data), m_size); 53 } 54 55 PassOwnPtr<PurgeableBuffer> PurgeableBuffer::create(const char* data, size_t size) 56 { 57 if (size < minPurgeableBufferSize) 58 return PassOwnPtr<PurgeableBuffer>(); 59 60 vm_address_t buffer = 0; 61 kern_return_t ret = vm_allocate(mach_task_self(), &buffer, size, VM_FLAGS_PURGABLE | VM_FLAGS_ANYWHERE | VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY); 62 63 ASSERT(ret == KERN_SUCCESS); 64 if (ret != KERN_SUCCESS) 65 return PassOwnPtr<PurgeableBuffer>(); 66 67 ret = vm_copy(mach_task_self(), reinterpret_cast<vm_address_t>(data), size, buffer); 68 69 ASSERT(ret == KERN_SUCCESS); 70 if (ret != KERN_SUCCESS) { 71 vm_deallocate(mach_task_self(), buffer, size); 72 return PassOwnPtr<PurgeableBuffer>(); 73 } 74 75 return adoptPtr(new PurgeableBuffer(reinterpret_cast<char*>(buffer), size)); 76 } 77 78 bool PurgeableBuffer::makePurgeable(bool purgeable) 79 { 80 if (purgeable) { 81 if (m_state != NonVolatile) 82 return true; 83 84 int volatileGroup; 85 if (m_purgePriority == PurgeFirst) 86 volatileGroup = VM_VOLATILE_GROUP_0; 87 else if (m_purgePriority == PurgeMiddle) 88 volatileGroup = VM_VOLATILE_GROUP_4; 89 else 90 volatileGroup = VM_VOLATILE_GROUP_7; 91 92 int state = VM_PURGABLE_VOLATILE | volatileGroup; 93 // So apparently "purgeable" is the correct spelling and the API here is misspelled. 94 kern_return_t ret = vm_purgable_control(mach_task_self(), reinterpret_cast<vm_address_t>(m_data), VM_PURGABLE_SET_STATE, &state); 95 96 if (ret != KERN_SUCCESS) { 97 // If that failed we have no clue what state we are in so assume purged. 98 m_state = Purged; 99 return true; 100 } 101 102 m_state = Volatile; 103 return true; 104 } 105 106 if (m_state == NonVolatile) 107 return true; 108 if (m_state == Purged) 109 return false; 110 111 int state = VM_PURGABLE_NONVOLATILE; 112 kern_return_t ret = vm_purgable_control(mach_task_self(), reinterpret_cast<vm_address_t>(m_data), VM_PURGABLE_SET_STATE, &state); 113 114 if (ret != KERN_SUCCESS) { 115 // If that failed we have no clue what state we are in so assume purged. 116 m_state = Purged; 117 return false; 118 } 119 120 m_state = state & VM_PURGABLE_EMPTY ? Purged : NonVolatile; 121 return m_state == NonVolatile; 122 } 123 124 bool PurgeableBuffer::wasPurged() const 125 { 126 if (m_state == NonVolatile) 127 return false; 128 if (m_state == Purged) 129 return true; 130 131 int state; 132 kern_return_t ret = vm_purgable_control(mach_task_self(), reinterpret_cast<vm_address_t>(m_data), VM_PURGABLE_GET_STATE, &state); 133 134 if (ret != KERN_SUCCESS) { 135 // If that failed we have no clue what state we are in so assume purged. 136 m_state = Purged; 137 return true; 138 } 139 140 if (state & VM_PURGABLE_EMPTY) { 141 m_state = Purged; 142 return true; 143 } 144 145 return false; 146 } 147 148 const char* PurgeableBuffer::data() const 149 { 150 ASSERT(m_state == NonVolatile); 151 return m_data; 152 } 153 154 } 155 156 #endif // BUILDING_ON_TIGER 157