Commit 4d921281 authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[wasm] Introduce --wasm-shared-engine flag.

This flag allows to share a single WasmEngine among all Isolates within
the same process. It will ultimately allow to share the WasmCode objects
associated with modules that are transferred via structured cloning.

R=clemensh@chromium.org
TEST=mjsunit/wasm/worker-module
BUG=v8:7424

Change-Id: I70d852d319b2a80bd02e0a2a838dcdfa071df6e1
Reviewed-on: https://chromium-review.googlesource.com/1138213
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54678}
parent 1465c36d
...@@ -612,6 +612,8 @@ DEFINE_BOOL(wasm_no_bounds_checks, false, ...@@ -612,6 +612,8 @@ DEFINE_BOOL(wasm_no_bounds_checks, false,
DEFINE_BOOL(wasm_no_stack_checks, false, DEFINE_BOOL(wasm_no_stack_checks, false,
"disable stack checks (performance testing only)") "disable stack checks (performance testing only)")
DEFINE_BOOL(wasm_shared_engine, false,
"shares one wasm engine between all isolates within a process")
DEFINE_BOOL(wasm_trap_handler, true, DEFINE_BOOL(wasm_trap_handler, true,
"use signal handlers to catch out of bounds memory access in wasm" "use signal handlers to catch out of bounds memory access in wasm"
" (currently Linux x86_64 only)") " (currently Linux x86_64 only)")
......
...@@ -2964,11 +2964,9 @@ bool Isolate::Init(StartupDeserializer* des) { ...@@ -2964,11 +2964,9 @@ bool Isolate::Init(StartupDeserializer* des) {
DCHECK(!heap_.HasBeenSetUp()); DCHECK(!heap_.HasBeenSetUp());
heap_.SetUp(); heap_.SetUp();
// Setup the wasm engine. Currently, there's one per Isolate by default. // Setup the wasm engine.
if (wasm_engine_ == nullptr) { if (wasm_engine_ == nullptr) {
wasm_engine_.reset( wasm_engine_ = wasm::WasmEngine::GetWasmEngine();
new wasm::WasmEngine(std::unique_ptr<wasm::WasmCodeManager>(
new wasm::WasmCodeManager(kMaxWasmCodeMemory))));
wasm::WasmCodeManager::InstallSamplingGCCallback(this); wasm::WasmCodeManager::InstallSamplingGCCallback(this);
} }
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "src/snapshot/natives.h" #include "src/snapshot/natives.h"
#include "src/snapshot/snapshot.h" #include "src/snapshot/snapshot.h"
#include "src/tracing/tracing-category-observer.h" #include "src/tracing/tracing-category-observer.h"
#include "src/wasm/wasm-engine.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -47,6 +48,7 @@ void V8::TearDown() { ...@@ -47,6 +48,7 @@ void V8::TearDown() {
#if defined(USE_SIMULATOR) #if defined(USE_SIMULATOR)
Simulator::GlobalTearDown(); Simulator::GlobalTearDown();
#endif #endif
wasm::WasmEngine::GlobalTearDown();
CallDescriptors::TearDown(); CallDescriptors::TearDown();
Bootstrapper::TearDownExtensions(); Bootstrapper::TearDownExtensions();
ElementsAccessor::TearDown(); ElementsAccessor::TearDown();
...@@ -84,6 +86,7 @@ void V8::InitializeOncePerProcessImpl() { ...@@ -84,6 +86,7 @@ void V8::InitializeOncePerProcessImpl() {
ElementsAccessor::InitializeOncePerProcess(); ElementsAccessor::InitializeOncePerProcess();
Bootstrapper::InitializeOncePerProcess(); Bootstrapper::InitializeOncePerProcess();
CallDescriptors::InitializeOncePerProcess(); CallDescriptors::InitializeOncePerProcess();
wasm::WasmEngine::InitializeOncePerProcess();
} }
......
...@@ -664,7 +664,7 @@ Address NativeModule::AllocateForCode(size_t size) { ...@@ -664,7 +664,7 @@ Address NativeModule::AllocateForCode(size_t size) {
if (!wasm_code_manager_->Commit(start, commit_size)) { if (!wasm_code_manager_->Commit(start, commit_size)) {
return kNullAddress; return kNullAddress;
} }
committed_code_space_ += commit_size; committed_code_space_.fetch_add(commit_size);
commit_end = start; commit_end = start;
} }
#else #else
...@@ -673,7 +673,7 @@ Address NativeModule::AllocateForCode(size_t size) { ...@@ -673,7 +673,7 @@ Address NativeModule::AllocateForCode(size_t size) {
if (!wasm_code_manager_->Commit(commit_start, commit_size)) { if (!wasm_code_manager_->Commit(commit_start, commit_size)) {
return kNullAddress; return kNullAddress;
} }
committed_code_space_ += commit_size; committed_code_space_.fetch_add(commit_size);
#endif #endif
} }
DCHECK(IsAligned(mem.start, kCodeAlignment)); DCHECK(IsAligned(mem.start, kCodeAlignment));
...@@ -794,9 +794,10 @@ void WasmCodeManager::TryAllocate(size_t size, VirtualMemory* ret, void* hint) { ...@@ -794,9 +794,10 @@ void WasmCodeManager::TryAllocate(size_t size, VirtualMemory* ret, void* hint) {
} }
void WasmCodeManager::SampleModuleSizes(Isolate* isolate) const { void WasmCodeManager::SampleModuleSizes(Isolate* isolate) const {
base::LockGuard<base::Mutex> lock(&native_modules_mutex_);
for (NativeModule* native_module : native_modules_) { for (NativeModule* native_module : native_modules_) {
base::LockGuard<base::Mutex> lock(&native_module->allocation_mutex_); int code_size =
int code_size = static_cast<int>(native_module->committed_code_space_ / MB); static_cast<int>(native_module->committed_code_space_.load() / MB);
isolate->counters()->wasm_module_code_size_mb()->AddSample(code_size); isolate->counters()->wasm_module_code_size_mb()->AddSample(code_size);
} }
} }
...@@ -840,19 +841,21 @@ size_t WasmCodeManager::EstimateNativeModuleSize(const WasmModule* module) { ...@@ -840,19 +841,21 @@ size_t WasmCodeManager::EstimateNativeModuleSize(const WasmModule* module) {
return estimate; return estimate;
} }
std::unique_ptr<NativeModule> WasmCodeManager::NewNativeModule( bool WasmCodeManager::ShouldForceCriticalMemoryPressureNotification() {
Isolate* isolate, size_t memory_estimate, bool can_request_more, base::LockGuard<base::Mutex> lock(&native_modules_mutex_);
std::shared_ptr<const WasmModule> module, const ModuleEnv& env) {
// TODO(titzer): we force a critical memory pressure notification // TODO(titzer): we force a critical memory pressure notification
// when the code space is almost exhausted, but only upon the next module // when the code space is almost exhausted, but only upon the next module
// creation. This is only for one isolate, and it should really do this for // creation. This is only for one isolate, and it should really do this for
// all isolates, at the point of commit. // all isolates, at the point of commit.
constexpr size_t kCriticalThreshold = 32 * 1024 * 1024; constexpr size_t kCriticalThreshold = 32 * 1024 * 1024;
bool force_critical_notification = return native_modules_.size() > 1 &&
(native_modules_.size() > 1) && remaining_uncommitted_code_space_.load() < kCriticalThreshold;
(remaining_uncommitted_code_space_.load() < kCriticalThreshold); }
if (force_critical_notification) { std::unique_ptr<NativeModule> WasmCodeManager::NewNativeModule(
Isolate* isolate, size_t memory_estimate, bool can_request_more,
std::shared_ptr<const WasmModule> module, const ModuleEnv& env) {
if (ShouldForceCriticalMemoryPressureNotification()) {
(reinterpret_cast<v8::Isolate*>(isolate)) (reinterpret_cast<v8::Isolate*>(isolate))
->MemoryPressureNotification(MemoryPressureLevel::kCritical); ->MemoryPressureNotification(MemoryPressureLevel::kCritical);
} }
...@@ -870,6 +873,7 @@ std::unique_ptr<NativeModule> WasmCodeManager::NewNativeModule( ...@@ -870,6 +873,7 @@ std::unique_ptr<NativeModule> WasmCodeManager::NewNativeModule(
TRACE_HEAP("New NativeModule %p: Mem: %" PRIuPTR ",+%zu\n", this, start, TRACE_HEAP("New NativeModule %p: Mem: %" PRIuPTR ",+%zu\n", this, start,
size); size);
AssignRanges(start, end, ret.get()); AssignRanges(start, end, ret.get());
base::LockGuard<base::Mutex> lock(&native_modules_mutex_);
native_modules_.emplace(ret.get()); native_modules_.emplace(ret.get());
return ret; return ret;
} }
...@@ -923,6 +927,7 @@ bool NativeModule::SetExecutable(bool executable) { ...@@ -923,6 +927,7 @@ bool NativeModule::SetExecutable(bool executable) {
} }
void WasmCodeManager::FreeNativeModule(NativeModule* native_module) { void WasmCodeManager::FreeNativeModule(NativeModule* native_module) {
base::LockGuard<base::Mutex> lock(&native_modules_mutex_);
DCHECK_EQ(1, native_modules_.count(native_module)); DCHECK_EQ(1, native_modules_.count(native_module));
native_modules_.erase(native_module); native_modules_.erase(native_module);
TRACE_HEAP("Freeing NativeModule %p\n", this); TRACE_HEAP("Freeing NativeModule %p\n", this);
...@@ -933,7 +938,7 @@ void WasmCodeManager::FreeNativeModule(NativeModule* native_module) { ...@@ -933,7 +938,7 @@ void WasmCodeManager::FreeNativeModule(NativeModule* native_module) {
} }
native_module->owned_code_space_.clear(); native_module->owned_code_space_.clear();
size_t code_size = native_module->committed_code_space_; size_t code_size = native_module->committed_code_space_.load();
DCHECK(IsAligned(code_size, AllocatePageSize())); DCHECK(IsAligned(code_size, AllocatePageSize()));
remaining_uncommitted_code_space_.fetch_add(code_size); remaining_uncommitted_code_space_.fetch_add(code_size);
} }
......
...@@ -405,7 +405,7 @@ class V8_EXPORT_PRIVATE NativeModule final { ...@@ -405,7 +405,7 @@ class V8_EXPORT_PRIVATE NativeModule final {
std::list<VirtualMemory> owned_code_space_; std::list<VirtualMemory> owned_code_space_;
WasmCodeManager* wasm_code_manager_; WasmCodeManager* wasm_code_manager_;
size_t committed_code_space_ = 0; std::atomic<size_t> committed_code_space_{0};
int modification_scope_depth_ = 0; int modification_scope_depth_ = 0;
bool can_request_more_memory_; bool can_request_more_memory_;
bool use_trap_handler_ = false; bool use_trap_handler_ = false;
...@@ -455,7 +455,9 @@ class V8_EXPORT_PRIVATE WasmCodeManager final { ...@@ -455,7 +455,9 @@ class V8_EXPORT_PRIVATE WasmCodeManager final {
void FreeNativeModule(NativeModule*); void FreeNativeModule(NativeModule*);
void Free(VirtualMemory* mem); void Free(VirtualMemory* mem);
void AssignRanges(Address start, Address end, NativeModule*); void AssignRanges(Address start, Address end, NativeModule*);
bool ShouldForceCriticalMemoryPressureNotification();
mutable base::Mutex native_modules_mutex_;
std::map<Address, std::pair<Address, NativeModule*>> lookup_map_; std::map<Address, std::pair<Address, NativeModule*>> lookup_map_;
std::unordered_set<NativeModule*> native_modules_; std::unordered_set<NativeModule*> native_modules_;
std::atomic<size_t> remaining_uncommitted_code_space_; std::atomic<size_t> remaining_uncommitted_code_space_;
......
...@@ -234,6 +234,44 @@ void WasmEngine::TearDown() { ...@@ -234,6 +234,44 @@ void WasmEngine::TearDown() {
jobs_.clear(); jobs_.clear();
} }
namespace {
WasmEngine* AllocateNewWasmEngine() {
return new WasmEngine(std::unique_ptr<WasmCodeManager>(
new WasmCodeManager(kMaxWasmCodeMemory)));
}
struct WasmEnginePointerConstructTrait final {
static void Construct(void* raw_ptr) {
auto engine_ptr = reinterpret_cast<std::shared_ptr<WasmEngine>*>(raw_ptr);
*engine_ptr = std::shared_ptr<WasmEngine>();
}
};
// Holds the global shared pointer to the single {WasmEngine} that is intended
// to be shared among Isolates within the same process. The {LazyStaticInstance}
// here is required because {std::shared_ptr} has a non-trivial initializer.
base::LazyStaticInstance<std::shared_ptr<WasmEngine>,
WasmEnginePointerConstructTrait>::type
global_wasm_engine;
} // namespace
void WasmEngine::InitializeOncePerProcess() {
if (!FLAG_wasm_shared_engine) return;
global_wasm_engine.Pointer()->reset(AllocateNewWasmEngine());
}
void WasmEngine::GlobalTearDown() {
if (!FLAG_wasm_shared_engine) return;
global_wasm_engine.Pointer()->reset();
}
std::shared_ptr<WasmEngine> WasmEngine::GetWasmEngine() {
if (FLAG_wasm_shared_engine) return global_wasm_engine.Get();
return std::shared_ptr<WasmEngine>(AllocateNewWasmEngine());
}
} // namespace wasm } // namespace wasm
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -121,6 +121,14 @@ class V8_EXPORT_PRIVATE WasmEngine { ...@@ -121,6 +121,14 @@ class V8_EXPORT_PRIVATE WasmEngine {
void TearDown(); void TearDown();
// Call on process start and exit.
static void InitializeOncePerProcess();
static void GlobalTearDown();
// Constructs a WasmEngine instance. Depending on whether we are sharing
// engines this might be a pointer to a new instance or to a shared one.
static std::shared_ptr<WasmEngine> GetWasmEngine();
private: private:
AsyncCompileJob* CreateAsyncCompileJob( AsyncCompileJob* CreateAsyncCompileJob(
Isolate* isolate, std::unique_ptr<byte[]> bytes_copy, size_t length, Isolate* isolate, std::unique_ptr<byte[]> bytes_copy, size_t length,
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --no-wasm-disable-structured-cloning // Flags: --wasm-shared-engine --no-wasm-disable-structured-cloning
load("test/mjsunit/wasm/wasm-constants.js"); load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js"); load("test/mjsunit/wasm/wasm-module-builder.js");
......
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