[wasm] Store WasmEngine in NativeModule

The {CompilationState} currently stores the {WasmEngine}, while the
{NativeModule} only stores the {WasmCodeManager}. From a high-level
view, this does not make much sense. The {NativeModule} belongs to
exactly one {WasmEngine}, so that link should be stored there. We can
then get to the {WasmCodeManager} from the {WasmEngine}.

This change requires a refactoring of the {WasmCodeManagerTest} which
created {WasmCodeManager}s independent of the {Isolate} and the
{WasmEngine}. This is not supported any more.
Note that in production, each {WasmEngine} owns exactly one
{WasmCodeManager} and one {WasmMemoryTracker}, so testing that a
{WasmMemoryTracker} can be shared by several {WasmCodeManager}s didn't
make sense in the first place.

R=mstarzinger@chromium.org

Bug: v8:8217
Change-Id: I582e698be35f97dbd38bf6e12eb7f8ee4fc1f0f2
Reviewed-on: https://chromium-review.googlesource.com/c/1297960
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56992}
This commit is contained in:
Clemens Hammacher 2018-10-25 15:29:13 +02:00 committed by Commit Bot
parent 5ed7e71f5c
commit 695466925c
5 changed files with 78 additions and 103 deletions

View File

@ -119,7 +119,7 @@ class CompilationState {
bool has_outstanding_units() const { return outstanding_units_ > 0; }
WasmEngine* wasm_engine() const { return wasm_engine_; }
WasmEngine* wasm_engine() const { return native_module_->wasm_engine(); }
CompileMode compile_mode() const { return compile_mode_; }
WasmFeatures* detected_features() { return &detected_features_; }
@ -131,10 +131,9 @@ class CompilationState {
: baseline_finish_units_;
}
// TODO(7423): Get rid of the Isolate field to make sure the CompilationState
// can be shared across multiple Isolates.
// TODO(mstarzinger): Get rid of the Isolate field to make sure the
// CompilationState can be shared across multiple Isolates.
Isolate* const isolate_;
WasmEngine* const wasm_engine_;
NativeModule* const native_module_;
const CompileMode compile_mode_;
bool baseline_compilation_finished_ = false;
@ -2848,7 +2847,6 @@ std::unique_ptr<CompilationState, CompilationStateDeleter> NewCompilationState(
CompilationState::CompilationState(internal::Isolate* isolate,
NativeModule* native_module)
: isolate_(isolate),
wasm_engine_(isolate->wasm_engine()),
native_module_(native_module),
compile_mode_(FLAG_wasm_tier_up &&
native_module->module()->origin == kWasmOrigin

View File

@ -337,7 +337,7 @@ WasmCode::~WasmCode() {
NativeModule::NativeModule(Isolate* isolate, const WasmFeatures& enabled,
bool can_request_more, VirtualMemory code_space,
WasmCodeManager* code_manager,
WasmEngine* wasm_engine,
std::shared_ptr<const WasmModule> module)
: enabled_features_(enabled),
module_(std::move(module)),
@ -345,7 +345,7 @@ NativeModule::NativeModule(Isolate* isolate, const WasmFeatures& enabled,
import_wrapper_cache_(std::unique_ptr<WasmImportWrapperCache>(
new WasmImportWrapperCache(this))),
free_code_space_(code_space.region()),
wasm_code_manager_(code_manager),
wasm_engine_(wasm_engine),
can_request_more_memory_(can_request_more),
use_trap_handler_(trap_handler::IsTrapHandlerEnabled() ? kUseTrapHandler
: kNoTrapHandler) {
@ -680,14 +680,15 @@ Vector<byte> NativeModule::AllocateForCode(size_t size) {
Address hint = owned_code_space_.empty() ? kNullAddress
: owned_code_space_.back().end();
VirtualMemory new_mem =
wasm_code_manager_->TryAllocate(size, reinterpret_cast<void*>(hint));
VirtualMemory new_mem = wasm_engine_->code_manager()->TryAllocate(
size, reinterpret_cast<void*>(hint));
if (!new_mem.IsReserved()) {
V8::FatalProcessOutOfMemory(nullptr,
"NativeModule::AllocateForCode reservation");
UNREACHABLE();
}
wasm_code_manager_->AssignRanges(new_mem.address(), new_mem.end(), this);
wasm_engine_->code_manager()->AssignRanges(new_mem.address(), new_mem.end(),
this);
free_code_space_.Merge(new_mem.region());
owned_code_space_.emplace_back(std::move(new_mem));
@ -720,7 +721,7 @@ Vector<byte> NativeModule::AllocateForCode(size_t size) {
Address start = std::max(commit_start, vmem.address());
Address end = std::min(commit_end, vmem.end());
size_t commit_size = static_cast<size_t>(end - start);
if (!wasm_code_manager_->Commit(start, commit_size)) {
if (!wasm_engine_->code_manager()->Commit(start, commit_size)) {
V8::FatalProcessOutOfMemory(nullptr,
"NativeModule::AllocateForCode commit");
UNREACHABLE();
@ -732,7 +733,8 @@ Vector<byte> NativeModule::AllocateForCode(size_t size) {
if (commit_start >= commit_end) break;
}
#else
if (!wasm_code_manager_->Commit(commit_start, commit_end - commit_start)) {
if (!wasm_engine_->code_manager()->Commit(commit_start,
commit_end - commit_start)) {
V8::FatalProcessOutOfMemory(nullptr,
"NativeModule::AllocateForCode commit");
UNREACHABLE();
@ -800,7 +802,7 @@ NativeModule::~NativeModule() {
// Cancel all background compilation before resetting any field of the
// NativeModule or freeing anything.
CancelAndWaitCompilationState(compilation_state_.get());
wasm_code_manager_->FreeNativeModule(this);
wasm_engine_->code_manager()->FreeNativeModule(this);
}
WasmCodeManager::WasmCodeManager(WasmMemoryTracker* memory_tracker,
@ -886,6 +888,10 @@ void WasmCodeManager::SampleModuleSizes(Isolate* isolate) const {
}
}
void WasmCodeManager::SetMaxCommittedMemoryForTesting(size_t limit) {
remaining_uncommitted_code_space_.store(limit);
}
namespace {
void ModuleSamplingCallback(v8::Isolate* v8_isolate, v8::GCType type,
@ -938,6 +944,7 @@ bool WasmCodeManager::ShouldForceCriticalMemoryPressureNotification() {
std::unique_ptr<NativeModule> WasmCodeManager::NewNativeModule(
Isolate* isolate, const WasmFeatures& enabled, size_t code_size_estimate,
bool can_request_more, std::shared_ptr<const WasmModule> module) {
DCHECK_EQ(this, isolate->wasm_engine()->code_manager());
if (ShouldForceCriticalMemoryPressureNotification()) {
(reinterpret_cast<v8::Isolate*>(isolate))
->MemoryPressureNotification(MemoryPressureLevel::kCritical);
@ -966,9 +973,9 @@ std::unique_ptr<NativeModule> WasmCodeManager::NewNativeModule(
Address start = code_space.address();
size_t size = code_space.size();
Address end = code_space.end();
std::unique_ptr<NativeModule> ret(
new NativeModule(isolate, enabled, can_request_more,
std::move(code_space), this, std::move(module)));
std::unique_ptr<NativeModule> ret(new NativeModule(
isolate, enabled, can_request_more, std::move(code_space),
isolate->wasm_engine(), std::move(module)));
TRACE_HEAP("New NativeModule %p: Mem: %" PRIuPTR ",+%zu\n", this, start,
size);
AssignRangesAndAddModule(start, end, ret.get());

View File

@ -30,6 +30,7 @@ namespace wasm {
class NativeModule;
class WasmCodeManager;
class WasmEngine;
class WasmMemoryTracker;
class WasmImportWrapperCache;
struct WasmModule;
@ -332,7 +333,7 @@ class V8_EXPORT_PRIVATE NativeModule final {
wire_bytes_ = std::move(wire_bytes);
}
const WasmModule* module() const { return module_.get(); }
WasmCodeManager* code_manager() const { return wasm_code_manager_; }
WasmEngine* wasm_engine() const { return wasm_engine_; }
WasmCode* Lookup(Address) const;
@ -352,7 +353,7 @@ class V8_EXPORT_PRIVATE NativeModule final {
NativeModule(Isolate* isolate, const WasmFeatures& enabled_features,
bool can_request_more, VirtualMemory code_space,
WasmCodeManager* code_manager,
WasmEngine* wasm_engine,
std::shared_ptr<const WasmModule> module);
WasmCode* AddAnonymousCode(Handle<Code>, WasmCode::Kind kind,
@ -453,7 +454,7 @@ class V8_EXPORT_PRIVATE NativeModule final {
// End of fields protected by {allocation_mutex_}.
//////////////////////////////////////////////////////////////////////////////
WasmCodeManager* wasm_code_manager_;
WasmEngine* const wasm_engine_;
std::atomic<size_t> committed_code_space_{0};
int modification_scope_depth_ = 0;
bool can_request_more_memory_;
@ -486,6 +487,8 @@ class V8_EXPORT_PRIVATE WasmCodeManager final {
// Add a sample of all module sizes.
void SampleModuleSizes(Isolate* isolate) const;
void SetMaxCommittedMemoryForTesting(size_t limit);
// TODO(v8:7424): For now we sample module sizes in a GC callback. This will
// bias samples towards apps with high memory pressure. We should switch to
// using sampling based on regular intervals independent of the GC.

View File

@ -188,7 +188,7 @@ std::shared_ptr<NativeModule> WasmEngine::ExportNativeModule(
Handle<WasmModuleObject> WasmEngine::ImportNativeModule(
Isolate* isolate, std::shared_ptr<NativeModule> shared_module) {
CHECK_EQ(code_manager(), shared_module->code_manager());
CHECK_EQ(this, shared_module->wasm_engine());
Vector<const byte> wire_bytes = shared_module->wire_bytes();
const WasmModule* module = shared_module->module();
Handle<Script> script =

View File

@ -8,6 +8,7 @@
#include "src/wasm/function-compiler.h"
#include "src/wasm/jump-table-assembler.h"
#include "src/wasm/wasm-code-manager.h"
#include "src/wasm/wasm-engine.h"
#include "src/wasm/wasm-memory.h"
namespace v8 {
@ -160,13 +161,12 @@ class WasmCodeManagerTest : public TestWithContext,
using NativeModulePtr = std::unique_ptr<NativeModule>;
NativeModulePtr AllocModule(WasmCodeManager* manager, size_t size,
ModuleStyle style) {
NativeModulePtr AllocModule(size_t size, ModuleStyle style) {
std::shared_ptr<WasmModule> module(new WasmModule);
module->num_declared_functions = kNumFunctions;
bool can_request_more = style == Growable;
return manager->NewNativeModule(i_isolate(), kAllWasmFeatures, size,
can_request_more, std::move(module));
return manager()->NewNativeModule(i_isolate(), kAllWasmFeatures, size,
can_request_more, std::move(module));
}
WasmCode* AddCode(NativeModule* native_module, uint32_t index, size_t size) {
@ -181,10 +181,13 @@ class WasmCodeManagerTest : public TestWithContext,
size_t page() const { return AllocatePageSize(); }
WasmMemoryTracker* memory_tracker() { return &memory_tracker_; }
WasmCodeManager* manager() {
return i_isolate()->wasm_engine()->code_manager();
}
private:
WasmMemoryTracker memory_tracker_;
void SetMaxCommittedMemory(size_t limit) {
manager()->SetMaxCommittedMemoryForTesting(limit);
}
};
INSTANTIATE_TEST_CASE_P(Parameterized, WasmCodeManagerTest,
@ -192,32 +195,32 @@ INSTANTIATE_TEST_CASE_P(Parameterized, WasmCodeManagerTest,
PrintWasmCodeManageTestParam);
TEST_P(WasmCodeManagerTest, EmptyCase) {
WasmCodeManager manager(memory_tracker(), 0 * page());
CHECK_EQ(0, manager.remaining_uncommitted_code_space());
SetMaxCommittedMemory(0 * page());
CHECK_EQ(0, manager()->remaining_uncommitted_code_space());
ASSERT_DEATH_IF_SUPPORTED(AllocModule(&manager, 1 * page(), GetParam()),
ASSERT_DEATH_IF_SUPPORTED(AllocModule(1 * page(), GetParam()),
"OOM in NativeModule::AllocateForCode commit");
}
TEST_P(WasmCodeManagerTest, AllocateAndGoOverLimit) {
WasmCodeManager manager(memory_tracker(), 1 * page());
CHECK_EQ(1 * page(), manager.remaining_uncommitted_code_space());
NativeModulePtr native_module = AllocModule(&manager, 1 * page(), GetParam());
SetMaxCommittedMemory(1 * page());
CHECK_EQ(1 * page(), manager()->remaining_uncommitted_code_space());
NativeModulePtr native_module = AllocModule(1 * page(), GetParam());
CHECK(native_module);
CHECK_EQ(0, manager.remaining_uncommitted_code_space());
CHECK_EQ(0, manager()->remaining_uncommitted_code_space());
uint32_t index = 0;
WasmCode* code = AddCode(native_module.get(), index++, 1 * kCodeAlignment);
CHECK_NOT_NULL(code);
CHECK_EQ(0, manager.remaining_uncommitted_code_space());
CHECK_EQ(0, manager()->remaining_uncommitted_code_space());
code = AddCode(native_module.get(), index++, 3 * kCodeAlignment);
CHECK_NOT_NULL(code);
CHECK_EQ(0, manager.remaining_uncommitted_code_space());
CHECK_EQ(0, manager()->remaining_uncommitted_code_space());
code = AddCode(native_module.get(), index++,
page() - 4 * kCodeAlignment - kJumpTableSize);
CHECK_NOT_NULL(code);
CHECK_EQ(0, manager.remaining_uncommitted_code_space());
CHECK_EQ(0, manager()->remaining_uncommitted_code_space());
// This fails in "reservation" if we cannot extend the code space, or in
// "commit" it we can (since we hit the allocation limit in the
@ -228,9 +231,9 @@ TEST_P(WasmCodeManagerTest, AllocateAndGoOverLimit) {
}
TEST_P(WasmCodeManagerTest, TotalLimitIrrespectiveOfModuleCount) {
WasmCodeManager manager(memory_tracker(), 3 * page());
NativeModulePtr nm1 = AllocModule(&manager, 2 * page(), GetParam());
NativeModulePtr nm2 = AllocModule(&manager, 2 * page(), GetParam());
SetMaxCommittedMemory(3 * page());
NativeModulePtr nm1 = AllocModule(2 * page(), GetParam());
NativeModulePtr nm2 = AllocModule(2 * page(), GetParam());
CHECK(nm1);
CHECK(nm2);
WasmCode* code = AddCode(nm1.get(), 0, 2 * page() - kJumpTableSize);
@ -239,23 +242,9 @@ TEST_P(WasmCodeManagerTest, TotalLimitIrrespectiveOfModuleCount) {
"OOM in NativeModule::AllocateForCode commit");
}
TEST_P(WasmCodeManagerTest, DifferentHeapsApplyLimitsIndependently) {
WasmCodeManager manager1(memory_tracker(), 1 * page());
WasmCodeManager manager2(memory_tracker(), 2 * page());
NativeModulePtr nm1 = AllocModule(&manager1, 1 * page(), GetParam());
NativeModulePtr nm2 = AllocModule(&manager2, 1 * page(), GetParam());
CHECK(nm1);
CHECK(nm2);
WasmCode* code = AddCode(nm1.get(), 0, 1 * page() - kJumpTableSize);
CHECK_NOT_NULL(code);
CHECK_EQ(0, manager1.remaining_uncommitted_code_space());
code = AddCode(nm2.get(), 0, 1 * page() - kJumpTableSize);
CHECK_NOT_NULL(code);
}
TEST_P(WasmCodeManagerTest, GrowingVsFixedModule) {
WasmCodeManager manager(memory_tracker(), 3 * page());
NativeModulePtr nm = AllocModule(&manager, 1 * page(), GetParam());
SetMaxCommittedMemory(3 * page());
NativeModulePtr nm = AllocModule(1 * page(), GetParam());
size_t module_size = GetParam() == Fixed ? kMaxWasmCodeMemory : 1 * page();
size_t remaining_space_in_module = module_size - kJumpTableSize;
if (GetParam() == Fixed) {
@ -268,29 +257,29 @@ TEST_P(WasmCodeManagerTest, GrowingVsFixedModule) {
// The module grows by one page. One page remains uncommitted.
CHECK_NOT_NULL(
AddCode(nm.get(), 0, remaining_space_in_module + kCodeAlignment));
CHECK_EQ(manager.remaining_uncommitted_code_space(), 1 * page());
CHECK_EQ(manager()->remaining_uncommitted_code_space(), 1 * page());
}
}
TEST_P(WasmCodeManagerTest, CommitIncrements) {
WasmCodeManager manager(memory_tracker(), 10 * page());
NativeModulePtr nm = AllocModule(&manager, 3 * page(), GetParam());
SetMaxCommittedMemory(10 * page());
NativeModulePtr nm = AllocModule(3 * page(), GetParam());
WasmCode* code = AddCode(nm.get(), 0, kCodeAlignment);
CHECK_NOT_NULL(code);
CHECK_EQ(manager.remaining_uncommitted_code_space(), 9 * page());
CHECK_EQ(manager()->remaining_uncommitted_code_space(), 9 * page());
code = AddCode(nm.get(), 1, 2 * page());
CHECK_NOT_NULL(code);
CHECK_EQ(manager.remaining_uncommitted_code_space(), 7 * page());
CHECK_EQ(manager()->remaining_uncommitted_code_space(), 7 * page());
code = AddCode(nm.get(), 2, page() - kCodeAlignment - kJumpTableSize);
CHECK_NOT_NULL(code);
CHECK_EQ(manager.remaining_uncommitted_code_space(), 7 * page());
CHECK_EQ(manager()->remaining_uncommitted_code_space(), 7 * page());
}
TEST_P(WasmCodeManagerTest, Lookup) {
WasmCodeManager manager(memory_tracker(), 2 * page());
SetMaxCommittedMemory(2 * page());
NativeModulePtr nm1 = AllocModule(&manager, 1 * page(), GetParam());
NativeModulePtr nm2 = AllocModule(&manager, 1 * page(), GetParam());
NativeModulePtr nm1 = AllocModule(1 * page(), GetParam());
NativeModulePtr nm2 = AllocModule(1 * page(), GetParam());
WasmCode* code1_0 = AddCode(nm1.get(), 0, kCodeAlignment);
CHECK_EQ(nm1.get(), code1_0->native_module());
WasmCode* code1_1 = AddCode(nm1.get(), 1, kCodeAlignment);
@ -305,63 +294,41 @@ TEST_P(WasmCodeManagerTest, Lookup) {
// we know the manager object is allocated here, so we shouldn't
// find any WasmCode* associated with that ptr.
WasmCode* not_found = manager.LookupCode(reinterpret_cast<Address>(&manager));
WasmCode* not_found =
manager()->LookupCode(reinterpret_cast<Address>(manager()));
CHECK_NULL(not_found);
WasmCode* found = manager.LookupCode(code1_0->instruction_start());
WasmCode* found = manager()->LookupCode(code1_0->instruction_start());
CHECK_EQ(found, code1_0);
found = manager.LookupCode(code2_1->instruction_start() +
(code2_1->instructions().size() / 2));
found = manager()->LookupCode(code2_1->instruction_start() +
(code2_1->instructions().size() / 2));
CHECK_EQ(found, code2_1);
found = manager.LookupCode(code2_1->instruction_start() +
code2_1->instructions().size() - 1);
found = manager()->LookupCode(code2_1->instruction_start() +
code2_1->instructions().size() - 1);
CHECK_EQ(found, code2_1);
found = manager.LookupCode(code2_1->instruction_start() +
code2_1->instructions().size());
found = manager()->LookupCode(code2_1->instruction_start() +
code2_1->instructions().size());
CHECK_NULL(found);
Address mid_code1_1 =
code1_1->instruction_start() + (code1_1->instructions().size() / 2);
CHECK_EQ(code1_1, manager.LookupCode(mid_code1_1));
CHECK_EQ(code1_1, manager()->LookupCode(mid_code1_1));
nm1.reset();
CHECK_NULL(manager.LookupCode(mid_code1_1));
}
TEST_P(WasmCodeManagerTest, MultiManagerLookup) {
WasmCodeManager manager1(memory_tracker(), 2 * page());
WasmCodeManager manager2(memory_tracker(), 2 * page());
NativeModulePtr nm1 = AllocModule(&manager1, 1 * page(), GetParam());
NativeModulePtr nm2 = AllocModule(&manager2, 1 * page(), GetParam());
WasmCode* code1_0 = AddCode(nm1.get(), 0, kCodeAlignment);
CHECK_EQ(nm1.get(), code1_0->native_module());
WasmCode* code1_1 = AddCode(nm1.get(), 1, kCodeAlignment);
WasmCode* code2_0 = AddCode(nm2.get(), 0, kCodeAlignment);
WasmCode* code2_1 = AddCode(nm2.get(), 1, kCodeAlignment);
CHECK_EQ(nm2.get(), code2_1->native_module());
CHECK_EQ(0, code1_0->index());
CHECK_EQ(1, code1_1->index());
CHECK_EQ(0, code2_0->index());
CHECK_EQ(1, code2_1->index());
CHECK_EQ(code1_0, manager1.LookupCode(code1_0->instruction_start()));
CHECK_NULL(manager2.LookupCode(code1_0->instruction_start()));
CHECK_NULL(manager()->LookupCode(mid_code1_1));
}
TEST_P(WasmCodeManagerTest, LookupWorksAfterRewrite) {
WasmCodeManager manager(memory_tracker(), 2 * page());
SetMaxCommittedMemory(2 * page());
NativeModulePtr nm1 = AllocModule(&manager, 1 * page(), GetParam());
NativeModulePtr nm1 = AllocModule(1 * page(), GetParam());
WasmCode* code0 = AddCode(nm1.get(), 0, kCodeAlignment);
WasmCode* code1 = AddCode(nm1.get(), 1, kCodeAlignment);
CHECK_EQ(0, code0->index());
CHECK_EQ(1, code1->index());
CHECK_EQ(code1, manager.LookupCode(code1->instruction_start()));
CHECK_EQ(code1, manager()->LookupCode(code1->instruction_start()));
WasmCode* code1_1 = AddCode(nm1.get(), 1, kCodeAlignment);
CHECK_EQ(1, code1_1->index());
CHECK_EQ(code1, manager.LookupCode(code1->instruction_start()));
CHECK_EQ(code1_1, manager.LookupCode(code1_1->instruction_start()));
CHECK_EQ(code1, manager()->LookupCode(code1->instruction_start()));
CHECK_EQ(code1_1, manager()->LookupCode(code1_1->instruction_start()));
}
} // namespace wasm_heap_unittest