Bug 1325200 part 1 - Simplify AllocateExecutableMemory a bit. r=luke
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 12 Jan 2017 12:48:36 +0100
changeset 374138 ab1fd5b320a457e8313dfcdb2d90c99850f3f1d9
parent 374137 a2819ba153127179602ef73c9fb593250ae21167
child 374139 21dab2e6926ae09b8a63dc7653dcf4e7c6f4efa9
push id6996
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 20:48:21 +0000
treeherdermozilla-beta@d89512dab048 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1325200
milestone53.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1325200 part 1 - Simplify AllocateExecutableMemory a bit. r=luke
js/src/jit/ExecutableAllocator.h
js/src/jit/ExecutableAllocatorPosix.cpp
js/src/jit/ExecutableAllocatorWin.cpp
js/src/jsmath.cpp
js/src/jsmath.h
js/src/wasm/WasmCode.cpp
--- a/js/src/jit/ExecutableAllocator.h
+++ b/js/src/jit/ExecutableAllocator.h
@@ -159,19 +159,16 @@ struct JitPoisonRange
 };
 
 typedef Vector<JitPoisonRange, 0, SystemAllocPolicy> JitPoisonRangeVector;
 
 #define NON_WRITABLE_JIT_CODE 1
 
 class ExecutableAllocator
 {
-#ifdef XP_WIN
-    mozilla::Maybe<mozilla::non_crypto::XorShift128PlusRNG> randomNumberGenerator;
-#endif
     JSRuntime* rt_;
 
   public:
     enum ProtectionSetting { Writable, Executable };
 
     explicit ExecutableAllocator(JSRuntime* rt);
     ~ExecutableAllocator();
 
@@ -194,17 +191,16 @@ class ExecutableAllocator
 
     static const size_t OVERSIZE_ALLOCATION = size_t(-1);
 
     static size_t roundUpAllocationSize(size_t request, size_t granularity);
 
     // On OOM, this will return an Allocation where pages is nullptr.
     ExecutablePool::Allocation systemAlloc(size_t n);
     static void systemRelease(const ExecutablePool::Allocation& alloc);
-    void* computeRandomAllocationAddress();
 
     ExecutablePool* createPool(size_t n);
     ExecutablePool* poolForSize(size_t n);
 
     static void reprotectPool(JSRuntime* rt, ExecutablePool* pool, ProtectionSetting protection);
 
   public:
     MOZ_MUST_USE
@@ -333,17 +329,17 @@ class ExecutableAllocator
     typedef js::HashSet<ExecutablePool*, js::DefaultHasher<ExecutablePool*>, js::SystemAllocPolicy>
             ExecPoolHashSet;
     ExecPoolHashSet m_pools;    // All pools, just for stats purposes.
 
     static size_t determinePageSize();
 };
 
 extern void*
-AllocateExecutableMemory(void* addr, size_t bytes, unsigned permissions, const char* tag,
+AllocateExecutableMemory(size_t bytes, unsigned permissions, const char* tag,
                          size_t pageSize);
 
 extern void
 DeallocateExecutableMemory(void* addr, size_t bytes, size_t pageSize);
 
 } // namespace jit
 } // namespace js
 
--- a/js/src/jit/ExecutableAllocatorPosix.cpp
+++ b/js/src/jit/ExecutableAllocatorPosix.cpp
@@ -39,36 +39,37 @@ using namespace js::jit;
 
 size_t
 ExecutableAllocator::determinePageSize()
 {
     return getpagesize();
 }
 
 void*
-js::jit::AllocateExecutableMemory(void* addr, size_t bytes, unsigned permissions, const char* tag,
+js::jit::AllocateExecutableMemory(size_t bytes, unsigned permissions, const char* tag,
                                   size_t pageSize)
 {
     MOZ_ASSERT(bytes % pageSize == 0);
-    void* p = MozTaggedAnonymousMmap(addr, bytes, permissions, MAP_PRIVATE | MAP_ANON, -1, 0, tag);
+    void* p = MozTaggedAnonymousMmap(nullptr, bytes, permissions, MAP_PRIVATE | MAP_ANON, -1, 0,
+                                     tag);
     return p == MAP_FAILED ? nullptr : p;
 }
 
 void
 js::jit::DeallocateExecutableMemory(void* addr, size_t bytes, size_t pageSize)
 {
     MOZ_ASSERT(bytes % pageSize == 0);
     mozilla::DebugOnly<int> result = munmap(addr, bytes);
     MOZ_ASSERT(!result || errno == ENOMEM);
 }
 
 ExecutablePool::Allocation
 ExecutableAllocator::systemAlloc(size_t n)
 {
-    void* allocation = AllocateExecutableMemory(nullptr, n, initialProtectionFlags(Executable),
+    void* allocation = AllocateExecutableMemory(n, initialProtectionFlags(Executable),
                                                 "js-jit-code", pageSize);
     ExecutablePool::Allocation alloc = { reinterpret_cast<char*>(allocation), n };
     return alloc;
 }
 
 void
 ExecutableAllocator::systemRelease(const ExecutablePool::Allocation& alloc)
 {
--- a/js/src/jit/ExecutableAllocatorWin.cpp
+++ b/js/src/jit/ExecutableAllocatorWin.cpp
@@ -40,18 +40,18 @@ using namespace js::jit;
 size_t
 ExecutableAllocator::determinePageSize()
 {
     SYSTEM_INFO system_info;
     GetSystemInfo(&system_info);
     return system_info.dwPageSize;
 }
 
-void*
-ExecutableAllocator::computeRandomAllocationAddress()
+static void*
+ComputeRandomAllocationAddress()
 {
     /*
      * Inspiration is V8's OS::Allocate in platform-win32.cc.
      *
      * VirtualAlloc takes 64K chunks out of the virtual address space, so we
      * keep 16b alignment.
      *
      * x86: V8 comments say that keeping addresses in the [64MiB, 1GiB) range
@@ -64,23 +64,17 @@ ExecutableAllocator::computeRandomAlloca
     static const uintptr_t mask = 0x000003ffffff0000;
 #elif defined(_M_IX86) || defined(__i386__)
     static const uintptr_t base = 0x04000000;
     static const uintptr_t mask = 0x3fff0000;
 #else
 # error "Unsupported architecture"
 #endif
 
-    if (randomNumberGenerator.isNothing()) {
-        mozilla::Array<uint64_t, 2> seed;
-        js::GenerateXorShift128PlusSeed(seed);
-        randomNumberGenerator.emplace(seed[0], seed[1]);
-    }
-
-    uint64_t rand = randomNumberGenerator.ref().next();
+    uint64_t rand = js::GenerateRandomSeed();
     return (void*) (base | (rand & mask));
 }
 
 #ifdef HAVE_64BIT_BUILD
 static js::JitExceptionHandler sJitExceptionHandler;
 
 JS_FRIEND_API(void)
 js::SetJitExceptionHandler(JitExceptionHandler handler)
@@ -189,29 +183,35 @@ UnregisterExecutableMemory(void* p, size
 
     RtlDeleteFunctionTable(&r->runtimeFunction);
 
     ReleaseStackWalkWorkaroundLock();
 }
 #endif
 
 void*
-js::jit::AllocateExecutableMemory(void* addr, size_t bytes, unsigned permissions, const char* tag,
+js::jit::AllocateExecutableMemory(size_t bytes, unsigned permissions, const char* tag,
                                   size_t pageSize)
 {
     MOZ_ASSERT(bytes % pageSize == 0);
 
 #ifdef HAVE_64BIT_BUILD
     if (sJitExceptionHandler)
         bytes += pageSize;
 #endif
 
-    void* p = VirtualAlloc(addr, bytes, MEM_COMMIT | MEM_RESERVE, permissions);
-    if (!p)
-        return nullptr;
+    void* randomAddr = ComputeRandomAllocationAddress();
+
+    void* p = VirtualAlloc(randomAddr, bytes, MEM_COMMIT | MEM_RESERVE, permissions);
+    if (!p) {
+        // Try again without randomAddr.
+        p = VirtualAlloc(nullptr, bytes, MEM_COMMIT | MEM_RESERVE, permissions);
+        if (!p)
+            return nullptr;
+    }
 
 #ifdef HAVE_64BIT_BUILD
     if (sJitExceptionHandler) {
         if (!RegisterExecutableMemory(p, bytes, pageSize)) {
             VirtualFree(p, 0, MEM_RELEASE);
             return nullptr;
         }
 
@@ -235,22 +235,19 @@ js::jit::DeallocateExecutableMemory(void
 #endif
 
     VirtualFree(addr, 0, MEM_RELEASE);
 }
 
 ExecutablePool::Allocation
 ExecutableAllocator::systemAlloc(size_t n)
 {
-    void* randomAddress = computeRandomAllocationAddress();
     unsigned flags = initialProtectionFlags(Executable);
-    void* allocation = AllocateExecutableMemory(randomAddress, n, flags, "js-jit-code", pageSize);
-    if (!allocation) {
-        allocation = AllocateExecutableMemory(nullptr, n, flags, "js-jit-code", pageSize);
-    }
+    void* allocation = AllocateExecutableMemory(n, flags, "js-jit-code", pageSize);
+
     ExecutablePool::Allocation alloc = { reinterpret_cast<char*>(allocation), n };
     return alloc;
 }
 
 void
 ExecutableAllocator::systemRelease(const ExecutablePool::Allocation& alloc)
 {
     DeallocateExecutableMemory(alloc.pages, alloc.size, pageSize);
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -671,46 +671,46 @@ js::math_pow_handle(JSContext* cx, Handl
 bool
 js::math_pow(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     return math_pow_handle(cx, args.get(0), args.get(1), args.rval());
 }
 
-static uint64_t
-GenerateSeed()
+uint64_t
+js::GenerateRandomSeed()
 {
     uint64_t seed = 0;
 
 #if defined(XP_WIN)
     MOZ_ALWAYS_TRUE(RtlGenRandom(&seed, sizeof(seed)));
 #elif defined(HAVE_ARC4RANDOM)
     seed = (static_cast<uint64_t>(arc4random()) << 32) | arc4random();
 #elif defined(XP_UNIX)
     int fd = open("/dev/urandom", O_RDONLY);
     if (fd >= 0) {
         mozilla::Unused << read(fd, static_cast<void*>(&seed), sizeof(seed));
         close(fd);
     }
 #else
-# error "Platform needs to implement GenerateSeed()"
+# error "Platform needs to implement GenerateRandomSeed()"
 #endif
 
     // Also mix in PRMJ_Now() in case we couldn't read random bits from the OS.
     return seed ^ PRMJ_Now();
 }
 
 void
 js::GenerateXorShift128PlusSeed(mozilla::Array<uint64_t, 2>& seed)
 {
     // XorShift128PlusRNG must be initialized with a non-zero seed.
     do {
-        seed[0] = GenerateSeed();
-        seed[1] = GenerateSeed();
+        seed[0] = GenerateRandomSeed();
+        seed[1] = GenerateRandomSeed();
     } while (seed[0] == 0 && seed[1] == 0);
 }
 
 void
 JSCompartment::ensureRandomNumberGenerator()
 {
     if (randomNumberGenerator.isNothing()) {
         mozilla::Array<uint64_t, 2> seed;
--- a/js/src/jsmath.h
+++ b/js/src/jsmath.h
@@ -81,16 +81,19 @@ class MathCache
 
 /*
  * JS math functions.
  */
 
 extern JSObject*
 InitMathClass(JSContext* cx, HandleObject obj);
 
+extern uint64_t
+GenerateRandomSeed();
+
 // Fill |seed[0]| and |seed[1]| with random bits, suitable for
 // seeding a XorShift128+ random number generator.
 extern void
 GenerateXorShift128PlusSeed(mozilla::Array<uint64_t, 2>& seed);
 
 extern uint64_t
 random_next(uint64_t* rngState, int bits);
 
--- a/js/src/wasm/WasmCode.cpp
+++ b/js/src/wasm/WasmCode.cpp
@@ -62,18 +62,18 @@ AllocateCodeSegment(ExclusiveContext* cx
 {
     if (wasmCodeAllocations >= MaxWasmCodeAllocations)
         return nullptr;
 
     // Allocate RW memory. DynamicallyLinkModule will reprotect the code as RX.
     unsigned permissions =
         ExecutableAllocator::initialProtectionFlags(ExecutableAllocator::Writable);
 
-    void* p = AllocateExecutableMemory(nullptr, totalLength, permissions,
-                                       "wasm-code-segment", gc::SystemPageSize());
+    void* p = AllocateExecutableMemory(totalLength, permissions, "wasm-code-segment",
+                                       gc::SystemPageSize());
     if (!p) {
         ReportOutOfMemory(cx);
         return nullptr;
     }
 
     wasmCodeAllocations++;
     return (uint8_t*)p;
 }