From 6dcef1d327d6b61f4ef235d9b2b30cbe10bca9f0 Mon Sep 17 00:00:00 2001 From: Clemens Hammacher Date: Wed, 15 May 2019 13:15:46 +0200 Subject: [PATCH] [wasm] Refactor splitting ranges by reservations On windows, when changing permissions for a range of pages, or committing or discarding a range of pages, we need to split that range by the reservations and potentially execute several system calls. This logic is currently implemented for committing memory. This CL extracts this to a helper function such that we can reuse this for discarding a range of pages. R=mstarzinger@chromium.org Bug: v8:8217 Change-Id: I65673eebe28362975f0165905d20b97ef7947f56 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1611544 Commit-Queue: Clemens Hammacher Reviewed-by: Michael Starzinger Cr-Commit-Position: refs/heads/master@{#61523} --- src/base/small-vector.h | 6 +++ src/wasm/wasm-code-manager.cc | 69 +++++++++++++++++++++++------------ 2 files changed, 52 insertions(+), 23 deletions(-) diff --git a/src/base/small-vector.h b/src/base/small-vector.h index 9c098c4829..bb024ca87e 100644 --- a/src/base/small-vector.h +++ b/src/base/small-vector.h @@ -5,7 +5,9 @@ #ifndef V8_BASE_SMALL_VECTOR_H_ #define V8_BASE_SMALL_VECTOR_H_ +#include #include +#include #include "src/base/bits.h" #include "src/base/macros.h" @@ -29,6 +31,10 @@ class SmallVector { explicit SmallVector(size_t size) { resize_no_init(size); } SmallVector(const SmallVector& other) V8_NOEXCEPT { *this = other; } SmallVector(SmallVector&& other) V8_NOEXCEPT { *this = std::move(other); } + SmallVector(std::initializer_list init) { + resize_no_init(init.size()); + memcpy(begin_, init.begin(), sizeof(T) * init.size()); + } ~SmallVector() { if (is_big()) free(begin_); diff --git a/src/wasm/wasm-code-manager.cc b/src/wasm/wasm-code-manager.cc index fc01064e65..c4ef522179 100644 --- a/src/wasm/wasm-code-manager.cc +++ b/src/wasm/wasm-code-manager.cc @@ -10,6 +10,7 @@ #include "src/base/adapters.h" #include "src/base/macros.h" #include "src/base/platform/platform.h" +#include "src/base/small-vector.h" #include "src/counters.h" #include "src/disassembler.h" #include "src/globals.h" @@ -415,6 +416,48 @@ WasmCodeAllocator::~WasmCodeAllocator() { committed_code_space()); } +namespace { +// On Windows, we cannot commit a region that straddles different reservations +// of virtual memory. Because we bump-allocate, and because, if we need more +// memory, we append that memory at the end of the owned_code_space_ list, we +// traverse that list in reverse order to find the reservation(s) that guide how +// to chunk the region to commit. +#if V8_OS_WIN +constexpr bool kNeedsToSplitRangeByReservations = true; +#else +constexpr bool kNeedsToSplitRangeByReservations = false; +#endif + +base::SmallVector SplitRangeByReservationsIfNeeded( + base::AddressRegion range, + const std::vector& owned_code_space) { + if (!kNeedsToSplitRangeByReservations) return {range}; + + base::SmallVector split_ranges; + for (auto& vmem : base::Reversed(owned_code_space)) { + Address overlap_start = std::max(range.begin(), vmem.address()); + Address overlap_end = std::min(range.end(), vmem.end()); + if (overlap_start >= overlap_end) continue; + split_ranges.emplace_back(overlap_start, overlap_end - overlap_start); + // Opportunistically reduce the commit range. This might terminate the + // loop early. + if (range.begin() == overlap_start) { + range = {overlap_end, range.end() - overlap_end}; + if (range.is_empty()) break; + } else if (range.end() == overlap_end) { + range = {range.begin(), overlap_start - range.begin()}; + } + } +#ifdef ENABLE_SLOW_DCHECKS + // The returned vector should cover the full range. + size_t total_split_size = 0; + for (auto split : split_ranges) total_split_size += split.size(); + DCHECK_EQ(range.size(), total_split_size); +#endif + return split_ranges; +} +} // namespace + Vector WasmCodeAllocator::AllocateForCode(NativeModule* native_module, size_t size) { base::MutexGuard lock(&mutex_); @@ -462,33 +505,13 @@ Vector WasmCodeAllocator::AllocateForCode(NativeModule* native_module, committed_code_space_.fetch_add(commit_end - commit_start); // Committed code cannot grow bigger than maximum code space size. DCHECK_LE(committed_code_space_.load(), kMaxWasmCodeMemory); -#if V8_OS_WIN - // On Windows, we cannot commit a region that straddles different - // reservations of virtual memory. Because we bump-allocate, and because, if - // we need more memory, we append that memory at the end of the - // owned_code_space_ list, we traverse that list in reverse order to find - // the reservation(s) that guide how to chunk the region to commit. - for (auto& vmem : base::Reversed(owned_code_space_)) { - if (commit_end <= vmem.address() || vmem.end() <= commit_start) continue; - Address start = std::max(commit_start, vmem.address()); - Address end = std::min(commit_end, vmem.end()); - size_t commit_size = static_cast(end - start); - if (!code_manager_->Commit(start, commit_size)) { + for (base::AddressRegion split_range : SplitRangeByReservationsIfNeeded( + {commit_start, commit_end - commit_start}, owned_code_space_)) { + if (!code_manager_->Commit(split_range.begin(), split_range.size())) { V8::FatalProcessOutOfMemory(nullptr, "wasm code commit"); UNREACHABLE(); } - // Opportunistically reduce the commit range. This might terminate the - // loop early. - if (commit_start == start) commit_start = end; - if (commit_end == end) commit_end = start; - if (commit_start >= commit_end) break; } -#else - if (!code_manager_->Commit(commit_start, commit_end - commit_start)) { - V8::FatalProcessOutOfMemory(nullptr, "wasm code commit"); - UNREACHABLE(); - } -#endif } DCHECK(IsAligned(code_space.begin(), kCodeAlignment)); allocated_code_space_.Merge(code_space);