]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - wtf/TCSystemAlloc.cpp
JavaScriptCore-584.tar.gz
[apple/javascriptcore.git] / wtf / TCSystemAlloc.cpp
index 1aeb99ef1847fad7fc5d35b6e13fb4d783398ed8..c46ff311f1cfd29bd11d1b5768de3908ae824d7f 100644 (file)
 // Author: Sanjay Ghemawat
 
 #include "config.h"
+#include "TCSystemAlloc.h"
+
+#include <algorithm>
+#include <fcntl.h>
+#include "Assertions.h"
+#include "TCSpinLock.h"
+#include "UnusedParam.h"
+#include "VMTags.h"
+
 #if HAVE(STDINT_H)
 #include <stdint.h>
 #elif HAVE(INTTYPES_H)
 #else
 #include <sys/types.h>
 #endif
-#if PLATFORM(WIN_OS)
+
+#if OS(WINDOWS)
 #include "windows.h"
 #else
 #include <errno.h>
 #include <unistd.h>
 #include <sys/mman.h>
 #endif
-#include <fcntl.h>
-#include "Assertions.h"
-#include "TCSystemAlloc.h"
-#include "TCSpinLock.h"
-#include "UnusedParam.h"
 
 #ifndef MAP_ANONYMOUS
 #define MAP_ANONYMOUS MAP_ANON
 #endif
 
-#if PLATFORM(DARWIN) && defined(VM_MEMORY_TCMALLOC)
-static const int mmapFileDescriptor = VM_MAKE_TAG(VM_MEMORY_TCMALLOC);
-#else
-static const int mmapFileDescriptor = -1;
-#endif
+using namespace std;
 
 // Structure for discovering alignment
 union MemoryAligner {
@@ -178,7 +179,7 @@ static void* TryMmap(size_t size, size_t *actual_size, size_t alignment) {
   void* result = mmap(NULL, size + extra,
                       PROT_READ | PROT_WRITE,
                       MAP_PRIVATE|MAP_ANONYMOUS,
-                      mmapFileDescriptor, 0);
+                      VM_TAG_FOR_TCMALLOC_MEMORY, 0);
   if (result == reinterpret_cast<void*>(MAP_FAILED)) {
     mmap_failure = true;
     return NULL;
@@ -387,13 +388,23 @@ void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size, size_t alignment) {
   return NULL;
 }
 
+#if HAVE(MADV_FREE_REUSE)
+
+void TCMalloc_SystemRelease(void* start, size_t length)
+{
+    while (madvise(start, length, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { }
+}
+
+#elif HAVE(MADV_FREE) || HAVE(MADV_DONTNEED)
+
 void TCMalloc_SystemRelease(void* start, size_t length)
 {
-#if HAVE(MADV_FREE) || HAVE(MADV_DONTNEED)
+    // MADV_FREE clears the modified bit on pages, which allows
+    // them to be discarded immediately.
 #if HAVE(MADV_FREE)
-  const int advice = MADV_FREE;
+    const int advice = MADV_FREE;
 #else
-  const int advice = MADV_DONTNEED;
+    const int advice = MADV_DONTNEED;
 #endif
   if (FLAGS_malloc_devmem_start) {
     // It's not safe to use MADV_DONTNEED if we've been mapping
@@ -425,25 +436,87 @@ void TCMalloc_SystemRelease(void* start, size_t length)
            errno == EAGAIN) {
       // NOP
     }
-    return;
   }
-#endif
+}
 
-#if HAVE(MMAP)
-  void* newAddress = mmap(start, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, mmapFileDescriptor, 0);
+#elif HAVE(MMAP)
+
+void TCMalloc_SystemRelease(void* start, size_t length)
+{
+  void* newAddress = mmap(start, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
   // If the mmap failed then that's ok, we just won't return the memory to the system.
   ASSERT_UNUSED(newAddress, newAddress == start || newAddress == reinterpret_cast<void*>(MAP_FAILED));
-  return;
-#endif
+}
+
+#elif HAVE(VIRTUALALLOC)
+
+void TCMalloc_SystemRelease(void* start, size_t length)
+{
+    if (VirtualFree(start, length, MEM_DECOMMIT))
+        return;
+
+    // The decommit may fail if the memory region consists of allocations
+    // from more than one call to VirtualAlloc.  In this case, fall back to
+    // using VirtualQuery to retrieve the allocation boundaries and decommit
+    // them each individually.
+
+    char* ptr = static_cast<char*>(start);
+    char* end = ptr + length;
+    MEMORY_BASIC_INFORMATION info;
+    while (ptr < end) {
+        size_t resultSize = VirtualQuery(ptr, &info, sizeof(info));
+        ASSERT_UNUSED(resultSize, resultSize == sizeof(info));
+
+        size_t decommitSize = min<size_t>(info.RegionSize, end - ptr);
+        BOOL success = VirtualFree(ptr, decommitSize, MEM_DECOMMIT);
+        ASSERT_UNUSED(success, success);
+        ptr += decommitSize;
+    }
+}
+
+#else
+
+// Platforms that don't support returning memory use an empty inline version of TCMalloc_SystemRelease
+// declared in TCSystemAlloc.h
 
-#if !HAVE(MADV_DONTNEED) && !HAVE(MMAP)
-  UNUSED_PARAM(start);
-  UNUSED_PARAM(length);
 #endif
+
+#if HAVE(MADV_FREE_REUSE)
+
+void TCMalloc_SystemCommit(void* start, size_t length)
+{
+    while (madvise(start, length, MADV_FREE_REUSE) == -1 && errno == EAGAIN) { }
 }
 
-#if HAVE(VIRTUALALLOC)
-void TCMalloc_SystemCommit(void*, size_t)
+#elif HAVE(VIRTUALALLOC)
+
+void TCMalloc_SystemCommit(void* start, size_t length)
 {
+    if (VirtualAlloc(start, length, MEM_COMMIT, PAGE_READWRITE) == start)
+        return;
+
+    // The commit may fail if the memory region consists of allocations
+    // from more than one call to VirtualAlloc.  In this case, fall back to
+    // using VirtualQuery to retrieve the allocation boundaries and commit them
+    // each individually.
+
+    char* ptr = static_cast<char*>(start);
+    char* end = ptr + length;
+    MEMORY_BASIC_INFORMATION info;
+    while (ptr < end) {
+        size_t resultSize = VirtualQuery(ptr, &info, sizeof(info));
+        ASSERT_UNUSED(resultSize, resultSize == sizeof(info));
+
+        size_t commitSize = min<size_t>(info.RegionSize, end - ptr);
+        void* newAddress = VirtualAlloc(ptr, commitSize, MEM_COMMIT, PAGE_READWRITE);
+        ASSERT_UNUSED(newAddress, newAddress == ptr);
+        ptr += commitSize;
+    }
 }
+
+#else
+
+// Platforms that don't need to explicitly commit memory use an empty inline version of TCMalloc_SystemCommit
+// declared in TCSystemAlloc.h
+
 #endif