Commit 2cbfa244 authored by Bill Budge's avatar Bill Budge Committed by Commit Bot

[Memory] Use madvise on POSIX to allow OS to reclaim memory.

- Use madvise when setting no permissions on memory.
- Move platform specific mmap flag calculations to a helper fn.

Bug: chromium:756050,chromium:788341
Change-Id: I7d420a0abee9656a57fb0317301322da2fd7d7b5
Reviewed-on: https://chromium-review.googlesource.com/790932
Commit-Queue: Bill Budge <bbudge@chromium.org>
Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49681}
parent adf0fc8c
...@@ -63,6 +63,10 @@ ...@@ -63,6 +63,10 @@
#define MAP_ANONYMOUS MAP_ANON #define MAP_ANONYMOUS MAP_ANON
#endif #endif
#ifndef MADV_FREE
#define MADV_FREE MADV_DONTNEED
#endif
namespace v8 { namespace v8 {
namespace base { namespace base {
...@@ -104,26 +108,47 @@ int GetProtectionFromMemoryPermission(OS::MemoryPermission access) { ...@@ -104,26 +108,47 @@ int GetProtectionFromMemoryPermission(OS::MemoryPermission access) {
UNREACHABLE(); UNREACHABLE();
} }
void* Allocate(void* address, size_t size, OS::MemoryPermission access) { int GetFlagsForMemoryPermission(OS::MemoryPermission access) {
const size_t actual_size = RoundUp(size, OS::AllocatePageSize());
int prot = GetProtectionFromMemoryPermission(access);
int flags = MAP_PRIVATE | MAP_ANONYMOUS; int flags = MAP_PRIVATE | MAP_ANONYMOUS;
if (access == OS::MemoryPermission::kNoAccess) { if (access == OS::MemoryPermission::kNoAccess) {
// TODO(bbudge) Improve readability by moving platform specific code into
// helper functions.
#if !V8_OS_AIX && !V8_OS_FREEBSD && !V8_OS_QNX #if !V8_OS_AIX && !V8_OS_FREEBSD && !V8_OS_QNX
flags |= MAP_NORESERVE; flags |= MAP_NORESERVE;
#endif #endif // !V8_OS_AIX && !V8_OS_FREEBSD && !V8_OS_QNX
#if V8_OS_QNX #if V8_OS_QNX
flags |= MAP_LAZY; flags |= MAP_LAZY;
#endif // V8_OS_QNX #endif // V8_OS_QNX
} }
return flags;
}
void* Allocate(void* address, size_t size, OS::MemoryPermission access) {
const size_t actual_size = RoundUp(size, OS::AllocatePageSize());
int prot = GetProtectionFromMemoryPermission(access);
int flags = GetFlagsForMemoryPermission(access);
void* result = void* result =
mmap(address, actual_size, prot, flags, kMmapFd, kMmapFdOffset); mmap(address, actual_size, prot, flags, kMmapFd, kMmapFdOffset);
if (result == MAP_FAILED) return nullptr; if (result == MAP_FAILED) return nullptr;
return result; return result;
} }
int ReclaimInaccessibleMemory(void* address, size_t size) {
#if defined(OS_MACOSX)
// On OSX, MADV_FREE_REUSABLE has comparable behavior to MADV_FREE, but also
// marks the pages with the reusable bit, which allows both Activity Monitor
// and memory-infra to correctly track the pages.
int ret = madvise(address, size, MADV_FREE_REUSABLE);
#else
int ret = madvise(address, size, MADV_FREE);
#endif
if (ret != 0 && errno == EINVAL) {
// MADV_FREE only works on Linux 4.5+ . If request failed, retry with older
// MADV_DONTNEED . Note that MADV_FREE being defined at compile time doesn't
// imply runtime support.
ret = madvise(address, size, MADV_DONTNEED);
}
return ret;
}
#endif // !V8_OS_FUCHSIA #endif // !V8_OS_FUCHSIA
} // namespace } // namespace
...@@ -286,8 +311,13 @@ bool OS::Release(void* address, size_t size) { ...@@ -286,8 +311,13 @@ bool OS::Release(void* address, size_t size) {
bool OS::SetPermissions(void* address, size_t size, MemoryPermission access) { bool OS::SetPermissions(void* address, size_t size, MemoryPermission access) {
DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize()); DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize());
DCHECK_EQ(0, size % CommitPageSize()); DCHECK_EQ(0, size % CommitPageSize());
int prot = GetProtectionFromMemoryPermission(access); int prot = GetProtectionFromMemoryPermission(access);
return mprotect(address, size, prot) == 0; int ret = mprotect(address, size, prot);
if (ret == 0 && access == OS::MemoryPermission::kNoAccess) {
ret = ReclaimInaccessibleMemory(address, size);
}
return ret == 0;
} }
// static // static
...@@ -819,6 +849,7 @@ void Thread::SetThreadLocal(LocalStorageKey key, void* value) { ...@@ -819,6 +849,7 @@ void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
#undef LOG_TAG #undef LOG_TAG
#undef MAP_ANONYMOUS #undef MAP_ANONYMOUS
#undef MADV_FREE
} // namespace base } // namespace base
} // namespace v8 } // namespace v8
...@@ -194,7 +194,8 @@ class V8_BASE_EXPORT OS { ...@@ -194,7 +194,8 @@ class V8_BASE_EXPORT OS {
V8_WARN_UNUSED_RESULT static bool Release(void* address, size_t size); V8_WARN_UNUSED_RESULT static bool Release(void* address, size_t size);
// Sets permissions according to the access argument. address and size must be // Sets permissions according to the access argument. address and size must be
// multiples of CommitPageSize(). Returns true on success, otherwise false. // multiples of CommitPageSize(). Setting permission to kNoAccess may cause
// the memory contents to be lost. Returns true on success, otherwise false.
V8_WARN_UNUSED_RESULT static bool SetPermissions(void* address, size_t size, V8_WARN_UNUSED_RESULT static bool SetPermissions(void* address, size_t size,
MemoryPermission access); MemoryPermission access);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment