1/* 2 * Copyright (C) 2009 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#include "ExecutableAllocator.h" 29 30#if ENABLE(EXECUTABLE_ALLOCATOR_FIXED) 31 32#include "CodeProfiling.h" 33#include <errno.h> 34#include <unistd.h> 35#include <wtf/MetaAllocator.h> 36#include <wtf/PageReservation.h> 37#include <wtf/VMTags.h> 38 39#if OS(DARWIN) 40#include <sys/mman.h> 41#endif 42 43#if OS(LINUX) 44#include <stdio.h> 45#endif 46 47#if !PLATFORM(IOS) && PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 1090 48// MADV_FREE_REUSABLE does not work for JIT memory on older OSes so use MADV_FREE in that case. 49#define WTF_USE_MADV_FREE_FOR_JIT_MEMORY 1 50#endif 51 52using namespace WTF; 53 54namespace JSC { 55 56uintptr_t startOfFixedExecutableMemoryPool; 57 58class FixedVMPoolExecutableAllocator : public MetaAllocator { 59 WTF_MAKE_FAST_ALLOCATED; 60public: 61 FixedVMPoolExecutableAllocator() 62 : MetaAllocator(jitAllocationGranule) // round up all allocations to 32 bytes 63 { 64 m_reservation = PageReservation::reserveWithGuardPages(fixedExecutableMemoryPoolSize, OSAllocator::JSJITCodePages, EXECUTABLE_POOL_WRITABLE, true); 65#if !ENABLE(LLINT) 66 RELEASE_ASSERT(m_reservation); 67#endif 68 if (m_reservation) { 69 ASSERT(m_reservation.size() == fixedExecutableMemoryPoolSize); 70 addFreshFreeSpace(m_reservation.base(), m_reservation.size()); 71 72 startOfFixedExecutableMemoryPool = reinterpret_cast<uintptr_t>(m_reservation.base()); 73 } 74 } 75 76 virtual ~FixedVMPoolExecutableAllocator(); 77 78protected: 79 virtual void* allocateNewSpace(size_t&) 80 { 81 // We're operating in a fixed pool, so new allocation is always prohibited. 82 return 0; 83 } 84 85 virtual void notifyNeedPage(void* page) 86 { 87#if USE(MADV_FREE_FOR_JIT_MEMORY) 88 UNUSED_PARAM(page); 89#else 90 m_reservation.commit(page, pageSize()); 91#endif 92 } 93 94 virtual void notifyPageIsFree(void* page) 95 { 96#if USE(MADV_FREE_FOR_JIT_MEMORY) 97 for (;;) { 98 int result = madvise(page, pageSize(), MADV_FREE); 99 if (!result) 100 return; 101 ASSERT(result == -1); 102 if (errno != EAGAIN) { 103 RELEASE_ASSERT_NOT_REACHED(); // In debug mode, this should be a hard failure. 104 break; // In release mode, we should just ignore the error - not returning memory to the OS is better than crashing, especially since we _will_ be able to reuse the memory internally anyway. 105 } 106 } 107#else 108 m_reservation.decommit(page, pageSize()); 109#endif 110 } 111 112private: 113 PageReservation m_reservation; 114}; 115 116static FixedVMPoolExecutableAllocator* allocator; 117 118void ExecutableAllocator::initializeAllocator() 119{ 120 ASSERT(!allocator); 121 allocator = new FixedVMPoolExecutableAllocator(); 122 CodeProfiling::notifyAllocator(allocator); 123} 124 125ExecutableAllocator::ExecutableAllocator(VM&) 126{ 127 ASSERT(allocator); 128} 129 130ExecutableAllocator::~ExecutableAllocator() 131{ 132} 133 134FixedVMPoolExecutableAllocator::~FixedVMPoolExecutableAllocator() 135{ 136 m_reservation.deallocate(); 137} 138 139bool ExecutableAllocator::isValid() const 140{ 141 return !!allocator->bytesReserved(); 142} 143 144bool ExecutableAllocator::underMemoryPressure() 145{ 146 MetaAllocator::Statistics statistics = allocator->currentStatistics(); 147 return statistics.bytesAllocated > statistics.bytesReserved / 2; 148} 149 150double ExecutableAllocator::memoryPressureMultiplier(size_t addedMemoryUsage) 151{ 152 MetaAllocator::Statistics statistics = allocator->currentStatistics(); 153 ASSERT(statistics.bytesAllocated <= statistics.bytesReserved); 154 size_t bytesAllocated = statistics.bytesAllocated + addedMemoryUsage; 155 if (bytesAllocated >= statistics.bytesReserved) 156 bytesAllocated = statistics.bytesReserved; 157 double result = 1.0; 158 size_t divisor = statistics.bytesReserved - bytesAllocated; 159 if (divisor) 160 result = static_cast<double>(statistics.bytesReserved) / divisor; 161 if (result < 1.0) 162 result = 1.0; 163 return result; 164} 165 166PassRefPtr<ExecutableMemoryHandle> ExecutableAllocator::allocate(VM& vm, size_t sizeInBytes, void* ownerUID, JITCompilationEffort effort) 167{ 168 RefPtr<ExecutableMemoryHandle> result = allocator->allocate(sizeInBytes, ownerUID); 169 if (!result) { 170 if (effort == JITCompilationCanFail) 171 return result; 172 releaseExecutableMemory(vm); 173 result = allocator->allocate(sizeInBytes, ownerUID); 174 RELEASE_ASSERT(result); 175 } 176 return result.release(); 177} 178 179size_t ExecutableAllocator::committedByteCount() 180{ 181 return allocator->bytesCommitted(); 182} 183 184#if ENABLE(META_ALLOCATOR_PROFILE) 185void ExecutableAllocator::dumpProfile() 186{ 187 allocator->dumpProfile(); 188} 189#endif 190 191} 192 193 194#endif // ENABLE(EXECUTABLE_ALLOCATOR_FIXED) 195