]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - wtf/TCSystemAlloc.cpp
JavaScriptCore-576.tar.gz
[apple/javascriptcore.git] / wtf / TCSystemAlloc.cpp
index 18a9fe5b5710b6e4e166484291ab9ffeda7c6cba..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 {
@@ -176,9 +177,9 @@ static void* TryMmap(size_t size, size_t *actual_size, size_t alignment) {
     extra = alignment - pagesize;
   }
   void* result = mmap(NULL, size + extra,
-                      PROT_READ|PROT_WRITE,
+                      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;
@@ -308,7 +309,7 @@ static void* TryDevMem(size_t size, size_t *actual_size, size_t alignment) {
     devmem_failure = true;
     return NULL;
   }
-  void *result = mmap(0, size + extra, PROT_WRITE|PROT_READ,
+  void *result = mmap(0, size + extra, PROT_READ | PROT_WRITE,
                       MAP_SHARED, physmem_fd, physmem_base);
   if (result == reinterpret_cast<void*>(MAP_FAILED)) {
     devmem_failure = true;
@@ -387,11 +388,24 @@ 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)
 {
-  UNUSED_PARAM(start);
-  UNUSED_PARAM(length);
-#if 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;
+#else
+    const int advice = MADV_DONTNEED;
+#endif
   if (FLAGS_malloc_devmem_start) {
     // It's not safe to use MADV_DONTNEED if we've been mapping
     // /dev/mem for heap memory
@@ -417,22 +431,92 @@ void TCMalloc_SystemRelease(void* start, size_t length)
   if (new_end > new_start) {
     // Note -- ignoring most return codes, because if this fails it
     // doesn't matter...
-    // The msync call with MS_KILLPAGES on Leopard is equivalent to an
-    // madvise call with MADV_FREE on SnowLeopard
-    while (msync(reinterpret_cast<char*>(new_start), new_end - new_start,
-                   MS_KILLPAGES) == -1 &&
+    while (madvise(reinterpret_cast<char*>(new_start), new_end - new_start,
+                   advice) == -1 &&
            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);
-  UNUSED_PARAM(newAddress);
+#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(newAddress == start || newAddress == reinterpret_cast<void*>(MAP_FAILED));
-  return;
+  ASSERT_UNUSED(newAddress, newAddress == start || newAddress == reinterpret_cast<void*>(MAP_FAILED));
+}
+
+#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
+
 #endif
+
+#if HAVE(MADV_FREE_REUSE)
+
+void TCMalloc_SystemCommit(void* start, size_t length)
+{
+    while (madvise(start, length, MADV_FREE_REUSE) == -1 && errno == EAGAIN) { }
 }
+
+#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