From 736d7696a55e5c589b5731b0e1b23a2bbdc5c127 Mon Sep 17 00:00:00 2001 From: Scott Graham Date: Thu, 17 Aug 2017 14:37:14 -0700 Subject: [PATCH] fuchsia: Implement VirtualMemory class This follows the POSIX-y implementations, using mx_ system calls in place of mmap, et al. Some references: https://fuchsia.googlesource.com/magenta/+/HEAD/docs/objects/vm_address_region.md https://fuchsia.googlesource.com/magenta/+/HEAD/docs/syscalls/vmo_create.md https://fuchsia.googlesource.com/magenta/+/HEAD/docs/syscalls/vmar_map.md https://fuchsia.googlesource.com/magenta/+/HEAD/docs/syscalls/vmar_unmap.md https://fuchsia.googlesource.com/magenta/+/HEAD/docs/syscalls/vmar_protect.md Bug: chromium:731217 Change-Id: I7a33c2cc2b41736e395bd3431b88e6b9621b7ca5 Reviewed-on: https://chromium-review.googlesource.com/619687 Reviewed-by: Michael Lippautz Commit-Queue: Scott Graham Cr-Commit-Position: refs/heads/master@{#47438} --- src/base/platform/platform-fuchsia.cc | 128 +++++++++++++++++++------- 1 file changed, 97 insertions(+), 31 deletions(-) diff --git a/src/base/platform/platform-fuchsia.cc b/src/base/platform/platform-fuchsia.cc index dc703162e3..51f3a110b5 100644 --- a/src/base/platform/platform-fuchsia.cc +++ b/src/base/platform/platform-fuchsia.cc @@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include +#include +#include #include "src/base/macros.h" #include "src/base/platform/platform-posix-time.h" @@ -18,79 +19,144 @@ TimezoneCache* OS::CreateTimezoneCache() { void* OS::Allocate(const size_t requested, size_t* allocated, OS::MemoryPermission access, void* hint) { - const size_t msize = RoundUp(requested, AllocateAlignment()); - int prot = GetProtectionFromMemoryPermission(access); - void* mbase = mmap(hint, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (mbase == MAP_FAILED) return NULL; - *allocated = msize; - return mbase; + CHECK(false); // TODO(scottmg): Port, https://crbug.com/731217. + return nullptr; } std::vector OS::GetSharedLibraryAddresses() { - CHECK(false); // TODO(fuchsia): Port, https://crbug.com/731217. + CHECK(false); // TODO(scottmg): Port, https://crbug.com/731217. return std::vector(); } void OS::SignalCodeMovingGC() { - CHECK(false); // TODO(fuchsia): Port, https://crbug.com/731217. + CHECK(false); // TODO(scottmg): Port, https://crbug.com/731217. } -VirtualMemory::VirtualMemory() : address_(NULL), size_(0) {} +VirtualMemory::VirtualMemory() : address_(nullptr), size_(0) {} VirtualMemory::VirtualMemory(size_t size, void* hint) - : address_(ReserveRegion(size, hint)), size_(size) { - CHECK(false); // TODO(fuchsia): Port, https://crbug.com/731217. -} + : address_(ReserveRegion(size, hint)), size_(size) {} VirtualMemory::VirtualMemory(size_t size, size_t alignment, void* hint) - : address_(NULL), size_(0) {} + : address_(nullptr), size_(0) { + DCHECK((alignment % OS::AllocateAlignment()) == 0); + hint = AlignedAddress(hint, alignment); + size_t request_size = + RoundUp(size + alignment, static_cast(OS::AllocateAlignment())); -VirtualMemory::~VirtualMemory() {} + mx_handle_t vmo; + if (mx_vmo_create(request_size, 0, &vmo) != MX_OK) return; + static const char kVirtualMemoryName[] = "v8-virtualmem"; + mx_object_set_property(vmo, MX_PROP_NAME, kVirtualMemoryName, + strlen(kVirtualMemoryName)); + uintptr_t reservation; + mx_status_t status = mx_vmar_map(mx_vmar_root_self(), 0, vmo, 0, request_size, + 0 /*no permissions*/, &reservation); + // Either the vmo is now referenced by the vmar, or we failed and are bailing, + // so close the vmo either way. + mx_handle_close(vmo); + if (status != MX_OK) return; -void VirtualMemory::Reset() {} + uint8_t* base = reinterpret_cast(reservation); + uint8_t* aligned_base = RoundUp(base, alignment); + DCHECK_LE(base, aligned_base); -bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) { - return false; + // Unmap extra memory reserved before and after the desired block. + if (aligned_base != base) { + size_t prefix_size = static_cast(aligned_base - base); + mx_vmar_unmap(mx_vmar_root_self(), reinterpret_cast(base), + prefix_size); + request_size -= prefix_size; + } + + size_t aligned_size = RoundUp(size, OS::AllocateAlignment()); + DCHECK_LE(aligned_size, request_size); + + if (aligned_size != request_size) { + size_t suffix_size = request_size - aligned_size; + mx_vmar_unmap(mx_vmar_root_self(), + reinterpret_cast(aligned_base + aligned_size), + suffix_size); + request_size -= suffix_size; + } + + DCHECK(aligned_size == request_size); + + address_ = static_cast(aligned_base); + size_ = aligned_size; } -bool VirtualMemory::Uncommit(void* address, size_t size) { return false; } +VirtualMemory::~VirtualMemory() { + if (IsReserved()) { + bool result = ReleaseRegion(address(), size()); + DCHECK(result); + USE(result); + } +} -bool VirtualMemory::Guard(void* address) { return false; } +void VirtualMemory::Reset() { + address_ = nullptr; + size_ = 0; +} + +bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) { + CHECK(InVM(address, size)); + return CommitRegion(address, size, is_executable); +} + +bool VirtualMemory::Uncommit(void* address, size_t size) { + return UncommitRegion(address, size); +} + +bool VirtualMemory::Guard(void* address) { + return mx_vmar_protect(mx_vmar_root_self(), + reinterpret_cast(address), + OS::CommitPageSize(), 0 /*no permissions*/) == MX_OK; +} // static void* VirtualMemory::ReserveRegion(size_t size, void* hint) { - CHECK(false); // TODO(fuchsia): Port, https://crbug.com/731217. - return NULL; + mx_handle_t vmo; + if (mx_vmo_create(size, 0, &vmo) != MX_OK) return nullptr; + uintptr_t result; + mx_status_t status = mx_vmar_map(mx_vmar_root_self(), 0, vmo, 0, size, + 0 /*no permissions*/, &result); + mx_handle_close(vmo); + if (status != MX_OK) return nullptr; + return reinterpret_cast(result); } // static bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) { - CHECK(false); // TODO(fuchsia): Port, https://crbug.com/731217. - return false; + uint32_t prot = MX_VM_FLAG_PERM_READ | MX_VM_FLAG_PERM_WRITE | + (is_executable ? MX_VM_FLAG_PERM_EXECUTE : 0); + return mx_vmar_protect(mx_vmar_root_self(), reinterpret_cast(base), + size, prot) == MX_OK; } // static bool VirtualMemory::UncommitRegion(void* base, size_t size) { - CHECK(false); // TODO(fuchsia): Port, https://crbug.com/731217. - return false; + return mx_vmar_protect(mx_vmar_root_self(), reinterpret_cast(base), + size, 0 /*no permissions*/) == MX_OK; } // static bool VirtualMemory::ReleasePartialRegion(void* base, size_t size, void* free_start, size_t free_size) { - CHECK(false); // TODO(fuchsia): Port, https://crbug.com/731217. - return false; + return mx_vmar_unmap(mx_vmar_root_self(), + reinterpret_cast(free_start), + free_size) == MX_OK; } // static bool VirtualMemory::ReleaseRegion(void* base, size_t size) { - CHECK(false); // TODO(fuchsia): Port, https://crbug.com/731217. - return false; + return mx_vmar_unmap(mx_vmar_root_self(), reinterpret_cast(base), + size) == MX_OK; } // static bool VirtualMemory::HasLazyCommits() { - CHECK(false); // TODO(fuchsia): Port, https://crbug.com/731217. + // TODO(scottmg): Port, https://crbug.com/731217. return false; }