Bug 1337561 - Baldr: call largeAllocationCallback and retry if executable allocation fails. r=jandem, a=jcristau
authorLuke Wagner <luke@mozilla.com>
Wed, 22 Feb 2017 16:12:27 -0600
changeset 379136 a3d1f3dbc5bcae03bbe1340ff3711ca3b416030b
parent 379135 92d8d94bfed5d3c0cd0627c64c914459a66d4598
child 379137 eb20f71a4f431d695b88ea5796a55d52cc9cf481
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem, jcristau
bugs1337561
milestone53.0
Bug 1337561 - Baldr: call largeAllocationCallback and retry if executable allocation fails. r=jandem, a=jcristau MozReview-Commit-ID: 1gMbNH13XuV
js/src/jit/ProcessExecutableMemory.cpp
js/src/wasm/WasmCode.cpp
--- a/js/src/jit/ProcessExecutableMemory.cpp
+++ b/js/src/jit/ProcessExecutableMemory.cpp
@@ -385,17 +385,17 @@ class PageBitSet
 #endif
 };
 
 // Limit on the number of bytes of executable memory to prevent JIT spraying
 // attacks.
 #if JS_BITS_PER_WORD == 32
 static const size_t MaxCodeBytesPerProcess = 140 * 1024 * 1024;
 #else
-static const size_t MaxCodeBytesPerProcess = 640 * 1024 * 1024;
+static const size_t MaxCodeBytesPerProcess = 1 * 1024 * 1024 * 1024;
 #endif
 
 // Per-process executable memory allocator. It reserves a block of memory of
 // MaxCodeBytesPerProcess bytes, then allocates/deallocates pages from that.
 //
 // This has a number of benefits compared to raw mmap/VirtualAlloc:
 //
 // * More resillient against certain attacks.
--- a/js/src/wasm/WasmCode.cpp
+++ b/js/src/wasm/WasmCode.cpp
@@ -53,26 +53,38 @@ using JS::GenericNaN;
 // and the kernel's default max_map_count is ~65k.
 //
 // Note: this can be removed once writable/non-executable global data stops
 // being stored in the code segment.
 static Atomic<uint32_t> wasmCodeAllocations(0);
 static const uint32_t MaxWasmCodeAllocations = 16384;
 
 static uint8_t*
-AllocateCodeSegment(ExclusiveContext* cx, uint32_t totalLength)
+AllocateCodeSegment(JSContext* cx, uint32_t totalLength)
 {
     if (wasmCodeAllocations >= MaxWasmCodeAllocations)
         return nullptr;
 
     // codeLength is a multiple of the system's page size, but not necessarily
     // a multiple of ExecutableCodePageSize.
     totalLength = JS_ROUNDUP(totalLength, ExecutableCodePageSize);
 
     void* p = AllocateExecutableMemory(totalLength, ProtectionSetting::Writable);
+
+    // If the allocation failed and the embedding gives us a last-ditch attempt
+    // to purge all memory (which, in gecko, does a purging GC/CC/GC), do that
+    // then retry the allocation.
+    if (!p) {
+        JSRuntime* rt = cx->runtime();
+        if (rt->largeAllocationFailureCallback) {
+            rt->largeAllocationFailureCallback(rt->largeAllocationFailureCallbackData);
+            p = AllocateExecutableMemory(totalLength, ProtectionSetting::Writable);
+        }
+    }
+
     if (!p) {
         ReportOutOfMemory(cx);
         return nullptr;
     }
 
     wasmCodeAllocations++;
     return (uint8_t*)p;
 }