X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/6fe7ccc865dc7d7541b93c5bcaf6368d2c98a174..refs/heads/master:/jit/ExecutableAllocatorFixedVMPool.cpp diff --git a/jit/ExecutableAllocatorFixedVMPool.cpp b/jit/ExecutableAllocatorFixedVMPool.cpp index 65a3a73..7fe9c8a 100644 --- a/jit/ExecutableAllocatorFixedVMPool.cpp +++ b/jit/ExecutableAllocatorFixedVMPool.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,79 +24,84 @@ */ #include "config.h" - #include "ExecutableAllocator.h" +#include "JSCInlines.h" + #if ENABLE(EXECUTABLE_ALLOCATOR_FIXED) #include "CodeProfiling.h" +#include "ExecutableAllocationFuzz.h" #include -#include +#if !PLATFORM(WIN) #include +#endif #include #include #include +#if OS(DARWIN) +#include +#endif + #if OS(LINUX) #include #endif - #define MMAP_FLAGS (MAP_PRIVATE | MAP_ANON | MAP_JIT) - using namespace WTF; namespace JSC { -#if CPU(ARM) -static const size_t fixedPoolSize = 16 * 1024 * 1024; -#elif CPU(X86_64) -static const size_t fixedPoolSize = 1024 * 1024 * 1024; -#else -static const size_t fixedPoolSize = 32 * 1024 * 1024; -#endif +uintptr_t startOfFixedExecutableMemoryPool; class FixedVMPoolExecutableAllocator : public MetaAllocator { + WTF_MAKE_FAST_ALLOCATED; public: FixedVMPoolExecutableAllocator() - : MetaAllocator(32) // round up all allocations to 32 bytes + : MetaAllocator(jitAllocationGranule) // round up all allocations to 32 bytes { - m_reservation = PageReservation::reserveWithGuardPages(fixedPoolSize, OSAllocator::JSJITCodePages, EXECUTABLE_POOL_WRITABLE, true); -#if !(ENABLE(CLASSIC_INTERPRETER) || ENABLE(LLINT)) - if (!m_reservation) - CRASH(); -#endif + size_t reservationSize; + if (Options::jitMemoryReservationSize()) + reservationSize = Options::jitMemoryReservationSize(); + else + reservationSize = fixedExecutableMemoryPoolSize; + m_reservation = PageReservation::reserveWithGuardPages(reservationSize, OSAllocator::JSJITCodePages, EXECUTABLE_POOL_WRITABLE, true); if (m_reservation) { - ASSERT(m_reservation.size() == fixedPoolSize); + ASSERT(m_reservation.size() == reservationSize); addFreshFreeSpace(m_reservation.base(), m_reservation.size()); + + startOfFixedExecutableMemoryPool = reinterpret_cast(m_reservation.base()); } } + + virtual ~FixedVMPoolExecutableAllocator(); protected: - virtual void* allocateNewSpace(size_t&) + virtual void* allocateNewSpace(size_t&) override { // We're operating in a fixed pool, so new allocation is always prohibited. return 0; } - virtual void notifyNeedPage(void* page) + virtual void notifyNeedPage(void* page) override { -#if OS(DARWIN) +#if USE(MADV_FREE_FOR_JIT_MEMORY) UNUSED_PARAM(page); #else m_reservation.commit(page, pageSize()); #endif } - virtual void notifyPageIsFree(void* page) + virtual void notifyPageIsFree(void* page) override { -#if OS(DARWIN) +#if USE(MADV_FREE_FOR_JIT_MEMORY) for (;;) { int result = madvise(page, pageSize(), MADV_FREE); if (!result) return; ASSERT(result == -1); if (errno != EAGAIN) { - ASSERT_NOT_REACHED(); // In debug mode, this should be a hard failure. + RELEASE_ASSERT_NOT_REACHED(); // In debug mode, this should be a hard failure. 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. } } @@ -118,7 +123,7 @@ void ExecutableAllocator::initializeAllocator() CodeProfiling::notifyAllocator(allocator); } -ExecutableAllocator::ExecutableAllocator(JSGlobalData&) +ExecutableAllocator::ExecutableAllocator(VM&) { ASSERT(allocator); } @@ -127,6 +132,11 @@ ExecutableAllocator::~ExecutableAllocator() { } +FixedVMPoolExecutableAllocator::~FixedVMPoolExecutableAllocator() +{ + m_reservation.deallocate(); +} + bool ExecutableAllocator::isValid() const { return !!allocator->bytesReserved(); @@ -143,29 +153,49 @@ double ExecutableAllocator::memoryPressureMultiplier(size_t addedMemoryUsage) MetaAllocator::Statistics statistics = allocator->currentStatistics(); ASSERT(statistics.bytesAllocated <= statistics.bytesReserved); size_t bytesAllocated = statistics.bytesAllocated + addedMemoryUsage; - if (bytesAllocated >= statistics.bytesReserved) - bytesAllocated = statistics.bytesReserved; + size_t bytesAvailable = static_cast( + statistics.bytesReserved * (1 - executablePoolReservationFraction)); + if (bytesAllocated >= bytesAvailable) + bytesAllocated = bytesAvailable; double result = 1.0; - size_t divisor = statistics.bytesReserved - bytesAllocated; + size_t divisor = bytesAvailable - bytesAllocated; if (divisor) - result = static_cast(statistics.bytesReserved) / divisor; + result = static_cast(bytesAvailable) / divisor; if (result < 1.0) result = 1.0; return result; } -PassRefPtr ExecutableAllocator::allocate(JSGlobalData& globalData, size_t sizeInBytes, void* ownerUID, JITCompilationEffort effort) +RefPtr ExecutableAllocator::allocate(VM&, size_t sizeInBytes, void* ownerUID, JITCompilationEffort effort) { + if (effort != JITCompilationCanFail && Options::reportMustSucceedExecutableAllocations()) { + dataLog("Allocating ", sizeInBytes, " bytes of executable memory with JITCompilationMustSucceed.\n"); + WTFReportBacktrace(); + } + + if (effort == JITCompilationCanFail + && doExecutableAllocationFuzzingIfEnabled() == PretendToFailExecutableAllocation) + return nullptr; + + if (effort == JITCompilationCanFail) { + // Don't allow allocations if we are down to reserve. + MetaAllocator::Statistics statistics = allocator->currentStatistics(); + size_t bytesAllocated = statistics.bytesAllocated + sizeInBytes; + size_t bytesAvailable = static_cast( + statistics.bytesReserved * (1 - executablePoolReservationFraction)); + if (bytesAllocated > bytesAvailable) + return nullptr; + } + RefPtr result = allocator->allocate(sizeInBytes, ownerUID); if (!result) { - if (effort == JITCompilationCanFail) - return result; - releaseExecutableMemory(globalData); - result = allocator->allocate(sizeInBytes, ownerUID); - if (!result) + if (effort != JITCompilationCanFail) { + dataLog("Ran out of executable memory while allocating ", sizeInBytes, " bytes.\n"); CRASH(); + } + return nullptr; } - return result.release(); + return result; } size_t ExecutableAllocator::committedByteCount() @@ -184,13 +214,3 @@ void ExecutableAllocator::dumpProfile() #endif // ENABLE(EXECUTABLE_ALLOCATOR_FIXED) - -#if !ENABLE(ASSEMBLER) -// FIXME: Needed to satisfy JavaScriptCore.exp requirements when building only the interpreter. -namespace JSC { -size_t ExecutableAllocator::committedByteCount() -{ - return 0; -} -} // namespace JSC -#endif // !ENABLE(JIT)