Reviewed by Darin.
[WebKit-https.git] / JavaScriptCore / kjs / collector.cpp
index a7f31fd3dced2b939f6545cfd3bffbdcd5ddc4c0..a4ef8d8ea493f4d505491ec690e704b2f6410bcd 100644 (file)
 #if PLATFORM(DARWIN)
 
 #include <mach/mach_port.h>
 #if PLATFORM(DARWIN)
 
 #include <mach/mach_port.h>
+#include <mach/mach_init.h>
 #include <mach/task.h>
 #include <mach/thread_act.h>
 #include <mach/task.h>
 #include <mach/thread_act.h>
+#include <mach/vm_map.h>
 
 #elif PLATFORM(WIN_OS)
 
 
 #elif PLATFORM(WIN_OS)
 
@@ -47,6 +49,9 @@
 
 #elif PLATFORM(UNIX)
 
 
 #elif PLATFORM(UNIX)
 
+#include <stdlib.h>
+#include <sys/mman.h>
+
 #if HAVE(PTHREAD_NP_H)
 #include <pthread_np.h>
 #endif
 #if HAVE(PTHREAD_NP_H)
 #include <pthread_np.h>
 #endif
@@ -60,14 +65,13 @@ using std::max;
 namespace KJS {
 
 
 namespace KJS {
 
 
-
 // tunable parameters
 
 template<size_t bytesPerWord> struct CellSize;
 template<> struct CellSize<sizeof(uint32_t)> { static const size_t m_value = 48; }; // 32-bit
 template<> struct CellSize<sizeof(uint64_t)> { static const size_t m_value = 80; }; // 64-bit
 
 // tunable parameters
 
 template<size_t bytesPerWord> struct CellSize;
 template<> struct CellSize<sizeof(uint32_t)> { static const size_t m_value = 48; }; // 32-bit
 template<> struct CellSize<sizeof(uint64_t)> { static const size_t m_value = 80; }; // 64-bit
 
-const size_t BLOCK_SIZE = (8 * 4096);
+const size_t BLOCK_SIZE = (16 * 4096); // 64k
 const size_t SPARE_EMPTY_BLOCKS = 2;
 const size_t MIN_ARRAY_SIZE = 14;
 const size_t GROWTH_FACTOR = 2;
 const size_t SPARE_EMPTY_BLOCKS = 2;
 const size_t MIN_ARRAY_SIZE = 14;
 const size_t GROWTH_FACTOR = 2;
@@ -75,6 +79,8 @@ const size_t LOW_WATER_FACTOR = 4;
 const size_t ALLOCATIONS_PER_COLLECTION = 1000;
 
 // derived constants
 const size_t ALLOCATIONS_PER_COLLECTION = 1000;
 
 // derived constants
+const size_t PTR_IN_BLOCK_MASK = (BLOCK_SIZE - 1);
+const size_t BLOCK_MASK = (~PTR_IN_BLOCK_MASK);
 const size_t MINIMUM_CELL_SIZE = CellSize<sizeof(void*)>::m_value;
 const size_t CELL_ARRAY_LENGTH = (MINIMUM_CELL_SIZE / sizeof(double)) + (MINIMUM_CELL_SIZE % sizeof(double) != 0 ? 1 : 0);
 const size_t CELL_SIZE = CELL_ARRAY_LENGTH * sizeof(double);
 const size_t MINIMUM_CELL_SIZE = CellSize<sizeof(void*)>::m_value;
 const size_t CELL_ARRAY_LENGTH = (MINIMUM_CELL_SIZE / sizeof(double)) + (MINIMUM_CELL_SIZE % sizeof(double) != 0 ? 1 : 0);
 const size_t CELL_SIZE = CELL_ARRAY_LENGTH * sizeof(double);
@@ -135,6 +141,58 @@ public:
 bool GCLock::isLocked = false;
 #endif
 
 bool GCLock::isLocked = false;
 #endif
 
+static CollectorBlock* allocateBlock()
+{
+#if PLATFORM(DARWIN)    
+    vm_address_t address = 0;
+    vm_map(current_task(), &address, BLOCK_SIZE, PTR_IN_BLOCK_MASK, VM_FLAGS_ANYWHERE, MEMORY_OBJECT_NULL, 0, FALSE, VM_PROT_DEFAULT, VM_PROT_DEFAULT, VM_INHERIT_DEFAULT);
+#elif PLATFORM(WIN)
+     // windows virtual address granularity is naturally 64k
+    LPVOID address = VirtualAlloc(NULL, BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+#elif HAVE(POSIX_MEMALIGN)
+    void* address;
+    posix_memalign(address, BLOCK_SIZE, BLOCK_SIZE);
+    memset(reinterpret_cast<void*>(address), 0, BLOCK_SIZE);
+#else
+    static size_t pagesize = getpagesize();
+    
+    size_t extra = 0;
+    if (BLOCK_SIZE > pagesize)
+        extra = BLOCK_SIZE - pagesize;
+
+    void* mmapResult = mmap(NULL, BLOCK_SIZE + extra, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+    uintptr_t address = reinterpret_cast<uintptr_t>(mmapResult);
+
+    size_t adjust = 0;
+    if ((address & PTR_IN_BLOCK_MASK) != 0)
+        adjust = BLOCK_SIZE - (address & PTR_IN_BLOCK_MASK);
+
+    if (adjust > 0)
+        munmap(reinterpret_cast<void*>(address), adjust);
+
+    if (adjust < extra)
+        munmap(reinterpret_cast<void*>(address + adjust + BLOCK_SIZE), extra - adjust);
+
+    address += adjust;
+    memset(reinterpret_cast<void*>(address), 0, BLOCK_SIZE);
+#endif
+
+    return reinterpret_cast<CollectorBlock*>(address);
+}
+
+static void freeBlock(CollectorBlock* block)
+{
+#if PLATFORM(DARWIN)    
+    vm_deallocate(current_task(), reinterpret_cast<vm_address_t>(block), BLOCK_SIZE);
+#elif PLATFORM(WIN)
+    VirtualFree(block, BLOCK_SIZE, MEM_RELEASE);
+#elif HAVE(POSIX_MEMALIGN)
+    free(block);
+#else
+    munmap(block, BLOCK_SIZE);
+#endif
+}
+
 void* Collector::allocate(size_t s)
 {
   ASSERT(JSLock::lockCount() > 0);
 void* Collector::allocate(size_t s)
 {
   ASSERT(JSLock::lockCount() > 0);
@@ -185,7 +243,7 @@ allocateNewBlock:
       heap.blocks = static_cast<CollectorBlock **>(fastRealloc(heap.blocks, numBlocks * sizeof(CollectorBlock *)));
     }
 
       heap.blocks = static_cast<CollectorBlock **>(fastRealloc(heap.blocks, numBlocks * sizeof(CollectorBlock *)));
     }
 
-    targetBlock = static_cast<CollectorBlock *>(fastCalloc(1, sizeof(CollectorBlock)));
+    targetBlock = allocateBlock();
     targetBlock->freeList = targetBlock->cells;
     targetBlockUsedCells = 0;
     heap.blocks[usedBlocks] = targetBlock;
     targetBlock->freeList = targetBlock->cells;
     targetBlockUsedCells = 0;
     heap.blocks[usedBlocks] = targetBlock;
@@ -799,7 +857,7 @@ bool Collector::collect()
       emptyBlocks++;
       if (emptyBlocks > SPARE_EMPTY_BLOCKS) {
 #if !DEBUG_COLLECTOR
       emptyBlocks++;
       if (emptyBlocks > SPARE_EMPTY_BLOCKS) {
 #if !DEBUG_COLLECTOR
-        fastFree(curBlock);
+        freeBlock(curBlock);
 #endif
         // swap with the last block so we compact as we go
         heap.blocks[block] = heap.blocks[heap.usedBlocks - 1];
 #endif
         // swap with the last block so we compact as we go
         heap.blocks[block] = heap.blocks[heap.usedBlocks - 1];