Commit 3df442d7 authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[wasm] Keep NativeModule alive in BackgroundCompileScope

We need to ensure that the NativeModule stays alive while any
{BackgroundCompileScope} exists, because during that time we hold
shared ownership of the mutex in the {BackgroundCompileToken}. If the
{NativeModule} dies during that period, we would need to get exclusive
ownership of the mutex and deadlock.

This change requires holding a {std::weak_ptr<NativeModule>} in the
BackgroundCompileToken instead of a raw pointer, hence it can only be
initialized after the NativeModule was created. This is done via a
separate {InitCompilationState} method.

R=ahaas@chromium.org

Bug: v8:8979
Change-Id: Ia14bd272ea0bc47aec547024da6020608418c9d2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1518178
Auto-Submit: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60203}
parent d358cf09
...@@ -126,8 +126,11 @@ class CompilationState { ...@@ -126,8 +126,11 @@ class CompilationState {
friend class WasmCompilationUnit; friend class WasmCompilationUnit;
CompilationState() = delete; CompilationState() = delete;
static std::unique_ptr<CompilationState> New(NativeModule*, // The CompilationState keeps a {std::weak_ptr} back to the {NativeModule}
std::shared_ptr<Counters>); // such that it can keep it alive (by regaining a {std::shared_ptr}) in
// certain scopes.
static std::unique_ptr<CompilationState> New(
const std::shared_ptr<NativeModule>&, std::shared_ptr<Counters>);
}; };
} // namespace wasm } // namespace wasm
......
...@@ -61,22 +61,23 @@ enum class CompileMode : uint8_t { kRegular, kTiering }; ...@@ -61,22 +61,23 @@ enum class CompileMode : uint8_t { kRegular, kTiering };
// on background compile jobs. // on background compile jobs.
class BackgroundCompileToken { class BackgroundCompileToken {
public: public:
explicit BackgroundCompileToken(NativeModule* native_module) explicit BackgroundCompileToken(
const std::shared_ptr<NativeModule>& native_module)
: native_module_(native_module) {} : native_module_(native_module) {}
void Cancel() { void Cancel() {
base::SharedMutexGuard<base::kExclusive> mutex_guard(&mutex_); base::SharedMutexGuard<base::kExclusive> mutex_guard(&mutex_);
native_module_ = nullptr; native_module_.reset();
} }
private: private:
friend class BackgroundCompileScope; friend class BackgroundCompileScope;
base::SharedMutex mutex_; base::SharedMutex mutex_;
NativeModule* native_module_; std::weak_ptr<NativeModule> native_module_;
NativeModule* StartScope() { std::shared_ptr<NativeModule> StartScope() {
mutex_.LockShared(); mutex_.LockShared();
return native_module_; return native_module_.lock();
} }
void ExitScope() { mutex_.UnlockShared(); } void ExitScope() { mutex_.UnlockShared(); }
...@@ -99,14 +100,15 @@ class BackgroundCompileScope { ...@@ -99,14 +100,15 @@ class BackgroundCompileScope {
NativeModule* native_module() { NativeModule* native_module() {
DCHECK(!cancelled()); DCHECK(!cancelled());
return native_module_; return native_module_.get();
} }
inline CompilationStateImpl* compilation_state(); inline CompilationStateImpl* compilation_state();
private: private:
BackgroundCompileToken* const token_; BackgroundCompileToken* const token_;
NativeModule* const native_module_; // Keep the native module alive while in this scope.
std::shared_ptr<NativeModule> const native_module_;
}; };
// The {CompilationStateImpl} keeps track of the compilation state of the // The {CompilationStateImpl} keeps track of the compilation state of the
...@@ -116,7 +118,8 @@ class BackgroundCompileScope { ...@@ -116,7 +118,8 @@ class BackgroundCompileScope {
// It's public interface {CompilationState} lives in compilation-environment.h. // It's public interface {CompilationState} lives in compilation-environment.h.
class CompilationStateImpl { class CompilationStateImpl {
public: public:
CompilationStateImpl(NativeModule*, std::shared_ptr<Counters> async_counters); CompilationStateImpl(const std::shared_ptr<NativeModule>& native_module,
std::shared_ptr<Counters> async_counters);
~CompilationStateImpl(); ~CompilationStateImpl();
// Cancel all background compilation and wait for all tasks to finish. Call // Cancel all background compilation and wait for all tasks to finish. Call
...@@ -310,7 +313,8 @@ void CompilationState::OnFinishedUnit(ExecutionTier tier, WasmCode* code) { ...@@ -310,7 +313,8 @@ void CompilationState::OnFinishedUnit(ExecutionTier tier, WasmCode* code) {
// static // static
std::unique_ptr<CompilationState> CompilationState::New( std::unique_ptr<CompilationState> CompilationState::New(
NativeModule* native_module, std::shared_ptr<Counters> async_counters) { const std::shared_ptr<NativeModule>& native_module,
std::shared_ptr<Counters> async_counters) {
return std::unique_ptr<CompilationState>(reinterpret_cast<CompilationState*>( return std::unique_ptr<CompilationState>(reinterpret_cast<CompilationState*>(
new CompilationStateImpl(native_module, std::move(async_counters)))); new CompilationStateImpl(native_module, std::move(async_counters))));
} }
...@@ -726,7 +730,7 @@ class BackgroundCompileTask : public CancelableTask { ...@@ -726,7 +730,7 @@ class BackgroundCompileTask : public CancelableTask {
} // namespace } // namespace
std::unique_ptr<NativeModule> CompileToNativeModule( std::shared_ptr<NativeModule> CompileToNativeModule(
Isolate* isolate, const WasmFeatures& enabled, ErrorThrower* thrower, Isolate* isolate, const WasmFeatures& enabled, ErrorThrower* thrower,
std::shared_ptr<const WasmModule> module, const ModuleWireBytes& wire_bytes, std::shared_ptr<const WasmModule> module, const ModuleWireBytes& wire_bytes,
Handle<FixedArray>* export_wrappers_out) { Handle<FixedArray>* export_wrappers_out) {
...@@ -1485,8 +1489,9 @@ bool AsyncStreamingProcessor::Deserialize(Vector<const uint8_t> module_bytes, ...@@ -1485,8 +1489,9 @@ bool AsyncStreamingProcessor::Deserialize(Vector<const uint8_t> module_bytes,
} }
CompilationStateImpl::CompilationStateImpl( CompilationStateImpl::CompilationStateImpl(
NativeModule* native_module, std::shared_ptr<Counters> async_counters) const std::shared_ptr<NativeModule>& native_module,
: native_module_(native_module), std::shared_ptr<Counters> async_counters)
: native_module_(native_module.get()),
background_compile_token_( background_compile_token_(
std::make_shared<BackgroundCompileToken>(native_module)), std::make_shared<BackgroundCompileToken>(native_module)),
compile_mode_(FLAG_wasm_tier_up && compile_mode_(FLAG_wasm_tier_up &&
......
...@@ -37,7 +37,7 @@ class NativeModule; ...@@ -37,7 +37,7 @@ class NativeModule;
class WasmCode; class WasmCode;
struct WasmModule; struct WasmModule;
std::unique_ptr<NativeModule> CompileToNativeModule( std::shared_ptr<NativeModule> CompileToNativeModule(
Isolate* isolate, const WasmFeatures& enabled, ErrorThrower* thrower, Isolate* isolate, const WasmFeatures& enabled, ErrorThrower* thrower,
std::shared_ptr<const WasmModule> module, const ModuleWireBytes& wire_bytes, std::shared_ptr<const WasmModule> module, const ModuleWireBytes& wire_bytes,
Handle<FixedArray>* export_wrappers_out); Handle<FixedArray>* export_wrappers_out);
......
...@@ -368,11 +368,10 @@ WasmCode::~WasmCode() { ...@@ -368,11 +368,10 @@ WasmCode::~WasmCode() {
NativeModule::NativeModule(WasmEngine* engine, const WasmFeatures& enabled, NativeModule::NativeModule(WasmEngine* engine, const WasmFeatures& enabled,
bool can_request_more, VirtualMemory code_space, bool can_request_more, VirtualMemory code_space,
std::shared_ptr<const WasmModule> module, std::shared_ptr<const WasmModule> module,
std::shared_ptr<Counters> async_counters) std::shared_ptr<Counters> async_counters,
std::shared_ptr<NativeModule>* shared_this)
: enabled_features_(enabled), : enabled_features_(enabled),
module_(std::move(module)), module_(std::move(module)),
compilation_state_(
CompilationState::New(this, std::move(async_counters))),
import_wrapper_cache_(std::unique_ptr<WasmImportWrapperCache>( import_wrapper_cache_(std::unique_ptr<WasmImportWrapperCache>(
new WasmImportWrapperCache(this))), new WasmImportWrapperCache(this))),
free_code_space_(code_space.region()), free_code_space_(code_space.region()),
...@@ -380,6 +379,13 @@ NativeModule::NativeModule(WasmEngine* engine, const WasmFeatures& enabled, ...@@ -380,6 +379,13 @@ NativeModule::NativeModule(WasmEngine* engine, const WasmFeatures& enabled,
can_request_more_memory_(can_request_more), can_request_more_memory_(can_request_more),
use_trap_handler_(trap_handler::IsTrapHandlerEnabled() ? kUseTrapHandler use_trap_handler_(trap_handler::IsTrapHandlerEnabled() ? kUseTrapHandler
: kNoTrapHandler) { : kNoTrapHandler) {
// We receive a pointer to an empty {std::shared_ptr}, and install ourselve
// there.
DCHECK_NOT_NULL(shared_this);
DCHECK_NULL(*shared_this);
shared_this->reset(this);
compilation_state_ =
CompilationState::New(*shared_this, std::move(async_counters));
DCHECK_NOT_NULL(module_); DCHECK_NOT_NULL(module_);
owned_code_space_.emplace_back(std::move(code_space)); owned_code_space_.emplace_back(std::move(code_space));
owned_code_.reserve(num_functions()); owned_code_.reserve(num_functions());
...@@ -1075,7 +1081,7 @@ size_t WasmCodeManager::EstimateNativeModuleNonCodeSize( ...@@ -1075,7 +1081,7 @@ size_t WasmCodeManager::EstimateNativeModuleNonCodeSize(
return wasm_module_estimate + native_module_estimate; return wasm_module_estimate + native_module_estimate;
} }
std::unique_ptr<NativeModule> WasmCodeManager::NewNativeModule( std::shared_ptr<NativeModule> WasmCodeManager::NewNativeModule(
WasmEngine* engine, Isolate* isolate, const WasmFeatures& enabled, WasmEngine* engine, Isolate* isolate, const WasmFeatures& enabled,
size_t code_size_estimate, bool can_request_more, size_t code_size_estimate, bool can_request_more,
std::shared_ptr<const WasmModule> module) { std::shared_ptr<const WasmModule> module) {
...@@ -1111,9 +1117,11 @@ std::unique_ptr<NativeModule> WasmCodeManager::NewNativeModule( ...@@ -1111,9 +1117,11 @@ std::unique_ptr<NativeModule> WasmCodeManager::NewNativeModule(
Address start = code_space.address(); Address start = code_space.address();
size_t size = code_space.size(); size_t size = code_space.size();
Address end = code_space.end(); Address end = code_space.end();
std::unique_ptr<NativeModule> ret( std::shared_ptr<NativeModule> ret;
new NativeModule(engine, enabled, can_request_more, std::move(code_space), new NativeModule(engine, enabled, can_request_more, std::move(code_space),
std::move(module), isolate->async_counters())); std::move(module), isolate->async_counters(), &ret);
// The constructor initialized the shared_ptr.
DCHECK_NOT_NULL(ret);
TRACE_HEAP("New NativeModule %p: Mem: %" PRIuPTR ",+%zu\n", ret.get(), start, TRACE_HEAP("New NativeModule %p: Mem: %" PRIuPTR ",+%zu\n", ret.get(), start,
size); size);
base::MutexGuard lock(&native_modules_mutex_); base::MutexGuard lock(&native_modules_mutex_);
......
...@@ -371,10 +371,12 @@ class V8_EXPORT_PRIVATE NativeModule final { ...@@ -371,10 +371,12 @@ class V8_EXPORT_PRIVATE NativeModule final {
friend class WasmCodeManager; friend class WasmCodeManager;
friend class NativeModuleModificationScope; friend class NativeModuleModificationScope;
// Private constructor, called via {WasmCodeManager::NewNativeModule()}.
NativeModule(WasmEngine* engine, const WasmFeatures& enabled_features, NativeModule(WasmEngine* engine, const WasmFeatures& enabled_features,
bool can_request_more, VirtualMemory code_space, bool can_request_more, VirtualMemory code_space,
std::shared_ptr<const WasmModule> module, std::shared_ptr<const WasmModule> module,
std::shared_ptr<Counters> async_counters); std::shared_ptr<Counters> async_counters,
std::shared_ptr<NativeModule>* shared_this);
WasmCode* AddAnonymousCode(Handle<Code>, WasmCode::Kind kind, WasmCode* AddAnonymousCode(Handle<Code>, WasmCode::Kind kind,
const char* name = nullptr); const char* name = nullptr);
...@@ -518,7 +520,7 @@ class V8_EXPORT_PRIVATE WasmCodeManager final { ...@@ -518,7 +520,7 @@ class V8_EXPORT_PRIVATE WasmCodeManager final {
friend class NativeModule; friend class NativeModule;
friend class WasmEngine; friend class WasmEngine;
std::unique_ptr<NativeModule> NewNativeModule( std::shared_ptr<NativeModule> NewNativeModule(
WasmEngine* engine, Isolate* isolate, WasmEngine* engine, Isolate* isolate,
const WasmFeatures& enabled_features, size_t code_size_estimate, const WasmFeatures& enabled_features, size_t code_size_estimate,
bool can_request_more, std::shared_ptr<const WasmModule> module); bool can_request_more, std::shared_ptr<const WasmModule> module);
......
...@@ -140,7 +140,7 @@ MaybeHandle<AsmWasmData> WasmEngine::SyncCompileTranslatedAsmJs( ...@@ -140,7 +140,7 @@ MaybeHandle<AsmWasmData> WasmEngine::SyncCompileTranslatedAsmJs(
// Transfer ownership of the WasmModule to the {Managed<WasmModule>} generated // Transfer ownership of the WasmModule to the {Managed<WasmModule>} generated
// in {CompileToNativeModule}. // in {CompileToNativeModule}.
Handle<FixedArray> export_wrappers; Handle<FixedArray> export_wrappers;
std::unique_ptr<NativeModule> native_module = std::shared_ptr<NativeModule> native_module =
CompileToNativeModule(isolate, kAsmjsWasmFeatures, thrower, CompileToNativeModule(isolate, kAsmjsWasmFeatures, thrower,
std::move(result).value(), bytes, &export_wrappers); std::move(result).value(), bytes, &export_wrappers);
if (!native_module) return {}; if (!native_module) return {};
...@@ -188,7 +188,7 @@ MaybeHandle<WasmModuleObject> WasmEngine::SyncCompile( ...@@ -188,7 +188,7 @@ MaybeHandle<WasmModuleObject> WasmEngine::SyncCompile(
// Transfer ownership of the WasmModule to the {Managed<WasmModule>} generated // Transfer ownership of the WasmModule to the {Managed<WasmModule>} generated
// in {CompileToModuleObject}. // in {CompileToModuleObject}.
Handle<FixedArray> export_wrappers; Handle<FixedArray> export_wrappers;
std::unique_ptr<NativeModule> native_module = std::shared_ptr<NativeModule> native_module =
CompileToNativeModule(isolate, enabled, thrower, CompileToNativeModule(isolate, enabled, thrower,
std::move(result).value(), bytes, &export_wrappers); std::move(result).value(), bytes, &export_wrappers);
if (!native_module) return {}; if (!native_module) return {};
...@@ -487,10 +487,10 @@ void WasmEngine::EnableCodeLogging(Isolate* isolate) { ...@@ -487,10 +487,10 @@ void WasmEngine::EnableCodeLogging(Isolate* isolate) {
it->second->log_codes = true; it->second->log_codes = true;
} }
std::unique_ptr<NativeModule> WasmEngine::NewNativeModule( std::shared_ptr<NativeModule> WasmEngine::NewNativeModule(
Isolate* isolate, const WasmFeatures& enabled, size_t code_size_estimate, Isolate* isolate, const WasmFeatures& enabled, size_t code_size_estimate,
bool can_request_more, std::shared_ptr<const WasmModule> module) { bool can_request_more, std::shared_ptr<const WasmModule> module) {
std::unique_ptr<NativeModule> native_module = std::shared_ptr<NativeModule> native_module =
code_manager_.NewNativeModule(this, isolate, enabled, code_size_estimate, code_manager_.NewNativeModule(this, isolate, enabled, code_size_estimate,
can_request_more, std::move(module)); can_request_more, std::move(module));
base::MutexGuard lock(&mutex_); base::MutexGuard lock(&mutex_);
......
...@@ -169,7 +169,7 @@ class V8_EXPORT_PRIVATE WasmEngine { ...@@ -169,7 +169,7 @@ class V8_EXPORT_PRIVATE WasmEngine {
// is determined with a heuristic based on the total size of wasm // is determined with a heuristic based on the total size of wasm
// code. The native module may later request more memory. // code. The native module may later request more memory.
// TODO(titzer): isolate is only required here for CompilationState. // TODO(titzer): isolate is only required here for CompilationState.
std::unique_ptr<NativeModule> NewNativeModule( std::shared_ptr<NativeModule> NewNativeModule(
Isolate* isolate, const WasmFeatures& enabled_features, Isolate* isolate, const WasmFeatures& enabled_features,
size_t code_size_estimate, bool can_request_more, size_t code_size_estimate, bool can_request_more,
std::shared_ptr<const WasmModule> module); std::shared_ptr<const WasmModule> module);
......
...@@ -118,7 +118,7 @@ Node* ToInt32(RawMachineAssembler& m, MachineType type, Node* a) { ...@@ -118,7 +118,7 @@ Node* ToInt32(RawMachineAssembler& m, MachineType type, Node* a) {
} }
} }
std::unique_ptr<wasm::NativeModule> AllocateNativeModule(Isolate* isolate, std::shared_ptr<wasm::NativeModule> AllocateNativeModule(Isolate* isolate,
size_t code_size) { size_t code_size) {
std::shared_ptr<wasm::WasmModule> module(new wasm::WasmModule()); std::shared_ptr<wasm::WasmModule> module(new wasm::WasmModule());
module->num_declared_functions = 1; module->num_declared_functions = 1;
...@@ -183,7 +183,7 @@ void TestReturnMultipleValues(MachineType type) { ...@@ -183,7 +183,7 @@ void TestReturnMultipleValues(MachineType type) {
if (i % 4 == 0) sign = -sign; if (i % 4 == 0) sign = -sign;
} }
std::unique_ptr<wasm::NativeModule> module = AllocateNativeModule( std::shared_ptr<wasm::NativeModule> module = AllocateNativeModule(
handles.main_isolate(), code->raw_instruction_size()); handles.main_isolate(), code->raw_instruction_size());
byte* code_start = byte* code_start =
module->AddCodeForTesting(code)->instructions().start(); module->AddCodeForTesting(code)->instructions().start();
...@@ -272,7 +272,7 @@ void ReturnLastValue(MachineType type) { ...@@ -272,7 +272,7 @@ void ReturnLastValue(MachineType type) {
AssemblerOptions::Default(handles.main_isolate()), m.Export()) AssemblerOptions::Default(handles.main_isolate()), m.Export())
.ToHandleChecked(); .ToHandleChecked();
std::unique_ptr<wasm::NativeModule> module = AllocateNativeModule( std::shared_ptr<wasm::NativeModule> module = AllocateNativeModule(
handles.main_isolate(), code->raw_instruction_size()); handles.main_isolate(), code->raw_instruction_size());
byte* code_start = module->AddCodeForTesting(code)->instructions().start(); byte* code_start = module->AddCodeForTesting(code)->instructions().start();
...@@ -333,7 +333,7 @@ void ReturnSumOfReturns(MachineType type) { ...@@ -333,7 +333,7 @@ void ReturnSumOfReturns(MachineType type) {
AssemblerOptions::Default(handles.main_isolate()), m.Export()) AssemblerOptions::Default(handles.main_isolate()), m.Export())
.ToHandleChecked(); .ToHandleChecked();
std::unique_ptr<wasm::NativeModule> module = AllocateNativeModule( std::shared_ptr<wasm::NativeModule> module = AllocateNativeModule(
handles.main_isolate(), code->raw_instruction_size()); handles.main_isolate(), code->raw_instruction_size());
byte* code_start = module->AddCodeForTesting(code)->instructions().start(); byte* code_start = module->AddCodeForTesting(code)->instructions().start();
......
...@@ -17,7 +17,7 @@ namespace internal { ...@@ -17,7 +17,7 @@ namespace internal {
namespace wasm { namespace wasm {
namespace test_wasm_import_wrapper_cache { namespace test_wasm_import_wrapper_cache {
std::unique_ptr<NativeModule> NewModule(Isolate* isolate) { std::shared_ptr<NativeModule> NewModule(Isolate* isolate) {
std::shared_ptr<WasmModule> module(new WasmModule); std::shared_ptr<WasmModule> module(new WasmModule);
bool can_request_more = false; bool can_request_more = false;
size_t size = 16384; size_t size = 16384;
......
...@@ -134,7 +134,7 @@ CallDescriptor* CreateRandomCallDescriptor(Zone* zone, size_t return_count, ...@@ -134,7 +134,7 @@ CallDescriptor* CreateRandomCallDescriptor(Zone* zone, size_t return_count,
return compiler::GetWasmCallDescriptor(zone, builder.Build()); return compiler::GetWasmCallDescriptor(zone, builder.Build());
} }
std::unique_ptr<wasm::NativeModule> AllocateNativeModule(i::Isolate* isolate, std::shared_ptr<wasm::NativeModule> AllocateNativeModule(i::Isolate* isolate,
size_t code_size) { size_t code_size) {
std::shared_ptr<wasm::WasmModule> module(new wasm::WasmModule); std::shared_ptr<wasm::WasmModule> module(new wasm::WasmModule);
module->num_declared_functions = 1; module->num_declared_functions = 1;
...@@ -243,7 +243,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { ...@@ -243,7 +243,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
AssemblerOptions::Default(i_isolate), callee.Export()) AssemblerOptions::Default(i_isolate), callee.Export())
.ToHandleChecked(); .ToHandleChecked();
std::unique_ptr<wasm::NativeModule> module = std::shared_ptr<wasm::NativeModule> module =
AllocateNativeModule(i_isolate, code->raw_instruction_size()); AllocateNativeModule(i_isolate, code->raw_instruction_size());
byte* code_start = module->AddCodeForTesting(code)->instructions().start(); byte* code_start = module->AddCodeForTesting(code)->instructions().start();
// Generate wrapper. // Generate wrapper.
......
...@@ -159,7 +159,7 @@ class WasmCodeManagerTest : public TestWithContext, ...@@ -159,7 +159,7 @@ class WasmCodeManagerTest : public TestWithContext,
static constexpr uint32_t kJumpTableSize = RoundUp<kCodeAlignment>( static constexpr uint32_t kJumpTableSize = RoundUp<kCodeAlignment>(
JumpTableAssembler::SizeForNumberOfSlots(kNumFunctions)); JumpTableAssembler::SizeForNumberOfSlots(kNumFunctions));
using NativeModulePtr = std::unique_ptr<NativeModule>; using NativeModulePtr = std::shared_ptr<NativeModule>;
NativeModulePtr AllocModule(size_t size, ModuleStyle style) { NativeModulePtr AllocModule(size_t size, ModuleStyle style) {
std::shared_ptr<WasmModule> module(new WasmModule); std::shared_ptr<WasmModule> module(new WasmModule);
......
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