]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - jit/ExecutableAllocatorFixedVMPool.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / jit / ExecutableAllocatorFixedVMPool.cpp
index 65a3a7371c5d48a192d3a1c168088ba707dde739..7fe9c8ae8aee4159745b0d56e7f28ecf15b577de 100644 (file)
@@ -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
  */
 
 #include "config.h"
-
 #include "ExecutableAllocator.h"
 
+#include "JSCInlines.h"
+
 #if ENABLE(EXECUTABLE_ALLOCATOR_FIXED)
 
 #include "CodeProfiling.h"
+#include "ExecutableAllocationFuzz.h"
 #include <errno.h>
-#include <sys/mman.h>
+#if !PLATFORM(WIN)
 #include <unistd.h>
+#endif
 #include <wtf/MetaAllocator.h>
 #include <wtf/PageReservation.h>
 #include <wtf/VMTags.h>
 
+#if OS(DARWIN)
+#include <sys/mman.h>
+#endif
+
 #if OS(LINUX)
 #include <stdio.h>
 #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<uintptr_t>(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<size_t>(
+        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<double>(statistics.bytesReserved) / divisor;
+        result = static_cast<double>(bytesAvailable) / divisor;
     if (result < 1.0)
         result = 1.0;
     return result;
 }
 
-PassRefPtr<ExecutableMemoryHandle> ExecutableAllocator::allocate(JSGlobalData& globalData, size_t sizeInBytes, void* ownerUID, JITCompilationEffort effort)
+RefPtr<ExecutableMemoryHandle> 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<size_t>(
+            statistics.bytesReserved * (1 - executablePoolReservationFraction));
+        if (bytesAllocated > bytesAvailable)
+            return nullptr;
+    }
+    
     RefPtr<ExecutableMemoryHandle> 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)