Author: Xan Lopez Origin: http://trac.webkit.org/browser/trunk/Source/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp?rev=75709 Description: Avoid crashes on amd64 with less than 3 or 4GB of RAM. See https://bugs.webkit.org/show_bug.cgi?id=42756 The FixedVMPool Allocator does not work well on systems where allocating very large amounts of memory upfront is not reasonable, like Linux without overcommit enabled. As a workaround, on Linux, default to the values used in embedded environments (in the MB range), and only jump to the GB range if we detect at runtime that overcommit is enabled. Should fix crashes on Linux/x86_64 with less than 3 or 4GB of RAM. * jit/ExecutableAllocatorFixedVMPool.cpp: (JSC::FixedVMPoolAllocator::free): use new variables for VM pool size and coalesce limit. (JSC::ExecutableAllocator::isValid): swap the variables from embedded to generic values at runtime, on linux, if overcommit is enabled. NOTE: This patch does the same that upstream did in svn revision 75709 except that we don't change the underMemoryPressure() because it doesn't exist yet in this version of qtwebkit. Therefore if we upgrade this package to a newer version providing the underMemoryPressure() management we must change that function as upstream did. --- JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp | 55 +++++++++++++++--- 1 file changed, 46 insertions(+), 9 deletions(-) --- a/Source/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp +++ b/Source/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp @@ -38,14 +38,29 @@ #include #include -#if CPU(X86_64) - // These limits suitable on 64-bit platforms (particularly x86-64, where we require all jumps to have a 2Gb max range). - #define VM_POOL_SIZE (2u * 1024u * 1024u * 1024u) // 2Gb - #define COALESCE_LIMIT (16u * 1024u * 1024u) // 16Mb +#if OS(LINUX) +#include +#endif + +static const unsigned vmPoolSizeGeneric = 2u * 1024u * 1024u * 1024u; // 2Gb +static const unsigned coalesceLimitGeneric = 16u * 1024u * 1024u; // 16Mb + +static const unsigned vmPoolSizeEmbedded = 32u * 1024u * 1024u; // 32Mb +static const unsigned coalesceLimitEmbedded = 4u * 1024u * 1024u; // 4Mb + +#if CPU(X86_64) && !OS(LINUX) +// These limits suitable on 64-bit platforms (particularly x86-64, +// where we require all jumps to have a 2Gb max range). We don't +// enable this by default on Linux, since it needs overcommit and +// distros commonly disable that feature. We'll check the value +// for the overcommit feature at runtime and re-assign the Generic +// values if it's enabled. +static unsigned vmPoolSize = vmPoolSizeGeneric; // 2Gb +static unsigned coalesceLimit = coalesceLimitGeneric; // 16Mb #else // These limits are hopefully sensible on embedded platforms. - #define VM_POOL_SIZE (32u * 1024u * 1024u) // 32Mb - #define COALESCE_LIMIT (4u * 1024u * 1024u) // 4Mb +static unsigned vmPoolSize = vmPoolSizeEmbedded; // 32Mb +static unsigned coalesceLimit = coalesceLimitEmbedded; // 4Mb #endif // ASLR currently only works on darwin (due to arc4random) & 64-bit (due to address space size). @@ -331,7 +346,7 @@ public: // 16MB of allocations have been freed, sweep m_freeList // coalescing any neighboring fragments. m_countFreedSinceLastCoalesce += size; - if (m_countFreedSinceLastCoalesce >= COALESCE_LIMIT) { + if (m_countFreedSinceLastCoalesce >= coalesceLimit) { m_countFreedSinceLastCoalesce = 0; coalesceFreeSpace(); } @@ -435,11 +450,33 @@ void ExecutableAllocator::intializePageS static FixedVMPoolAllocator* allocator = 0; static SpinLock spinlock = SPINLOCK_INITIALIZER; +#if OS(LINUX) +static void maybeModifyVMPoolSize() +{ + FILE* fp = fopen("/proc/sys/vm/overcommit_memory", "r"); + if (!fp) + return; + + unsigned overcommit = 0; + fscanf(fp, "%u", &overcommit); + if (overcommit == 1) { + vmPoolSize = vmPoolSizeGeneric; // 2Gb + coalesceLimit = coalesceLimitGeneric; // 16Mb + } + + fclose(fp); +} +#endif + bool ExecutableAllocator::isValid() const { SpinLockHolder lock_holder(&spinlock); - if (!allocator) - allocator = new FixedVMPoolAllocator(JIT_ALLOCATOR_LARGE_ALLOC_SIZE, VM_POOL_SIZE); + if (!allocator) { +#if OS(LINUX) + maybeModifyVMPoolSize(); +#endif + allocator = new FixedVMPoolAllocator(JIT_ALLOCATOR_LARGE_ALLOC_SIZE, vmPoolSize); + } return allocator->isValid(); }